jellyfin/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs

179 lines
6.2 KiB
C#
Raw Normal View History

#nullable disable
using System;
using System.Collections.Generic;
2022-03-28 23:11:21 +02:00
using System.IO;
using System.Linq;
2020-09-27 21:56:12 +02:00
using System.Threading;
using System.Threading.Tasks;
using Emby.Naming.Audio;
using Emby.Naming.Common;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
2014-02-13 06:11:54 +01:00
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
2016-10-25 21:02:04 +02:00
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
2022-03-31 16:17:37 +02:00
/// The music album resolver.
/// </summary>
public class MusicAlbumResolver : ItemResolver<MusicAlbum>
{
private readonly ILogger<MusicAlbumResolver> _logger;
private readonly NamingOptions _namingOptions;
2014-07-26 19:30:15 +02:00
2019-11-01 18:38:54 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="MusicAlbumResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, NamingOptions namingOptions)
2014-07-26 19:30:15 +02:00
{
_logger = logger;
_namingOptions = namingOptions;
2014-07-26 19:30:15 +02:00
}
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>The priority.</value>
public override ResolverPriority Priority => ResolverPriority.Third;
/// <summary>
/// Resolves the specified args.
/// </summary>
/// <param name="args">The args.</param>
/// <returns>MusicAlbum.</returns>
protected override MusicAlbum Resolve(ItemResolveArgs args)
{
var collectionType = args.GetCollectionType();
2014-12-20 07:06:27 +01:00
var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase);
2014-07-30 05:31:35 +02:00
2014-03-06 06:17:13 +01:00
// If there's a collection type and it's not music, don't allow it.
2014-07-30 05:31:35 +02:00
if (!isMusicMediaFolder)
{
return null;
}
2014-06-29 19:58:04 +02:00
2019-11-01 18:38:54 +01:00
if (!args.IsDirectory)
{
return null;
}
2018-09-12 19:26:21 +02:00
// Avoid mis-identifying top folders
2019-11-01 18:38:54 +01:00
if (args.HasParent<MusicAlbum>())
{
return null;
}
if (args.Parent.IsRoot)
{
return null;
}
2018-09-12 19:26:21 +02:00
2014-11-16 21:44:08 +01:00
return IsMusicAlbum(args) ? new MusicAlbum() : null;
}
/// <summary>
2020-01-22 22:18:56 +01:00
/// Determine if the supplied file data points to a music album.
/// </summary>
2021-10-02 19:59:58 +02:00
/// <param name="path">The path to check.</param>
/// <param name="directoryService">The directory service.</param>
2022-10-07 14:14:21 +02:00
/// <returns><c>true</c> if the provided path points to a music album; otherwise, <c>false</c>.</returns>
2020-02-19 21:56:35 +01:00
public bool IsMusicAlbum(string path, IDirectoryService directoryService)
{
return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService);
}
/// <summary>
2020-01-22 22:18:56 +01:00
/// Determine if the supplied resolve args should be considered a music album.
/// </summary>
/// <param name="args">The args.</param>
2022-10-07 14:14:21 +02:00
/// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
2014-11-16 21:44:08 +01:00
private bool IsMusicAlbum(ItemResolveArgs args)
{
if (args.IsDirectory)
{
2022-03-31 16:17:37 +02:00
// If args is a artist subfolder it's not a music album
2022-03-28 23:11:21 +02:00
foreach (var subfolder in _namingOptions.ArtistSubfolders)
{
if (Path.GetDirectoryName(args.Path.AsSpan()).Equals(subfolder, StringComparison.OrdinalIgnoreCase))
{
_logger.LogDebug("Found release folder: {Path}", args.Path);
return false;
}
}
2022-03-31 16:17:37 +02:00
// If args contains music it's a music album
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
2019-11-01 18:38:54 +01:00
{
return true;
}
}
return false;
}
/// <summary>
2020-01-22 22:18:56 +01:00
/// Determine if the supplied list contains what we should consider music.
/// </summary>
2022-10-07 14:14:21 +02:00
/// <returns><c>true</c> if the provided path list contains music; otherwise, <c>false</c>.</returns>
2019-11-01 18:38:54 +01:00
private bool ContainsMusic(
2021-12-15 18:25:36 +01:00
ICollection<FileSystemMetadata> list,
2014-08-27 05:25:39 +02:00
bool allowSubfolders,
IDirectoryService directoryService)
{
2022-03-31 16:17:37 +02:00
// Check for audio files before digging down into directories
var foundAudioFile = list.Any(fileSystemInfo => !fileSystemInfo.IsDirectory && AudioFileParser.IsAudioFile(fileSystemInfo.FullName, _namingOptions));
2020-09-27 22:28:19 +02:00
if (foundAudioFile)
{
2022-03-31 16:17:37 +02:00
// At least one audio file exists
return true;
}
if (!allowSubfolders)
{
2022-03-31 16:17:37 +02:00
// Not music since no audio file exists and we're not looking into subfolders
return false;
}
2014-07-26 19:30:15 +02:00
var discSubfolderCount = 0;
var parser = new AlbumParser(_namingOptions);
var directories = list.Where(fileSystemInfo => fileSystemInfo.IsDirectory);
var result = Parallel.ForEach(directories, (fileSystemInfo, state) =>
{
var path = fileSystemInfo.FullName;
var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService);
if (hasMusic)
2014-06-25 17:12:39 +02:00
{
if (parser.IsMultiPart(path))
2014-06-29 19:58:04 +02:00
{
_logger.LogDebug("Found multi-disc folder: {Path}", path);
2020-09-27 21:56:12 +02:00
Interlocked.Increment(ref discSubfolderCount);
2014-06-29 19:58:04 +02:00
}
else
2017-01-15 23:53:24 +01:00
{
// If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album
state.Stop();
2017-01-15 23:53:24 +01:00
}
}
});
2020-09-27 21:56:12 +02:00
if (!result.IsCompleted)
2014-06-29 19:58:04 +02:00
{
2014-12-28 07:21:39 +01:00
return false;
2014-06-29 19:58:04 +02:00
}
2015-01-09 05:05:45 +01:00
return discSubfolderCount > 0;
2014-06-29 19:58:04 +02:00
}
}
}