Simplify StackResolver

This commit is contained in:
cvium
2021-12-10 14:23:31 +01:00
parent 6030946d78
commit 220443eca1
7 changed files with 131 additions and 177 deletions

View File

@@ -2,7 +2,6 @@ using System;
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;
@@ -51,19 +50,13 @@ namespace Emby.Naming.Video
{
foreach (var file in directory)
{
var stack = new FileStack { Name = Path.GetFileNameWithoutExtension(file.Path), IsDirectoryStack = false };
stack.Files.Add(file.Path);
var stack = new FileStack(Path.GetFileNameWithoutExtension(file.Path), false, new[] { 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);
}
var stack = new FileStack(Path.GetFileName(directory.Key), false, directory.Select(f => f.Path).ToArray());
yield return stack;
}
}
@@ -77,166 +70,87 @@ namespace Emby.Naming.Video
/// <returns>Enumerable <see cref="FileStack"/> of videos.</returns>
public static IEnumerable<FileStack> Resolve(IEnumerable<FileSystemMetadata> files, NamingOptions namingOptions)
{
var list = files
var potentialFiles = files
.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();
.OrderBy(i => i.FullName);
// 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++)
var potentialStacks = new Dictionary<string, StackMetadata>();
foreach (var file in potentialFiles)
{
var offset = 0;
var file1 = list[i];
var expressionIndex = 0;
while (expressionIndex < expressions.Length)
for (var i = 0; i < namingOptions.VideoFileStackingRules.Length; i++)
{
var exp = expressions[expressionIndex];
FileStack? stack = null;
// (Title)(Volume)(Ignore)(Extension)
var match1 = FindMatch(file1.FileName, exp, offset, cache);
if (match1.Success)
var name = file.Name;
if (string.IsNullOrEmpty(name))
{
var title1 = match1.Groups[1].Value;
var volume1 = match1.Groups[2].Value;
var ignore1 = match1.Groups[3].Value;
var extension1 = match1.Groups[4].Value;
name = Path.GetFileName(file.FullName);
}
var j = i + 1;
while (j < list.Count)
var rule = namingOptions.VideoFileStackingRules[i];
if (!rule.Match(name, out var stackParsingResult))
{
continue;
}
var stackName = stackParsingResult.Value.StackName;
var partNumber = stackParsingResult.Value.PartNumber;
var partType = stackParsingResult.Value.PartType;
if (!potentialStacks.TryGetValue(stackName, out var stackResult))
{
stackResult = new StackMetadata(file.IsDirectory, rule.IsNumerical, partType);
potentialStacks[stackName] = stackResult;
}
if (stackResult.Parts.Count > 0)
{
if (stackResult.IsDirectory != file.IsDirectory
|| !string.Equals(partType, stackResult.PartType, StringComparison.OrdinalIgnoreCase)
|| stackResult.ContainsPart(partNumber))
{
var file2 = list[j];
if (file1.IsDirectory != file2.IsDirectory)
{
j++;
continue;
}
// (Title)(Volume)(Ignore)(Extension)
var match2 = FindMatch(file2.FileName, exp, offset, cache);
if (match2.Success)
{
var title2 = match2.Groups[1].Value;
var volume2 = match2.Groups[2].Value;
var ignore2 = match2.Groups[3].Value;
var extension2 = match2.Groups[4].Value;
if (string.Equals(title1, title2, StringComparison.OrdinalIgnoreCase))
{
if (!string.Equals(volume1, volume2, StringComparison.OrdinalIgnoreCase))
{
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;
stack.IsDirectoryStack = file1.IsDirectory;
stack.Files.Add(file1.FullName);
}
stack.Files.Add(file2.FullName);
}
else
{
// Sequel
offset = 0;
expressionIndex++;
break;
}
}
else if (!string.Equals(ignore1, ignore2, StringComparison.OrdinalIgnoreCase))
{
// False positive, try again with offset
offset = match1.Groups[3].Index;
break;
}
else
{
// Extension mismatch
offset = 0;
expressionIndex++;
break;
}
}
else
{
// Title mismatch
offset = 0;
expressionIndex++;
break;
}
}
else
{
// No match 2, next expression
offset = 0;
expressionIndex++;
break;
}
j++;
continue;
}
if (j == list.Count)
if (rule.IsNumerical != stackResult.IsNumerical)
{
expressionIndex = expressions.Length;
break;
}
}
else
{
// No match 1
offset = 0;
expressionIndex++;
}
if (stack?.Files.Count > 1)
{
yield return stack;
i += stack.Files.Count - 1;
break;
}
stackResult.Parts.Add(partNumber, file);
break;
}
}
foreach (var (fileName, stack) in potentialStacks)
{
if (stack.Parts.Count < 2)
{
continue;
}
yield return new FileStack(fileName, stack.IsDirectory, stack.Parts.Select(kv => kv.Value.FullName).ToArray());
}
}
private static string GetFileNameWithExtension(FileSystemMetadata file)
private class StackMetadata
{
// For directories, dummy up an extension otherwise the expressions will fail
var input = file.FullName;
if (file.IsDirectory)
public StackMetadata(bool isDirectory, bool isNumerical, string partType)
{
input = Path.ChangeExtension(input, "mkv");
Parts = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
IsDirectory = isDirectory;
IsNumerical = isNumerical;
PartType = partType;
}
return Path.GetFileName(input);
}
public Dictionary<string, FileSystemMetadata> Parts { get; }
private static Match FindMatch(string input, Regex regex, int offset, Dictionary<(string, Regex, int), Match> cache)
{
if (offset < 0 || offset >= input.Length)
{
return Match.Empty;
}
public bool IsDirectory { get; }
if (!cache.TryGetValue((input, regex, offset), out var result))
{
result = regex.Match(input, offset, input.Length - offset);
cache.Add((input, regex, offset), result);
}
public bool IsNumerical { get; }
return result;
public string PartType { get; }
public bool ContainsPart(string partNumber) => Parts.ContainsKey(partNumber);
}
}
}