From 2db2b53f2551f4717a108057794fc37a9ee79028 Mon Sep 17 00:00:00 2001 From: Mikal Stordal Date: Fri, 29 Mar 2024 01:55:50 +0100 Subject: [PATCH] chore: flatten text util file --- Shokofin/Utils/Text.cs | 669 ++++++++++++++++++++--------------------- 1 file changed, 334 insertions(+), 335 deletions(-) diff --git a/Shokofin/Utils/Text.cs b/Shokofin/Utils/Text.cs index ca030fb9..81e0626b 100644 --- a/Shokofin/Utils/Text.cs +++ b/Shokofin/Utils/Text.cs @@ -5,389 +5,388 @@ using System.Linq; using System.Text.RegularExpressions; -namespace Shokofin.Utils +namespace Shokofin.Utils; + +public static class Text { - public static class Text - { - private static HashSet PunctuationMarks = new() { - // Common punctuation marks - '.', // period - ',', // comma - ';', // semicolon - ':', // colon - '!', // exclamation point - '?', // question mark - ')', // right parenthesis - ']', // right bracket - '}', // right brace - '"', // double quote - '\'', // single quote - ',', // Chinese comma - '、', // Chinese enumeration comma - '!', // Chinese exclamation point - '?', // Chinese question mark - '“', // Chinese double quote - '”', // Chinese double quote - '‘', // Chinese single quote - '’', // Chinese single quote - '】', // Chinese right bracket - '》', // Chinese right angle bracket - ')', // Chinese right parenthesis - '・', // Japanese middle dot - - // Less common punctuation marks - '‽', // interrobang - '❞', // double question mark - '❝', // double exclamation mark - '⁇', // question mark variation - '⁈', // exclamation mark variation - '❕', // white exclamation mark - '❔', // white question mark - '‽', // interrobang - '⁉', // exclamation mark - '‽', // interrobang - '※', // reference mark - '⟩', // right angle bracket - '❯', // right angle bracket - '❭', // right angle bracket - '〉', // right angle bracket - '⌉', // right angle bracket - '⌋', // right angle bracket - '⦄', // right angle bracket - '⦆', // right angle bracket - '⦈', // right angle bracket - '⦊', // right angle bracket - '⦌', // right angle bracket - '⦎', // right angle bracket - }; + private static HashSet PunctuationMarks = new() { + // Common punctuation marks + '.', // period + ',', // comma + ';', // semicolon + ':', // colon + '!', // exclamation point + '?', // question mark + ')', // right parenthesis + ']', // right bracket + '}', // right brace + '"', // double quote + '\'', // single quote + ',', // Chinese comma + '、', // Chinese enumeration comma + '!', // Chinese exclamation point + '?', // Chinese question mark + '“', // Chinese double quote + '”', // Chinese double quote + '‘', // Chinese single quote + '’', // Chinese single quote + '】', // Chinese right bracket + '》', // Chinese right angle bracket + ')', // Chinese right parenthesis + '・', // Japanese middle dot + + // Less common punctuation marks + '‽', // interrobang + '❞', // double question mark + '❝', // double exclamation mark + '⁇', // question mark variation + '⁈', // exclamation mark variation + '❕', // white exclamation mark + '❔', // white question mark + '‽', // interrobang + '⁉', // exclamation mark + '‽', // interrobang + '※', // reference mark + '⟩', // right angle bracket + '❯', // right angle bracket + '❭', // right angle bracket + '〉', // right angle bracket + '⌉', // right angle bracket + '⌋', // right angle bracket + '⦄', // right angle bracket + '⦆', // right angle bracket + '⦈', // right angle bracket + '⦊', // right angle bracket + '⦌', // right angle bracket + '⦎', // right angle bracket + }; + + private static HashSet IgnoredSubTitles = new() { + "Complete Movie", + "OVA", + }; + + /// + /// Where to get text the text from. + /// + public enum TextSourceType { + /// + /// Use the default source for the current series grouping. + /// + Default = 1, - private static HashSet IgnoredSubTitles = new() { - "Complete Movie", - "OVA", - }; + /// + /// Only use AniDb, or null if no data is available. + /// + OnlyAniDb = 2, /// - /// Where to get text the text from. + /// Prefer the AniDb data, but use the other provider if there is no + /// AniDb data available. /// - public enum TextSourceType { - /// - /// Use the default source for the current series grouping. - /// - Default = 1, - - /// - /// Only use AniDb, or null if no data is available. - /// - OnlyAniDb = 2, - - /// - /// Prefer the AniDb data, but use the other provider if there is no - /// AniDb data available. - /// - PreferAniDb = 3, - - /// - /// Prefer the other provider (e.g. TvDB/TMDB) - /// - PreferOther = 4, - - /// - /// Only use the other provider, or null if no data is available. - /// - OnlyOther = 5, - } + PreferAniDb = 3, /// - /// Determines the language to construct the title in. + /// Prefer the other provider (e.g. TvDB/TMDB) /// - public enum DisplayLanguageType { - /// - /// Let Shoko decide what to display. - /// - Default = 1, - - /// - /// Prefer to use the selected metadata language for the library if - /// available, but fallback to the default view if it's not - /// available. - /// - MetadataPreferred = 2, - - /// - /// Use the origin language for the series. - /// - Origin = 3, - - /// - /// Don't display a title. - /// - Ignore = 4, - - /// - /// Use the main title for the series. - /// - Main = 5, - } + PreferOther = 4, /// - /// Determines the type of title to construct. + /// Only use the other provider, or null if no data is available. /// - public enum DisplayTitleType { - /// - /// Only construct the main title. - /// - MainTitle = 1, - - /// - /// Only construct the sub title. - /// - SubTitle = 2, - - /// - /// Construct a combined main and sub title. - /// - FullTitle = 3, - } + OnlyOther = 5, + } - public static string GetDescription(ShowInfo show) - => GetDescription(show.DefaultSeason); - - public static string GetDescription(SeasonInfo season) - => GetDescription(season.AniDB.Description, season.TvDB?.Description); - - public static string GetDescription(EpisodeInfo episode) - => GetDescription(episode.AniDB.Description, episode.TvDB?.Description); - - public static string GetDescription(IEnumerable episodeList) - => JoinText(episodeList.Select(episode => GetDescription(episode))); - - private static string GetDescription(string aniDbDescription, string otherDescription) - { - string overview; - switch (Plugin.Instance.Configuration.DescriptionSource) { - default: - case TextSourceType.PreferAniDb: - overview = SanitizeTextSummary(aniDbDescription); - if (string.IsNullOrEmpty(overview)) - goto case TextSourceType.OnlyOther; - break; - case TextSourceType.PreferOther: - overview = otherDescription ?? ""; - if (string.IsNullOrEmpty(overview)) - goto case TextSourceType.OnlyAniDb; - break; - case TextSourceType.OnlyAniDb: - overview = SanitizeTextSummary(aniDbDescription); - break; - case TextSourceType.OnlyOther: - overview = otherDescription ?? ""; - break; - } - return overview; - } + /// + /// Determines the language to construct the title in. + /// + public enum DisplayLanguageType { + /// + /// Let Shoko decide what to display. + /// + Default = 1, /// - /// Based on ShokoMetadata's summary sanitizer which in turn is based on HAMA's summary sanitizer. + /// Prefer to use the selected metadata language for the library if + /// available, but fallback to the default view if it's not + /// available. /// - /// The raw AniDB summary - /// The sanitized AniDB summary - public static string SanitizeTextSummary(string summary) - { - if (string.IsNullOrWhiteSpace(summary)) - return ""; + MetadataPreferred = 2, - var config = Plugin.Instance.Configuration; + /// + /// Use the origin language for the series. + /// + Origin = 3, - if (config.SynopsisCleanLinks) - summary = Regex.Replace(summary, @"https?:\/\/\w+.\w+(?:\/?\w+)? \[([^\]]+)\]", match => match.Groups[1].Value); + /// + /// Don't display a title. + /// + Ignore = 4, - if (config.SynopsisCleanMiscLines) - summary = Regex.Replace(summary, @"^(\*|--|~) .*", "", RegexOptions.Multiline); + /// + /// Use the main title for the series. + /// + Main = 5, + } - if (config.SynopsisRemoveSummary) - summary = Regex.Replace(summary, @"\n(Source|Note|Summary):.*", "", RegexOptions.Singleline); + /// + /// Determines the type of title to construct. + /// + public enum DisplayTitleType { + /// + /// Only construct the main title. + /// + MainTitle = 1, - if (config.SynopsisCleanMultiEmptyLines) - summary = Regex.Replace(summary, @"\n{2,}", "\n", RegexOptions.Singleline); + /// + /// Only construct the sub title. + /// + SubTitle = 2, - return summary.Trim(); - } + /// + /// Construct a combined main and sub title. + /// + FullTitle = 3, + } - public static ( string, string ) GetEpisodeTitles(IEnumerable seriesTitles, IEnumerable<Title> episodeTitles, string episodeTitle, string metadataLanguage) - => GetTitles(seriesTitles, episodeTitles, null, episodeTitle, DisplayTitleType.SubTitle, metadataLanguage); + public static string GetDescription(ShowInfo show) + => GetDescription(show.DefaultSeason); - public static ( string, string ) GetSeriesTitles(IEnumerable<Title> seriesTitles, string seriesTitle, string metadataLanguage) - => GetTitles(seriesTitles, null, seriesTitle, null, DisplayTitleType.MainTitle, metadataLanguage); + public static string GetDescription(SeasonInfo season) + => GetDescription(season.AniDB.Description, season.TvDB?.Description); - public static ( string, string ) GetMovieTitles(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, string metadataLanguage) - => GetTitles(seriesTitles, episodeTitles, seriesTitle, episodeTitle, DisplayTitleType.FullTitle, metadataLanguage); + public static string GetDescription(EpisodeInfo episode) + => GetDescription(episode.AniDB.Description, episode.TvDB?.Description); - public static ( string, string ) GetTitles(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayTitleType outputType, string metadataLanguage) - { - // Don't process anything if the series titles are not provided. - if (seriesTitles == null) - return (null, null); - return ( - GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleMainType, outputType, metadataLanguage), - GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleAlternateType, outputType, metadataLanguage) - ); + public static string GetDescription(IEnumerable<EpisodeInfo> episodeList) + => JoinText(episodeList.Select(episode => GetDescription(episode))); + + private static string GetDescription(string aniDbDescription, string otherDescription) + { + string overview; + switch (Plugin.Instance.Configuration.DescriptionSource) { + default: + case TextSourceType.PreferAniDb: + overview = SanitizeTextSummary(aniDbDescription); + if (string.IsNullOrEmpty(overview)) + goto case TextSourceType.OnlyOther; + break; + case TextSourceType.PreferOther: + overview = otherDescription ?? ""; + if (string.IsNullOrEmpty(overview)) + goto case TextSourceType.OnlyAniDb; + break; + case TextSourceType.OnlyAniDb: + overview = SanitizeTextSummary(aniDbDescription); + break; + case TextSourceType.OnlyOther: + overview = otherDescription ?? ""; + break; } + return overview; + } - public static string JoinText(IEnumerable<string> textList) - { - var filteredList = textList - .Where(title => !string.IsNullOrWhiteSpace(title)) - .Select(title => title.Trim()) - // We distinct the list because some episode entries contain the **exact** same description. - .Distinct() - .ToList(); - - if (filteredList.Count == 0) - return ""; - - var index = 1; - var outputText = filteredList[0]; - while (index < filteredList.Count) { - var lastChar = outputText[^1]; - outputText += PunctuationMarks.Contains(lastChar) ? " " : ". "; - outputText += filteredList[index++]; - } + /// <summary> + /// Based on ShokoMetadata's summary sanitizer which in turn is based on HAMA's summary sanitizer. + /// </summary> + /// <param name="summary">The raw AniDB summary</param> + /// <returns>The sanitized AniDB summary</returns> + public static string SanitizeTextSummary(string summary) + { + if (string.IsNullOrWhiteSpace(summary)) + return ""; - if (filteredList.Count > 1) - outputText.TrimEnd(); + var config = Plugin.Instance.Configuration; - return outputText; + if (config.SynopsisCleanLinks) + summary = Regex.Replace(summary, @"https?:\/\/\w+.\w+(?:\/?\w+)? \[([^\]]+)\]", match => match.Groups[1].Value); + + if (config.SynopsisCleanMiscLines) + summary = Regex.Replace(summary, @"^(\*|--|~) .*", "", RegexOptions.Multiline); + + if (config.SynopsisRemoveSummary) + summary = Regex.Replace(summary, @"\n(Source|Note|Summary):.*", "", RegexOptions.Singleline); + + if (config.SynopsisCleanMultiEmptyLines) + summary = Regex.Replace(summary, @"\n{2,}", "\n", RegexOptions.Singleline); + + return summary.Trim(); + } + + public static ( string, string ) GetEpisodeTitles(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string episodeTitle, string metadataLanguage) + => GetTitles(seriesTitles, episodeTitles, null, episodeTitle, DisplayTitleType.SubTitle, metadataLanguage); + + public static ( string, string ) GetSeriesTitles(IEnumerable<Title> seriesTitles, string seriesTitle, string metadataLanguage) + => GetTitles(seriesTitles, null, seriesTitle, null, DisplayTitleType.MainTitle, metadataLanguage); + + public static ( string, string ) GetMovieTitles(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, string metadataLanguage) + => GetTitles(seriesTitles, episodeTitles, seriesTitle, episodeTitle, DisplayTitleType.FullTitle, metadataLanguage); + + public static ( string, string ) GetTitles(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayTitleType outputType, string metadataLanguage) + { + // Don't process anything if the series titles are not provided. + if (seriesTitles == null) + return (null, null); + return ( + GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleMainType, outputType, metadataLanguage), + GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleAlternateType, outputType, metadataLanguage) + ); + } + + public static string JoinText(IEnumerable<string> textList) + { + var filteredList = textList + .Where(title => !string.IsNullOrWhiteSpace(title)) + .Select(title => title.Trim()) + // We distinct the list because some episode entries contain the **exact** same description. + .Distinct() + .ToList(); + + if (filteredList.Count == 0) + return ""; + + var index = 1; + var outputText = filteredList[0]; + while (index < filteredList.Count) { + var lastChar = outputText[^1]; + outputText += PunctuationMarks.Contains(lastChar) ? " " : ". "; + outputText += filteredList[index++]; } - public static string GetEpisodeTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string episodeTitle, string metadataLanguage) - => GetTitle(seriesTitles, episodeTitles, null, episodeTitle, DisplayTitleType.SubTitle, metadataLanguage); + if (filteredList.Count > 1) + outputText.TrimEnd(); + + return outputText; + } + + public static string GetEpisodeTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string episodeTitle, string metadataLanguage) + => GetTitle(seriesTitles, episodeTitles, null, episodeTitle, DisplayTitleType.SubTitle, metadataLanguage); - public static string GetSeriesTitle(IEnumerable<Title> seriesTitles, string seriesTitle, string metadataLanguage) - => GetTitle(seriesTitles, null, seriesTitle, null, DisplayTitleType.MainTitle, metadataLanguage); + public static string GetSeriesTitle(IEnumerable<Title> seriesTitles, string seriesTitle, string metadataLanguage) + => GetTitle(seriesTitles, null, seriesTitle, null, DisplayTitleType.MainTitle, metadataLanguage); - public static string GetMovieTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, string metadataLanguage) - => GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, DisplayTitleType.FullTitle, metadataLanguage); + public static string GetMovieTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, string metadataLanguage) + => GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, DisplayTitleType.FullTitle, metadataLanguage); - public static string GetTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayTitleType outputType, string metadataLanguage) - => GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleMainType, outputType, metadataLanguage); + public static string GetTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayTitleType outputType, string metadataLanguage) + => GetTitle(seriesTitles, episodeTitles, seriesTitle, episodeTitle, Plugin.Instance.Configuration.TitleMainType, outputType, metadataLanguage); - public static string GetTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayLanguageType languageType, DisplayTitleType outputType, string displayLanguage) - { - // Don't process anything if the series titles are not provided. - if (seriesTitles == null) + public static string GetTitle(IEnumerable<Title> seriesTitles, IEnumerable<Title> episodeTitles, string seriesTitle, string episodeTitle, DisplayLanguageType languageType, DisplayTitleType outputType, string displayLanguage) + { + // Don't process anything if the series titles are not provided. + if (seriesTitles == null) + return null; + var mainTitleLanguage = GetMainLanguage(seriesTitles); + var originLanguages = GuessOriginLanguage(mainTitleLanguage); + switch (languageType) { + // 'Ignore' will always return null, and all other values will also return null. + default: + case DisplayLanguageType.Ignore: return null; - var mainTitleLanguage = GetMainLanguage(seriesTitles); - var originLanguages = GuessOriginLanguage(mainTitleLanguage); - switch (languageType) { - // 'Ignore' will always return null, and all other values will also return null. - default: - case DisplayLanguageType.Ignore: - return null; - // Let Shoko decide the title. - case DisplayLanguageType.Default: - return ConstructTitle(() => seriesTitle, () => episodeTitle, outputType); - // Display in metadata-preferred language, or fallback to default. - case DisplayLanguageType.MetadataPreferred: { - var allowAny = Plugin.Instance.Configuration.TitleAllowAny; - var getSeriesTitle = () => GetTitleByTypeAndLanguage(seriesTitles, TitleType.Official, displayLanguage) ?? (allowAny ? GetTitleByLanguages(seriesTitles, displayLanguage) : null) ?? seriesTitle; - var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, displayLanguage) ?? episodeTitle; - var title = ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); - if (string.IsNullOrEmpty(title)) - goto case DisplayLanguageType.Default; - return title; - } - // Display in origin language. - case DisplayLanguageType.Origin: { - var allowAny = Plugin.Instance.Configuration.TitleAllowAny; - var getSeriesTitle = () => GetTitleByTypeAndLanguage(seriesTitles, TitleType.Official, originLanguages) ?? (allowAny ? GetTitleByLanguages(seriesTitles, originLanguages) : null) ?? seriesTitle; - var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, originLanguages) ?? episodeTitle; - return ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); - } - // Display the main title. - case DisplayLanguageType.Main: { - var getSeriesTitle = () => GetTitleByType(seriesTitles, TitleType.Main) ?? seriesTitle; - var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, "en", mainTitleLanguage) ?? episodeTitle; - return ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); - } + // Let Shoko decide the title. + case DisplayLanguageType.Default: + return ConstructTitle(() => seriesTitle, () => episodeTitle, outputType); + // Display in metadata-preferred language, or fallback to default. + case DisplayLanguageType.MetadataPreferred: { + var allowAny = Plugin.Instance.Configuration.TitleAllowAny; + var getSeriesTitle = () => GetTitleByTypeAndLanguage(seriesTitles, TitleType.Official, displayLanguage) ?? (allowAny ? GetTitleByLanguages(seriesTitles, displayLanguage) : null) ?? seriesTitle; + var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, displayLanguage) ?? episodeTitle; + var title = ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); + if (string.IsNullOrEmpty(title)) + goto case DisplayLanguageType.Default; + return title; } - } - - private static string ConstructTitle(Func<string> getSeriesTitle, Func<string> getEpisodeTitle, DisplayTitleType outputType) - { - switch (outputType) { - // Return series title. - case DisplayTitleType.MainTitle: - return getSeriesTitle()?.Trim(); - // Return episode title. - case DisplayTitleType.SubTitle: - return getEpisodeTitle()?.Trim(); - // Return combined series and episode title. - case DisplayTitleType.FullTitle: { - var mainTitle = getSeriesTitle()?.Trim(); - var subTitle = getEpisodeTitle()?.Trim(); - // Include sub-title if it does not strictly equals any ignored sub titles. - if (!string.IsNullOrWhiteSpace(subTitle) && !IgnoredSubTitles.Contains(mainTitle)) - return $"{mainTitle}: {subTitle}"; - return mainTitle; - } - default: - return null; + // Display in origin language. + case DisplayLanguageType.Origin: { + var allowAny = Plugin.Instance.Configuration.TitleAllowAny; + var getSeriesTitle = () => GetTitleByTypeAndLanguage(seriesTitles, TitleType.Official, originLanguages) ?? (allowAny ? GetTitleByLanguages(seriesTitles, originLanguages) : null) ?? seriesTitle; + var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, originLanguages) ?? episodeTitle; + return ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); } - } - - public static string GetTitleByType(IEnumerable<Title> titles, TitleType type) - { - if (titles != null) { - string title = titles.FirstOrDefault(s => s.Type == type)?.Value; - if (title != null) - return title; + // Display the main title. + case DisplayLanguageType.Main: { + var getSeriesTitle = () => GetTitleByType(seriesTitles, TitleType.Main) ?? seriesTitle; + var getEpisodeTitle = () => GetTitleByLanguages(episodeTitles, "en", mainTitleLanguage) ?? episodeTitle; + return ConstructTitle(getSeriesTitle, getEpisodeTitle, outputType); } - return null; } + } - public static string GetTitleByTypeAndLanguage(IEnumerable<Title> titles, TitleType type, params string[] langs) - { - if (titles != null) foreach (string lang in langs) { - string title = titles.FirstOrDefault(s => s.LanguageCode == lang && s.Type == type)?.Value; - if (title != null) - return title; + private static string ConstructTitle(Func<string> getSeriesTitle, Func<string> getEpisodeTitle, DisplayTitleType outputType) + { + switch (outputType) { + // Return series title. + case DisplayTitleType.MainTitle: + return getSeriesTitle()?.Trim(); + // Return episode title. + case DisplayTitleType.SubTitle: + return getEpisodeTitle()?.Trim(); + // Return combined series and episode title. + case DisplayTitleType.FullTitle: { + var mainTitle = getSeriesTitle()?.Trim(); + var subTitle = getEpisodeTitle()?.Trim(); + // Include sub-title if it does not strictly equals any ignored sub titles. + if (!string.IsNullOrWhiteSpace(subTitle) && !IgnoredSubTitles.Contains(mainTitle)) + return $"{mainTitle}: {subTitle}"; + return mainTitle; } - return null; + default: + return null; } + } - public static string GetTitleByLanguages(IEnumerable<Title> titles, params string[] langs) - { - if (titles != null) foreach (string lang in langs) { - string title = titles.FirstOrDefault(s => lang.Equals(s.LanguageCode, System.StringComparison.OrdinalIgnoreCase))?.Value; - if (title != null) - return title; - } - return null; + public static string GetTitleByType(IEnumerable<Title> titles, TitleType type) + { + if (titles != null) { + string title = titles.FirstOrDefault(s => s.Type == type)?.Value; + if (title != null) + return title; } + return null; + } - /// <summary> - /// Get the main title language from the series list. - /// </summary> - /// <param name="titles">Series title list.</param> - /// <returns></returns> - private static string GetMainLanguage(IEnumerable<Title> titles) { - return titles.FirstOrDefault(t => t?.Type == TitleType.Main)?.LanguageCode ?? titles.FirstOrDefault()?.LanguageCode ?? "x-other"; + public static string GetTitleByTypeAndLanguage(IEnumerable<Title> titles, TitleType type, params string[] langs) + { + if (titles != null) foreach (string lang in langs) { + string title = titles.FirstOrDefault(s => s.LanguageCode == lang && s.Type == type)?.Value; + if (title != null) + return title; } + return null; + } - /// <summary> - /// Guess the origin language based on the main title. - /// </summary> - /// <param name="titles">Series title list.</param> - /// <returns></returns> - private static string[] GuessOriginLanguage(string langCode) - { - // Guess the origin language based on the main title language. - return langCode switch { - "x-other" => new string[] { "ja" }, - "x-jat" => new string[] { "ja" }, - "x-zht" => new string[] { "zn-hans", "zn-hant", "zn-c-mcm", "zn" }, - _ => new string[] { langCode }, - }; + public static string GetTitleByLanguages(IEnumerable<Title> titles, params string[] langs) + { + if (titles != null) foreach (string lang in langs) { + string title = titles.FirstOrDefault(s => lang.Equals(s.LanguageCode, System.StringComparison.OrdinalIgnoreCase))?.Value; + if (title != null) + return title; } + return null; + } + + /// <summary> + /// Get the main title language from the series list. + /// </summary> + /// <param name="titles">Series title list.</param> + /// <returns></returns> + private static string GetMainLanguage(IEnumerable<Title> titles) { + return titles.FirstOrDefault(t => t?.Type == TitleType.Main)?.LanguageCode ?? titles.FirstOrDefault()?.LanguageCode ?? "x-other"; + } + + /// <summary> + /// Guess the origin language based on the main title. + /// </summary> + /// <param name="titles">Series title list.</param> + /// <returns></returns> + private static string[] GuessOriginLanguage(string langCode) + { + // Guess the origin language based on the main title language. + return langCode switch { + "x-other" => new string[] { "ja" }, + "x-jat" => new string[] { "ja" }, + "x-zht" => new string[] { "zn-hans", "zn-hant", "zn-c-mcm", "zn" }, + _ => new string[] { langCode }, + }; } }