// // Copyright (c) PlaceholderCompany. All rights reserved. // namespace Emby.Naming.ExternalFiles { using System; using System.IO; using System.Linq; using Emby.Naming.Common; using Jellyfin.Extensions; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; /// /// External media file parser class. /// public class ExternalPathParser { private readonly NamingOptions _namingOptions; private readonly DlnaProfileType _type; private readonly ILocalizationManager _localizationManager; /// /// Initializes a new instance of the class. /// /// The localization manager. /// The object containing FileExtensions, MediaDefaultFlags, MediaForcedFlags and MediaFlagDelimiters. /// The of the parsed file. public ExternalPathParser(NamingOptions namingOptions, ILocalizationManager localizationManager, DlnaProfileType type) { this._localizationManager = localizationManager; this._namingOptions = namingOptions; this._type = type; } /// /// Parse filename and extract information. /// /// Path to file. /// Part of the filename only containing the extra information. /// Returns null or an object if parsing is successful. public ExternalPathParserResult? ParseFile(string path, string? extraString) { if (path.Length == 0) { return null; } var extension = Path.GetExtension(path.AsSpan()); if (!(this._type == DlnaProfileType.Subtitle && this._namingOptions.SubtitleFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)) && !(this._type == DlnaProfileType.Audio && this._namingOptions.AudioFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase)) && !(this._type == DlnaProfileType.Lyric && this._namingOptions.LyricFileExtensions.Contains(extension, StringComparison.OrdinalIgnoreCase))) { return null; } var pathInfo = new ExternalPathParserResult(path); if (string.IsNullOrEmpty(extraString)) { return pathInfo; } foreach (var separator in this._namingOptions.MediaFlagDelimiters) { var languageString = extraString; var titleString = string.Empty; const int SeparatorLength = 1; while (languageString.Length > 0) { int lastSeparator = languageString.LastIndexOf(separator, StringComparison.Ordinal); if (lastSeparator == -1) { break; } string currentSlice = languageString[lastSeparator..]; string currentSliceWithoutSeparator = currentSlice[SeparatorLength..]; if (this._namingOptions.MediaDefaultFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase))) { pathInfo.IsDefault = true; extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); languageString = languageString[..lastSeparator]; continue; } if (this._namingOptions.MediaForcedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase))) { pathInfo.IsForced = true; extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); languageString = languageString[..lastSeparator]; continue; } // Try to translate to three character code var culture = this._localizationManager.FindLanguageInfo(currentSliceWithoutSeparator); if (culture is not null && pathInfo.Language is null) { pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase) ? culture.Name : culture.ThreeLetterISOLanguageName; extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); } else if (culture is not null && pathInfo.Language == "hin") { // Hindi language code "hi" collides with a hearing impaired flag - use as Hindi only if no other language is set pathInfo.IsHearingImpaired = true; pathInfo.Language = culture.Name.Contains('-', StringComparison.OrdinalIgnoreCase) ? culture.Name : culture.ThreeLetterISOLanguageName; extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); } else if (this._namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase))) { pathInfo.IsHearingImpaired = true; extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase); } else { titleString = currentSlice + titleString; } languageString = languageString[..lastSeparator]; } pathInfo.Title = titleString.Length >= SeparatorLength ? titleString[SeparatorLength..] : null; } return pathInfo; } } }