aboutsummaryrefslogtreecommitdiff
path: root/Emby.Naming
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Naming')
-rw-r--r--Emby.Naming/Book/BookFileNameParser.cs29
-rw-r--r--Emby.Naming/Book/BookFileNameParserResult.cs8
-rw-r--r--Emby.Naming/Common/NamingOptions.cs8
-rw-r--r--Emby.Naming/TV/EpisodePathParser.cs2
-rw-r--r--Emby.Naming/TV/SeriesInfo.cs6
-rw-r--r--Emby.Naming/TV/SeriesResolver.cs5
-rw-r--r--Emby.Naming/Video/Format3DParser.cs13
7 files changed, 54 insertions, 17 deletions
diff --git a/Emby.Naming/Book/BookFileNameParser.cs b/Emby.Naming/Book/BookFileNameParser.cs
index 28625f16de..080e25969b 100644
--- a/Emby.Naming/Book/BookFileNameParser.cs
+++ b/Emby.Naming/Book/BookFileNameParser.cs
@@ -1,3 +1,4 @@
+using System;
using System.Text.RegularExpressions;
namespace Emby.Naming.Book
@@ -5,7 +6,7 @@ namespace Emby.Naming.Book
/// <summary>
/// Helper class to retrieve basic metadata from a book filename.
/// </summary>
- public static class BookFileNameParser
+ public static partial class BookFileNameParser
{
private const string NameMatchGroup = "name";
private const string IndexMatchGroup = "index";
@@ -15,14 +16,17 @@ namespace Emby.Naming.Book
private static readonly Regex[] _nameMatches =
[
// seriesName (seriesYear) #index (of count) (year) where only seriesName and index are required
- new Regex(@"^(?<seriesName>.+?)((\s\((?<seriesYear>[0-9]{4})\))?)\s#(?<index>[0-9]+)((\s\(of\s(?<count>[0-9]+)\))?)((\s\((?<year>[0-9]{4})\))?)$"),
- new Regex(@"^(?<name>.+?)\s\((?<seriesName>.+?),\s#(?<index>[0-9]+)\)((\s\((?<year>[0-9]{4})\))?)$"),
- new Regex(@"^(?<index>[0-9]+)\s\-\s(?<name>.+?)((\s\((?<year>[0-9]{4})\))?)$"),
+ new Regex(@"^(?<seriesName>.+?)((\s\((?<seriesYear>[0-9]{4})\))?)\s#(?<index>[0-9]+)(?:\.0)?((\s\(of\s(?<count>[0-9]+)\))?)((\s\((?<year>[0-9]{4})\))?)$"),
+ new Regex(@"^(?<name>.+?)\s\((?<seriesName>.+?),\s#(?<index>[0-9]+)\)(?:\.0)?((\s\((?<year>[0-9]{4})\))?)$"),
+ new Regex(@"^(?<index>[0-9]+)(?:\.0)?\s\-\s(?<name>.+?)((\s\((?<year>[0-9]{4})\))?)$"),
new Regex(@"(?<name>.*)\((?<year>[0-9]{4})\)"),
// last resort matches the whole string as the name
new Regex(@"(?<name>.*)")
];
+ [GeneratedRegex(@"^(?<name>.+?)(\sv(?<volume>[0-9]+))?(\sc(?<chapter>[0-9]+))?$")]
+ private static partial Regex ComicRegex();
+
/// <summary>
/// Parse a filename name to retrieve the book name, series name, index, and year.
/// </summary>
@@ -48,7 +52,22 @@ namespace Emby.Naming.Book
if (match.Groups.TryGetValue(NameMatchGroup, out Group? nameGroup) && nameGroup.Success)
{
- result.Name = nameGroup.Value.Trim();
+ var comicMatch = ComicRegex().Match(nameGroup.Value.Trim());
+
+ if (comicMatch.Success)
+ {
+ if (comicMatch.Groups.TryGetValue("volume", out Group? volumeGroup) && volumeGroup.Success && int.TryParse(volumeGroup.ValueSpan, out var volume))
+ {
+ result.ParentIndex = volume;
+ }
+
+ if (comicMatch.Groups.TryGetValue("chapter", out Group? chapterGroup) && chapterGroup.Success && int.TryParse(chapterGroup.ValueSpan, out var chapter))
+ {
+ result.Index = chapter;
+ }
+ }
+
+ result.Name = nameGroup.ValueSpan.Trim().ToString();
}
if (match.Groups.TryGetValue(IndexMatchGroup, out Group? indexGroup) && indexGroup.Success && int.TryParse(indexGroup.Value, out var index))
diff --git a/Emby.Naming/Book/BookFileNameParserResult.cs b/Emby.Naming/Book/BookFileNameParserResult.cs
index f29716b9e3..f313b202c5 100644
--- a/Emby.Naming/Book/BookFileNameParserResult.cs
+++ b/Emby.Naming/Book/BookFileNameParserResult.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace Emby.Naming.Book
{
/// <summary>
@@ -14,6 +12,7 @@ namespace Emby.Naming.Book
{
Name = null;
Index = null;
+ ParentIndex = null;
Year = null;
SeriesName = null;
}
@@ -29,6 +28,11 @@ namespace Emby.Naming.Book
public int? Index { get; set; }
/// <summary>
+ /// Gets or sets the parent index number.
+ /// </summary>
+ public int? ParentIndex { get; set; }
+
+ /// <summary>
/// Gets or sets the publication year.
/// </summary>
public int? Year { get; set; }
diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index 21638ba9e7..9ecefb4c7b 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/Emby.Naming/Common/NamingOptions.cs
@@ -57,7 +57,6 @@ namespace Emby.Naming.Common
".nrg",
".nsv",
".nuv",
- ".ogg",
".ogm",
".ogv",
".pva",
@@ -152,7 +151,7 @@ namespace Emby.Naming.Common
CleanStrings =
[
- @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multi|subs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|blu-ray|x264|x265|h264|h265|xvid|xvidvd|xxx|www.www|AAC|DTS)(?=[ _\,\.\(\)\[\]\-]|$)",
+ @"^\s*(?<cleaned>.+?)[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multi|subs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r5|bd5|bd|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|web-dl|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|blu-ray|x264|x265|h264|h265|xvid|xvidvd|xxx|www.www|AAC|DTS)(?=[ _\,\.\(\)\[\]\-]|$)",
@"^\s*(?<cleaned>.+?)((\s*\[[^\]]+\]\s*)+)(\.[^\s]+)?$",
@"^\s*(?<cleaned>.+?)\WE[0-9]+(-|~)E?[0-9]+(\W|$)",
@"^\s*\[[^\]]+\](?!\.\w+$)\s*(?<cleaned>.+)",
@@ -362,7 +361,10 @@ namespace Emby.Naming.Common
// Not a Kodi rule as well, but the expression below also causes false positives,
// so we make sure this one gets tested first.
// "Foo Bar 889"
- new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endingepnumber>[0-9]{2,4}))*[^\\\/x]*$")
+ // Names carrying an SxxEyy marker are excluded because the Kodi expression above already covers them.
+ // Without that guard this expression reads digits out of the title instead, turning
+ // "S01E01 1-23-45 [Bluray-1080p]" into episodes 1 through 45.
+ new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?![^\\\/]*[Ss][0-9]+[][ ._-]*[Ee][0-9]+)(?<seriesname>[\w\s]+?)\s(?<epnumber>[0-9]{1,4})(-(?<endingepnumber>[0-9]{2,4}))*[^\\\/x]*$")
{
IsNamed = true
},
diff --git a/Emby.Naming/TV/EpisodePathParser.cs b/Emby.Naming/TV/EpisodePathParser.cs
index 8cd5a126e0..0c737964b4 100644
--- a/Emby.Naming/TV/EpisodePathParser.cs
+++ b/Emby.Naming/TV/EpisodePathParser.cs
@@ -125,7 +125,7 @@ namespace Emby.Naming.TV
result.Success = true;
}
}
- else if (DateTime.TryParse(match.Groups[0].ValueSpan, out date))
+ else if (DateTime.TryParse(match.Groups[0].ValueSpan, CultureInfo.InvariantCulture, out date))
{
result.Year = date.Year;
result.Month = date.Month;
diff --git a/Emby.Naming/TV/SeriesInfo.cs b/Emby.Naming/TV/SeriesInfo.cs
index 5d6cb4bd37..e145ff8003 100644
--- a/Emby.Naming/TV/SeriesInfo.cs
+++ b/Emby.Naming/TV/SeriesInfo.cs
@@ -25,5 +25,11 @@ namespace Emby.Naming.TV
/// </summary>
/// <value>The name of the series.</value>
public string? Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the year of the series.
+ /// </summary>
+ /// <value>The year of the series.</value>
+ public int? Year { get; set; }
}
}
diff --git a/Emby.Naming/TV/SeriesResolver.cs b/Emby.Naming/TV/SeriesResolver.cs
index 0b7309bae0..733e2418c2 100644
--- a/Emby.Naming/TV/SeriesResolver.cs
+++ b/Emby.Naming/TV/SeriesResolver.cs
@@ -21,7 +21,7 @@ namespace Emby.Naming.TV
/// Regex that matches titles with year in parentheses. Captures the title (which may be
/// numeric) before the year, i.e. turns "1923 (2022)" into "1923".
/// </summary>
- [GeneratedRegex(@"(?<title>.+?)\s*\(\d{4}\)")]
+ [GeneratedRegex(@"(?<title>.+?)\s*\((?<year>[0-9]{4})\)")]
private static partial Regex TitleWithYearRegex();
/// <summary>
@@ -43,7 +43,8 @@ namespace Emby.Naming.TV
seriesName = titleWithYearMatch.Groups["title"].Value.Trim();
return new SeriesInfo(path)
{
- Name = seriesName
+ Name = seriesName,
+ Year = int.TryParse(titleWithYearMatch.Groups["year"].ValueSpan, out var year) ? year : null
};
}
}
diff --git a/Emby.Naming/Video/Format3DParser.cs b/Emby.Naming/Video/Format3DParser.cs
index eb5e71d78f..a287a2525b 100644
--- a/Emby.Naming/Video/Format3DParser.cs
+++ b/Emby.Naming/Video/Format3DParser.cs
@@ -52,13 +52,18 @@ namespace Emby.Naming.Video
while (path.Length > 0)
{
var index = path.IndexOfAny(delimiters);
+ ReadOnlySpan<char> currentSlice;
if (index == -1)
{
- index = path.Length - 1;
+ // No delimiter left, the last token is the remainder of the path
+ currentSlice = path;
+ path = default;
+ }
+ else
+ {
+ currentSlice = path[..index];
+ path = path[(index + 1)..];
}
-
- var currentSlice = path[..index];
- path = path[(index + 1)..];
if (!foundPrefix)
{