jellyfin/Emby.Naming/Video/StackResolver.cs

157 lines
6.0 KiB
C#
Raw Permalink Normal View History

using System;
2018-09-12 17:26:21 +00:00
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Emby.Naming.AudioBook;
2019-01-13 19:17:29 +00:00
using Emby.Naming.Common;
2018-09-12 17:26:21 +00:00
using MediaBrowser.Model.IO;
namespace Emby.Naming.Video
{
2020-11-10 18:23:10 +00:00
/// <summary>
/// Resolve <see cref="FileStack"/> from list of paths.
/// </summary>
2021-12-07 14:18:17 +00:00
public static class StackResolver
2018-09-12 17:26:21 +00:00
{
2020-11-10 18:23:10 +00:00
/// <summary>
/// Resolves only directories from paths.
/// </summary>
/// <param name="files">List of paths.</param>
2021-12-07 14:18:17 +00:00
/// <param name="namingOptions">The naming options.</param>
2020-11-10 18:23:10 +00:00
/// <returns>Enumerable <see cref="FileStack"/> of directories.</returns>
2021-12-07 14:18:17 +00:00
public static IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files, NamingOptions namingOptions)
2018-09-12 17:26:21 +00:00
{
2021-12-07 14:18:17 +00:00
return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true }), namingOptions);
2018-09-12 17:26:21 +00:00
}
2020-11-10 18:23:10 +00:00
/// <summary>
/// Resolves only files from paths.
/// </summary>
/// <param name="files">List of paths.</param>
2021-12-07 14:18:17 +00:00
/// <param name="namingOptions">The naming options.</param>
2020-11-10 18:23:10 +00:00
/// <returns>Enumerable <see cref="FileStack"/> of files.</returns>
2021-12-07 14:18:17 +00:00
public static IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files, NamingOptions namingOptions)
2018-09-12 17:26:21 +00:00
{
2021-12-07 14:18:17 +00:00
return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false }), namingOptions);
2018-09-12 17:26:21 +00:00
}
2020-11-10 18:23:10 +00:00
/// <summary>
/// Resolves audiobooks from paths.
/// </summary>
/// <param name="files">List of paths.</param>
/// <returns>Enumerable <see cref="FileStack"/> of directories.</returns>
2021-12-07 14:18:17 +00:00
public static IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<AudioBookFileInfo> files)
2018-09-12 17:26:21 +00:00
{
var groupedDirectoryFiles = files.GroupBy(file => Path.GetDirectoryName(file.Path));
2020-03-25 20:33:44 +00:00
foreach (var directory in groupedDirectoryFiles)
2018-09-12 17:26:21 +00:00
{
if (string.IsNullOrEmpty(directory.Key))
2018-09-12 17:26:21 +00:00
{
foreach (var file in directory)
{
2021-12-10 13:23:31 +00:00
var stack = new FileStack(Path.GetFileNameWithoutExtension(file.Path), false, new[] { file.Path });
yield return stack;
}
2018-09-12 17:26:21 +00:00
}
else
{
2021-12-10 13:23:31 +00:00
var stack = new FileStack(Path.GetFileName(directory.Key), false, directory.Select(f => f.Path).ToArray());
yield return stack;
}
2018-09-12 17:26:21 +00:00
}
}
2020-11-10 18:23:10 +00:00
/// <summary>
/// Resolves videos from paths.
/// </summary>
/// <param name="files">List of paths.</param>
2021-12-07 14:18:17 +00:00
/// <param name="namingOptions">The naming options.</param>
2020-11-10 18:23:10 +00:00
/// <returns>Enumerable <see cref="FileStack"/> of videos.</returns>
2021-12-07 14:18:17 +00:00
public static IEnumerable<FileStack> Resolve(IEnumerable<FileSystemMetadata> files, NamingOptions namingOptions)
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
var potentialFiles = files
2021-12-07 14:18:17 +00:00
.Where(i => i.IsDirectory || VideoResolver.IsVideoFile(i.FullName, namingOptions) || VideoResolver.IsStubFile(i.FullName, namingOptions))
2021-12-10 13:23:31 +00:00
.OrderBy(i => i.FullName);
2018-09-12 17:26:21 +00:00
2021-12-10 13:23:31 +00:00
var potentialStacks = new Dictionary<string, StackMetadata>();
foreach (var file in potentialFiles)
2018-09-12 17:26:21 +00:00
{
2021-12-14 22:05:45 +00:00
var name = file.Name;
if (string.IsNullOrEmpty(name))
2018-09-12 17:26:21 +00:00
{
2021-12-14 22:05:45 +00:00
name = Path.GetFileName(file.FullName);
}
2021-12-10 13:23:31 +00:00
2021-12-14 22:05:45 +00:00
for (var i = 0; i < namingOptions.VideoFileStackingRules.Length; i++)
{
2021-12-10 13:23:31 +00:00
var rule = namingOptions.VideoFileStackingRules[i];
if (!rule.Match(name, out var stackParsingResult))
{
continue;
}
2018-09-12 17:26:21 +00:00
2021-12-10 13:23:31 +00:00
var stackName = stackParsingResult.Value.StackName;
var partNumber = stackParsingResult.Value.PartNumber;
var partType = stackParsingResult.Value.PartType;
2018-09-12 17:26:21 +00:00
2021-12-10 13:23:31 +00:00
if (!potentialStacks.TryGetValue(stackName, out var stackResult))
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
stackResult = new StackMetadata(file.IsDirectory, rule.IsNumerical, partType);
potentialStacks[stackName] = stackResult;
}
2018-09-12 17:26:21 +00:00
2021-12-10 13:23:31 +00:00
if (stackResult.Parts.Count > 0)
{
if (stackResult.IsDirectory != file.IsDirectory
|| !string.Equals(partType, stackResult.PartType, StringComparison.OrdinalIgnoreCase)
|| stackResult.ContainsPart(partNumber))
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
continue;
2018-09-12 17:26:21 +00:00
}
2021-12-10 13:23:31 +00:00
if (rule.IsNumerical != stackResult.IsNumerical)
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
break;
2018-09-12 17:26:21 +00:00
}
}
2021-12-10 13:23:31 +00:00
stackResult.Parts.Add(partNumber, file);
break;
2018-09-12 17:26:21 +00:00
}
}
2021-12-10 13:23:31 +00:00
foreach (var (fileName, stack) in potentialStacks)
2021-12-07 14:18:17 +00:00
{
2021-12-10 13:23:31 +00:00
if (stack.Parts.Count < 2)
{
continue;
}
2018-09-12 17:26:21 +00:00
2021-12-10 13:23:31 +00:00
yield return new FileStack(fileName, stack.IsDirectory, stack.Parts.Select(kv => kv.Value.FullName).ToArray());
}
2018-09-12 17:26:21 +00:00
}
2021-12-10 13:23:31 +00:00
private class StackMetadata
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
public StackMetadata(bool isDirectory, bool isNumerical, string partType)
2018-09-12 17:26:21 +00:00
{
2021-12-10 13:23:31 +00:00
Parts = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
IsDirectory = isDirectory;
IsNumerical = isNumerical;
PartType = partType;
2018-09-12 17:26:21 +00:00
}
2021-12-10 13:23:31 +00:00
public Dictionary<string, FileSystemMetadata> Parts { get; }
public bool IsDirectory { get; }
public bool IsNumerical { get; }
public string PartType { get; }
2021-12-07 14:18:17 +00:00
2021-12-10 13:23:31 +00:00
public bool ContainsPart(string partNumber) => Parts.ContainsKey(partNumber);
2018-09-12 17:26:21 +00:00
}
}
}