SubtitleResolver.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using MediaBrowser.Model.Extensions;
  2. using MediaBrowser.Controller.Entities;
  3. using MediaBrowser.Controller.Providers;
  4. using MediaBrowser.Model.Entities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using MediaBrowser.Model.IO;
  10. using MediaBrowser.Model.Globalization;
  11. namespace MediaBrowser.Providers.MediaInfo
  12. {
  13. public class SubtitleResolver
  14. {
  15. private readonly ILocalizationManager _localization;
  16. private readonly IFileSystem _fileSystem;
  17. public SubtitleResolver(ILocalizationManager localization, IFileSystem fileSystem)
  18. {
  19. _localization = localization;
  20. _fileSystem = fileSystem;
  21. }
  22. public IEnumerable<MediaStream> GetExternalSubtitleStreams(Video video,
  23. int startIndex,
  24. IDirectoryService directoryService,
  25. bool clearCache)
  26. {
  27. var files = GetSubtitleFiles(video, directoryService, _fileSystem, clearCache);
  28. var streams = new List<MediaStream>();
  29. var videoFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(video.Path);
  30. videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension);
  31. foreach (var fullName in files)
  32. {
  33. var fileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(fullName);
  34. fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension);
  35. var codec = Path.GetExtension(fullName).ToLower().TrimStart('.');
  36. if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
  37. {
  38. codec = "srt";
  39. }
  40. // If the subtitle file matches the video file name
  41. if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
  42. {
  43. streams.Add(new MediaStream
  44. {
  45. Index = startIndex++,
  46. Type = MediaStreamType.Subtitle,
  47. IsExternal = true,
  48. Path = fullName,
  49. Codec = codec
  50. });
  51. }
  52. else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
  53. {
  54. var isForced = fullName.IndexOf(".forced.", StringComparison.OrdinalIgnoreCase) != -1 ||
  55. fullName.IndexOf(".foreign.", StringComparison.OrdinalIgnoreCase) != -1;
  56. var isDefault = fullName.IndexOf(".default.", StringComparison.OrdinalIgnoreCase) != -1;
  57. // Support xbmc naming conventions - 300.spanish.srt
  58. var language = fileNameWithoutExtension
  59. .Replace(".forced", string.Empty, StringComparison.OrdinalIgnoreCase)
  60. .Replace(".foreign", string.Empty, StringComparison.OrdinalIgnoreCase)
  61. .Split('.')
  62. .LastOrDefault();
  63. // Try to translate to three character code
  64. // Be flexible and check against both the full and three character versions
  65. var culture = _localization.GetCultures()
  66. .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) ||
  67. string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) ||
  68. string.Equals(i.ThreeLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase) ||
  69. string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase));
  70. if (culture != null)
  71. {
  72. language = culture.ThreeLetterISOLanguageName;
  73. }
  74. streams.Add(new MediaStream
  75. {
  76. Index = startIndex++,
  77. Type = MediaStreamType.Subtitle,
  78. IsExternal = true,
  79. Path = fullName,
  80. Codec = codec,
  81. Language = language,
  82. IsForced = isForced,
  83. IsDefault = isDefault
  84. });
  85. }
  86. }
  87. return streams;
  88. }
  89. private string NormalizeFilenameForSubtitleComparison(string filename)
  90. {
  91. // Try to account for sloppy file naming
  92. filename = filename.Replace("_", string.Empty);
  93. filename = filename.Replace(" ", string.Empty);
  94. // can't normalize this due to languages such as pt-br
  95. //filename = filename.Replace("-", string.Empty);
  96. //filename = filename.Replace(".", string.Empty);
  97. return filename;
  98. }
  99. private static IEnumerable<string> SubtitleExtensions
  100. {
  101. get
  102. {
  103. return new[] { ".srt", ".ssa", ".ass", ".sub", ".smi", ".sami" };
  104. }
  105. }
  106. public static IEnumerable<string> GetSubtitleFiles(Video video, IDirectoryService directoryService, IFileSystem fileSystem, bool clearCache)
  107. {
  108. var containingPath = video.ContainingFolderPath;
  109. if (string.IsNullOrEmpty(containingPath))
  110. {
  111. throw new ArgumentException(string.Format("Cannot search for items that don't have a path: {0} {1}", video.Name, video.Id));
  112. }
  113. var files = directoryService.GetFilePaths(containingPath, clearCache);
  114. var videoFileNameWithoutExtension = fileSystem.GetFileNameWithoutExtension(video.Path);
  115. return files.Where(i =>
  116. {
  117. var extension = Path.GetExtension(i);
  118. if (SubtitleExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
  119. {
  120. var fileNameWithoutExtension = fileSystem.GetFileNameWithoutExtension(i);
  121. if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
  122. {
  123. return true;
  124. }
  125. if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
  126. {
  127. return true;
  128. }
  129. }
  130. return false;
  131. });
  132. }
  133. }
  134. }