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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.IO;
namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
/// Class MusicAlbumResolver
/// </summary>
public class MusicAlbumResolver : ItemResolver<MusicAlbum>
{
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem)
{
_logger = logger;
_fileSystem = fileSystem;
}
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>The priority.</value>
public override ResolverPriority Priority
{
get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one
}
/// <summary>
/// Resolves the specified args.
/// </summary>
/// <param name="args">The args.</param>
/// <returns>MusicAlbum.</returns>
protected override MusicAlbum Resolve(ItemResolveArgs args)
{
if (!args.IsDirectory) return null;
//Avoid mis-identifying top folders
if (args.Parent == null) return null;
if (args.Parent.IsRoot) return null;
if (args.Parent is MusicAlbum) return null;
// Optimization
if (args.Parent is BoxSet || args.Parent is Series || args.Parent is Season)
{
return null;
}
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;
}
return IsMusicAlbum(args, isMusicMediaFolder) ? new MusicAlbum() : null;
}
/// <summary>
/// Determine if the supplied file data points to a music album
/// </summary>
/// <param name="path">The path.</param>
/// <param name="isMusicMediaFolder">if set to <c>true</c> [is music media folder].</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <returns><c>true</c> if [is music album] [the specified data]; otherwise, <c>false</c>.</returns>
public static bool IsMusicAlbum(string path, bool isMusicMediaFolder, IDirectoryService directoryService, ILogger logger, IFileSystem fileSystem)
{
return ContainsMusic(directoryService.GetFileSystemEntries(path), isMusicMediaFolder, true, directoryService, logger, fileSystem);
}
/// <summary>
/// Determine if the supplied resolve args should be considered a music album
/// </summary>
/// <param name="args">The args.</param>
/// <param name="isMusicMediaFolder">if set to <c>true</c> [is music media folder].</param>
/// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
private bool IsMusicAlbum(ItemResolveArgs args, bool isMusicMediaFolder)
{
// 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, isMusicMediaFolder, true, args.DirectoryService, _logger, _fileSystem)) return true;
}
return false;
}
/// <summary>
/// Determine if the supplied list contains what we should consider music
/// </summary>
/// <param name="list">The list.</param>
/// <param name="isMusicMediaFolder">if set to <c>true</c> [is music media folder].</param>
/// <param name="allowSubfolders">if set to <c>true</c> [allow subfolders].</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <returns><c>true</c> if the specified list contains music; otherwise, <c>false</c>.</returns>
private static bool ContainsMusic(IEnumerable<FileSystemInfo> list,
bool isMusicMediaFolder,
bool allowSubfolders,
IDirectoryService directoryService,
ILogger logger,
IFileSystem fileSystem)
{
// If list contains at least 2 audio files or at least one and no video files consider it to contain music
var foundAudio = 0;
var discSubfolderCount = 0;
foreach (var fileSystemInfo in list)
{
if ((fileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
{
if (isMusicMediaFolder && allowSubfolders && IsAlbumSubfolder(fileSystemInfo, true, directoryService, logger, fileSystem))
{
discSubfolderCount++;
}
if (!IsAdditionalSubfolderAllowed(fileSystemInfo))
{
return false;
}
}
var fullName = fileSystemInfo.FullName;
if (EntityResolutionHelper.IsAudioFile(fullName))
{
// Don't resolve these into audio files
if (string.Equals(fileSystem.GetFileNameWithoutExtension(fullName), BaseItem.ThemeSongFilename))
{
continue;
}
foundAudio++;
}
else if (EntityResolutionHelper.IsVideoFile(fullName)) return false;
else if (EntityResolutionHelper.IsVideoPlaceHolder(fullName)) return false;
if (foundAudio >= 2)
{
return true;
}
}
// or a single audio file and no video files
return foundAudio > 0 || discSubfolderCount > 0;
}
private static bool IsAlbumSubfolder(FileSystemInfo directory, bool isMusicMediaFolder, IDirectoryService directoryService, ILogger logger, IFileSystem fileSystem)
{
var path = directory.FullName;
if (IsMultiDiscFolder(path))
{
logger.Debug("Found multi-disc folder: " + path);
return ContainsMusic(directoryService.GetFileSystemEntries(path), isMusicMediaFolder, false, directoryService, logger, fileSystem);
}
return false;
}
private static bool IsMultiDiscFolder(string path)
{
return false;
//return EntityResolutionHelper.IsMultiPartFolder(path);
}
private static bool IsAdditionalSubfolderAllowed(FileSystemInfo directory)
{
// Resolver will ignore them based on rules engine
return true;
}
}
}
|