From e7a37bedfca159ab6a305833395aead07ccd872f Mon Sep 17 00:00:00 2001 From: Stepan Date: Sun, 1 Nov 2020 13:42:56 +0100 Subject: Simplify AudioBookResolver since there is no option of passing directories into it (AudioResolver.cs:179) and handling directories were not implemented anyway --- Emby.Naming/Video/StackResolver.cs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'Emby.Naming/Video/StackResolver.cs') diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index f733cd2620..ce3152739b 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Emby.Naming.AudioBook; using Emby.Naming.Common; using MediaBrowser.Model.IO; @@ -29,24 +30,16 @@ namespace Emby.Naming.Video return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false })); } - public IEnumerable ResolveAudioBooks(IEnumerable files) + public IEnumerable ResolveAudioBooks(IEnumerable files) { - var groupedDirectoryFiles = files.GroupBy(file => - file.IsDirectory - ? file.FullName - : Path.GetDirectoryName(file.FullName)); + var groupedDirectoryFiles = files.GroupBy(file => Path.GetDirectoryName(file.Path)); foreach (var directory in groupedDirectoryFiles) { var stack = new FileStack { Name = Path.GetFileName(directory.Key), IsDirectoryStack = false }; foreach (var file in directory) { - if (file.IsDirectory) - { - continue; - } - - stack.Files.Add(file.FullName); + stack.Files.Add(file.Path); } yield return stack; -- cgit v1.2.3 From 1e7177568887d0f808660454e5eb7ca7ebcd6998 Mon Sep 17 00:00:00 2001 From: Stepan Date: Mon, 2 Nov 2020 20:03:12 +0100 Subject: Add Name and Year parsing for audiobooks --- Emby.Naming/AudioBook/AudioBookInfo.cs | 4 +- Emby.Naming/AudioBook/AudioBookListResolver.cs | 6 +- Emby.Naming/AudioBook/AudioBookNameParser.cs | 59 ++++++++++++++++ Emby.Naming/AudioBook/AudioBookNameParserResult.cs | 12 ++++ Emby.Naming/Common/NamingOptions.cs | 9 +++ Emby.Naming/Video/StackResolver.cs | 20 ++++-- .../AudioBook/AudioBookListResolverTests.cs | 78 +++++++++++++++++----- .../AudioBook/AudioBookResolverTests.cs | 1 - 8 files changed, 163 insertions(+), 26 deletions(-) create mode 100644 Emby.Naming/AudioBook/AudioBookNameParser.cs create mode 100644 Emby.Naming/AudioBook/AudioBookNameParserResult.cs (limited to 'Emby.Naming/Video/StackResolver.cs') diff --git a/Emby.Naming/AudioBook/AudioBookInfo.cs b/Emby.Naming/AudioBook/AudioBookInfo.cs index fba11ea726..353a0f4a01 100644 --- a/Emby.Naming/AudioBook/AudioBookInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookInfo.cs @@ -11,12 +11,14 @@ namespace Emby.Naming.AudioBook /// Initializes a new instance of the class. /// /// Name of audiobook. - public AudioBookInfo(string name) + /// Year of audiobook release. + public AudioBookInfo(string name, int? year) { Files = new List(); Extras = new List(); AlternateVersions = new List(); Name = name; + Year = year; } /// diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs index 795065a6c9..86ba2eeeaf 100644 --- a/Emby.Naming/AudioBook/AudioBookListResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs @@ -41,9 +41,9 @@ namespace Emby.Naming.AudioBook stackFiles.Sort(); - // stack.Name can be empty when we have file without folder, but always have some files - var name = string.IsNullOrEmpty(stack.Name) ? stack.Files[0] : stack.Name; - var info = new AudioBookInfo(name) { Files = stackFiles }; + var result = new AudioBookNameParser(_options).Parse(stack.Name); + + var info = new AudioBookInfo(result.Name, result.Year) { Files = stackFiles }; yield return info; } diff --git a/Emby.Naming/AudioBook/AudioBookNameParser.cs b/Emby.Naming/AudioBook/AudioBookNameParser.cs new file mode 100644 index 0000000000..c48db93b37 --- /dev/null +++ b/Emby.Naming/AudioBook/AudioBookNameParser.cs @@ -0,0 +1,59 @@ +#nullable enable +#pragma warning disable CS1591 + +using System.Globalization; +using System.IO; +using System.Text.RegularExpressions; +using Emby.Naming.Common; + +namespace Emby.Naming.AudioBook +{ + public class AudioBookNameParser + { + private readonly NamingOptions _options; + + public AudioBookNameParser(NamingOptions options) + { + _options = options; + } + + public AudioBookNameParserResult Parse(string name) + { + AudioBookNameParserResult result = default; + foreach (var expression in _options.AudioBookNamesExpressions) + { + var match = new Regex(expression, RegexOptions.IgnoreCase).Match(name); + if (match.Success) + { + if (result.Name == null) + { + var value = match.Groups["name"]; + if (value.Success) + { + result.Name = value.Value; + } + } + + if (!result.Year.HasValue) + { + var value = match.Groups["year"]; + if (value.Success) + { + if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue)) + { + result.Year = intValue; + } + } + } + } + } + + if (string.IsNullOrEmpty(result.Name)) + { + result.Name = name; + } + + return result; + } + } +} diff --git a/Emby.Naming/AudioBook/AudioBookNameParserResult.cs b/Emby.Naming/AudioBook/AudioBookNameParserResult.cs new file mode 100644 index 0000000000..b28e259dda --- /dev/null +++ b/Emby.Naming/AudioBook/AudioBookNameParserResult.cs @@ -0,0 +1,12 @@ +#nullable enable +#pragma warning disable CS1591 + +namespace Emby.Naming.AudioBook +{ + public struct AudioBookNameParserResult + { + public string Name { get; set; } + + public int? Year { get; set; } + } +} diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 537de63d55..5bf232451b 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -575,6 +575,13 @@ namespace Emby.Naming.Common @"dis(?:c|k)[\s_-]?(?[0-9]+)" }; + AudioBookNamesExpressions = new[] + { + // Detect year usually in brackets after name Batman (2020) + @"^(?.+?)\s*\(\s*(?\d{4})\s*\)\s*$", + @"^\s*(?.+?)\s*$" + }; + var extensions = VideoFileExtensions.ToList(); extensions.AddRange(new[] @@ -658,6 +665,8 @@ namespace Emby.Naming.Common public string[] AudioBookPartsExpressions { get; set; } + public string[] AudioBookNamesExpressions { get; set; } + public StubTypeRule[] StubTypes { get; set; } public char[] VideoFlagDelimiters { get; set; } diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index ce3152739b..e11b4063ce 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -36,13 +36,25 @@ namespace Emby.Naming.Video foreach (var directory in groupedDirectoryFiles) { - var stack = new FileStack { Name = Path.GetFileName(directory.Key), IsDirectoryStack = false }; - foreach (var file in directory) + if (string.IsNullOrEmpty(directory.Key)) { - stack.Files.Add(file.Path); + foreach (var file in directory) + { + var stack = new FileStack { Name = Path.GetFileNameWithoutExtension(file.Path), IsDirectoryStack = false }; + stack.Files.Add(file.Path); + yield return stack; + } } + else + { + var stack = new FileStack { Name = Path.GetFileName(directory.Key), IsDirectoryStack = false }; + foreach (var file in directory) + { + stack.Files.Add(file.Path); + } - yield return stack; + yield return stack; + } } } diff --git a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs index c4b061b4e9..91492d46c9 100644 --- a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs +++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookListResolverTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Emby.Naming.AudioBook; using Emby.Naming.Common; @@ -72,33 +73,69 @@ namespace Jellyfin.Naming.Tests.AudioBook } [Fact] - public void TestYearExtraction() + public void TestNameYearExtraction() { - var files = new[] + var data = new[] { - "Harry Potter and the Deathly Hallows (2007)/Chapter 1.ogg", - "Harry Potter and the Deathly Hallows (2007)/Chapter 2.mp3", - - "Batman (2020).ogg", - - "Batman(2021).mp3", - - "Batman.mp3" + new NameYearPath + { + Name = "Harry Potter and the Deathly Hallows", + Path = "Harry Potter and the Deathly Hallows (2007)/Chapter 1.ogg", + Year = 2007 + }, + new NameYearPath + { + Name = "Batman", + Path = "Batman (2020).ogg", + Year = 2020 + }, + new NameYearPath + { + Name = "Batman", + Path = "Batman( 2021 ).mp3", + Year = 2021 + }, + new NameYearPath + { + Name = "Batman(*2021*)", + Path = "Batman(*2021*).mp3", + Year = null + }, + new NameYearPath + { + Name = "Batman", + Path = "Batman.mp3", + Year = null + }, + new NameYearPath + { + Name = "+ Batman .", + Path = " + Batman . .mp3", + Year = null + }, + new NameYearPath + { + Name = " ", + Path = " .mp3", + Year = null + } }; var resolver = GetResolver(); - var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + var result = resolver.Resolve(data.Select(i => new FileSystemMetadata { IsDirectory = false, - FullName = i + FullName = i.Path })).ToList(); - Assert.Equal(3, result[0].Files.Count); - Assert.Equal(2007, result[0].Year); - Assert.Equal(2020, result[1].Year); - Assert.Equal(2021, result[2].Year); - Assert.Null(result[2].Year); + Assert.Equal(data.Length, result.Count); + + for (int i = 0; i < data.Length; i++) + { + Assert.Equal(data[i].Name, result[i].Name); + Assert.Equal(data[i].Year, result[i].Year); + } } [Fact] @@ -180,5 +217,12 @@ namespace Jellyfin.Naming.Tests.AudioBook { return new AudioBookListResolver(_namingOptions); } + + internal struct NameYearPath + { + public string Name; + public string Path; + public int? Year; + } } } diff --git a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs index 5e9d12970a..b3257ace3b 100644 --- a/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs +++ b/tests/Jellyfin.Naming.Tests/AudioBook/AudioBookResolverTests.cs @@ -35,7 +35,6 @@ namespace Jellyfin.Naming.Tests.AudioBook }; } - [Theory] [MemberData(nameof(GetResolveFileTestData))] public void Resolve_ValidFileName_Success(AudioBookFileInfo expectedResult) -- cgit v1.2.3 From 3466dc558186f435eafae9b9d3fd80621fdbd79f Mon Sep 17 00:00:00 2001 From: Stepan Date: Thu, 5 Nov 2020 16:59:15 +0100 Subject: Finish coverage for Emby.Naming.Video --- Emby.Naming/Common/NamingOptions.cs | 6 +- Emby.Naming/Video/ExtraResolver.cs | 7 +- Emby.Naming/Video/FlagParser.cs | 2 +- Emby.Naming/Video/StackResolver.cs | 8 +- Emby.Naming/Video/StubResolver.cs | 2 +- Emby.Naming/Video/VideoFileInfo.cs | 34 ++- Emby.Naming/Video/VideoResolver.cs | 28 ++- tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs | 25 ++- tests/Jellyfin.Naming.Tests/Video/StubTests.cs | 3 +- .../Video/VideoListResolverTests.cs | 29 ++- .../Video/VideoResolverTests.cs | 235 ++++++++++----------- 11 files changed, 230 insertions(+), 149 deletions(-) (limited to 'Emby.Naming/Video/StackResolver.cs') diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 3a7bcb7d72..a1b95954ec 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -120,9 +120,9 @@ namespace Emby.Naming.Common VideoFileStackingExpressions = new[] { - "(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[0-9]+)(.*?)(\\.[^.]+)$", - "(.*?)([ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[a-d])(.*?)(\\.[^.]+)$", - "(.*?)([ ._-]*[a-d])(.*?)(\\.[^.]+)$" + "(?.*?)(?<volume>[ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[0-9]+)(?<ignore>.*?)(?<extension>\\.[^.]+)$", + "(?<title>.*?)(?<volume>[ _.-]*(?:cd|dvd|p(?:ar)?t|dis[ck])[ _.-]*[a-d])(?<ignore>.*?)(?<extension>\\.[^.]+)$", + "(?<title>.*?)(?<volume>[ ._-]*[a-d])(?<ignore>.*?)(?<extension>\\.[^.]+)$" }; CleanDateTimes = new[] diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs index fc0424faab..bd78299dcd 100644 --- a/Emby.Naming/Video/ExtraResolver.cs +++ b/Emby.Naming/Video/ExtraResolver.cs @@ -45,7 +45,8 @@ namespace Emby.Naming.Video } else { - return result; + // Currently unreachable code if new rule.MediaType is desired add if clause with proper tests + throw new InvalidOperationException(); } if (rule.RuleType == ExtraRuleType.Filename) @@ -70,6 +71,9 @@ namespace Emby.Naming.Video } else if (rule.RuleType == ExtraRuleType.Regex) { + // Currently unreachable code if new rule.MediaType is desired add if clause with proper tests + throw new InvalidOperationException(); + /* var filename = Path.GetFileName(path); var regex = new Regex(rule.Token, RegexOptions.IgnoreCase); @@ -79,6 +83,7 @@ namespace Emby.Naming.Video result.ExtraType = rule.ExtraType; result.Rule = rule; } + */ } else if (rule.RuleType == ExtraRuleType.DirectoryName) { diff --git a/Emby.Naming/Video/FlagParser.cs b/Emby.Naming/Video/FlagParser.cs index 27ca1abf1a..6015c41a0c 100644 --- a/Emby.Naming/Video/FlagParser.cs +++ b/Emby.Naming/Video/FlagParser.cs @@ -24,7 +24,7 @@ namespace Emby.Naming.Video { if (string.IsNullOrEmpty(path)) { - throw new ArgumentNullException(nameof(path)); + return Array.Empty<string>(); } // Note: the tags need be be surrounded be either a space ( ), hyphen -, dot . or underscore _. diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index e11b4063ce..30b812e21d 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -86,10 +86,10 @@ namespace Emby.Naming.Video if (match1.Success) { - var title1 = match1.Groups[1].Value; - var volume1 = match1.Groups[2].Value; - var ignore1 = match1.Groups[3].Value; - var extension1 = match1.Groups[4].Value; + var title1 = match1.Groups["title"].Value; + var volume1 = match1.Groups["volume"].Value; + var ignore1 = match1.Groups["ignore"].Value; + var extension1 = match1.Groups["extension"].Value; var j = i + 1; while (j < list.Count) diff --git a/Emby.Naming/Video/StubResolver.cs b/Emby.Naming/Video/StubResolver.cs index f1b5d7bcca..b0eb92e53e 100644 --- a/Emby.Naming/Video/StubResolver.cs +++ b/Emby.Naming/Video/StubResolver.cs @@ -14,7 +14,7 @@ namespace Emby.Naming.Video { stubType = default; - if (path == null) + if (string.IsNullOrEmpty(path)) { return false; } diff --git a/Emby.Naming/Video/VideoFileInfo.cs b/Emby.Naming/Video/VideoFileInfo.cs index 12bd8c4364..7d7411a563 100644 --- a/Emby.Naming/Video/VideoFileInfo.cs +++ b/Emby.Naming/Video/VideoFileInfo.cs @@ -7,6 +7,35 @@ namespace Emby.Naming.Video /// </summary> public class VideoFileInfo { + /// <summary> + /// Initializes a new instance of the <see cref="VideoFileInfo"/> class. + /// </summary> + /// <param name="name">Name of file.</param> + /// <param name="path">Path to the file.</param> + /// <param name="container">Container type.</param> + /// <param name="year">Year of release.</param> + /// <param name="extraType">Extra type.</param> + /// <param name="extraRule">Extra rule.</param> + /// <param name="format3D">Format 3D.</param> + /// <param name="is3D">Is 3D.</param> + /// <param name="isStub">Is Stub.</param> + /// <param name="stubType">Stub type.</param> + /// <param name="isDirectory">Is directory.</param> + public VideoFileInfo(string name, string? path, string? container, int? year = default, ExtraType? extraType = default, ExtraRule? extraRule = default, string? format3D = default, bool is3D = default, bool isStub = default, string? stubType = default, bool isDirectory = default) + { + Path = path; + Container = container; + Name = name; + Year = year; + ExtraType = extraType; + ExtraRule = extraRule; + Format3D = format3D; + Is3D = is3D; + IsStub = isStub; + StubType = stubType; + IsDirectory = isDirectory; + } + /// <summary> /// Gets or sets the path. /// </summary> @@ -23,7 +52,7 @@ namespace Emby.Naming.Video /// Gets or sets the name. /// </summary> /// <value>The name.</value> - public string? Name { get; set; } + public string Name { get; set; } /// <summary> /// Gets or sets the year. @@ -84,8 +113,7 @@ namespace Emby.Naming.Video /// <inheritdoc /> public override string ToString() { - // Makes debugging easier - return Name ?? base.ToString(); + return "VideoFileInfo(Name: '" + Name + "')"; } } } diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index b9ff90179f..fed567d03d 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -49,7 +49,7 @@ namespace Emby.Naming.Video { if (string.IsNullOrEmpty(path)) { - throw new ArgumentNullException(nameof(path)); + return null; } bool isStub = false; @@ -99,20 +99,18 @@ namespace Emby.Naming.Video } } - return new VideoFileInfo - { - Path = path, - Container = container, - IsStub = isStub, - Name = name, - Year = year, - StubType = stubType, - Is3D = format3DResult.Is3D, - Format3D = format3DResult.Format3D, - ExtraType = extraResult.ExtraType, - IsDirectory = isDirectory, - ExtraRule = extraResult.Rule - }; + return new VideoFileInfo( + path: path, + container: container, + isStub: isStub, + name: name, + year: year, + stubType: stubType, + is3D: format3DResult.Is3D, + format3D: format3DResult.Format3D, + extraType: extraResult.ExtraType, + isDirectory: isDirectory, + extraRule: extraResult.Rule); } public bool IsVideoFile(string path) diff --git a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs index 8dfb8f8591..12a9b023bf 100644 --- a/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/ExtraTests.cs @@ -1,7 +1,9 @@ -using Emby.Naming.Common; +using System; +using Emby.Naming.Common; using Emby.Naming.Video; using MediaBrowser.Model.Entities; using Xunit; +using MediaType = Emby.Naming.Common.MediaType; namespace Jellyfin.Naming.Tests.Video { @@ -93,6 +95,27 @@ namespace Jellyfin.Naming.Tests.Video } } + [Fact] + public void TestExtraInfo_InvalidRuleMediaType() + { + var options = new NamingOptions { VideoExtraRules = new[] { new ExtraRule(ExtraType.Unknown, ExtraRuleType.DirectoryName, " ", MediaType.Photo) } }; + Assert.Throws<InvalidOperationException>(() => GetExtraTypeParser(options).GetExtraInfo("sample.jpg")); + } + + [Fact] + public void TestExtraInfo_InvalidRuleType() + { + var options = new NamingOptions { VideoExtraRules = new[] { new ExtraRule(ExtraType.Unknown, ExtraRuleType.Regex, " ", MediaType.Video) } }; + Assert.Throws<InvalidOperationException>(() => GetExtraTypeParser(options).GetExtraInfo("sample.mp4")); + } + + [Fact] + public void TestFlagsParser() + { + var flags = new FlagParser(_videoOptions).GetFlags(string.Empty); + Assert.Empty(flags); + } + private ExtraResolver GetExtraTypeParser(NamingOptions videoOptions) { return new ExtraResolver(videoOptions); diff --git a/tests/Jellyfin.Naming.Tests/Video/StubTests.cs b/tests/Jellyfin.Naming.Tests/Video/StubTests.cs index 30ba941365..6e759c6d6b 100644 --- a/tests/Jellyfin.Naming.Tests/Video/StubTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/StubTests.cs @@ -1,4 +1,4 @@ -using Emby.Naming.Common; +using Emby.Naming.Common; using Emby.Naming.Video; using Xunit; @@ -23,6 +23,7 @@ namespace Jellyfin.Naming.Tests.Video Test("video.hdtv.disc", true, "tv"); Test("video.pdtv.disc", true, "tv"); Test("video.dsr.disc", true, "tv"); + Test(string.Empty, false, "tv"); } [Fact] diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs index 12c4a50fe3..215c7e5405 100644 --- a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Emby.Naming.Common; using Emby.Naming.Video; using MediaBrowser.Model.IO; @@ -369,6 +369,26 @@ namespace Jellyfin.Naming.Tests.Video Assert.Single(result); } + [Fact] + public void TestFourRooms() + { + var files = new[] + { + @"Four Rooms - A.avi", + @"Four Rooms - A.mp4" + }; + + var resolver = GetResolver(); + + var result = resolver.Resolve(files.Select(i => new FileSystemMetadata + { + IsDirectory = false, + FullName = i + }).ToList()).ToList(); + + Assert.Equal(2, result.Count); + } + [Fact] public void TestMovieTrailer() { @@ -431,6 +451,13 @@ namespace Jellyfin.Naming.Tests.Video Assert.Single(result); } + [Fact] + public void TestDirectoryStack() + { + var stack = new FileStack(); + Assert.False(stack.ContainsFile("XX", true)); + } + private VideoListResolver GetResolver() { return new VideoListResolver(_namingOptions); diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs index 99828b2eb7..3bdafa84d9 100644 --- a/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/VideoResolverTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using Emby.Naming.Common; using Emby.Naming.Video; using MediaBrowser.Model.Entities; @@ -14,165 +15,135 @@ namespace Jellyfin.Naming.Tests.Video { yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/7 Psychos.mkv/7 Psychos.mkv", - Container = "mkv", - Name = "7 Psychos" - } + new VideoFileInfo( + path: @"/server/Movies/7 Psychos.mkv/7 Psychos.mkv", + container: "mkv", + name: "7 Psychos") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/3 days to kill (2005)/3 days to kill (2005).mkv", - Container = "mkv", - Name = "3 days to kill", - Year = 2005 - } + new VideoFileInfo( + path: @"/server/Movies/3 days to kill (2005)/3 days to kill (2005).mkv", + container: "mkv", + name: "3 days to kill", + year: 2005) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/American Psycho/American.Psycho.mkv", - Container = "mkv", - Name = "American.Psycho", - } + new VideoFileInfo( + path: @"/server/Movies/American Psycho/American.Psycho.mkv", + container: "mkv", + name: "American.Psycho") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/brave (2007)/brave (2006).3d.sbs.mkv", - Container = "mkv", - Name = "brave", - Year = 2006, - Is3D = true, - Format3D = "sbs", - } + new VideoFileInfo( + path: @"/server/Movies/brave (2007)/brave (2006).3d.sbs.mkv", + container: "mkv", + name: "brave", + year: 2006, + is3D: true, + format3D: "sbs") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006).3d1.sbas.mkv", - Container = "mkv", - Name = "300", - Year = 2006 - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006).3d1.sbas.mkv", + container: "mkv", + name: "300", + year: 2006) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006).3d.sbs.mkv", - Container = "mkv", - Name = "300", - Year = 2006, - Is3D = true, - Format3D = "sbs", - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006).3d.sbs.mkv", + container: "mkv", + name: "300", + year: 2006, + is3D: true, + format3D: "sbs") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/brave (2007)/brave (2006)-trailer.bluray.disc", - Container = "disc", - Name = "brave", - Year = 2006, - IsStub = true, - StubType = "bluray", - } + new VideoFileInfo( + path: @"/server/Movies/brave (2007)/brave (2006)-trailer.bluray.disc", + container: "disc", + name: "brave", + year: 2006, + isStub: true, + stubType: "bluray") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006)-trailer.bluray.disc", - Container = "disc", - Name = "300", - Year = 2006, - IsStub = true, - StubType = "bluray", - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006)-trailer.bluray.disc", + container: "disc", + name: "300", + year: 2006, + isStub: true, + stubType: "bluray") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/Brave (2007)/Brave (2006).bluray.disc", - Container = "disc", - Name = "Brave", - Year = 2006, - IsStub = true, - StubType = "bluray", - } + new VideoFileInfo( + path: @"/server/Movies/Brave (2007)/Brave (2006).bluray.disc", + container: "disc", + name: "Brave", + year: 2006, + isStub: true, + stubType: "bluray") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006).bluray.disc", - Container = "disc", - Name = "300", - Year = 2006, - IsStub = true, - StubType = "bluray", - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006).bluray.disc", + container: "disc", + name: "300", + year: 2006, + isStub: true, + stubType: "bluray") }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006)-trailer.mkv", - Container = "mkv", - Name = "300", - Year = 2006, - ExtraType = ExtraType.Trailer, - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006)-trailer.mkv", + container: "mkv", + name: "300", + year: 2006, + extraType: ExtraType.Trailer) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/Brave (2007)/Brave (2006)-trailer.mkv", - Container = "mkv", - Name = "Brave", - Year = 2006, - ExtraType = ExtraType.Trailer, - } + new VideoFileInfo( + path: @"/server/Movies/Brave (2007)/Brave (2006)-trailer.mkv", + container: "mkv", + name: "Brave", + year: 2006, + extraType: ExtraType.Trailer) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/300 (2007)/300 (2006).mkv", - Container = "mkv", - Name = "300", - Year = 2006 - } + new VideoFileInfo( + path: @"/server/Movies/300 (2007)/300 (2006).mkv", + container: "mkv", + name: "300", + year: 2006) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/Bad Boys (1995)/Bad Boys (1995).mkv", - Container = "mkv", - Name = "Bad Boys", - Year = 1995, - } + new VideoFileInfo( + path: @"/server/Movies/Bad Boys (1995)/Bad Boys (1995).mkv", + container: "mkv", + name: "Bad Boys", + year: 1995) }; yield return new object[] { - new VideoFileInfo() - { - Path = @"/server/Movies/Brave (2007)/Brave (2006).mkv", - Container = "mkv", - Name = "Brave", - Year = 2006, - } + new VideoFileInfo( + path: @"/server/Movies/Brave (2007)/Brave (2006).mkv", + container: "mkv", + name: "Brave", + year: 2006) }; } @@ -194,6 +165,34 @@ namespace Jellyfin.Naming.Tests.Video Assert.Equal(result?.StubType, expectedResult.StubType); Assert.Equal(result?.IsDirectory, expectedResult.IsDirectory); Assert.Equal(result?.FileNameWithoutExtension, expectedResult.FileNameWithoutExtension); + Assert.Equal(result?.ToString(), expectedResult.ToString()); + } + + [Fact] + public void ResolveFile_EmptyPath() + { + var result = new VideoResolver(_namingOptions).ResolveFile(string.Empty); + + Assert.Null(result); + } + + [Fact] + public void ResolveDirectoryTest() + { + var paths = new[] + { + @"/Server/Iron Man", + @"Batman", + string.Empty + }; + + var resolver = new VideoResolver(_namingOptions); + var results = paths.Select(path => resolver.ResolveDirectory(path)).ToList(); + + Assert.Equal(3, results.Count); + Assert.NotNull(results[0]); + Assert.NotNull(results[1]); + Assert.Null(results[2]); } } } -- cgit v1.2.3 From 693760e38ae51b9267f9383c3957df742bb136a6 Mon Sep 17 00:00:00 2001 From: Stepan <ste.martinek+git@gmail.com> Date: Tue, 10 Nov 2020 17:11:48 +0100 Subject: Xml-doc part1 --- Emby.Naming/Audio/AlbumParser.cs | 15 +++++++-- Emby.Naming/Audio/AudioFileParser.cs | 12 +++++-- Emby.Naming/AudioBook/AudioBookFilePathParser.cs | 15 +++++++-- .../AudioBook/AudioBookFilePathParserResult.cs | 12 +++++-- Emby.Naming/AudioBook/AudioBookListResolver.cs | 14 ++++++-- Emby.Naming/AudioBook/AudioBookNameParser.cs | 15 +++++++-- Emby.Naming/AudioBook/AudioBookNameParserResult.cs | 12 +++++-- Emby.Naming/AudioBook/AudioBookResolver.cs | 15 +++++++-- Emby.Naming/Common/EpisodeExpression.cs | 38 +++++++++++++++++----- Emby.Naming/Common/MediaType.cs | 2 -- Emby.Naming/Common/NamingOptions.cs | 2 -- Emby.Naming/Subtitles/SubtitleInfo.cs | 2 -- Emby.Naming/Subtitles/SubtitleParser.cs | 3 -- Emby.Naming/TV/EpisodeInfo.cs | 30 +++++++++++++++-- Emby.Naming/TV/EpisodePathParser.cs | 20 ++++++++++-- Emby.Naming/TV/EpisodePathParserResult.cs | 33 +++++++++++++++++-- Emby.Naming/TV/EpisodeResolver.cs | 3 -- Emby.Naming/TV/SeasonPathParser.cs | 2 -- Emby.Naming/TV/SeasonPathParserResult.cs | 2 -- Emby.Naming/Video/CleanDateTimeParser.cs | 9 +++-- Emby.Naming/Video/CleanDateTimeResult.cs | 19 +++++------ Emby.Naming/Video/CleanStringParser.cs | 10 ++++-- Emby.Naming/Video/ExtraResolver.cs | 3 -- Emby.Naming/Video/ExtraResult.cs | 2 -- Emby.Naming/Video/ExtraRule.cs | 2 -- Emby.Naming/Video/ExtraRuleType.cs | 5 +-- Emby.Naming/Video/FileStack.cs | 2 -- Emby.Naming/Video/FlagParser.cs | 2 -- Emby.Naming/Video/Format3DParser.cs | 2 -- Emby.Naming/Video/Format3DResult.cs | 2 -- Emby.Naming/Video/Format3DRule.cs | 2 -- Emby.Naming/Video/StackResolver.cs | 2 -- Emby.Naming/Video/StubResolver.cs | 3 -- Emby.Naming/Video/StubTypeRule.cs | 2 -- Emby.Naming/Video/VideoListResolver.cs | 2 -- Emby.Naming/Video/VideoResolver.cs | 3 -- 36 files changed, 218 insertions(+), 101 deletions(-) (limited to 'Emby.Naming/Video/StackResolver.cs') diff --git a/Emby.Naming/Audio/AlbumParser.cs b/Emby.Naming/Audio/AlbumParser.cs index b63be3a647..bbfdccc902 100644 --- a/Emby.Naming/Audio/AlbumParser.cs +++ b/Emby.Naming/Audio/AlbumParser.cs @@ -1,6 +1,3 @@ -#nullable enable -#pragma warning disable CS1591 - using System; using System.Globalization; using System.IO; @@ -9,15 +6,27 @@ using Emby.Naming.Common; namespace Emby.Naming.Audio { + /// <summary> + /// Helper class to determine if Album is multipart. + /// </summary> public class AlbumParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="AlbumParser"/> class. + /// </summary> + /// <param name="options">Naming options containing AlbumStackingPrefixes.</param> public AlbumParser(NamingOptions options) { _options = options; } + /// <summary> + /// Function that determines if album is multipart. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>True if album is multipart.</returns> public bool IsMultiPart(string path) { var filename = Path.GetFileName(path); diff --git a/Emby.Naming/Audio/AudioFileParser.cs b/Emby.Naming/Audio/AudioFileParser.cs index 6b2f4be93e..8b47dd12e4 100644 --- a/Emby.Naming/Audio/AudioFileParser.cs +++ b/Emby.Naming/Audio/AudioFileParser.cs @@ -1,6 +1,3 @@ -#nullable enable -#pragma warning disable CS1591 - using System; using System.IO; using System.Linq; @@ -8,8 +5,17 @@ using Emby.Naming.Common; namespace Emby.Naming.Audio { + /// <summary> + /// Static helper class to determine if file at path is audio file. + /// </summary> public static class AudioFileParser { + /// <summary> + /// Static helper method to determine if file at path is audio file. + /// </summary> + /// <param name="path">Path to file.</param> + /// <param name="options"><see cref="NamingOptions"/> containing AudioFileExtensions.</param> + /// <returns>True if file at path is audio file.</returns> public static bool IsAudioFile(string path, NamingOptions options) { var extension = Path.GetExtension(path); diff --git a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs index 56580f194b..7b4429ab15 100644 --- a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs +++ b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs @@ -1,6 +1,3 @@ -#nullable enable -#pragma warning disable CS1591 - using System.Globalization; using System.IO; using System.Text.RegularExpressions; @@ -8,15 +5,27 @@ using Emby.Naming.Common; namespace Emby.Naming.AudioBook { + /// <summary> + /// Parser class to extract part and/or chapter number from audiobook filename. + /// </summary> public class AudioBookFilePathParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="AudioBookFilePathParser"/> class. + /// </summary> + /// <param name="options">Naming options containing AudioBookPartsExpressions.</param> public AudioBookFilePathParser(NamingOptions options) { _options = options; } + /// <summary> + /// Based on regex determines if filename includes part/chapter number. + /// </summary> + /// <param name="path">Path to audiobook file.</param> + /// <returns>Returns <see cref="AudioBookFilePathParser"/> object.</returns> public AudioBookFilePathParserResult Parse(string path) { AudioBookFilePathParserResult result = default; diff --git a/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs b/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs index b65d231dfd..48ab8b57dc 100644 --- a/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs +++ b/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs @@ -1,12 +1,18 @@ -#nullable enable -#pragma warning disable CS1591 - namespace Emby.Naming.AudioBook { + /// <summary> + /// Data object for passing result of audiobook part/chapter extraction. + /// </summary> public struct AudioBookFilePathParserResult { + /// <summary> + /// Gets or sets optional number of path extracted from audiobook filename. + /// </summary> public int? PartNumber { get; set; } + /// <summary> + /// Gets or sets optional number of chapter extracted from audiobook filename. + /// </summary> public int? ChapterNumber { get; set; } } } diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs index e8908aa37c..b203f99022 100644 --- a/Emby.Naming/AudioBook/AudioBookListResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.IO; @@ -10,15 +8,27 @@ using MediaBrowser.Model.IO; namespace Emby.Naming.AudioBook { + /// <summary> + /// Class used to resolve Name, Year, alternative files and extras from stack of files. + /// </summary> public class AudioBookListResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="AudioBookListResolver"/> class. + /// </summary> + /// <param name="options">Naming options passed along to <see cref="AudioBookResolver"/> and <see cref="AudioBookNameParser"/>.</param> public AudioBookListResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Resolves Name, Year and differentiate alternative files and extras from regular audiobook files. + /// </summary> + /// <param name="files">List of files related to audiobook.</param> + /// <returns>Returns IEnumerable of <see cref="AudioBookInfo"/>.</returns> public IEnumerable<AudioBookInfo> Resolve(IEnumerable<FileSystemMetadata> files) { var audioBookResolver = new AudioBookResolver(_options); diff --git a/Emby.Naming/AudioBook/AudioBookNameParser.cs b/Emby.Naming/AudioBook/AudioBookNameParser.cs index 7c86161241..120482bc2c 100644 --- a/Emby.Naming/AudioBook/AudioBookNameParser.cs +++ b/Emby.Naming/AudioBook/AudioBookNameParser.cs @@ -1,21 +1,30 @@ -#nullable enable -#pragma warning disable CS1591 - using System.Globalization; using System.Text.RegularExpressions; using Emby.Naming.Common; namespace Emby.Naming.AudioBook { + /// <summary> + /// Helper class to retrieve name and year from audiobook previously retrieved name. + /// </summary> public class AudioBookNameParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="AudioBookNameParser"/> class. + /// </summary> + /// <param name="options">Naming options containing AudioBookNamesExpressions.</param> public AudioBookNameParser(NamingOptions options) { _options = options; } + /// <summary> + /// Parse name and year from previously determined name of audiobook. + /// </summary> + /// <param name="name">Name of the audiobook.</param> + /// <returns>Returns <see cref="AudioBookNameParserResult"/> object.</returns> public AudioBookNameParserResult Parse(string name) { AudioBookNameParserResult result = default; diff --git a/Emby.Naming/AudioBook/AudioBookNameParserResult.cs b/Emby.Naming/AudioBook/AudioBookNameParserResult.cs index b28e259dda..3f2d7b2b0b 100644 --- a/Emby.Naming/AudioBook/AudioBookNameParserResult.cs +++ b/Emby.Naming/AudioBook/AudioBookNameParserResult.cs @@ -1,12 +1,18 @@ -#nullable enable -#pragma warning disable CS1591 - namespace Emby.Naming.AudioBook { + /// <summary> + /// Data object used to pass result of name and year parsing. + /// </summary> public struct AudioBookNameParserResult { + /// <summary> + /// Gets or sets name of audiobook. + /// </summary> public string Name { get; set; } + /// <summary> + /// Gets or sets optional year of release. + /// </summary> public int? Year { get; set; } } } diff --git a/Emby.Naming/AudioBook/AudioBookResolver.cs b/Emby.Naming/AudioBook/AudioBookResolver.cs index c7b3b2d2d1..f6ad3601d7 100644 --- a/Emby.Naming/AudioBook/AudioBookResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookResolver.cs @@ -1,6 +1,3 @@ -#nullable enable -#pragma warning disable CS1591 - using System; using System.IO; using System.Linq; @@ -8,15 +5,27 @@ using Emby.Naming.Common; namespace Emby.Naming.AudioBook { + /// <summary> + /// Resolve specifics (path, container, partNumber, chapterNumber) about audiobook file. + /// </summary> public class AudioBookResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="AudioBookResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> containing AudioFileExtensions and also used to pass to AudioBookFilePathParser.</param> public AudioBookResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Resolve specifics (path, container, partNumber, chapterNumber) about audiobook file. + /// </summary> + /// <param name="path">Path to audiobook file.</param> + /// <returns>Returns <see cref="AudioBookResolver"/> object.</returns> public AudioBookFileInfo? Resolve(string path) { if (path.Length == 0 || Path.GetFileNameWithoutExtension(path).Length == 0) diff --git a/Emby.Naming/Common/EpisodeExpression.cs b/Emby.Naming/Common/EpisodeExpression.cs index 00b27541a6..19d3c7aab0 100644 --- a/Emby.Naming/Common/EpisodeExpression.cs +++ b/Emby.Naming/Common/EpisodeExpression.cs @@ -1,16 +1,22 @@ -#pragma warning disable CS1591 - using System; using System.Text.RegularExpressions; namespace Emby.Naming.Common { + /// <summary> + /// Regular expressions for parsing TV Episodes. + /// </summary> public class EpisodeExpression { private string _expression; private Regex? _regex; - public EpisodeExpression(string expression, bool byDate) + /// <summary> + /// Initializes a new instance of the <see cref="EpisodeExpression"/> class. + /// </summary> + /// <param name="expression">Regular expressions.</param> + /// <param name="byDate">True if date is expected.</param> + public EpisodeExpression(string expression, bool byDate = false) { _expression = expression; IsByDate = byDate; @@ -18,11 +24,9 @@ namespace Emby.Naming.Common SupportsAbsoluteEpisodeNumbers = true; } - public EpisodeExpression(string expression) - : this(expression, false) - { - } - + /// <summary> + /// Gets or sets raw expressions string. + /// </summary> public string Expression { get => _expression; @@ -33,16 +37,34 @@ namespace Emby.Naming.Common } } + /// <summary> + /// Gets or sets a value indicating whether gets or sets property indicating if date can be find in expression. + /// </summary> public bool IsByDate { get; set; } + /// <summary> + /// Gets or sets a value indicating whether gets or sets property indicating if expression is optimistic. + /// </summary> public bool IsOptimistic { get; set; } + /// <summary> + /// Gets or sets a value indicating whether gets or sets property indicating if expression is named. + /// </summary> public bool IsNamed { get; set; } + /// <summary> + /// Gets or sets a value indicating whether gets or sets property indicating if expression supports episodes with absolute numbers. + /// </summary> public bool SupportsAbsoluteEpisodeNumbers { get; set; } + /// <summary> + /// Gets or sets optional list of date formats used for date parsing. + /// </summary> public string[] DateTimeFormats { get; set; } + /// <summary> + /// Gets a <see cref="Regex"/> expressions objects (creates it if null). + /// </summary> public Regex Regex => _regex ??= new Regex(Expression, RegexOptions.IgnoreCase | RegexOptions.Compiled); } } diff --git a/Emby.Naming/Common/MediaType.cs b/Emby.Naming/Common/MediaType.cs index 148833765f..1231b18871 100644 --- a/Emby.Naming/Common/MediaType.cs +++ b/Emby.Naming/Common/MediaType.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.Common { public enum MediaType diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 471491d22c..0f02c03cbb 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Linq; using System.Text.RegularExpressions; diff --git a/Emby.Naming/Subtitles/SubtitleInfo.cs b/Emby.Naming/Subtitles/SubtitleInfo.cs index 2f16fb2df9..62cc3ead17 100644 --- a/Emby.Naming/Subtitles/SubtitleInfo.cs +++ b/Emby.Naming/Subtitles/SubtitleInfo.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.Subtitles { public class SubtitleInfo diff --git a/Emby.Naming/Subtitles/SubtitleParser.cs b/Emby.Naming/Subtitles/SubtitleParser.cs index c8659e1b26..476a83cf35 100644 --- a/Emby.Naming/Subtitles/SubtitleParser.cs +++ b/Emby.Naming/Subtitles/SubtitleParser.cs @@ -1,6 +1,3 @@ -#nullable enable -#pragma warning disable CS1591 - using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/TV/EpisodeInfo.cs b/Emby.Naming/TV/EpisodeInfo.cs index e01c810628..a8920b36ae 100644 --- a/Emby.Naming/TV/EpisodeInfo.cs +++ b/Emby.Naming/TV/EpisodeInfo.cs @@ -1,9 +1,14 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.TV { + /// <summary> + /// Holder object for Episode information. + /// </summary> public class EpisodeInfo { + /// <summary> + /// Initializes a new instance of the <see cref="EpisodeInfo"/> class. + /// </summary> + /// <param name="path">Path to the file.</param> public EpisodeInfo(string path) { Path = path; @@ -51,18 +56,39 @@ namespace Emby.Naming.TV /// <value>The type of the stub.</value> public string? StubType { get; set; } + /// <summary> + /// Gets or sets optional season number. + /// </summary> public int? SeasonNumber { get; set; } + /// <summary> + /// Gets or sets optional episode number. + /// </summary> public int? EpisodeNumber { get; set; } + /// <summary> + /// Gets or sets optional ending episode number. For multi-episode files 1-13. + /// </summary> public int? EndingEpisodeNumber { get; set; } + /// <summary> + /// Gets or sets optional year of release. + /// </summary> public int? Year { get; set; } + /// <summary> + /// Gets or sets optional year of release. + /// </summary> public int? Month { get; set; } + /// <summary> + /// Gets or sets optional day of release. + /// </summary> public int? Day { get; set; } + /// <summary> + /// Gets or sets a value indicating whether by date expression was used. + /// </summary> public bool IsByDate { get; set; } } } diff --git a/Emby.Naming/TV/EpisodePathParser.cs b/Emby.Naming/TV/EpisodePathParser.cs index d9cc8172bd..6d0597356b 100644 --- a/Emby.Naming/TV/EpisodePathParser.cs +++ b/Emby.Naming/TV/EpisodePathParser.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System; using System.Collections.Generic; using System.Globalization; @@ -9,15 +6,32 @@ using Emby.Naming.Common; namespace Emby.Naming.TV { + /// <summary> + /// Used to parse information about episode from path. + /// </summary> public class EpisodePathParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="EpisodePathParser"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing EpisodeExpressions and MultipleEpisodeExpressions.</param> public EpisodePathParser(NamingOptions options) { _options = options; } + /// <summary> + /// Parses information about episode from path. + /// </summary> + /// <param name="path">Path.</param> + /// <param name="isDirectory">Is path for a directory or file.</param> + /// <param name="isNamed">Do we want to use IsNamed expressions.</param> + /// <param name="isOptimistic">Do we want to use Optimistic expressions.</param> + /// <param name="supportsAbsoluteNumbers">Do we want to use expressions supporting absolute episode numbers.</param> + /// <param name="fillExtendedInfo">Should we attempt to retrieve extended information.</param> + /// <returns>Returns <see cref="EpisodePathParserResult"/> object.</returns> public EpisodePathParserResult Parse( string path, bool isDirectory, diff --git a/Emby.Naming/TV/EpisodePathParserResult.cs b/Emby.Naming/TV/EpisodePathParserResult.cs index 5fa0b6f0b4..233d5a4f6c 100644 --- a/Emby.Naming/TV/EpisodePathParserResult.cs +++ b/Emby.Naming/TV/EpisodePathParserResult.cs @@ -1,25 +1,54 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.TV { + /// <summary> + /// Holder object for <see cref="EpisodePathParser"/> result. + /// </summary> public class EpisodePathParserResult { + /// <summary> + /// Gets or sets optional season number. + /// </summary> public int? SeasonNumber { get; set; } + /// <summary> + /// Gets or sets optional episode number. + /// </summary> public int? EpisodeNumber { get; set; } + /// <summary> + /// Gets or sets optional ending episode number. For multi-episode files 1-13. + /// </summary> public int? EndingEpisodeNumber { get; set; } + /// <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; } + /// <summary> + /// Gets or sets a value indicating whether by date expression was used. + /// </summary> public bool IsByDate { get; set; } + /// <summary> + /// Gets or sets optional year of release. + /// </summary> public int? Year { get; set; } + /// <summary> + /// Gets or sets optional year of release. + /// </summary> public int? Month { get; set; } + /// <summary> + /// Gets or sets optional day of release. + /// </summary> public int? Day { get; set; } } } diff --git a/Emby.Naming/TV/EpisodeResolver.cs b/Emby.Naming/TV/EpisodeResolver.cs index 5f02c553de..26dd6915b9 100644 --- a/Emby.Naming/TV/EpisodeResolver.cs +++ b/Emby.Naming/TV/EpisodeResolver.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index 142680f0cd..cf99097bc4 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Globalization; using System.IO; diff --git a/Emby.Naming/TV/SeasonPathParserResult.cs b/Emby.Naming/TV/SeasonPathParserResult.cs index a142fafea0..f52f941a7c 100644 --- a/Emby.Naming/TV/SeasonPathParserResult.cs +++ b/Emby.Naming/TV/SeasonPathParserResult.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.TV { public class SeasonPathParserResult diff --git a/Emby.Naming/Video/CleanDateTimeParser.cs b/Emby.Naming/Video/CleanDateTimeParser.cs index f05d540f8b..0ee633dcc6 100644 --- a/Emby.Naming/Video/CleanDateTimeParser.cs +++ b/Emby.Naming/Video/CleanDateTimeParser.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System.Collections.Generic; using System.Globalization; using System.Text.RegularExpressions; @@ -12,6 +9,12 @@ namespace Emby.Naming.Video /// </summary> public static class CleanDateTimeParser { + /// <summary> + /// Attempts to clean the name. + /// </summary> + /// <param name="name">Name of video.</param> + /// <param name="cleanDateTimeRegexes">Optional list of regexes to clean the name.</param> + /// <returns>Returns <see cref="CleanDateTimeResult"/> object.</returns> public static CleanDateTimeResult Clean(string name, IReadOnlyList<Regex> cleanDateTimeRegexes) { CleanDateTimeResult result = new CleanDateTimeResult(name); diff --git a/Emby.Naming/Video/CleanDateTimeResult.cs b/Emby.Naming/Video/CleanDateTimeResult.cs index 57eeaa7e32..c675a19d0f 100644 --- a/Emby.Naming/Video/CleanDateTimeResult.cs +++ b/Emby.Naming/Video/CleanDateTimeResult.cs @@ -1,22 +1,21 @@ -#pragma warning disable CS1591 -#nullable enable - namespace Emby.Naming.Video { + /// <summary> + /// Holder structure for name and year. + /// </summary> public readonly struct CleanDateTimeResult { - public CleanDateTimeResult(string name, int? year) + /// <summary> + /// Initializes a new instance of the <see cref="CleanDateTimeResult"/> struct. + /// </summary> + /// <param name="name">Name of video.</param> + /// <param name="year">Year of release.</param> + public CleanDateTimeResult(string name, int? year = null) { Name = name; Year = year; } - public CleanDateTimeResult(string name) - { - Name = name; - Year = null; - } - /// <summary> /// Gets the name. /// </summary> diff --git a/Emby.Naming/Video/CleanStringParser.cs b/Emby.Naming/Video/CleanStringParser.cs index 3f584d5847..09a0cd1893 100644 --- a/Emby.Naming/Video/CleanStringParser.cs +++ b/Emby.Naming/Video/CleanStringParser.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System; using System.Collections.Generic; using System.Text.RegularExpressions; @@ -12,6 +9,13 @@ namespace Emby.Naming.Video /// </summary> public static class CleanStringParser { + /// <summary> + /// Attempts to extract clean name with regular expressions. + /// </summary> + /// <param name="name">Name of file.</param> + /// <param name="expressions">List of regex to parse name and year from.</param> + /// <param name="newName">Parsing result string.</param> + /// <returns>True if parsing was successful.</returns> public static bool TryClean(string name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName) { var len = expressions.Count; diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs index bd78299dcd..98ea342acc 100644 --- a/Emby.Naming/Video/ExtraResolver.cs +++ b/Emby.Naming/Video/ExtraResolver.cs @@ -1,9 +1,6 @@ -#pragma warning disable CS1591 - using System; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using Emby.Naming.Audio; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/ExtraResult.cs b/Emby.Naming/Video/ExtraResult.cs index 6be7e60525..f3b8d2a2fc 100644 --- a/Emby.Naming/Video/ExtraResult.cs +++ b/Emby.Naming/Video/ExtraResult.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using MediaBrowser.Model.Entities; namespace Emby.Naming.Video diff --git a/Emby.Naming/Video/ExtraRule.cs b/Emby.Naming/Video/ExtraRule.cs index c018894fdf..a93474bc69 100644 --- a/Emby.Naming/Video/ExtraRule.cs +++ b/Emby.Naming/Video/ExtraRule.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using MediaBrowser.Model.Entities; using MediaType = Emby.Naming.Common.MediaType; diff --git a/Emby.Naming/Video/ExtraRuleType.cs b/Emby.Naming/Video/ExtraRuleType.cs index 98114c7e8b..3243195057 100644 --- a/Emby.Naming/Video/ExtraRuleType.cs +++ b/Emby.Naming/Video/ExtraRuleType.cs @@ -1,7 +1,8 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.Video { + /// <summary> + /// Extra rules type to determine against what <see cref="ExtraRule.Token"/> should be matched. + /// </summary> public enum ExtraRuleType { /// <summary> diff --git a/Emby.Naming/Video/FileStack.cs b/Emby.Naming/Video/FileStack.cs index b0a22b18b0..75620e9610 100644 --- a/Emby.Naming/Video/FileStack.cs +++ b/Emby.Naming/Video/FileStack.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Linq; diff --git a/Emby.Naming/Video/FlagParser.cs b/Emby.Naming/Video/FlagParser.cs index 6015c41a0c..cd15b4666f 100644 --- a/Emby.Naming/Video/FlagParser.cs +++ b/Emby.Naming/Video/FlagParser.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.IO; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/Format3DParser.cs b/Emby.Naming/Video/Format3DParser.cs index fb881f978f..73ad36af46 100644 --- a/Emby.Naming/Video/Format3DParser.cs +++ b/Emby.Naming/Video/Format3DParser.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Linq; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/Format3DResult.cs b/Emby.Naming/Video/Format3DResult.cs index 36dc1c12b2..539060c982 100644 --- a/Emby.Naming/Video/Format3DResult.cs +++ b/Emby.Naming/Video/Format3DResult.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System.Collections.Generic; namespace Emby.Naming.Video diff --git a/Emby.Naming/Video/Format3DRule.cs b/Emby.Naming/Video/Format3DRule.cs index 7679164b30..bee5c109e1 100644 --- a/Emby.Naming/Video/Format3DRule.cs +++ b/Emby.Naming/Video/Format3DRule.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.Video { public class Format3DRule diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index 30b812e21d..d6de468cc9 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.IO; diff --git a/Emby.Naming/Video/StubResolver.cs b/Emby.Naming/Video/StubResolver.cs index b0eb92e53e..6241a46b03 100644 --- a/Emby.Naming/Video/StubResolver.cs +++ b/Emby.Naming/Video/StubResolver.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/Video/StubTypeRule.cs b/Emby.Naming/Video/StubTypeRule.cs index fa42af6049..df2d3c7d22 100644 --- a/Emby.Naming/Video/StubTypeRule.cs +++ b/Emby.Naming/Video/StubTypeRule.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - namespace Emby.Naming.Video { public class StubTypeRule diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index be9b4959a7..dda3225217 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -1,5 +1,3 @@ -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.IO; diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index fed567d03d..31b47cdf15 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -1,6 +1,3 @@ -#pragma warning disable CS1591 -#nullable enable - using System; using System.IO; using System.Linq; -- cgit v1.2.3 From 158eff62d75db2d5e6e6f09fbe6e03eac607fc56 Mon Sep 17 00:00:00 2001 From: Stepan <ste.martinek+git@gmail.com> Date: Tue, 10 Nov 2020 19:23:10 +0100 Subject: Xml-doc part2 --- Emby.Naming/Common/MediaType.cs | 3 + Emby.Naming/Common/NamingOptions.cs | 87 ++++++++++++++++++++++ Emby.Naming/Subtitles/SubtitleInfo.cs | 9 +++ Emby.Naming/Subtitles/SubtitleParser.cs | 14 +++- Emby.Naming/TV/EpisodeResolver.cs | 17 +++++ Emby.Naming/TV/SeasonPathParser.cs | 10 +++ Emby.Naming/TV/SeasonPathParserResult.cs | 7 ++ Emby.Naming/Video/ExtraResolver.cs | 12 +++ Emby.Naming/Video/ExtraResult.cs | 3 + Emby.Naming/Video/ExtraRule.cs | 7 ++ Emby.Naming/Video/FileStack.cs | 21 ++++++ Emby.Naming/Video/FlagParser.cs | 18 +++++ Emby.Naming/Video/Format3DParser.cs | 12 +++ Emby.Naming/Video/Format3DResult.cs | 6 ++ Emby.Naming/Video/Format3DRule.cs | 8 ++ Emby.Naming/Video/StackResolver.cs | 27 +++++++ Emby.Naming/Video/StubResolver.cs | 10 +++ Emby.Naming/Video/StubTypeRule.cs | 8 ++ Emby.Naming/Video/VideoListResolver.cs | 13 ++++ Emby.Naming/Video/VideoResolver.cs | 29 ++++++++ .../Subtitles/SubtitleParserTests.cs | 7 +- 21 files changed, 321 insertions(+), 7 deletions(-) (limited to 'Emby.Naming/Video/StackResolver.cs') diff --git a/Emby.Naming/Common/MediaType.cs b/Emby.Naming/Common/MediaType.cs index 1231b18871..dc9784c6da 100644 --- a/Emby.Naming/Common/MediaType.cs +++ b/Emby.Naming/Common/MediaType.cs @@ -1,5 +1,8 @@ namespace Emby.Naming.Common { + /// <summary> + /// Type of audiovisual media. + /// </summary> public enum MediaType { /// <summary> diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 0f02c03cbb..035d1b2280 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -8,8 +8,14 @@ using MediaBrowser.Model.Entities; namespace Emby.Naming.Common { + /// <summary> + /// Big ugly class containing lot of different naming options that should be split and injected instead of passes everywhere. + /// </summary> public class NamingOptions { + /// <summary> + /// Initializes a new instance of the <see cref="NamingOptions"/> class. + /// </summary> public NamingOptions() { VideoFileExtensions = new[] @@ -644,58 +650,139 @@ namespace Emby.Naming.Common Compile(); } + /// <summary> + /// Gets or sets list of audio file extensions. + /// </summary> public string[] AudioFileExtensions { get; set; } + /// <summary> + /// Gets or sets list of album stacking prefixes. + /// </summary> public string[] AlbumStackingPrefixes { get; set; } + /// <summary> + /// Gets or sets list of subtitle file extensions. + /// </summary> public string[] SubtitleFileExtensions { get; set; } + /// <summary> + /// Gets or sets list of subtitles flag delimiters. + /// </summary> public char[] SubtitleFlagDelimiters { get; set; } + /// <summary> + /// Gets or sets list of subtitle forced flags. + /// </summary> public string[] SubtitleForcedFlags { get; set; } + /// <summary> + /// Gets or sets list of subtitle default flags. + /// </summary> public string[] SubtitleDefaultFlags { get; set; } + /// <summary> + /// Gets or sets list of episode regular expressions. + /// </summary> public EpisodeExpression[] EpisodeExpressions { get; set; } + /// <summary> + /// Gets or sets list of raw episode without season regular expressions strings. + /// </summary> public string[] EpisodeWithoutSeasonExpressions { get; set; } + /// <summary> + /// Gets or sets list of raw multi-part episodes regular expressions strings. + /// </summary> public string[] EpisodeMultiPartExpressions { get; set; } + /// <summary> + /// Gets or sets list of video file extensions. + /// </summary> public string[] VideoFileExtensions { get; set; } + /// <summary> + /// Gets or sets list of video stub file extensions. + /// </summary> public string[] StubFileExtensions { get; set; } + /// <summary> + /// Gets or sets list of raw audiobook parts regular expressions strings. + /// </summary> public string[] AudioBookPartsExpressions { get; set; } + /// <summary> + /// Gets or sets list of raw audiobook names regular expressions strings. + /// </summary> public string[] AudioBookNamesExpressions { get; set; } + /// <summary> + /// Gets or sets list of stub type rules. + /// </summary> public StubTypeRule[] StubTypes { get; set; } + /// <summary> + /// Gets or sets list of video flag delimiters. + /// </summary> public char[] VideoFlagDelimiters { get; set; } + /// <summary> + /// Gets or sets list of 3D Format rules. + /// </summary> public Format3DRule[] Format3DRules { get; set; } + /// <summary> + /// Gets or sets list of raw video file-stacking expressions strings. + /// </summary> public string[] VideoFileStackingExpressions { get; set; } + /// <summary> + /// Gets or sets list of raw clean DateTimes regular expressions strings. + /// </summary> public string[] CleanDateTimes { get; set; } + /// <summary> + /// Gets or sets list of raw clean strings regular expressions strings. + /// </summary> public string[] CleanStrings { get; set; } + /// <summary> + /// Gets or sets list of multi-episode regular expressions. + /// </summary> public EpisodeExpression[] MultipleEpisodeExpressions { get; set; } + /// <summary> + /// Gets or sets list of extra rules for videos. + /// </summary> public ExtraRule[] VideoExtraRules { get; set; } + /// <summary> + /// Gets list of video file-stack regular expressions. + /// </summary> public Regex[] VideoFileStackingRegexes { get; private set; } = Array.Empty<Regex>(); + /// <summary> + /// Gets list of clean datetime regular expressions. + /// </summary> public Regex[] CleanDateTimeRegexes { get; private set; } = Array.Empty<Regex>(); + /// <summary> + /// Gets list of clean string regular expressions. + /// </summary> public Regex[] CleanStringRegexes { get; private set; } = Array.Empty<Regex>(); + /// <summary> + /// Gets list of episode without season regular expressions. + /// </summary> public Regex[] EpisodeWithoutSeasonRegexes { get; private set; } = Array.Empty<Regex>(); + /// <summary> + /// Gets list of multi-part episode regular expressions. + /// </summary> public Regex[] EpisodeMultiPartRegexes { get; private set; } = Array.Empty<Regex>(); + /// <summary> + /// Compiles raw regex strings into regexes. + /// </summary> public void Compile() { VideoFileStackingRegexes = VideoFileStackingExpressions.Select(Compile).ToArray(); diff --git a/Emby.Naming/Subtitles/SubtitleInfo.cs b/Emby.Naming/Subtitles/SubtitleInfo.cs index 62cc3ead17..1fb2e0dc89 100644 --- a/Emby.Naming/Subtitles/SubtitleInfo.cs +++ b/Emby.Naming/Subtitles/SubtitleInfo.cs @@ -1,7 +1,16 @@ namespace Emby.Naming.Subtitles { + /// <summary> + /// Class holding information about subtitle. + /// </summary> public class SubtitleInfo { + /// <summary> + /// Initializes a new instance of the <see cref="SubtitleInfo"/> class. + /// </summary> + /// <param name="path">Path to file.</param> + /// <param name="isDefault">Is subtitle default.</param> + /// <param name="isForced">Is subtitle forced.</param> public SubtitleInfo(string path, bool isDefault, bool isForced) { Path = path; diff --git a/Emby.Naming/Subtitles/SubtitleParser.cs b/Emby.Naming/Subtitles/SubtitleParser.cs index 476a83cf35..e872452519 100644 --- a/Emby.Naming/Subtitles/SubtitleParser.cs +++ b/Emby.Naming/Subtitles/SubtitleParser.cs @@ -5,20 +5,32 @@ using Emby.Naming.Common; namespace Emby.Naming.Subtitles { + /// <summary> + /// Subtitle Parser class. + /// </summary> public class SubtitleParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="SubtitleParser"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing SubtitleFileExtensions, SubtitleDefaultFlags, SubtitleForcedFlags and SubtitleFlagDelimiters.</param> public SubtitleParser(NamingOptions options) { _options = options; } + /// <summary> + /// Parse file to determine if is subtitle and <see cref="SubtitleInfo"/>. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>Returns null or <see cref="SubtitleInfo"/> object if parsing is successful.</returns> public SubtitleInfo? ParseFile(string path) { if (path.Length == 0) { - throw new ArgumentException("File path can't be empty.", nameof(path)); + return null; } var extension = Path.GetExtension(path); diff --git a/Emby.Naming/TV/EpisodeResolver.cs b/Emby.Naming/TV/EpisodeResolver.cs index 26dd6915b9..f7df587864 100644 --- a/Emby.Naming/TV/EpisodeResolver.cs +++ b/Emby.Naming/TV/EpisodeResolver.cs @@ -6,15 +6,32 @@ using Emby.Naming.Video; namespace Emby.Naming.TV { + /// <summary> + /// Used to resolve information about episode from path. + /// </summary> public class EpisodeResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="EpisodeResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoFileExtensions and passed to <see cref="StubResolver"/>, <see cref="FlagParser"/>, <see cref="Format3DParser"/> and <see cref="EpisodePathParser"/>.</param> public EpisodeResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Resolve information about episode from path. + /// </summary> + /// <param name="path">Path.</param> + /// <param name="isDirectory">Is path for a directory or file.</param> + /// <param name="isNamed">Do we want to use IsNamed expressions.</param> + /// <param name="isOptimistic">Do we want to use Optimistic expressions.</param> + /// <param name="supportsAbsoluteNumbers">Do we want to use expressions supporting absolute episode numbers.</param> + /// <param name="fillExtendedInfo">Should we attempt to retrieve extended information.</param> + /// <returns>Returns null or <see cref="EpisodeInfo"/> object if successful.</returns> public EpisodeInfo? Resolve( string path, bool isDirectory, diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index cf99097bc4..d11c7c99e8 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -4,6 +4,9 @@ using System.IO; namespace Emby.Naming.TV { + /// <summary> + /// Class to parse season paths. + /// </summary> public static class SeasonPathParser { /// <summary> @@ -21,6 +24,13 @@ namespace Emby.Naming.TV "stagione" }; + /// <summary> + /// Attempts to parse season number from path. + /// </summary> + /// <param name="path">Path to season.</param> + /// <param name="supportSpecialAliases">Support special aliases when parsing.</param> + /// <param name="supportNumericSeasonFolders">Support numeric season folders when parsing.</param> + /// <returns>Returns <see cref="SeasonPathParserResult"/> object.</returns> public static SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders) { var result = new SeasonPathParserResult(); diff --git a/Emby.Naming/TV/SeasonPathParserResult.cs b/Emby.Naming/TV/SeasonPathParserResult.cs index f52f941a7c..b4b6f236a7 100644 --- a/Emby.Naming/TV/SeasonPathParserResult.cs +++ b/Emby.Naming/TV/SeasonPathParserResult.cs @@ -1,5 +1,8 @@ namespace Emby.Naming.TV { + /// <summary> + /// Data object to pass result of <see cref="SeasonPathParser"/>. + /// </summary> public class SeasonPathParserResult { /// <summary> @@ -14,6 +17,10 @@ namespace Emby.Naming.TV /// <value><c>true</c> if success; otherwise, <c>false</c>.</value> public bool Success { get; set; } + /// <summary> + /// Gets or sets a value indicating whether "Is season folder". + /// Seems redundant and barely used. + /// </summary> public bool IsSeasonFolder { get; set; } } } diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs index 98ea342acc..dd934d91b0 100644 --- a/Emby.Naming/Video/ExtraResolver.cs +++ b/Emby.Naming/Video/ExtraResolver.cs @@ -6,15 +6,27 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { + /// <summary> + /// Resolve if file is extra for video. + /// </summary> public class ExtraResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="ExtraResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoExtraRules and passed to <see cref="AudioFileParser"/> and <see cref="VideoResolver"/>.</param> public ExtraResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Attempts to resolve if file is extra. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>Returns <see cref="ExtraResult"/> object.</returns> public ExtraResult GetExtraInfo(string path) { return _options.VideoExtraRules diff --git a/Emby.Naming/Video/ExtraResult.cs b/Emby.Naming/Video/ExtraResult.cs index f3b8d2a2fc..243fc2b415 100644 --- a/Emby.Naming/Video/ExtraResult.cs +++ b/Emby.Naming/Video/ExtraResult.cs @@ -2,6 +2,9 @@ using MediaBrowser.Model.Entities; namespace Emby.Naming.Video { + /// <summary> + /// Holder object for passing results from ExtraResolver. + /// </summary> public class ExtraResult { /// <summary> diff --git a/Emby.Naming/Video/ExtraRule.cs b/Emby.Naming/Video/ExtraRule.cs index a93474bc69..e267ac55fc 100644 --- a/Emby.Naming/Video/ExtraRule.cs +++ b/Emby.Naming/Video/ExtraRule.cs @@ -8,6 +8,13 @@ namespace Emby.Naming.Video /// </summary> public class ExtraRule { + /// <summary> + /// Initializes a new instance of the <see cref="ExtraRule"/> class. + /// </summary> + /// <param name="extraType">Type of extra.</param> + /// <param name="ruleType">Type of rule.</param> + /// <param name="token">Token.</param> + /// <param name="mediaType">Media type.</param> public ExtraRule(ExtraType extraType, ExtraRuleType ruleType, string token, MediaType mediaType) { Token = token; diff --git a/Emby.Naming/Video/FileStack.cs b/Emby.Naming/Video/FileStack.cs index 75620e9610..6519db57c3 100644 --- a/Emby.Naming/Video/FileStack.cs +++ b/Emby.Naming/Video/FileStack.cs @@ -4,19 +4,40 @@ using System.Linq; namespace Emby.Naming.Video { + /// <summary> + /// Object holding list of files paths with additional information. + /// </summary> public class FileStack { + /// <summary> + /// Initializes a new instance of the <see cref="FileStack"/> class. + /// </summary> public FileStack() { Files = new List<string>(); } + /// <summary> + /// Gets or sets name of file stack. + /// </summary> public string Name { get; set; } = string.Empty; + /// <summary> + /// Gets or sets list of paths in stack. + /// </summary> public List<string> Files { get; set; } + /// <summary> + /// Gets or sets a value indicating whether stack is directory stack. + /// </summary> public bool IsDirectoryStack { get; set; } + /// <summary> + /// Helper function to determine if path is in the stack. + /// </summary> + /// <param name="file">Path of desired file.</param> + /// <param name="isDirectory">Requested type of stack.</param> + /// <returns>True if file is in the stack.</returns> public bool ContainsFile(string file, bool isDirectory) { if (IsDirectoryStack == isDirectory) diff --git a/Emby.Naming/Video/FlagParser.cs b/Emby.Naming/Video/FlagParser.cs index cd15b4666f..439de18138 100644 --- a/Emby.Naming/Video/FlagParser.cs +++ b/Emby.Naming/Video/FlagParser.cs @@ -4,20 +4,38 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { + /// <summary> + /// Parses list of flags from filename based on delimiters. + /// </summary> public class FlagParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="FlagParser"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoFlagDelimiters.</param> public FlagParser(NamingOptions options) { _options = options; } + /// <summary> + /// Calls GetFlags function with _options.VideoFlagDelimiters parameter. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>List of found flags.</returns> public string[] GetFlags(string path) { return GetFlags(path, _options.VideoFlagDelimiters); } + /// <summary> + /// Parses flags from filename based on delimiters. + /// </summary> + /// <param name="path">Path to file.</param> + /// <param name="delimiters">Delimiters used to extract flags.</param> + /// <returns>List of found flags.</returns> public string[] GetFlags(string path, char[] delimiters) { if (string.IsNullOrEmpty(path)) diff --git a/Emby.Naming/Video/Format3DParser.cs b/Emby.Naming/Video/Format3DParser.cs index 73ad36af46..4fd5d78ba7 100644 --- a/Emby.Naming/Video/Format3DParser.cs +++ b/Emby.Naming/Video/Format3DParser.cs @@ -4,15 +4,27 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { + /// <summary> + /// Parste 3D format related flags. + /// </summary> public class Format3DParser { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="Format3DParser"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoFlagDelimiters and passes options to <see cref="FlagParser"/>.</param> public Format3DParser(NamingOptions options) { _options = options; } + /// <summary> + /// Parse 3D format related flags. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>Returns <see cref="Format3DResult"/> object.</returns> public Format3DResult Parse(string path) { int oldLen = _options.VideoFlagDelimiters.Length; diff --git a/Emby.Naming/Video/Format3DResult.cs b/Emby.Naming/Video/Format3DResult.cs index 539060c982..ac935f2030 100644 --- a/Emby.Naming/Video/Format3DResult.cs +++ b/Emby.Naming/Video/Format3DResult.cs @@ -2,8 +2,14 @@ using System.Collections.Generic; namespace Emby.Naming.Video { + /// <summary> + /// Helper object to return data from <see cref="Format3DParser"/>. + /// </summary> public class Format3DResult { + /// <summary> + /// Initializes a new instance of the <see cref="Format3DResult"/> class. + /// </summary> public Format3DResult() { Tokens = new List<string>(); diff --git a/Emby.Naming/Video/Format3DRule.cs b/Emby.Naming/Video/Format3DRule.cs index bee5c109e1..e562691df9 100644 --- a/Emby.Naming/Video/Format3DRule.cs +++ b/Emby.Naming/Video/Format3DRule.cs @@ -1,7 +1,15 @@ namespace Emby.Naming.Video { + /// <summary> + /// Data holder class for 3D format rule. + /// </summary> public class Format3DRule { + /// <summary> + /// Initializes a new instance of the <see cref="Format3DRule"/> class. + /// </summary> + /// <param name="token">Token.</param> + /// <param name="precedingToken">Token present before current token.</param> public Format3DRule(string token, string? precedingToken = null) { Token = token; diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index d6de468cc9..550c429614 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -9,25 +9,47 @@ using MediaBrowser.Model.IO; namespace Emby.Naming.Video { + /// <summary> + /// Resolve <see cref="FileStack"/> from list of paths. + /// </summary> public class StackResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="StackResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoFileStackingRegexes and passes options to <see cref="VideoResolver"/>.</param> public StackResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Resolves only directories from paths. + /// </summary> + /// <param name="files">List of paths.</param> + /// <returns>Enumerable <see cref="FileStack"/> of directories.</returns> public IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files) { return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true })); } + /// <summary> + /// Resolves only files from paths. + /// </summary> + /// <param name="files">List of paths.</param> + /// <returns>Enumerable <see cref="FileStack"/> of files.</returns> public IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files) { return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false })); } + /// <summary> + /// Resolves audiobooks from paths. + /// </summary> + /// <param name="files">List of paths.</param> + /// <returns>Enumerable <see cref="FileStack"/> of directories.</returns> public IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<AudioBookFileInfo> files) { var groupedDirectoryFiles = files.GroupBy(file => Path.GetDirectoryName(file.Path)); @@ -56,6 +78,11 @@ namespace Emby.Naming.Video } } + /// <summary> + /// Resolves videos from paths. + /// </summary> + /// <param name="files">List of paths.</param> + /// <returns>Enumerable <see cref="FileStack"/> of videos.</returns> public IEnumerable<FileStack> Resolve(IEnumerable<FileSystemMetadata> files) { var resolver = new VideoResolver(_options); diff --git a/Emby.Naming/Video/StubResolver.cs b/Emby.Naming/Video/StubResolver.cs index 6241a46b03..079987fe8a 100644 --- a/Emby.Naming/Video/StubResolver.cs +++ b/Emby.Naming/Video/StubResolver.cs @@ -5,8 +5,18 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { + /// <summary> + /// Resolve if file is stub (.disc). + /// </summary> public static class StubResolver { + /// <summary> + /// Tries to resolve if file is stub (.disc). + /// </summary> + /// <param name="path">Path to file.</param> + /// <param name="options">NamingOptions containing StubFileExtensions and StubTypes.</param> + /// <param name="stubType">Stub type.</param> + /// <returns>True if file is a stub.</returns> public static bool TryResolveFile(string path, NamingOptions options, out string? stubType) { stubType = default; diff --git a/Emby.Naming/Video/StubTypeRule.cs b/Emby.Naming/Video/StubTypeRule.cs index df2d3c7d22..dfb3ac013d 100644 --- a/Emby.Naming/Video/StubTypeRule.cs +++ b/Emby.Naming/Video/StubTypeRule.cs @@ -1,7 +1,15 @@ namespace Emby.Naming.Video { + /// <summary> + /// Data class holding information about Stub type rule. + /// </summary> public class StubTypeRule { + /// <summary> + /// Initializes a new instance of the <see cref="StubTypeRule"/> class. + /// </summary> + /// <param name="token">Token.</param> + /// <param name="stubType">Stub type.</param> public StubTypeRule(string token, string stubType) { Token = token; diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index dda3225217..ee0e4d4659 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -9,15 +9,28 @@ using MediaBrowser.Model.IO; namespace Emby.Naming.Video { + /// <summary> + /// Resolves alternative versions and extras from list of video files. + /// </summary> public class VideoListResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="VideoListResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing CleanStringRegexes and VideoFlagDelimiters and passes options to <see cref="StackResolver"/> and <see cref="VideoResolver"/>.</param> public VideoListResolver(NamingOptions options) { _options = options; } + /// <summary> + /// Resolves alternative versions and extras from list of video files. + /// </summary> + /// <param name="files">List of related video files.</param> + /// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param> + /// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files togeather when related.</returns> public IEnumerable<VideoInfo> Resolve(List<FileSystemMetadata> files, bool supportMultiVersion = true) { var videoResolver = new VideoResolver(_options); diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index 31b47cdf15..d7165d8d7f 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -5,10 +5,18 @@ using Emby.Naming.Common; namespace Emby.Naming.Video { + /// <summary> + /// Resolves <see cref="VideoFileInfo"/> from file path. + /// </summary> public class VideoResolver { private readonly NamingOptions _options; + /// <summary> + /// Initializes a new instance of the <see cref="VideoResolver"/> class. + /// </summary> + /// <param name="options"><see cref="NamingOptions"/> object containing VideoFileExtensions, StubFileExtensions, CleanStringRegexes and CleanDateTimeRegexes + /// and passes options in <see cref="StubResolver"/>, <see cref="FlagParser"/>, <see cref="Format3DParser"/> and <see cref="ExtraResolver"/>.</param> public VideoResolver(NamingOptions options) { _options = options; @@ -110,23 +118,44 @@ namespace Emby.Naming.Video extraRule: extraResult.Rule); } + /// <summary> + /// Determines if path is video file based on extension. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>True if is video file.</returns> public bool IsVideoFile(string path) { var extension = Path.GetExtension(path) ?? string.Empty; return _options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase); } + /// <summary> + /// Determines if path is video file stub based on extension. + /// </summary> + /// <param name="path">Path to file.</param> + /// <returns>True if is video file stub.</returns> public bool IsStubFile(string path) { var extension = Path.GetExtension(path) ?? string.Empty; return _options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase); } + /// <summary> + /// Tries to clean name of clutter. + /// </summary> + /// <param name="name">Raw name.</param> + /// <param name="newName">Clean name.</param> + /// <returns>True if cleaning of name was successful.</returns> public bool TryCleanString(string name, out ReadOnlySpan<char> newName) { return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName); } + /// <summary> + /// Tries to get name and year from raw name. + /// </summary> + /// <param name="name">Raw name.</param> + /// <returns>Returns <see cref="CleanDateTimeResult"/> with name and optional year.</returns> public CleanDateTimeResult CleanDateTime(string name) { return CleanDateTimeParser.Clean(name, _options.CleanDateTimeRegexes); diff --git a/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs b/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs index 5152098908..f3abacb4f9 100644 --- a/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs +++ b/tests/Jellyfin.Naming.Tests/Subtitles/SubtitleParserTests.cs @@ -31,17 +31,12 @@ namespace Jellyfin.Naming.Tests.Subtitles [Theory] [InlineData("The Skin I Live In (2011).mp4")] + [InlineData("")] public void SubtitleParser_InvalidFileName_ReturnsNull(string input) { var parser = new SubtitleParser(_namingOptions); Assert.Null(parser.ParseFile(input)); } - - [Fact] - public void SubtitleParser_EmptyFileName_ThrowsArgumentException() - { - Assert.Throws<ArgumentException>(() => new SubtitleParser(_namingOptions).ParseFile(string.Empty)); - } } } -- cgit v1.2.3