aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2013-05-27 12:53:10 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2013-05-27 12:53:10 -0400
commit9a820efde33b7a4cfe1dd3e5c37a2f1beaaec896 (patch)
tree44905e755b26f13ab4815956763a08499a2f7c7d
parent390f1653327e15248c0b0181b338c6a14d04732a (diff)
fixes #280 - MB3 Local metadata fetcher for Music not seeing/using Artist Folder.jpg
-rw-r--r--MediaBrowser.Api/LibraryService.cs18
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs4
-rw-r--r--MediaBrowser.Controller/Library/ILibraryPostScanTask.cs20
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Controller/Providers/ImagesByNameProvider.cs9
-rw-r--r--MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs132
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs111
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj2
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130509.zip.REMOVED.git-id1
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130523.zip.REMOVED.git-id1
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs3
11 files changed, 280 insertions, 23 deletions
diff --git a/MediaBrowser.Api/LibraryService.cs b/MediaBrowser.Api/LibraryService.cs
index 681bbd851..4998a122d 100644
--- a/MediaBrowser.Api/LibraryService.cs
+++ b/MediaBrowser.Api/LibraryService.cs
@@ -178,15 +178,15 @@ namespace MediaBrowser.Api
var items = GetItems(request.UserId).ToList();
var counts = new ItemCounts
- {
- AlbumCount = items.OfType<MusicAlbum>().Count(),
- EpisodeCount = items.OfType<Episode>().Count(),
- GameCount = items.OfType<BaseGame>().Count(),
- MovieCount = items.OfType<Movie>().Count(),
- SeriesCount = items.OfType<Series>().Count(),
- SongCount = items.OfType<Audio>().Count(),
- TrailerCount = items.OfType<Trailer>().Count()
- };
+ {
+ AlbumCount = items.OfType<MusicAlbum>().Count(),
+ EpisodeCount = items.OfType<Episode>().Count(),
+ GameCount = items.OfType<BaseGame>().Count(),
+ MovieCount = items.OfType<Movie>().Count(),
+ SeriesCount = items.OfType<Series>().Count(),
+ SongCount = items.OfType<Audio>().Count(),
+ TrailerCount = items.OfType<Trailer>().Count()
+ };
return ToOptimizedResult(counts);
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 90c96c1ee..f5abb8dcd 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -144,12 +144,14 @@ namespace MediaBrowser.Controller.Library
/// <param name="introProviders">The intro providers.</param>
/// <param name="itemComparers">The item comparers.</param>
/// <param name="prescanTasks">The prescan tasks.</param>
+ /// <param name="postscanTasks">The postscan tasks.</param>
void AddParts(IEnumerable<IResolverIgnoreRule> rules,
IEnumerable<IVirtualFolderCreator> pluginFolders,
IEnumerable<IItemResolver> resolvers,
IEnumerable<IIntroProvider> introProviders,
IEnumerable<IBaseItemComparer> itemComparers,
- IEnumerable<ILibraryPrescanTask> prescanTasks);
+ IEnumerable<ILibraryPrescanTask> prescanTasks,
+ IEnumerable<ILibraryPostScanTask> postscanTasks);
/// <summary>
/// Sorts the specified items.
diff --git a/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs
new file mode 100644
index 000000000..694422907
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILibraryPostScanTask.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Library
+{
+ /// <summary>
+ /// An interface for tasks that run after the media library scan
+ /// </summary>
+ public interface ILibraryPostScanTask
+ {
+ /// <summary>
+ /// Runs the specified progress.
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task Run(IProgress<double> progress, CancellationToken cancellationToken);
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 921e16eed..d3f8ba927 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -73,8 +73,10 @@
<Compile Include="Configuration\IServerConfigurationManager.cs" />
<Compile Include="Dto\SessionInfoDtoBuilder.cs" />
<Compile Include="Entities\Audio\MusicAlbumDisc.cs" />
+ <Compile Include="Library\ILibraryPostScanTask.cs" />
<Compile Include="Library\ILibraryPrescanTask.cs" />
<Compile Include="Providers\Movies\MovieDbImagesProvider.cs" />
+ <Compile Include="Providers\Music\ArtistsPostScanTask.cs" />
<Compile Include="Providers\Music\FanArtUpdatesPrescanTask.cs" />
<Compile Include="Providers\TV\FanArtSeasonProvider.cs" />
<Compile Include="Providers\TV\TvdbPrescanTask.cs" />
diff --git a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
index 54a6f3a89..20305006e 100644
--- a/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
+++ b/MediaBrowser.Controller/Providers/ImagesByNameProvider.cs
@@ -155,7 +155,14 @@ namespace MediaBrowser.Controller.Providers
{
var location = GetLocation(item);
- var files = new DirectoryInfo(location).EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList();
+ var directoryInfo = new DirectoryInfo(location);
+
+ if (!directoryInfo.Exists)
+ {
+ return null;
+ }
+
+ var files = directoryInfo.EnumerateFiles("*", SearchOption.TopDirectoryOnly).ToList();
var file = files.FirstOrDefault(i => string.Equals(i.Name, filenameWithoutExtension + ".png", StringComparison.OrdinalIgnoreCase));
diff --git a/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs b/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs
new file mode 100644
index 000000000..67bb35b63
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/Music/ArtistsPostScanTask.cs
@@ -0,0 +1,132 @@
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Entities;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers.Music
+{
+ /// <summary>
+ /// Class ArtistsPostScanTask
+ /// </summary>
+ public class ArtistsPostScanTask : ILibraryPostScanTask
+ {
+ /// <summary>
+ /// The _library manager
+ /// </summary>
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ArtistsPostScanTask"/> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public ArtistsPostScanTask(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <summary>
+ /// Runs the specified progress.
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
+
+ var allArtists = await GetAllArtists(allItems).ConfigureAwait(false);
+
+ progress.Report(10);
+
+ var allMusicArtists = allItems.OfType<MusicArtist>().ToList();
+
+ var numComplete = 0;
+
+ foreach (var artist in allArtists)
+ {
+ var musicArtist = FindMusicArtist(artist, allMusicArtists);
+
+ if (musicArtist != null)
+ {
+ artist.Images = new Dictionary<ImageType, string>(musicArtist.Images);
+
+ artist.BackdropImagePaths = musicArtist.BackdropImagePaths.ToList();
+ artist.ScreenshotImagePaths = musicArtist.ScreenshotImagePaths.ToList();
+ artist.SetProviderId(MetadataProviders.Musicbrainz, musicArtist.GetProviderId(MetadataProviders.Musicbrainz));
+ }
+
+ numComplete++;
+ double percent = numComplete;
+ percent /= allArtists.Length;
+ percent *= 5;
+
+ progress.Report(10 + percent);
+ }
+
+ var innerProgress = new ActionableProgress<double>();
+
+ innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85));
+
+ await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Gets all artists.
+ /// </summary>
+ /// <param name="allItems">All items.</param>
+ /// <returns>Task{Artist[]}.</returns>
+ private Task<Artist[]> GetAllArtists(IEnumerable<BaseItem> allItems)
+ {
+ var itemsList = allItems.OfType<Audio>().ToList();
+
+ var tasks = itemsList
+ .SelectMany(i =>
+ {
+ var list = new List<string>();
+
+ if (!string.IsNullOrEmpty(i.AlbumArtist))
+ {
+ list.Add(i.AlbumArtist);
+ }
+ if (!string.IsNullOrEmpty(i.Artist))
+ {
+ list.Add(i.Artist);
+ }
+
+ return list;
+ })
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(i => _libraryManager.GetArtist(i));
+
+ return Task.WhenAll(tasks);
+ }
+
+ /// <summary>
+ /// Finds the music artist.
+ /// </summary>
+ /// <param name="artist">The artist.</param>
+ /// <param name="allMusicArtists">All music artists.</param>
+ /// <returns>MusicArtist.</returns>
+ private static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists)
+ {
+ var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
+
+ return allMusicArtists.FirstOrDefault(i =>
+ {
+ if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0;
+ });
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index c82ebad51..cf5d75bb7 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -32,6 +32,15 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
public class LibraryManager : ILibraryManager
{
+ /// <summary>
+ /// Gets or sets the postscan tasks.
+ /// </summary>
+ /// <value>The postscan tasks.</value>
+ private IEnumerable<ILibraryPostScanTask> PostscanTasks { get; set; }
+ /// <summary>
+ /// Gets or sets the prescan tasks.
+ /// </summary>
+ /// <value>The prescan tasks.</value>
private IEnumerable<ILibraryPrescanTask> PrescanTasks { get; set; }
/// <summary>
@@ -100,6 +109,9 @@ namespace MediaBrowser.Server.Implementations.Library
/// </summary>
private readonly IUserManager _userManager;
+ /// <summary>
+ /// The _user data repository
+ /// </summary>
private readonly IUserDataRepository _userDataRepository;
/// <summary>
@@ -113,11 +125,25 @@ namespace MediaBrowser.Server.Implementations.Library
/// (typically, multiple user roots). We store them here and be sure they all reference a
/// single instance.
/// </summary>
+ /// <value>The by reference items.</value>
private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
+ /// <summary>
+ /// The _library items cache
+ /// </summary>
private ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
+ /// <summary>
+ /// The _library items cache sync lock
+ /// </summary>
private object _libraryItemsCacheSyncLock = new object();
+ /// <summary>
+ /// The _library items cache initialized
+ /// </summary>
private bool _libraryItemsCacheInitialized;
+ /// <summary>
+ /// Gets the library items cache.
+ /// </summary>
+ /// <value>The library items cache.</value>
private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache
{
get
@@ -127,6 +153,9 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
+ /// <summary>
+ /// The _user root folders
+ /// </summary>
private readonly ConcurrentDictionary<string, UserRootFolder> _userRootFolders =
new ConcurrentDictionary<string, UserRootFolder>();
@@ -161,12 +190,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="introProviders">The intro providers.</param>
/// <param name="itemComparers">The item comparers.</param>
/// <param name="prescanTasks">The prescan tasks.</param>
+ /// <param name="postscanTasks">The postscan tasks.</param>
public void AddParts(IEnumerable<IResolverIgnoreRule> rules,
IEnumerable<IVirtualFolderCreator> pluginFolders,
IEnumerable<IItemResolver> resolvers,
IEnumerable<IIntroProvider> introProviders,
IEnumerable<IBaseItemComparer> itemComparers,
- IEnumerable<ILibraryPrescanTask> prescanTasks)
+ IEnumerable<ILibraryPrescanTask> prescanTasks,
+ IEnumerable<ILibraryPostScanTask> postscanTasks)
{
EntityResolutionIgnoreRules = rules;
PluginFolderCreators = pluginFolders;
@@ -174,6 +205,7 @@ namespace MediaBrowser.Server.Implementations.Library
IntroProviders = introProviders;
Comparers = itemComparers;
PrescanTasks = prescanTasks;
+ PostscanTasks = postscanTasks;
}
/// <summary>
@@ -210,11 +242,27 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
+ /// <summary>
+ /// The _internet providers enabled
+ /// </summary>
private bool _internetProvidersEnabled;
+ /// <summary>
+ /// The _people image fetching enabled
+ /// </summary>
private bool _peopleImageFetchingEnabled;
+ /// <summary>
+ /// The _items by name path
+ /// </summary>
private string _itemsByNamePath;
+ /// <summary>
+ /// The _season zero display name
+ /// </summary>
private string _seasonZeroDisplayName;
+ /// <summary>
+ /// Records the configuration values.
+ /// </summary>
+ /// <param name="configuration">The configuration.</param>
private void RecordConfigurationValues(ServerConfiguration configuration)
{
_seasonZeroDisplayName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
@@ -227,7 +275,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// Configurations the updated.
/// </summary>
/// <param name="sender">The sender.</param>
- /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
void ConfigurationUpdated(object sender, EventArgs e)
{
var config = ConfigurationManager.Configuration;
@@ -373,7 +421,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <summary>
/// Ensure supplied item has only one instance throughout
/// </summary>
- /// <param name="item"></param>
+ /// <param name="item">The item.</param>
/// <returns>The proper instance to the item</returns>
public BaseItem GetOrAddByReferenceItem(BaseItem item)
{
@@ -800,6 +848,12 @@ namespace MediaBrowser.Server.Implementations.Library
_logger.Info("People validation complete");
}
+ /// <summary>
+ /// Validates the artists.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
public async Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
{
const int maxTasks = 25;
@@ -924,11 +978,10 @@ namespace MediaBrowser.Server.Implementations.Library
// Now validate the entire media library
await RootFolder.ValidateChildren(innerProgress, cancellationToken, recursive: true).ConfigureAwait(false);
- innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(pct => progress.Report(80 + pct * .2));
-
- await ValidateArtists(cancellationToken, innerProgress);
+ progress.Report(80);
+
+ // Run post-scan tasks
+ await RunPostScanTasks(progress, cancellationToken).ConfigureAwait(false);
progress.Report(100);
}
@@ -971,7 +1024,47 @@ namespace MediaBrowser.Server.Implementations.Library
}
}));
- // Run prescan tasks
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// Runs the post scan tasks.
+ /// </summary>
+ /// <param name="progress">The progress.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ private async Task RunPostScanTasks(IProgress<double> progress, CancellationToken cancellationToken)
+ {
+ var postscanTasks = PostscanTasks.ToList();
+ var progressDictionary = new Dictionary<ILibraryPostScanTask, double>();
+
+ var tasks = postscanTasks.Select(i => Task.Run(async () =>
+ {
+ var innerProgress = new ActionableProgress<double>();
+
+ innerProgress.RegisterAction(pct =>
+ {
+ lock (progressDictionary)
+ {
+ progressDictionary[i] = pct;
+
+ double percent = progressDictionary.Values.Sum();
+ percent /= postscanTasks.Count;
+
+ progress.Report(80 + percent * .2);
+ }
+ });
+
+ try
+ {
+ await i.Run(innerProgress, cancellationToken);
+ }
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error running postscan task", ex);
+ }
+ }));
+
await Task.WhenAll(tasks).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 82d3fec46..8799f4db3 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -272,7 +272,7 @@
<ItemGroup>
<EmbeddedResource Include="MediaEncoder\fonts\ARIALUNI.TTF" />
<EmbeddedResource Include="MediaEncoder\fonts\fonts.conf" />
- <EmbeddedResource Include="MediaEncoder\ffmpeg20130509.zip" />
+ <EmbeddedResource Include="MediaEncoder\ffmpeg20130523.zip" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130509.zip.REMOVED.git-id b/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130509.zip.REMOVED.git-id
deleted file mode 100644
index d05d7c224..000000000
--- a/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130509.zip.REMOVED.git-id
+++ /dev/null
@@ -1 +0,0 @@
-2ecea48340becd42b1a3136c8ae551c96a2de324 \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130523.zip.REMOVED.git-id b/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130523.zip.REMOVED.git-id
new file mode 100644
index 000000000..1bb538541
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/ffmpeg20130523.zip.REMOVED.git-id
@@ -0,0 +1 @@
+4d70588f0da1095974027f09130938f318f865c5 \ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index f1350b8a5..eba92a57d 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -372,7 +372,8 @@ namespace MediaBrowser.ServerApplication
GetExports<IItemResolver>(),
GetExports<IIntroProvider>(),
GetExports<IBaseItemComparer>(),
- GetExports<ILibraryPrescanTask>()),
+ GetExports<ILibraryPrescanTask>(),
+ GetExports<ILibraryPostScanTask>()),
() => ProviderManager.AddMetadataProviders(GetExports<BaseMetadataProvider>().ToArray())