ExternalPathParser.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using Emby.Naming.Common;
  5. using Jellyfin.Extensions;
  6. using MediaBrowser.Model.Dlna;
  7. using MediaBrowser.Model.Globalization;
  8. namespace Emby.Naming.ExternalFiles
  9. {
  10. /// <summary>
  11. /// External media file parser class.
  12. /// </summary>
  13. public class ExternalPathParser
  14. {
  15. private readonly NamingOptions _namingOptions;
  16. private readonly DlnaProfileType _type;
  17. private readonly ILocalizationManager _localizationManager;
  18. /// <summary>
  19. /// Initializes a new instance of the <see cref="ExternalPathParser"/> class.
  20. /// </summary>
  21. /// <param name="localizationManager">The localization manager.</param>
  22. /// <param name="namingOptions">The <see cref="NamingOptions"/> object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters.</param>
  23. /// <param name="type">The <see cref="DlnaProfileType"/> of the parsed file.</param>
  24. public ExternalPathParser(NamingOptions namingOptions, ILocalizationManager localizationManager, DlnaProfileType type)
  25. {
  26. _localizationManager = localizationManager;
  27. _namingOptions = namingOptions;
  28. _type = type;
  29. }
  30. /// <summary>
  31. /// Parse filename and extract information.
  32. /// </summary>
  33. /// <param name="path">Path to file.</param>
  34. /// <param name="extraString">Part of the filename only containing the extra information.</param>
  35. /// <returns>Returns null or an <see cref="ExternalPathParserResult"/> object if parsing is successful.</returns>
  36. public ExternalPathParserResult? ParseFile(string path, string? extraString)
  37. {
  38. if (path.Length == 0)
  39. {
  40. return null;
  41. }
  42. var extension = Path.GetExtension(path.AsSpan());
  43. if (!(_type == DlnaProfileType.Subtitle && _namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
  44. && !(_type == DlnaProfileType.Audio && _namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
  45. && !(_type == DlnaProfileType.Lyric && _namingOptions.LyricFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)))
  46. {
  47. return null;
  48. }
  49. var pathInfo = new ExternalPathParserResult(path);
  50. if (string.IsNullOrEmpty(extraString))
  51. {
  52. return pathInfo;
  53. }
  54. foreach (var separator in _namingOptions.MediaFlagDelimiters)
  55. {
  56. var languageString = extraString;
  57. var titleString = string.Empty;
  58. const int SeparatorLength = 1;
  59. while (languageString.Length > 0)
  60. {
  61. int lastSeparator = languageString.LastIndexOf(separator);
  62. if (lastSeparator == -1)
  63. {
  64. break;
  65. }
  66. string currentSlice = languageString[lastSeparator..];
  67. string currentSliceWithoutSeparator = currentSlice[SeparatorLength..];
  68. if (_namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
  69. {
  70. pathInfo.IsDefault = true;
  71. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  72. languageString = languageString[..lastSeparator];
  73. continue;
  74. }
  75. if (_namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
  76. {
  77. pathInfo.IsForced = true;
  78. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  79. languageString = languageString[..lastSeparator];
  80. continue;
  81. }
  82. // Try to translate to three character code
  83. var culture = _localizationManager.FindLanguageInfo(currentSliceWithoutSeparator);
  84. if (culture is not null && pathInfo.Language is null)
  85. {
  86. pathInfo.Language = culture.ThreeLetterISOLanguageName;
  87. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  88. }
  89. else if (culture is not null && pathInfo.Language == "hin")
  90. {
  91. // Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
  92. pathInfo.IsHearingImpaired = true;
  93. pathInfo.Language = culture.ThreeLetterISOLanguageName;
  94. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  95. }
  96. else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase)))
  97. {
  98. pathInfo.IsHearingImpaired = true;
  99. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  100. }
  101. else
  102. {
  103. titleString = currentSlice + titleString;
  104. }
  105. languageString = languageString[..lastSeparator];
  106. }
  107. pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null;
  108. }
  109. return pathInfo;
  110. }
  111. }
  112. }