SubtitleResolver.cs 6.6 KB

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