aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2013-09-10 14:56:00 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2013-09-10 14:56:00 -0400
commit740a10a4e3f85ffcfd26ec18263d4c78d4b14ecc (patch)
tree61462d05ce44c1bb17f48e557b02e14bb480816d /MediaBrowser.Server.Implementations/Library/LibraryManager.cs
parentd078edfb96fe2dcfebdc34e9189f85b0487ac242 (diff)
de-normalize item by name data. create counts during library scan for fast access.
Diffstat (limited to 'MediaBrowser.Server.Implementations/Library/LibraryManager.cs')
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs219
1 files changed, 129 insertions, 90 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index d9ab75397..d017a5f7e 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -13,6 +13,7 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Implementations.Library.Validators;
using MediaBrowser.Server.Implementations.ScheduledTasks;
using MoreLinq;
using System;
@@ -597,11 +598,11 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="name">The name.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
- /// <param name="forceCreation">if set to <c>true</c> [force creation].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [force creation].</param>
/// <returns>Task{Person}.</returns>
- private Task<Person> GetPerson(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool forceCreation = false)
+ private Task<Person> GetPerson(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
{
- return GetItemByName<Person>(ConfigurationManager.ApplicationPaths.PeoplePath, name, cancellationToken, allowSlowProviders, forceCreation);
+ return GetItemByName<Person>(ConfigurationManager.ApplicationPaths.PeoplePath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -612,7 +613,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task{Studio}.</returns>
public Task<Studio> GetStudio(string name, bool allowSlowProviders = false)
{
- return GetItemByName<Studio>(ConfigurationManager.ApplicationPaths.StudioPath, name, CancellationToken.None, allowSlowProviders);
+ return GetStudio(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ /// <summary>
+ /// Gets the studio.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [refresh metadata].</param>
+ /// <returns>Task{Studio}.</returns>
+ internal Task<Studio> GetStudio(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
+ {
+ return GetItemByName<Studio>(ConfigurationManager.ApplicationPaths.StudioPath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -623,7 +637,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public Task<Genre> GetGenre(string name, bool allowSlowProviders = false)
{
- return GetItemByName<Genre>(ConfigurationManager.ApplicationPaths.GenrePath, name, CancellationToken.None, allowSlowProviders);
+ return GetGenre(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ /// <summary>
+ /// Gets the genre.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [refresh metadata].</param>
+ /// <returns>Task{Genre}.</returns>
+ internal Task<Genre> GetGenre(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
+ {
+ return GetItemByName<Genre>(ConfigurationManager.ApplicationPaths.GenrePath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -634,7 +661,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task{MusicGenre}.</returns>
public Task<MusicGenre> GetMusicGenre(string name, bool allowSlowProviders = false)
{
- return GetItemByName<MusicGenre>(ConfigurationManager.ApplicationPaths.MusicGenrePath, name, CancellationToken.None, allowSlowProviders);
+ return GetMusicGenre(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ /// <summary>
+ /// Gets the music genre.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [refresh metadata].</param>
+ /// <returns>Task{MusicGenre}.</returns>
+ internal Task<MusicGenre> GetMusicGenre(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
+ {
+ return GetItemByName<MusicGenre>(ConfigurationManager.ApplicationPaths.MusicGenrePath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -645,7 +685,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task{GameGenre}.</returns>
public Task<GameGenre> GetGameGenre(string name, bool allowSlowProviders = false)
{
- return GetItemByName<GameGenre>(ConfigurationManager.ApplicationPaths.GameGenrePath, name, CancellationToken.None, allowSlowProviders);
+ return GetGameGenre(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ /// <summary>
+ /// Gets the game genre.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [refresh metadata].</param>
+ /// <returns>Task{GameGenre}.</returns>
+ internal Task<GameGenre> GetGameGenre(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
+ {
+ return GetItemByName<GameGenre>(ConfigurationManager.ApplicationPaths.GameGenrePath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -665,11 +718,11 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="name">The name.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
- /// <param name="forceCreation">if set to <c>true</c> [force creation].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [force creation].</param>
/// <returns>Task{Artist}.</returns>
- private Task<Artist> GetArtist(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool forceCreation = false)
+ internal Task<Artist> GetArtist(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool refreshMetadata = false)
{
- return GetItemByName<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, cancellationToken, allowSlowProviders, forceCreation);
+ return GetItemByName<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, cancellationToken, allowSlowProviders, refreshMetadata);
}
/// <summary>
@@ -707,11 +760,11 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="name">The name.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
- /// <param name="forceCreation">if set to <c>true</c> [force creation].</param>
+ /// <param name="refreshMetadata">if set to <c>true</c> [force creation].</param>
/// <returns>Task{``0}.</returns>
/// <exception cref="System.ArgumentNullException">
/// </exception>
- private async Task<T> GetItemByName<T>(string path, string name, CancellationToken cancellationToken, bool allowSlowProviders = true, bool forceCreation = false)
+ private async Task<T> GetItemByName<T>(string path, string name, CancellationToken cancellationToken, bool allowSlowProviders = true, bool refreshMetadata = false)
where T : BaseItem, new()
{
if (string.IsNullOrEmpty(path))
@@ -730,11 +783,25 @@ namespace MediaBrowser.Server.Implementations.Library
if (!_itemsByName.TryGetValue(key, out obj))
{
- obj = await CreateItemByName<T>(path, name, cancellationToken, allowSlowProviders).ConfigureAwait(false);
+ var tuple = CreateItemByName<T>(path, name, cancellationToken);
+
+ obj = tuple.Item2;
_itemsByName.AddOrUpdate(key, obj, (keyName, oldValue) => obj);
+
+ try
+ {
+ await obj.RefreshMetadata(cancellationToken, tuple.Item1, allowSlowProviders: allowSlowProviders).ConfigureAwait(false);
+ }
+ catch (OperationCanceledException)
+ {
+ BaseItem removed;
+ _itemsByName.TryRemove(key, out removed);
+
+ throw;
+ }
}
- else if (forceCreation)
+ else if (refreshMetadata)
{
await obj.RefreshMetadata(cancellationToken, false, allowSlowProviders: allowSlowProviders).ConfigureAwait(false);
}
@@ -749,10 +816,9 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="path">The path.</param>
/// <param name="name">The name.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
/// <returns>Task{``0}.</returns>
/// <exception cref="System.IO.IOException">Path not created: + path</exception>
- private async Task<T> CreateItemByName<T>(string path, string name, CancellationToken cancellationToken, bool allowSlowProviders = true)
+ private Tuple<bool, T> CreateItemByName<T>(string path, string name, CancellationToken cancellationToken)
where T : BaseItem, new()
{
cancellationToken.ThrowIfCancellationRequested();
@@ -783,6 +849,7 @@ namespace MediaBrowser.Server.Implementations.Library
var id = path.GetMBId(type);
var item = RetrieveItem(id) as T;
+
if (item == null)
{
item = new T
@@ -796,16 +863,10 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true;
}
- cancellationToken.ThrowIfCancellationRequested();
-
// Set this now so we don't cause additional file system access during provider executions
item.ResetResolveArgs(fileInfo);
- await item.RefreshMetadata(cancellationToken, isNew, allowSlowProviders: allowSlowProviders).ConfigureAwait(false);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- return item;
+ return new Tuple<bool,T>(isNew, item);
}
/// <summary>
@@ -884,75 +945,53 @@ namespace MediaBrowser.Server.Implementations.Library
/// <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)
+ public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
{
- const int maxTasks = 25;
-
- var tasks = new List<Task>();
-
- var artists = RootFolder.RecursiveChildren
- .OfType<Audio>()
- .SelectMany(c =>
- {
- var list = new List<string>();
-
- if (!string.IsNullOrEmpty(c.AlbumArtist))
- {
- list.Add(c.AlbumArtist);
- }
- list.AddRange(c.Artists);
-
- return list;
- })
- .Distinct(StringComparer.OrdinalIgnoreCase)
- .ToList();
-
- var numComplete = 0;
-
- foreach (var artist in artists)
- {
- if (tasks.Count > maxTasks)
- {
- await Task.WhenAll(tasks).ConfigureAwait(false);
- tasks.Clear();
-
- // Safe cancellation point, when there are no pending tasks
- cancellationToken.ThrowIfCancellationRequested();
- }
-
- // Avoid accessing the foreach variable within the closure
- var currentArtist = artist;
-
- tasks.Add(Task.Run(async () =>
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- await GetArtist(currentArtist, cancellationToken, true, true).ConfigureAwait(false);
- }
- catch (IOException ex)
- {
- _logger.ErrorException("Error validating Artist {0}", ex, currentArtist);
- }
-
- // Update progress
- lock (progress)
- {
- numComplete++;
- double percent = numComplete;
- percent /= artists.Count;
+ return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
+ }
- progress.Report(100 * percent);
- }
- }));
- }
+ /// <summary>
+ /// Validates the music genres.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return new MusicGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
+ }
- await Task.WhenAll(tasks).ConfigureAwait(false);
+ /// <summary>
+ /// Validates the game genres.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return new GameGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
+ }
- progress.Report(100);
+ /// <summary>
+ /// Validates the studios.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return new StudiosValidator(this, _userManager, _logger).Run(progress, cancellationToken);
+ }
- _logger.Info("Artist validation complete");
+ /// <summary>
+ /// Validates the genres.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return new GenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
}
/// <summary>
@@ -1000,12 +1039,12 @@ namespace MediaBrowser.Server.Implementations.Library
var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(pct => progress.Report(15 + pct * .65));
+ innerProgress.RegisterAction(pct => progress.Report(15 + pct * .6));
// Now validate the entire media library
await RootFolder.ValidateChildren(innerProgress, cancellationToken, recursive: true).ConfigureAwait(false);
- progress.Report(80);
+ progress.Report(75);
// Run post-scan tasks
await RunPostScanTasks(progress, cancellationToken).ConfigureAwait(false);
@@ -1078,7 +1117,7 @@ namespace MediaBrowser.Server.Implementations.Library
double percent = progressDictionary.Values.Sum();
percent /= postscanTasks.Count;
- progress.Report(80 + percent * .2);
+ progress.Report(75 + percent * .25);
}
});