mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-16 07:12:18 +01:00
new Artist entity
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user