SubtitleResolver.cs 6.3 KB

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