diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations')
7 files changed, 194 insertions, 13 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 4d66d1422..692176efc 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -103,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Library private readonly IUserManager _userManager; private readonly IUserDataRepository _userDataRepository; - + /// <summary> /// Gets or sets the configuration manager. /// </summary> @@ -244,7 +245,7 @@ namespace MediaBrowser.Server.Implementations.Library { // Any number of configuration settings could change the way the library is refreshed, so do that now _taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>(); - + if (refreshPeopleAfterUpdate) { _taskManager.CancelIfRunningAndQueue<PeopleValidationTask>(); @@ -285,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.Library items.AddRange(userFolders); - return new ConcurrentDictionary<Guid,BaseItem>(items.ToDictionary(i => i.Id)); + return new ConcurrentDictionary<Guid, BaseItem>(items.ToDictionary(i => i.Id)); } /// <summary> @@ -505,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.Library { return _userRootFolders.GetOrAdd(userRootPath, key => RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(userRootPath)); } - + /// <summary> /// Gets a Person /// </summary> @@ -560,7 +561,20 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>Task{Genre}.</returns> public Task<Artist> GetArtist(string name, bool allowSlowProviders = false) { - return GetImagesByNameItem<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, CancellationToken.None, allowSlowProviders); + return GetArtist(name, CancellationToken.None, allowSlowProviders); + } + + /// <summary> + /// Gets the artist. + /// </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="forceCreation">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) + { + return GetImagesByNameItem<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, cancellationToken, allowSlowProviders, forceCreation); } /// <summary> @@ -764,6 +778,76 @@ namespace MediaBrowser.Server.Implementations.Library _logger.Info("People validation complete"); } + public async 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 = c.Artists.ToList(); + + if (!string.IsNullOrEmpty(c.AlbumArtist)) + { + list.Add(c.AlbumArtist); + } + + 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; + + progress.Report(100 * percent); + } + })); + } + + await Task.WhenAll(tasks).ConfigureAwait(false); + + progress.Report(100); + + _logger.Info("Artist validation complete"); + } + /// <summary> /// Reloads the root media folder /// </summary> @@ -796,8 +880,20 @@ namespace MediaBrowser.Server.Implementations.Library await ValidateCollectionFolders(folder, cancellationToken).ConfigureAwait(false); } + var innerProgress = new ActionableProgress<double>(); + + innerProgress.RegisterAction(pct => progress.Report(pct * .8)); + // Now validate the entire media library - await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); + 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(100); } /// <summary> diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 79aee7ad2..6d278bb18 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -145,6 +145,7 @@ <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Providers\ProviderManager.cs" /> <Compile Include="Reflection\TypeMapper.cs" /> + <Compile Include="ScheduledTasks\ArtistValidationTask.cs" /> <Compile Include="ScheduledTasks\PeopleValidationTask.cs" /> <Compile Include="ScheduledTasks\ChapterImagesTask.cs" /> <Compile Include="ScheduledTasks\ImageCleanupTask.cs" /> diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs index 8c74b8aed..8bdf597a1 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs @@ -757,8 +757,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder throw new ArgumentNullException("outputPath"); } - var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath) : - string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath); + var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath) : + string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath); var probeSize = GetProbeSizeArgument(type); diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index e4f57e8d9..4d5123cc5 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -330,11 +330,12 @@ namespace MediaBrowser.Server.Implementations.Providers /// <param name="item">The item.</param> /// <param name="source">The source.</param> /// <param name="targetName">Name of the target.</param> + /// <param name="saveLocally">if set to <c>true</c> [save locally].</param> /// <param name="resourcePool">The resource pool.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.String}.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public async Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + public async Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken) { if (item == null) { @@ -354,13 +355,13 @@ namespace MediaBrowser.Server.Implementations.Providers } //download and save locally - var localPath = (ConfigurationManager.Configuration.SaveLocalMeta && item.MetaLocation != null) ? + var localPath = (saveLocally && item.MetaLocation != null) ? Path.Combine(item.MetaLocation, targetName) : _remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetName); var img = await _httpClient.Get(source, resourcePool, cancellationToken).ConfigureAwait(false); - if (ConfigurationManager.Configuration.SaveLocalMeta) // queue to media directories + if (saveLocally) // queue to media directories { await SaveToLibraryFilesystem(item, localPath, img, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs new file mode 100644 index 000000000..a67db1b2d --- /dev/null +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs @@ -0,0 +1,81 @@ +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Library; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.ScheduledTasks +{ + public class ArtistValidationTask + { + /// <summary> + /// The _library manager + /// </summary> + private readonly ILibraryManager _libraryManager; + + /// <summary> + /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class. + /// </summary> + /// <param name="libraryManager">The library manager.</param> + public ArtistValidationTask(ILibraryManager libraryManager) + { + _libraryManager = libraryManager; + } + + /// <summary> + /// Creates the triggers that define when the task will run + /// </summary> + /// <returns>IEnumerable{BaseTaskTrigger}.</returns> + public IEnumerable<ITaskTrigger> GetDefaultTriggers() + { + return new ITaskTrigger[] + { + new DailyTrigger { TimeOfDay = TimeSpan.FromHours(5) }, + + new IntervalTrigger{ Interval = TimeSpan.FromHours(12)} + }; + } + + /// <summary> + /// Returns the task to be executed + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="progress">The progress.</param> + /// <returns>Task.</returns> + public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) + { + return _libraryManager.ValidateArtists(cancellationToken, progress); + } + + /// <summary> + /// Gets the name of the task + /// </summary> + /// <value>The name.</value> + public string Name + { + get { return "Refresh music artists"; } + } + + /// <summary> + /// Gets the description. + /// </summary> + /// <value>The description.</value> + public string Description + { + get { return "Updates metadata for music artists in your media library."; } + } + + /// <summary> + /// Gets the category. + /// </summary> + /// <value>The category.</value> + public string Category + { + get + { + return "Library"; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs index 6b8113480..ce15f5606 100644 --- a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs +++ b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks /// <value>The description.</value> public string Description { - get { return "Updates metadata for actors, artists and directors in your media library."; } + get { return "Updates metadata for actors and directors in your media library."; } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs index 575cd81ba..897ece764 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs @@ -150,6 +150,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite GC.SuppressFinalize(this); } + private readonly object _disposeLock = new object(); + /// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> @@ -160,7 +162,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite { try { - lock (this) + lock (_disposeLock) { if (connection != null) { |
