< Summary - Jellyfin

Information
Class: Emby.Naming.Video.StackResolver
Assembly: Emby.Naming
File(s): /srv/git/jellyfin/Emby.Naming/Video/StackResolver.cs
Line coverage
100%
Covered lines: 5
Uncovered lines: 0
Coverable lines: 5
Total lines: 156
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ResolveDirectories(...)100%11100%
ResolveFiles(...)100%11100%
.ctor(...)100%11100%
ContainsPart(...)100%11100%

File(s)

/srv/git/jellyfin/Emby.Naming/Video/StackResolver.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using System.Linq;
 5using Emby.Naming.AudioBook;
 6using Emby.Naming.Common;
 7using MediaBrowser.Model.IO;
 8
 9namespace Emby.Naming.Video
 10{
 11    /// <summary>
 12    /// Resolve <see cref="FileStack"/> from list of paths.
 13    /// </summary>
 14    public static class StackResolver
 15    {
 16        /// <summary>
 17        /// Resolves only directories from paths.
 18        /// </summary>
 19        /// <param name="files">List of paths.</param>
 20        /// <param name="namingOptions">The naming options.</param>
 21        /// <returns>Enumerable <see cref="FileStack"/> of directories.</returns>
 22        public static IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files, NamingOptions namingOptions)
 23        {
 224            return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = true }), namingOptions
 25        }
 26
 27        /// <summary>
 28        /// Resolves only files from paths.
 29        /// </summary>
 30        /// <param name="files">List of paths.</param>
 31        /// <param name="namingOptions">The naming options.</param>
 32        /// <returns>Enumerable <see cref="FileStack"/> of files.</returns>
 33        public static IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files, NamingOptions namingOptions)
 34        {
 1935            return Resolve(files.Select(i => new FileSystemMetadata { FullName = i, IsDirectory = false }), namingOption
 36        }
 37
 38        /// <summary>
 39        /// Resolves audiobooks from paths.
 40        /// </summary>
 41        /// <param name="files">List of paths.</param>
 42        /// <returns>Enumerable <see cref="FileStack"/> of directories.</returns>
 43        public static IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<AudioBookFileInfo> files)
 44        {
 45            var groupedDirectoryFiles = files.GroupBy(file => Path.GetDirectoryName(file.Path));
 46
 47            foreach (var directory in groupedDirectoryFiles)
 48            {
 49                if (string.IsNullOrEmpty(directory.Key))
 50                {
 51                    foreach (var file in directory)
 52                    {
 53                        var stack = new FileStack(Path.GetFileNameWithoutExtension(file.Path), false, new[] { file.Path 
 54                        yield return stack;
 55                    }
 56                }
 57                else
 58                {
 59                    var stack = new FileStack(Path.GetFileName(directory.Key), false, directory.Select(f => f.Path).ToAr
 60                    yield return stack;
 61                }
 62            }
 63        }
 64
 65        /// <summary>
 66        /// Resolves videos from paths.
 67        /// </summary>
 68        /// <param name="files">List of paths.</param>
 69        /// <param name="namingOptions">The naming options.</param>
 70        /// <returns>Enumerable <see cref="FileStack"/> of videos.</returns>
 71        public static IEnumerable<FileStack> Resolve(IEnumerable<FileSystemMetadata> files, NamingOptions namingOptions)
 72        {
 73            var potentialFiles = files
 74                .Where(i => i.IsDirectory || VideoResolver.IsVideoFile(i.FullName, namingOptions) || VideoResolver.IsStu
 75                .OrderBy(i => i.FullName);
 76
 77            var potentialStacks = new Dictionary<string, StackMetadata>();
 78            foreach (var file in potentialFiles)
 79            {
 80                var name = file.Name;
 81                if (string.IsNullOrEmpty(name))
 82                {
 83                    name = Path.GetFileName(file.FullName);
 84                }
 85
 86                for (var i = 0; i < namingOptions.VideoFileStackingRules.Length; i++)
 87                {
 88                    var rule = namingOptions.VideoFileStackingRules[i];
 89                    if (!rule.Match(name, out var stackParsingResult))
 90                    {
 91                        continue;
 92                    }
 93
 94                    var stackName = stackParsingResult.Value.StackName;
 95                    var partNumber = stackParsingResult.Value.PartNumber;
 96                    var partType = stackParsingResult.Value.PartType;
 97
 98                    if (!potentialStacks.TryGetValue(stackName, out var stackResult))
 99                    {
 100                        stackResult = new StackMetadata(file.IsDirectory, rule.IsNumerical, partType);
 101                        potentialStacks[stackName] = stackResult;
 102                    }
 103
 104                    if (stackResult.Parts.Count > 0)
 105                    {
 106                        if (stackResult.IsDirectory != file.IsDirectory
 107                            || !string.Equals(partType, stackResult.PartType, StringComparison.OrdinalIgnoreCase)
 108                            || stackResult.ContainsPart(partNumber))
 109                        {
 110                            continue;
 111                        }
 112
 113                        if (rule.IsNumerical != stackResult.IsNumerical)
 114                        {
 115                            break;
 116                        }
 117                    }
 118
 119                    stackResult.Parts.Add(partNumber, file);
 120                    break;
 121                }
 122            }
 123
 124            foreach (var (fileName, stack) in potentialStacks)
 125            {
 126                if (stack.Parts.Count < 2)
 127                {
 128                    continue;
 129                }
 130
 131                yield return new FileStack(fileName, stack.IsDirectory, stack.Parts.Select(kv => kv.Value.FullName).ToAr
 132            }
 133        }
 134
 135        private class StackMetadata
 136        {
 137            public StackMetadata(bool isDirectory, bool isNumerical, string partType)
 138            {
 22139                Parts = new Dictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
 140                IsDirectory = isDirectory;
 141                IsNumerical = isNumerical;
 142                PartType = partType;
 22143            }
 144
 145            public Dictionary<string, FileSystemMetadata> Parts { get; }
 146
 147            public bool IsDirectory { get; }
 148
 149            public bool IsNumerical { get; }
 150
 151            public string PartType { get; }
 152
 42153            public bool ContainsPart(string partNumber) => Parts.ContainsKey(partNumber);
 154        }
 155    }
 156}