ExternalPathParser.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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);
  43. if (!(_type == DlnaProfileType.Subtitle && _namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))
  44. && !(_type == DlnaProfileType.Audio && _namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)))
  45. {
  46. return null;
  47. }
  48. var pathInfo = new ExternalPathParserResult(path);
  49. if (string.IsNullOrEmpty(extraString))
  50. {
  51. return pathInfo;
  52. }
  53. foreach (var separator in _namingOptions.MediaFlagDelimiters)
  54. {
  55. var languageString = extraString;
  56. var titleString = string.Empty;
  57. const int SeparatorLength = 1;
  58. while (languageString.Length > 0)
  59. {
  60. int lastSeparator = languageString.LastIndexOf(separator);
  61. if (lastSeparator == -1)
  62. {
  63. break;
  64. }
  65. string currentSlice = languageString[lastSeparator..];
  66. string currentSliceWithoutSeparator = currentSlice[SeparatorLength..];
  67. if (_namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
  68. {
  69. pathInfo.IsDefault = true;
  70. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  71. languageString = languageString[..lastSeparator];
  72. continue;
  73. }
  74. if (_namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
  75. {
  76. pathInfo.IsForced = true;
  77. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  78. languageString = languageString[..lastSeparator];
  79. continue;
  80. }
  81. // Try to translate to three character code
  82. var culture = _localizationManager.FindLanguageInfo(currentSliceWithoutSeparator);
  83. if (culture is not null && pathInfo.Language is null)
  84. {
  85. pathInfo.Language = culture.ThreeLetterISOLanguageName;
  86. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  87. }
  88. else if (culture is not null && pathInfo.Language == "hin")
  89. {
  90. // Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set
  91. pathInfo.IsHearingImpaired = true;
  92. pathInfo.Language = culture.ThreeLetterISOLanguageName;
  93. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  94. }
  95. else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
  96. {
  97. pathInfo.IsHearingImpaired = true;
  98. extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
  99. }
  100. else
  101. {
  102. titleString = currentSlice + titleString;
  103. }
  104. languageString = languageString[..lastSeparator];
  105. }
  106. pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null;
  107. }
  108. return pathInfo;
  109. }
  110. }
  111. }