SubtitleResolver.cs 7.0 KB

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