123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using Emby.Naming.Common;
- using Emby.Naming.Video;
- 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;
- private readonly AudioBookResolver _audioBookResolver;
- /// <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;
- _audioBookResolver = new AudioBookResolver(_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)
- {
- // File with empty fullname will be sorted out here.
- var audiobookFileInfos = files
- .Select(i => _audioBookResolver.Resolve(i.FullName))
- .OfType<AudioBookFileInfo>();
- var stackResult = StackResolver.ResolveAudioBooks(audiobookFileInfos);
- foreach (var stack in stackResult)
- {
- var stackFiles = stack.Files
- .Select(i => _audioBookResolver.Resolve(i))
- .OfType<AudioBookFileInfo>()
- .ToList();
- stackFiles.Sort();
- var nameParserResult = new AudioBookNameParser(_options).Parse(stack.Name);
- FindExtraAndAlternativeFiles(ref stackFiles, out var extras, out var alternativeVersions, nameParserResult);
- var info = new AudioBookInfo(
- nameParserResult.Name,
- nameParserResult.Year,
- stackFiles,
- extras,
- alternativeVersions);
- yield return info;
- }
- }
- private void FindExtraAndAlternativeFiles(ref List<AudioBookFileInfo> stackFiles, out List<AudioBookFileInfo> extras, out List<AudioBookFileInfo> alternativeVersions, AudioBookNameParserResult nameParserResult)
- {
- extras = new List<AudioBookFileInfo>();
- alternativeVersions = new List<AudioBookFileInfo>();
- var haveChaptersOrPages = stackFiles.Any(x => x.ChapterNumber is not null || x.PartNumber is not null);
- var groupedBy = stackFiles.GroupBy(file => new { file.ChapterNumber, file.PartNumber });
- var nameWithReplacedDots = nameParserResult.Name.Replace(' ', '.');
- foreach (var group in groupedBy)
- {
- if (group.Key.ChapterNumber is null && group.Key.PartNumber is null)
- {
- if (group.Count() > 1 || haveChaptersOrPages)
- {
- var ex = new List<AudioBookFileInfo>();
- var alt = new List<AudioBookFileInfo>();
- foreach (var audioFile in group)
- {
- var name = Path.GetFileNameWithoutExtension(audioFile.Path);
- if (name.Equals("audiobook", StringComparison.OrdinalIgnoreCase) ||
- name.Contains(nameParserResult.Name, StringComparison.OrdinalIgnoreCase) ||
- name.Contains(nameWithReplacedDots, StringComparison.OrdinalIgnoreCase))
- {
- alt.Add(audioFile);
- }
- else
- {
- ex.Add(audioFile);
- }
- }
- if (ex.Count > 0)
- {
- var extra = ex
- .OrderBy(x => x.Container)
- .ThenBy(x => x.Path)
- .ToList();
- stackFiles = stackFiles.Except(extra).ToList();
- extras.AddRange(extra);
- }
- if (alt.Count > 0)
- {
- var alternatives = alt
- .OrderBy(x => x.Container)
- .ThenBy(x => x.Path)
- .ToList();
- var main = FindMainAudioBookFile(alternatives, nameParserResult.Name);
- alternatives.Remove(main);
- stackFiles = stackFiles.Except(alternatives).ToList();
- alternativeVersions.AddRange(alternatives);
- }
- }
- }
- else if (group.Count() > 1)
- {
- var alternatives = group
- .OrderBy(x => x.Container)
- .ThenBy(x => x.Path)
- .Skip(1)
- .ToList();
- stackFiles = stackFiles.Except(alternatives).ToList();
- alternativeVersions.AddRange(alternatives);
- }
- }
- }
- private AudioBookFileInfo FindMainAudioBookFile(List<AudioBookFileInfo> files, string name)
- {
- var main = files.Find(x => Path.GetFileNameWithoutExtension(x.Path).Equals(name, StringComparison.OrdinalIgnoreCase));
- main ??= files.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x.Path).Equals("audiobook", StringComparison.OrdinalIgnoreCase));
- main ??= files.OrderBy(x => x.Container)
- .ThenBy(x => x.Path)
- .First();
- return main;
- }
- }
- }
|