diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs
index 1e4a8d2edc..dd8a05bb3e 100644
--- a/Emby.Naming/AudioBook/AudioBookListResolver.cs
+++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs
@@ -14,6 +14,7 @@ namespace Emby.Naming.AudioBook
public class AudioBookListResolver
{
private readonly NamingOptions _options;
+ private readonly AudioBookResolver _audioBookResolver;
///
/// Initializes a new instance of the class.
@@ -22,6 +23,7 @@ namespace Emby.Naming.AudioBook
public AudioBookListResolver(NamingOptions options)
{
_options = options;
+ _audioBookResolver = new AudioBookResolver(_options);
}
///
@@ -31,21 +33,19 @@ namespace Emby.Naming.AudioBook
/// Returns IEnumerable of .
public IEnumerable Resolve(IEnumerable files)
{
- var audioBookResolver = new AudioBookResolver(_options);
// File with empty fullname will be sorted out here.
var audiobookFileInfos = files
- .Select(i => audioBookResolver.Resolve(i.FullName))
+ .Select(i => _audioBookResolver.Resolve(i.FullName))
.OfType()
.ToList();
- var stackResult = new StackResolver(_options)
- .ResolveAudioBooks(audiobookFileInfos);
+ var stackResult = StackResolver.ResolveAudioBooks(audiobookFileInfos);
foreach (var stack in stackResult)
{
var stackFiles = stack.Files
- .Select(i => audioBookResolver.Resolve(i))
+ .Select(i => _audioBookResolver.Resolve(i))
.OfType()
.ToList();
diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index 7bc9fbce84..86c79166d1 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/Emby.Naming/Common/NamingOptions.cs
@@ -126,9 +126,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])(?.*?)(?\\.[^.]+)$"
+ "^(?.*?)(?[ _.-]*(?:cd|dvd|part|pt|dis[ck])[ _.-]*[0-9]+)(?.*?)(?\\.[^.]+)$",
+ "^(?.*?)(?[ _.-]*(?:cd|dvd|part|pt|dis[ck])[ _.-]*[a-d])(?.*?)(?\\.[^.]+)$",
+ "^(?.*?)(?[ ._-]*[a-d])(?.*?)(?\\.[^.]+)$"
};
CleanDateTimes = new[]
@@ -403,6 +403,12 @@ namespace Emby.Naming.Common
VideoExtraRules = new[]
{
+ new ExtraRule(
+ ExtraType.Trailer,
+ ExtraRuleType.DirectoryName,
+ "trailers",
+ MediaType.Video),
+
new ExtraRule(
ExtraType.Trailer,
ExtraRuleType.Filename,
diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs
index 7bc226614e..cd7a6c0d7a 100644
--- a/Emby.Naming/Video/ExtraResolver.cs
+++ b/Emby.Naming/Video/ExtraResolver.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text.RegularExpressions;
using Emby.Naming.Audio;
using Emby.Naming.Common;
@@ -9,45 +11,27 @@ namespace Emby.Naming.Video
///
/// Resolve if file is extra for video.
///
- public class ExtraResolver
+ public static class ExtraResolver
{
- private static readonly char[] _digits = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
- private readonly NamingOptions _options;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// object containing VideoExtraRules and passed to and .
- public ExtraResolver(NamingOptions options)
- {
- _options = options;
- }
+ private static readonly char[] _digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
///
/// Attempts to resolve if file is extra.
///
/// Path to file.
+ /// The naming options.
/// Returns object.
- public ExtraResult GetExtraInfo(string path)
+ public static ExtraResult GetExtraInfo(string path, NamingOptions namingOptions)
{
var result = new ExtraResult();
- for (var i = 0; i < _options.VideoExtraRules.Length; i++)
+ for (var i = 0; i < namingOptions.VideoExtraRules.Length; i++)
{
- var rule = _options.VideoExtraRules[i];
- if (rule.MediaType == MediaType.Audio)
+ var rule = namingOptions.VideoExtraRules[i];
+ if ((rule.MediaType == MediaType.Audio && !AudioFileParser.IsAudioFile(path, namingOptions))
+ || (rule.MediaType == MediaType.Video && !VideoResolver.IsVideoFile(path, namingOptions)))
{
- if (!AudioFileParser.IsAudioFile(path, _options))
- {
- continue;
- }
- }
- else if (rule.MediaType == MediaType.Video)
- {
- if (!VideoResolver.IsVideoFile(path, _options))
- {
- continue;
- }
+ continue;
}
var pathSpan = path.AsSpan();
@@ -76,7 +60,7 @@ namespace Emby.Naming.Video
{
var filename = Path.GetFileName(path);
- var regex = new Regex(rule.Token, RegexOptions.IgnoreCase);
+ var regex = new Regex(rule.Token, RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (regex.IsMatch(filename))
{
@@ -102,5 +86,68 @@ namespace Emby.Naming.Video
return result;
}
+
+ ///
+ /// Finds extras matching the video info.
+ ///
+ /// The list of file video infos.
+ /// The video to compare against.
+ /// The video flag delimiters.
+ /// A list of video extras for [videoInfo].
+ public static IReadOnlyList GetExtras(IReadOnlyList files, VideoFileInfo videoInfo, ReadOnlySpan videoFlagDelimiters)
+ {
+ var parentDir = videoInfo.IsDirectory ? videoInfo.Path : Path.GetDirectoryName(videoInfo.Path.AsSpan());
+
+ var trimmedFileName = TrimFilenameDelimiters(videoInfo.Name, videoFlagDelimiters);
+ var trimmedFileNameWithoutExtension = TrimFilenameDelimiters(videoInfo.FileNameWithoutExtension, videoFlagDelimiters);
+ var trimmedVideoInfoName = TrimFilenameDelimiters(videoInfo.Name, videoFlagDelimiters);
+
+ var result = new List();
+ for (var pos = files.Count - 1; pos >= 0; pos--)
+ {
+ var current = files[pos];
+ // ignore non-extras and multi-file (can this happen?)
+ if (current.ExtraType == null || current.Files.Count > 1)
+ {
+ continue;
+ }
+
+ var currentFile = files[pos].Files[0];
+ var trimmedCurrentFileName = TrimFilenameDelimiters(currentFile.Name, videoFlagDelimiters);
+
+ // first check filenames
+ bool isValid = StartsWith(trimmedCurrentFileName, trimmedFileNameWithoutExtension)
+ || (StartsWith(trimmedCurrentFileName, trimmedFileName) && currentFile.Year == videoInfo.Year)
+ || (StartsWith(trimmedCurrentFileName, trimmedVideoInfoName) && currentFile.Year == videoInfo.Year);
+
+ // then by directory
+ if (!isValid)
+ {
+ // When the extra rule type is DirectoryName we must go one level higher to get the "real" dir name
+ var currentParentDir = currentFile.ExtraRule?.RuleType == ExtraRuleType.DirectoryName
+ ? Path.GetDirectoryName(Path.GetDirectoryName(currentFile.Path.AsSpan()))
+ : Path.GetDirectoryName(currentFile.Path.AsSpan());
+
+ isValid = !currentParentDir.IsEmpty && !parentDir.IsEmpty && currentParentDir.Equals(parentDir, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (isValid)
+ {
+ result.Add(currentFile);
+ }
+ }
+
+ return result.OrderBy(r => r.Path).ToArray();
+ }
+
+ private static ReadOnlySpan TrimFilenameDelimiters(ReadOnlySpan name, ReadOnlySpan videoFlagDelimiters)
+ {
+ return name.IsEmpty ? name : name.TrimEnd().TrimEnd(videoFlagDelimiters).TrimEnd();
+ }
+
+ private static bool StartsWith(ReadOnlySpan fileName, ReadOnlySpan baseName)
+ {
+ return !baseName.IsEmpty && fileName.StartsWith(baseName, StringComparison.OrdinalIgnoreCase);
+ }
}
}
diff --git a/Emby.Naming/Video/FileStack.cs b/Emby.Naming/Video/FileStack.cs
index 6519db57c3..a4a4716ca9 100644
--- a/Emby.Naming/Video/FileStack.cs
+++ b/Emby.Naming/Video/FileStack.cs
@@ -40,6 +40,11 @@ namespace Emby.Naming.Video
/// True if file is in the stack.
public bool ContainsFile(string file, bool isDirectory)
{
+ if (string.IsNullOrEmpty(file))
+ {
+ return false;
+ }
+
if (IsDirectoryStack == isDirectory)
{
return Files.Contains(file, StringComparer.OrdinalIgnoreCase);
diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs
index 36f65a5624..be73f69db1 100644
--- a/Emby.Naming/Video/StackResolver.cs
+++ b/Emby.Naming/Video/StackResolver.cs
@@ -12,37 +12,28 @@ namespace Emby.Naming.Video
///
/// Resolve from list of paths.
///
- public class StackResolver
+ public static class StackResolver
{
- private readonly NamingOptions _options;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// object containing VideoFileStackingRegexes and passes options to .
- public StackResolver(NamingOptions options)
- {
- _options = options;
- }
-
///
/// Resolves only directories from paths.
///
/// List of paths.
+ /// The naming options.
/// Enumerable of directories.
- public IEnumerable ResolveDirectories(IEnumerable files)
+ public static IEnumerable ResolveDirectories(IEnumerable files, NamingOptions namingOptions)
{
- return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true }));
+ return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true }), namingOptions);
}
///
/// Resolves only files from paths.
///
/// List of paths.
+ /// The naming options.
/// Enumerable of files.
- public IEnumerable ResolveFiles(IEnumerable files)
+ public static IEnumerable ResolveFiles(IEnumerable files, NamingOptions namingOptions)
{
- return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false }));
+ return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false }), namingOptions);
}
///
@@ -50,7 +41,7 @@ namespace Emby.Naming.Video
///
/// List of paths.
/// Enumerable of directories.
- public IEnumerable ResolveAudioBooks(IEnumerable files)
+ public static IEnumerable ResolveAudioBooks(IEnumerable files)
{
var groupedDirectoryFiles = files.GroupBy(file => Path.GetDirectoryName(file.Path));
@@ -82,15 +73,20 @@ namespace Emby.Naming.Video
/// Resolves videos from paths.
///
/// List of paths.
+ /// The naming options.
/// Enumerable of videos.
- public IEnumerable Resolve(IEnumerable files)
+ public static IEnumerable Resolve(IEnumerable files, NamingOptions namingOptions)
{
var list = files
- .Where(i => i.IsDirectory || VideoResolver.IsVideoFile(i.FullName, _options) || VideoResolver.IsStubFile(i.FullName, _options))
+ .Where(i => i.IsDirectory || VideoResolver.IsVideoFile(i.FullName, namingOptions) || VideoResolver.IsStubFile(i.FullName, namingOptions))
.OrderBy(i => i.FullName)
+ .Select(f => (f.IsDirectory, FileName: GetFileNameWithExtension(f), f.FullName))
.ToList();
- var expressions = _options.VideoFileStackingRegexes;
+ // TODO is there a "nicer" way?
+ var cache = new Dictionary<(string, Regex, int), Match>();
+
+ var expressions = namingOptions.VideoFileStackingRegexes;
for (var i = 0; i < list.Count; i++)
{
@@ -102,17 +98,17 @@ namespace Emby.Naming.Video
while (expressionIndex < expressions.Length)
{
var exp = expressions[expressionIndex];
- var stack = new FileStack();
+ FileStack? stack = null;
// (Title)(Volume)(Ignore)(Extension)
- var match1 = FindMatch(file1, exp, offset);
+ var match1 = FindMatch(file1.FileName, exp, offset, cache);
if (match1.Success)
{
- 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 title1 = match1.Groups[1].Value;
+ var volume1 = match1.Groups[2].Value;
+ var ignore1 = match1.Groups[3].Value;
+ var extension1 = match1.Groups[4].Value;
var j = i + 1;
while (j < list.Count)
@@ -126,7 +122,7 @@ namespace Emby.Naming.Video
}
// (Title)(Volume)(Ignore)(Extension)
- var match2 = FindMatch(file2, exp, offset);
+ var match2 = FindMatch(file2.FileName, exp, offset, cache);
if (match2.Success)
{
@@ -142,6 +138,7 @@ namespace Emby.Naming.Video
if (string.Equals(ignore1, ignore2, StringComparison.OrdinalIgnoreCase)
&& string.Equals(extension1, extension2, StringComparison.OrdinalIgnoreCase))
{
+ stack ??= new FileStack();
if (stack.Files.Count == 0)
{
stack.Name = title1 + ignore1;
@@ -204,7 +201,7 @@ namespace Emby.Naming.Video
expressionIndex++;
}
- if (stack.Files.Count > 1)
+ if (stack?.Files.Count > 1)
{
yield return stack;
i += stack.Files.Count - 1;
@@ -214,26 +211,32 @@ namespace Emby.Naming.Video
}
}
- private static string GetRegexInput(FileSystemMetadata file)
+ private static string GetFileNameWithExtension(FileSystemMetadata file)
{
// For directories, dummy up an extension otherwise the expressions will fail
- var input = !file.IsDirectory
- ? file.FullName
- : file.FullName + ".mkv";
+ var input = file.FullName;
+ if (file.IsDirectory)
+ {
+ input = Path.ChangeExtension(input, "mkv");
+ }
return Path.GetFileName(input);
}
- private static Match FindMatch(FileSystemMetadata input, Regex regex, int offset)
+ private static Match FindMatch(string input, Regex regex, int offset, Dictionary<(string, Regex, int), Match> cache)
{
- var regexInput = GetRegexInput(input);
-
- if (offset < 0 || offset >= regexInput.Length)
+ if (offset < 0 || offset >= input.Length)
{
return Match.Empty;
}
- return regex.Match(regexInput, offset);
+ if (!cache.TryGetValue((input, regex, offset), out var result))
+ {
+ result = regex.Match(input, offset, input.Length - offset);
+ cache.Add((input, regex, offset), result);
+ }
+
+ return result;
}
}
}
diff --git a/Emby.Naming/Video/VideoInfo.cs b/Emby.Naming/Video/VideoInfo.cs
index 930fdb33f8..8847ee9bc9 100644
--- a/Emby.Naming/Video/VideoInfo.cs
+++ b/Emby.Naming/Video/VideoInfo.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
namespace Emby.Naming.Video
{
@@ -17,7 +18,6 @@ namespace Emby.Naming.Video
Name = name;
Files = Array.Empty();
- Extras = Array.Empty();
AlternateVersions = Array.Empty();
}
@@ -39,16 +39,15 @@ namespace Emby.Naming.Video
/// The files.
public IReadOnlyList Files { get; set; }
- ///
- /// Gets or sets the extras.
- ///
- /// The extras.
- public IReadOnlyList Extras { get; set; }
-
///
/// Gets or sets the alternate versions.
///
/// The alternate versions.
public IReadOnlyList AlternateVersions { get; set; }
+
+ ///
+ /// Gets or sets the extra type.
+ ///
+ public ExtraType? ExtraType { get; set; }
}
}
diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs
index ed7d511a39..bce7cb47f1 100644
--- a/Emby.Naming/Video/VideoListResolver.cs
+++ b/Emby.Naming/Video/VideoListResolver.cs
@@ -4,7 +4,6 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Emby.Naming.Common;
-using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
namespace Emby.Naming.Video
@@ -20,11 +19,12 @@ namespace Emby.Naming.Video
/// List of related video files.
/// The naming options.
/// Indication we should consider multi-versions of content.
+ /// Whether to parse the name or use the filename.
/// Returns enumerable of which groups files together when related.
- public static IEnumerable Resolve(IEnumerable files, NamingOptions namingOptions, bool supportMultiVersion = true)
+ public static IReadOnlyList Resolve(IEnumerable files, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true)
{
var videoInfos = files
- .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, namingOptions))
+ .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, namingOptions, parseName))
.OfType()
.ToList();
@@ -34,12 +34,25 @@ namespace Emby.Naming.Video
.Where(i => i.ExtraType == null)
.Select(i => new FileSystemMetadata { FullName = i.Path, IsDirectory = i.IsDirectory });
- var stackResult = new StackResolver(namingOptions)
- .Resolve(nonExtras).ToList();
+ var stackResult = StackResolver.Resolve(nonExtras, namingOptions).ToList();
- var remainingFiles = videoInfos
- .Where(i => !stackResult.Any(s => i.Path != null && s.ContainsFile(i.Path, i.IsDirectory)))
- .ToList();
+ var remainingFiles = new List();
+ var standaloneMedia = new List();
+
+ for (var i = 0; i < videoInfos.Count; i++)
+ {
+ var current = videoInfos[i];
+ if (stackResult.Any(s => s.ContainsFile(current.Path, current.IsDirectory)))
+ {
+ continue;
+ }
+
+ remainingFiles.Add(current);
+ if (current.ExtraType == null)
+ {
+ standaloneMedia.Add(current);
+ }
+ }
var list = new List();
@@ -47,27 +60,15 @@ namespace Emby.Naming.Video
{
var info = new VideoInfo(stack.Name)
{
- Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions))
+ Files = stack.Files.Select(i => VideoResolver.Resolve(i, stack.IsDirectoryStack, namingOptions, parseName))
.OfType()
.ToList()
};
info.Year = info.Files[0].Year;
-
- var extras = ExtractExtras(remainingFiles, stack.Name, Path.GetFileNameWithoutExtension(stack.Files[0].AsSpan()), namingOptions.VideoFlagDelimiters);
-
- if (extras.Count > 0)
- {
- info.Extras = extras;
- }
-
list.Add(info);
}
- var standaloneMedia = remainingFiles
- .Where(i => i.ExtraType == null)
- .ToList();
-
foreach (var media in standaloneMedia)
{
var info = new VideoInfo(media.Name) { Files = new[] { media } };
@@ -75,10 +76,6 @@ namespace Emby.Naming.Video
info.Year = info.Files[0].Year;
remainingFiles.Remove(media);
- var extras = ExtractExtras(remainingFiles, media.FileNameWithoutExtension, namingOptions.VideoFlagDelimiters);
-
- info.Extras = extras;
-
list.Add(info);
}
@@ -87,58 +84,12 @@ namespace Emby.Naming.Video
list = GetVideosGroupedByVersion(list, namingOptions);
}
- // If there's only one resolved video, use the folder name as well to find extras
- if (list.Count == 1)
- {
- var info = list[0];
- var videoPath = list[0].Files[0].Path;
- var parentPath = Path.GetDirectoryName(videoPath.AsSpan());
-
- if (!parentPath.IsEmpty)
- {
- var folderName = Path.GetFileName(parentPath);
- if (!folderName.IsEmpty)
- {
- var extras = ExtractExtras(remainingFiles, folderName, namingOptions.VideoFlagDelimiters);
- extras.AddRange(info.Extras);
- info.Extras = extras;
- }
- }
-
- // Add the extras that are just based on file name as well
- var extrasByFileName = remainingFiles
- .Where(i => i.ExtraRule != null && i.ExtraRule.RuleType == ExtraRuleType.Filename)
- .ToList();
-
- remainingFiles = remainingFiles
- .Except(extrasByFileName)
- .ToList();
-
- extrasByFileName.AddRange(info.Extras);
- info.Extras = extrasByFileName;
- }
-
- // If there's only one video, accept all trailers
- // Be lenient because people use all kinds of mishmash conventions with trailers.
- if (list.Count == 1)
- {
- var trailers = remainingFiles
- .Where(i => i.ExtraType == ExtraType.Trailer)
- .ToList();
-
- trailers.AddRange(list[0].Extras);
- list[0].Extras = trailers;
-
- remainingFiles = remainingFiles
- .Except(trailers)
- .ToList();
- }
-
// Whatever files are left, just add them
list.AddRange(remainingFiles.Select(i => new VideoInfo(i.Name)
{
Files = new[] { i },
- Year = i.Year
+ Year = i.Year,
+ ExtraType = i.ExtraType
}));
return list;
@@ -162,6 +113,11 @@ namespace Emby.Naming.Video
for (var i = 0; i < videos.Count; i++)
{
var video = videos[i];
+ if (video.ExtraType != null)
+ {
+ continue;
+ }
+
if (!IsEligibleForMultiVersion(folderName, video.Files[0].Path, namingOptions))
{
return videos;
@@ -178,17 +134,14 @@ namespace Emby.Naming.Video
var alternateVersionsLen = videos.Count - 1;
var alternateVersions = new VideoFileInfo[alternateVersionsLen];
- var extras = new List(list[0].Extras);
for (int i = 0; i < alternateVersionsLen; i++)
{
var video = videos[i + 1];
alternateVersions[i] = video.Files[0];
- extras.AddRange(video.Extras);
}
list[0].AlternateVersions = alternateVersions;
list[0].Name = folderName.ToString();
- list[0].Extras = extras;
return list;
}
@@ -230,7 +183,7 @@ namespace Emby.Naming.Video
var tmpTestFilename = testFilename.ToString();
if (CleanStringParser.TryClean(tmpTestFilename, namingOptions.CleanStringRegexes, out var cleanName))
{
- tmpTestFilename = cleanName.Trim().ToString();
+ tmpTestFilename = cleanName.Trim();
}
// The CleanStringParser should have removed common keywords etc.
@@ -238,67 +191,5 @@ namespace Emby.Naming.Video
|| testFilename[0] == '-'
|| Regex.IsMatch(tmpTestFilename, @"^\[([^]]*)\]", RegexOptions.Compiled);
}
-
- private static ReadOnlySpan TrimFilenameDelimiters(ReadOnlySpan name, ReadOnlySpan videoFlagDelimiters)
- {
- return name.IsEmpty ? name : name.TrimEnd().TrimEnd(videoFlagDelimiters).TrimEnd();
- }
-
- private static bool StartsWith(ReadOnlySpan fileName, ReadOnlySpan baseName, ReadOnlySpan trimmedBaseName)
- {
- if (baseName.IsEmpty)
- {
- return false;
- }
-
- return fileName.StartsWith(baseName, StringComparison.OrdinalIgnoreCase)
- || (!trimmedBaseName.IsEmpty && fileName.StartsWith(trimmedBaseName, StringComparison.OrdinalIgnoreCase));
- }
-
- ///
- /// Finds similar filenames to that of [baseName] and removes any matches from [remainingFiles].
- ///
- /// The list of remaining filenames.
- /// The base name to use for the comparison.
- /// The video flag delimiters.
- /// A list of video extras for [baseName].
- private static List ExtractExtras(IList remainingFiles, ReadOnlySpan baseName, ReadOnlySpan videoFlagDelimiters)
- {
- return ExtractExtras(remainingFiles, baseName, ReadOnlySpan.Empty, videoFlagDelimiters);
- }
-
- ///
- /// Finds similar filenames to that of [firstBaseName] and [secondBaseName] and removes any matches from [remainingFiles].
- ///
- /// The list of remaining filenames.
- /// The first base name to use for the comparison.
- /// The second base name to use for the comparison.
- /// The video flag delimiters.
- /// A list of video extras for [firstBaseName] and [secondBaseName].
- private static List ExtractExtras(IList remainingFiles, ReadOnlySpan firstBaseName, ReadOnlySpan secondBaseName, ReadOnlySpan videoFlagDelimiters)
- {
- var trimmedFirstBaseName = TrimFilenameDelimiters(firstBaseName, videoFlagDelimiters);
- var trimmedSecondBaseName = TrimFilenameDelimiters(secondBaseName, videoFlagDelimiters);
-
- var result = new List();
- for (var pos = remainingFiles.Count - 1; pos >= 0; pos--)
- {
- var file = remainingFiles[pos];
- if (file.ExtraType == null)
- {
- continue;
- }
-
- var filename = file.FileNameWithoutExtension;
- if (StartsWith(filename, firstBaseName, trimmedFirstBaseName)
- || StartsWith(filename, secondBaseName, trimmedSecondBaseName))
- {
- result.Add(file);
- remainingFiles.RemoveAt(pos);
- }
- }
-
- return result;
- }
}
}
diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs
index 4c9df27f50..9cadc14658 100644
--- a/Emby.Naming/Video/VideoResolver.cs
+++ b/Emby.Naming/Video/VideoResolver.cs
@@ -16,10 +16,11 @@ namespace Emby.Naming.Video
///
/// The path.
/// The naming options.
+ /// Whether to parse the name or use the filename.
/// VideoFileInfo.
- public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions)
+ public static VideoFileInfo? ResolveDirectory(string? path, NamingOptions namingOptions, bool parseName = true)
{
- return Resolve(path, true, namingOptions);
+ return Resolve(path, true, namingOptions, parseName);
}
///
@@ -74,7 +75,7 @@ namespace Emby.Naming.Video
var format3DResult = Format3DParser.Parse(path, namingOptions);
- var extraResult = new ExtraResolver(namingOptions).GetExtraInfo(path);
+ var extraResult = ExtraResolver.GetExtraInfo(path, namingOptions);
var name = Path.GetFileNameWithoutExtension(path);
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 778b6225e1..01749242fa 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -11,11 +11,9 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using Emby.Naming.Audio;
using Emby.Naming.Common;
using Emby.Naming.TV;
using Emby.Naming.Video;
-using Emby.Server.Implementations.Library.Resolvers;
using Emby.Server.Implementations.Library.Validators;
using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.ScheduledTasks;
@@ -677,7 +675,7 @@ namespace Emby.Server.Implementations.Library
{
var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService);
- if (result != null && result.Items.Count > 0)
+ if (result?.Items.Count > 0)
{
var items = new List();
items.AddRange(result.Items);
@@ -2685,89 +2683,58 @@ namespace Emby.Server.Implementations.Library
};
}
- public IEnumerable