using System; using System.Collections.Generic; using Emby.Naming.Audio; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library.Resolvers.Audio { /// /// Class MusicAlbumResolver. /// public class MusicAlbumResolver : ItemResolver { private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly ILibraryManager _libraryManager; /// /// Initializes a new instance of the class. /// /// The logger. /// The file system. /// The library manager. public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager) { _logger = logger; _fileSystem = fileSystem; _libraryManager = libraryManager; } /// /// Gets the priority. /// /// The priority. public override ResolverPriority Priority => ResolverPriority.Second; /// /// Resolves the specified args. /// /// The args. /// MusicAlbum. protected override MusicAlbum Resolve(ItemResolveArgs args) { var collectionType = args.GetCollectionType(); var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not music, don't allow it. if (!isMusicMediaFolder) { return null; } if (!args.IsDirectory) { return null; } // Avoid mis-identifying top folders if (args.HasParent()) { return null; } if (args.Parent.IsRoot) { return null; } return IsMusicAlbum(args) ? new MusicAlbum() : null; } /// /// Determine if the supplied file data points to a music album /// public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions) { return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, libraryOptions, _libraryManager); } /// /// Determine if the supplied resolve args should be considered a music album /// /// The args. /// true if [is music album] [the specified args]; otherwise, false. private bool IsMusicAlbum(ItemResolveArgs args) { // Args points to an album if parent is an Artist folder or it directly contains music if (args.IsDirectory) { // if (args.Parent is MusicArtist) return true; //saves us from testing children twice if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager)) { return true; } } return false; } /// /// Determine if the supplied list contains what we should consider music /// private bool ContainsMusic( IEnumerable list, bool allowSubfolders, IDirectoryService directoryService, ILogger logger, IFileSystem fileSystem, LibraryOptions libraryOptions, ILibraryManager libraryManager) { var discSubfolderCount = 0; var notMultiDisc = false; foreach (var fileSystemInfo in list) { if (fileSystemInfo.IsDirectory) { if (allowSubfolders) { if (notMultiDisc) { continue; } var path = fileSystemInfo.FullName; var hasMusic = ContainsMusic(directoryService.GetFileSystemEntries(path), false, directoryService, logger, fileSystem, libraryOptions, libraryManager); if (hasMusic) { if (IsMultiDiscFolder(path, libraryOptions)) { logger.LogDebug("Found multi-disc folder: " + path); discSubfolderCount++; } else { // If there are folders underneath with music that are not multidisc, then this can't be a multi-disc album notMultiDisc = true; } } } } else { var fullName = fileSystemInfo.FullName; if (libraryManager.IsAudioFile(fullName, libraryOptions)) { return true; } } } if (notMultiDisc) { return false; } return discSubfolderCount > 0; } private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions) { var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions(); var parser = new AlbumParser(namingOptions); var result = parser.ParseMultiPart(path); return result.IsMultiPart; } } }