diff options
| author | Fredrik Lindberg <fli@shapeshifter.se> | 2021-08-26 20:01:56 +0200 |
|---|---|---|
| committer | Fredrik Lindberg <fli@shapeshifter.se> | 2021-09-13 17:59:33 +0200 |
| commit | ea439c5ccf7a61157544accd60109afc12dbc2d2 (patch) | |
| tree | 0da06983169048f5136861bfe10dc423090b0f11 /Emby.Naming/TV | |
| parent | e15fea5dade9478d9667399eb0c245917d3e1513 (diff) | |
Improve series name matching
Add a series path resolver that attempts to extract only the series
name from a path that contains more information that just the name.
Diffstat (limited to 'Emby.Naming/TV')
| -rw-r--r-- | Emby.Naming/TV/SeriesInfo.cs | 29 | ||||
| -rw-r--r-- | Emby.Naming/TV/SeriesPathParser.cs | 61 | ||||
| -rw-r--r-- | Emby.Naming/TV/SeriesPathParserResult.cs | 19 | ||||
| -rw-r--r-- | Emby.Naming/TV/SeriesResolver.cs | 49 |
4 files changed, 158 insertions, 0 deletions
diff --git a/Emby.Naming/TV/SeriesInfo.cs b/Emby.Naming/TV/SeriesInfo.cs new file mode 100644 index 000000000..5d6cb4bd3 --- /dev/null +++ b/Emby.Naming/TV/SeriesInfo.cs @@ -0,0 +1,29 @@ +namespace Emby.Naming.TV +{ + /// <summary> + /// Holder object for Series information. + /// </summary> + public class SeriesInfo + { + /// <summary> + /// Initializes a new instance of the <see cref="SeriesInfo"/> class. + /// </summary> + /// <param name="path">Path to the file.</param> + public SeriesInfo(string path) + { + Path = path; + } + + /// <summary> + /// Gets or sets the path. + /// </summary> + /// <value>The path.</value> + public string Path { get; set; } + + /// <summary> + /// Gets or sets the name of the series. + /// </summary> + /// <value>The name of the series.</value> + public string? Name { get; set; } + } +} diff --git a/Emby.Naming/TV/SeriesPathParser.cs b/Emby.Naming/TV/SeriesPathParser.cs new file mode 100644 index 000000000..a62e5f4d6 --- /dev/null +++ b/Emby.Naming/TV/SeriesPathParser.cs @@ -0,0 +1,61 @@ +using System.Globalization; +using Emby.Naming.Common; + +namespace Emby.Naming.TV +{ + /// <summary> + /// Used to parse information about series from paths containing more information that only the series name. + /// Uses the same regular expressions as the EpisodePathParser but have different success criteria. + /// </summary> + public static class SeriesPathParser + { + /// <summary> + /// Parses information about series from path. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing EpisodeExpressions and MultipleEpisodeExpressions.</param> + /// <param name="path">Path.</param> + /// <returns>Returns <see cref="SeriesPathParserResult"/> object.</returns> + public static SeriesPathParserResult Parse(NamingOptions options, string path) + { + SeriesPathParserResult? result = null; + + foreach (var expression in options.EpisodeExpressions) + { + var currentResult = Parse(path, expression); + if (currentResult.Success) + { + result = currentResult; + break; + } + } + + if (result != null) + { + if (!string.IsNullOrEmpty(result.SeriesName)) + { + result.SeriesName = result.SeriesName.Trim(' ', '_', '.', '-'); + } + } + + return result ?? new SeriesPathParserResult(); + } + + private static SeriesPathParserResult Parse(string name, EpisodeExpression expression) + { + var result = new SeriesPathParserResult(); + + var match = expression.Regex.Match(name); + + if (match.Success && match.Groups.Count >= 3) + { + if (expression.IsNamed) + { + result.SeriesName = match.Groups["seriesname"].Value; + result.Success = !string.IsNullOrEmpty(result.SeriesName) && !string.IsNullOrEmpty(match.Groups["seasonnumber"]?.Value); + } + } + + return result; + } + } +} diff --git a/Emby.Naming/TV/SeriesPathParserResult.cs b/Emby.Naming/TV/SeriesPathParserResult.cs new file mode 100644 index 000000000..44cd2fdfa --- /dev/null +++ b/Emby.Naming/TV/SeriesPathParserResult.cs @@ -0,0 +1,19 @@ +namespace Emby.Naming.TV +{ + /// <summary> + /// Holder object for <see cref="SeriesPathParser"/> result. + /// </summary> + public class SeriesPathParserResult + { + /// <summary> + /// Gets or sets the name of the series. + /// </summary> + /// <value>The name of the series.</value> + public string? SeriesName { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether parsing was successful. + /// </summary> + public bool Success { get; set; } + } +} diff --git a/Emby.Naming/TV/SeriesResolver.cs b/Emby.Naming/TV/SeriesResolver.cs new file mode 100644 index 000000000..156a03c9e --- /dev/null +++ b/Emby.Naming/TV/SeriesResolver.cs @@ -0,0 +1,49 @@ +using System.IO; +using System.Text.RegularExpressions; +using Emby.Naming.Common; + +namespace Emby.Naming.TV +{ + /// <summary> + /// Used to resolve information about series from path. + /// </summary> + public static class SeriesResolver + { + /// <summary> + /// Regex that matches strings of at least 2 characters separated by a dot or underscore. + /// Used for removing separators between words, i.e turns "The_show" into "The show" while + /// preserving namings like "S.H.O.W". + /// </summary> + private static readonly Regex _seriesNameRegex = new Regex(@"((?<a>[^\._]{2,})[\._]*)|([\._](?<b>[^\._]{2,}))"); + + /// <summary> + /// Resolve information about series from path. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object passed to <see cref="SeriesPathParser"/>.</param> + /// <param name="path">Path to series.</param> + /// <returns>SeriesInfo.</returns> + public static SeriesInfo Resolve(NamingOptions options, string path) + { + string seriesName = Path.GetFileName(path); + + SeriesPathParserResult result = SeriesPathParser.Parse(options, path); + if (result.Success) + { + if (!string.IsNullOrEmpty(result.SeriesName)) + { + seriesName = result.SeriesName; + } + } + + if (!string.IsNullOrEmpty(seriesName)) + { + seriesName = _seriesNameRegex.Replace(seriesName, "${a} ${b}").Trim(); + } + + return new SeriesInfo(path) + { + Name = seriesName + }; + } + } +} |
