SubtitleResolver.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using MediaBrowser.Controller.Entities;
  6. using MediaBrowser.Controller.Providers;
  7. using MediaBrowser.Model.Entities;
  8. using MediaBrowser.Model.Globalization;
  9. using MediaBrowser.Model.IO;
  10. namespace MediaBrowser.Providers.MediaInfo
  11. {
  12. public class SubtitleResolver
  13. {
  14. private readonly ILocalizationManager _localization;
  15. private readonly IFileSystem _fileSystem;
  16. private static readonly HashSet<string> SubtitleExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
  17. {
  18. ".srt",
  19. ".ssa",
  20. ".ass",
  21. ".sub",
  22. ".smi",
  23. ".sami",
  24. ".vtt"
  25. };
  26. public SubtitleResolver(ILocalizationManager localization, IFileSystem fileSystem)
  27. {
  28. _localization = localization;
  29. _fileSystem = fileSystem;
  30. }
  31. public List<MediaStream> GetExternalSubtitleStreams(Video video,
  32. int startIndex,
  33. IDirectoryService directoryService,
  34. bool clearCache)
  35. {
  36. var streams = new List<MediaStream>();
  37. if (!video.IsFileProtocol)
  38. {
  39. return streams;
  40. }
  41. AddExternalSubtitleStreams(streams, video.ContainingFolderPath, video.Path, startIndex, directoryService, clearCache);
  42. startIndex += streams.Count;
  43. string folder = video.GetInternalMetadataPath();
  44. if (!Directory.Exists(folder))
  45. {
  46. return streams;
  47. }
  48. try
  49. {
  50. AddExternalSubtitleStreams(streams, folder, video.Path, startIndex, directoryService, clearCache);
  51. }
  52. catch (IOException)
  53. {
  54. }
  55. return streams;
  56. }
  57. public List<string> GetExternalSubtitleFiles(Video video,
  58. IDirectoryService directoryService,
  59. bool clearCache)
  60. {
  61. var list = new List<string>();
  62. if (!video.IsFileProtocol)
  63. {
  64. return list;
  65. }
  66. var streams = GetExternalSubtitleStreams(video, 0, directoryService, clearCache);
  67. foreach (var stream in streams)
  68. {
  69. list.Add(stream.Path);
  70. }
  71. return list;
  72. }
  73. private void AddExternalSubtitleStreams(List<MediaStream> streams, string folder,
  74. string videoPath,
  75. int startIndex,
  76. IDirectoryService directoryService,
  77. bool clearCache)
  78. {
  79. var files = directoryService.GetFilePaths(folder, clearCache).OrderBy(i => i).ToArray();
  80. AddExternalSubtitleStreams(streams, videoPath, startIndex, files);
  81. }
  82. public void AddExternalSubtitleStreams(List<MediaStream> streams,
  83. string videoPath,
  84. int startIndex,
  85. string[] files)
  86. {
  87. var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoPath);
  88. videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension);
  89. foreach (var fullName in files)
  90. {
  91. var extension = Path.GetExtension(fullName);
  92. if (!SubtitleExtensions.Contains(extension))
  93. {
  94. continue;
  95. }
  96. var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName);
  97. fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension);
  98. if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) &&
  99. !fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
  100. {
  101. continue;
  102. }
  103. var codec = Path.GetExtension(fullName).ToLowerInvariant().TrimStart('.');
  104. if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase))
  105. {
  106. codec = "srt";
  107. }
  108. // If the subtitle file matches the video file name
  109. if (string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
  110. {
  111. streams.Add(new MediaStream
  112. {
  113. Index = startIndex++,
  114. Type = MediaStreamType.Subtitle,
  115. IsExternal = true,
  116. Path = fullName,
  117. Codec = codec
  118. });
  119. }
  120. else if (fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension + ".", StringComparison.OrdinalIgnoreCase))
  121. {
  122. var isForced = fullName.IndexOf(".forced.", StringComparison.OrdinalIgnoreCase) != -1 ||
  123. fullName.IndexOf(".foreign.", StringComparison.OrdinalIgnoreCase) != -1;
  124. var isDefault = fullName.IndexOf(".default.", StringComparison.OrdinalIgnoreCase) != -1;
  125. // Support xbmc naming conventions - 300.spanish.srt
  126. var language = fileNameWithoutExtension
  127. .Replace(".forced", string.Empty, StringComparison.OrdinalIgnoreCase)
  128. .Replace(".foreign", string.Empty, StringComparison.OrdinalIgnoreCase)
  129. .Replace(".default", string.Empty, StringComparison.OrdinalIgnoreCase)
  130. .Split('.')
  131. .LastOrDefault();
  132. // Try to translate to three character code
  133. // Be flexible and check against both the full and three character versions
  134. var culture = _localization.FindLanguageInfo(language);
  135. if (culture != null)
  136. {
  137. language = culture.ThreeLetterISOLanguageName;
  138. }
  139. streams.Add(new MediaStream
  140. {
  141. Index = startIndex++,
  142. Type = MediaStreamType.Subtitle,
  143. IsExternal = true,
  144. Path = fullName,
  145. Codec = codec,
  146. Language = language,
  147. IsForced = isForced,
  148. IsDefault = isDefault
  149. });
  150. }
  151. }
  152. }
  153. private string NormalizeFilenameForSubtitleComparison(string filename)
  154. {
  155. // Try to account for sloppy file naming
  156. filename = filename.Replace("_", string.Empty);
  157. filename = filename.Replace(" ", string.Empty);
  158. // can't normalize this due to languages such as pt-br
  159. //filename = filename.Replace("-", string.Empty);
  160. //filename = filename.Replace(".", string.Empty);
  161. return filename;
  162. }
  163. }
  164. }