SubtitleResolver.cs 6.4 KB

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