aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
blob: 79b6dded3b99ca6087201bfefc0b6981aa0fc491 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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.Entities;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;

namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
    /// <summary>
    /// Class MusicAlbumResolver.
    /// </summary>
    public class MusicAlbumResolver : ItemResolver<MusicAlbum>
    {
        private readonly ILogger<MusicAlbumResolver> _logger;
        private readonly IFileSystem _fileSystem;
        private readonly ILibraryManager _libraryManager;

        /// <summary>
        /// Initializes a new instance of the <see cref="MusicAlbumResolver"/> class.
        /// </summary>
        /// <param name="logger">The logger.</param>
        /// <param name="fileSystem">The file system.</param>
        /// <param name="libraryManager">The library manager.</param>
        public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, IFileSystem fileSystem, ILibraryManager libraryManager)
        {
            _logger = logger;
            _fileSystem = fileSystem;
            _libraryManager = libraryManager;
        }

        /// <summary>
        /// Gets the priority.
        /// </summary>
        /// <value>The priority.</value>
        public override ResolverPriority Priority => ResolverPriority.Second;

        /// <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();
            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<MusicAlbum>())
            {
                return null;
            }

            if (args.Parent.IsRoot)
            {
                return null;
            }

            return IsMusicAlbum(args) ? new MusicAlbum() : null;
        }

        /// <summary>
        /// Determine if the supplied file data points to a music album.
        /// </summary>
        public bool IsMusicAlbum(string path, IDirectoryService directoryService)
        {
            return ContainsMusic(directoryService.GetFileSystemEntries(path), true, directoryService, _logger, _fileSystem, _libraryManager);
        }

        /// <summary>
        /// Determine if the supplied resolve args should be considered a music album.
        /// </summary>
        /// <param name="args">The args.</param>
        /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
        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, _libraryManager))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Determine if the supplied list contains what we should consider music.
        /// </summary>
        private bool ContainsMusic(
            IEnumerable<FileSystemMetadata> list,
            bool allowSubfolders,
            IDirectoryService directoryService,
            ILogger<MusicAlbumResolver> logger,
            IFileSystem fileSystem,
            ILibraryManager libraryManager)
        {
            var discSubfolderCount = 0;
            var notMultiDisc = false;

            var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
            var parser = new AlbumParser(namingOptions);
            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, libraryManager);

                        if (hasMusic)
                        {
                            if (parser.IsMultiPart(path))
                            {
                                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))
                    {
                        return true;
                    }
                }
            }

            if (notMultiDisc)
            {
                return false;
            }

            return discSubfolderCount > 0;
        }
    }
}