mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-12-26 18:54:48 +03:00
de-normalize item by name data. create counts during library scan for fast access.
This commit is contained in:
@@ -107,6 +107,15 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
if (fields.Contains(ItemFields.ItemCounts))
|
||||
{
|
||||
var itemByName = item as IItemByName;
|
||||
if (itemByName != null)
|
||||
{
|
||||
AttachItemByNameCounts(dto, itemByName, user);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all the tasks we kicked off have completed.
|
||||
if (tasks.Count > 0)
|
||||
{
|
||||
@@ -116,6 +125,41 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
return dto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches the item by name counts.
|
||||
/// </summary>
|
||||
/// <param name="dto">The dto.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
private void AttachItemByNameCounts(BaseItemDto dto, IItemByName item, User user)
|
||||
{
|
||||
ItemByNameCounts counts;
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
counts = item.ItemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!item.UserItemCounts.TryGetValue(user.Id, out counts))
|
||||
{
|
||||
counts = new ItemByNameCounts();
|
||||
}
|
||||
}
|
||||
|
||||
dto.ChildCount = counts.TotalCount;
|
||||
|
||||
dto.AdultVideoCount = counts.AdultVideoCount;
|
||||
dto.AlbumCount = counts.AlbumCount;
|
||||
dto.EpisodeCount = counts.EpisodeCount;
|
||||
dto.GameCount = counts.GameCount;
|
||||
dto.MovieCount = counts.MovieCount;
|
||||
dto.MusicVideoCount = counts.MusicVideoCount;
|
||||
dto.SeriesCount = counts.SeriesCount;
|
||||
dto.SongCount = counts.SongCount;
|
||||
dto.TrailerCount = counts.TrailerCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches the user specific info.
|
||||
/// </summary>
|
||||
@@ -380,7 +424,9 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
_logger.ErrorException("Error getting {0} image info for {1}", ex, type, path);
|
||||
return null;
|
||||
}
|
||||
} /// <summary>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches People DTO's to a DTOBaseItem
|
||||
/// </summary>
|
||||
/// <param name="dto">The dto.</param>
|
||||
@@ -913,12 +959,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
|
||||
|
||||
dto.Artists =
|
||||
songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
dto.Artists = album.Artists;
|
||||
}
|
||||
|
||||
var hasAlbumArtist = item as IHasAlbumArtist;
|
||||
@@ -935,7 +976,6 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||
dto.VideoType = video.VideoType;
|
||||
dto.Video3DFormat = video.Video3DFormat;
|
||||
dto.IsoType = video.IsoType;
|
||||
dto.MainFeaturePlaylistName = video.MainFeaturePlaylistName;
|
||||
|
||||
dto.PartCount = video.AdditionalPartIds.Count + 1;
|
||||
|
||||
|
||||
@@ -81,6 +81,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer
|
||||
{
|
||||
bytes = await ReceiveBytesAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (WebSocketException ex)
|
||||
{
|
||||
_logger.ErrorException("Error receiving web socket message", ex);
|
||||
|
||||
@@ -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;
|
||||
return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
|
||||
}
|
||||
|
||||
var tasks = new List<Task>();
|
||||
/// <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);
|
||||
}
|
||||
|
||||
var artists = RootFolder.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.SelectMany(c =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
/// <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);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(c.AlbumArtist))
|
||||
{
|
||||
list.Add(c.AlbumArtist);
|
||||
}
|
||||
list.AddRange(c.Artists);
|
||||
/// <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);
|
||||
}
|
||||
|
||||
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>
|
||||
/// 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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
}
|
||||
|
||||
// Find genres, from non-audio items
|
||||
var genres = items.Where(i => !(i is Audio) && !(i is MusicAlbum) && !(i is MusicArtist) && !(i is MusicVideo) && !(i is Game))
|
||||
var genres = items.Where(i => !(i is IHasMusicGenres) && !(i is Game))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
@@ -181,7 +181,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||
}
|
||||
|
||||
// Find music genres
|
||||
var musicGenres = items.Where(i => (i is Audio) || (i is MusicAlbum) || (i is MusicArtist) || (i is MusicVideo))
|
||||
var musicGenres = items.Where(i => i is IHasMusicGenres)
|
||||
.SelectMany(i => i.Genres)
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <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 Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.ValidateArtists(cancellationToken, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ArtistsValidator
|
||||
/// </summary>
|
||||
public class ArtistsValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly LibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public ArtistsValidator(LibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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 allMusicArtists = allItems.OfType<MusicArtist>().ToList();
|
||||
var allSongs = allItems.OfType<Audio>().ToList();
|
||||
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
|
||||
innerProgress.RegisterAction(pct => progress.Report(pct * .8));
|
||||
|
||||
var allArtists = await GetAllArtists(allSongs, cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
|
||||
progress.Report(80);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<IHasArtist>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<IHasArtist>().ToList()))
|
||||
.ToList();
|
||||
|
||||
foreach (var artist in allArtists)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
artist.ValidateImages();
|
||||
artist.ValidateBackdrops();
|
||||
|
||||
var musicArtist = FindMusicArtist(artist, allMusicArtists);
|
||||
|
||||
if (musicArtist != null)
|
||||
{
|
||||
MergeImages(musicArtist.Images, artist.Images);
|
||||
|
||||
// Merge backdrops
|
||||
var backdrops = musicArtist.BackdropImagePaths.ToList();
|
||||
backdrops.InsertRange(0, artist.BackdropImagePaths);
|
||||
artist.BackdropImagePaths = backdrops.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (!artist.LockedFields.Contains(MetadataFields.Genres))
|
||||
{
|
||||
// Avoid implicitly captured closure
|
||||
var artist1 = artist;
|
||||
|
||||
artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name))
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(artist, null, allItems.OfType<IHasArtist>());
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(artist, lib.Item1, lib.Item2);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= allArtists.Count;
|
||||
percent *= 20;
|
||||
|
||||
progress.Report(80 + percent);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item counts.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="allItems">All items.</param>
|
||||
private void SetItemCounts(Artist artist, Guid? userId, IEnumerable<IHasArtist> allItems)
|
||||
{
|
||||
var name = artist.Name;
|
||||
|
||||
var items = allItems
|
||||
.Where(i => i.HasArtist(name))
|
||||
.ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.OfType<MusicAlbum>().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count()
|
||||
};
|
||||
|
||||
if (userId.HasValue)
|
||||
{
|
||||
artist.UserItemCounts[userId.Value] = counts;
|
||||
}
|
||||
else
|
||||
{
|
||||
artist.ItemCounts = counts;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges the images.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
/// <param name="target">The target.</param>
|
||||
private void MergeImages(Dictionary<ImageType, string> source, Dictionary<ImageType, string> target)
|
||||
{
|
||||
foreach (var key in source.Keys
|
||||
.ToList()
|
||||
.Where(k => !target.ContainsKey(k)))
|
||||
{
|
||||
string path;
|
||||
|
||||
if (source.TryGetValue(key, out path))
|
||||
{
|
||||
target[key] = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all artists.
|
||||
/// </summary>
|
||||
/// <param name="allSongs">All songs.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task{Artist[]}.</returns>
|
||||
private async Task<List<Artist>> GetAllArtists(IEnumerable<Audio> allSongs, CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var allArtists = allSongs
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
const int maxTasks = 5;
|
||||
|
||||
var tasks = new List<Task>();
|
||||
|
||||
var returnArtists = new ConcurrentBag<Artist>();
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var artist in allArtists)
|
||||
{
|
||||
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
|
||||
{
|
||||
var artistItem = await _libraryManager.GetArtist(currentArtist, cancellationToken, true, true)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
returnArtists.Add(artistItem);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.ErrorException("Error validating Artist {0}", ex, currentArtist);
|
||||
}
|
||||
|
||||
// Update progress
|
||||
lock (progress)
|
||||
{
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= allArtists.Count;
|
||||
|
||||
progress.Report(100 * percent);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return returnArtists.ToList();
|
||||
}
|
||||
|
||||
/// <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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class CountHelpers
|
||||
/// </summary>
|
||||
internal static class CountHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds to dictionary.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="counts">The counts.</param>
|
||||
internal static void AddToDictionary(BaseItem item, Dictionary<string, int> counts)
|
||||
{
|
||||
if (item is Movie)
|
||||
{
|
||||
IncrementCount(counts, "Movie");
|
||||
}
|
||||
else if (item is Trailer)
|
||||
{
|
||||
IncrementCount(counts, "Trailer");
|
||||
}
|
||||
else if (item is Series)
|
||||
{
|
||||
IncrementCount(counts, "Series");
|
||||
}
|
||||
else if (item is Game)
|
||||
{
|
||||
IncrementCount(counts, "Game");
|
||||
}
|
||||
else if (item is Audio)
|
||||
{
|
||||
IncrementCount(counts, "Audio");
|
||||
}
|
||||
else if (item is MusicAlbum)
|
||||
{
|
||||
IncrementCount(counts, "MusicAlbum");
|
||||
}
|
||||
else if (item is Episode)
|
||||
{
|
||||
IncrementCount(counts, "Episode");
|
||||
}
|
||||
else if (item is MusicVideo)
|
||||
{
|
||||
IncrementCount(counts, "MusicVideo");
|
||||
}
|
||||
else if (item is AdultVideo)
|
||||
{
|
||||
IncrementCount(counts, "AdultVideo");
|
||||
}
|
||||
|
||||
IncrementCount(counts, "Total");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the count.
|
||||
/// </summary>
|
||||
/// <param name="counts">The counts.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
internal static void IncrementCount(Dictionary<string, int> counts, string key)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (counts.TryGetValue(key, out count))
|
||||
{
|
||||
count++;
|
||||
counts[key] = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
counts.Add(key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the counts.
|
||||
/// </summary>
|
||||
/// <param name="counts">The counts.</param>
|
||||
/// <returns>ItemByNameCounts.</returns>
|
||||
internal static ItemByNameCounts GetCounts(Dictionary<string, int> counts)
|
||||
{
|
||||
return new ItemByNameCounts
|
||||
{
|
||||
AdultVideoCount = GetCount(counts, "AdultVideo"),
|
||||
AlbumCount = GetCount(counts, "MusicAlbum"),
|
||||
EpisodeCount = GetCount(counts, "Episode"),
|
||||
GameCount = GetCount(counts, "Game"),
|
||||
MovieCount = GetCount(counts, "Movie"),
|
||||
MusicVideoCount = GetCount(counts, "MusicVideo"),
|
||||
SeriesCount = GetCount(counts, "Series"),
|
||||
SongCount = GetCount(counts, "Audio"),
|
||||
TrailerCount = GetCount(counts, "Trailer"),
|
||||
TotalCount = GetCount(counts, "Total")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count.
|
||||
/// </summary>
|
||||
/// <param name="counts">The counts.</param>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <returns>System.Int32.</returns>
|
||||
internal static int GetCount(Dictionary<string, int> counts, string key)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (counts.TryGetValue(key, out count))
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the item counts.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="media">The media.</param>
|
||||
/// <param name="names">The names.</param>
|
||||
/// <param name="masterDictionary">The master dictionary.</param>
|
||||
internal static void SetItemCounts(Guid? userId, BaseItem media, List<string> names, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
Dictionary<Guid, Dictionary<string, int>> libraryCounts;
|
||||
|
||||
if (!masterDictionary.TryGetValue(name, out libraryCounts))
|
||||
{
|
||||
libraryCounts = new Dictionary<Guid, Dictionary<string, int>>();
|
||||
masterDictionary.Add(name, libraryCounts);
|
||||
}
|
||||
|
||||
var userLibId = userId ?? Guid.Empty;
|
||||
Dictionary<string, int> userDictionary;
|
||||
|
||||
if (!libraryCounts.TryGetValue(userLibId, out userDictionary))
|
||||
{
|
||||
userDictionary = new Dictionary<string, int>();
|
||||
libraryCounts.Add(userLibId, userDictionary);
|
||||
}
|
||||
|
||||
AddToDictionary(media, userDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GameGenresPostScanTask
|
||||
/// </summary>
|
||||
public class GameGenresPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameGenresPostScanTask"/> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
public GameGenresPostScanTask(ILibraryManager libraryManager, IUserManager userManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.ValidateGameGenres(cancellationToken, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
class GameGenresValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly LibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public GameGenresValidator(LibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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.OfType<Game>().ToList();
|
||||
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<Game>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<Game>().ToList()))
|
||||
.ToList();
|
||||
|
||||
var allLibraryItems = allItems;
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(null, allLibraryItems, masterDictionary);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var names = masterDictionary.Keys.ToList();
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= names.Count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
|
||||
{
|
||||
var itemByName = await _libraryManager.GetGameGenre(name, cancellationToken, true, true).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys.ToList())
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
if (libraryId == Guid.Empty)
|
||||
{
|
||||
itemByName.ItemCounts = itemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemByName.UserItemCounts[libraryId] = itemCounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
public class GenresPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
public GenresPostScanTask(ILibraryManager libraryManager, IUserManager userManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.ValidateGenres(cancellationToken, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
class GenresValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly LibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public GenresValidator(LibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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
|
||||
.Where(i => !(i is IHasMusicGenres) && !(i is Game))
|
||||
.ToList();
|
||||
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => !(m is IHasMusicGenres) && !(m is Game)).ToList()))
|
||||
.ToList();
|
||||
|
||||
var allLibraryItems = allItems;
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(null, allLibraryItems, masterDictionary);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var names = masterDictionary.Keys.ToList();
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= names.Count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
|
||||
{
|
||||
var itemByName = await _libraryManager.GetGenre(name, cancellationToken, true, true).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys.ToList())
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
if (libraryId == Guid.Empty)
|
||||
{
|
||||
itemByName.ItemCounts = itemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemByName.UserItemCounts[libraryId] = itemCounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MusicGenresPostScanTask
|
||||
/// </summary>
|
||||
public class MusicGenresPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
public MusicGenresPostScanTask(ILibraryManager libraryManager, IUserManager userManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.ValidateMusicGenres(cancellationToken, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
class MusicGenresValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly LibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MusicGenresValidator(LibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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
|
||||
.Where(i => i is IHasMusicGenres)
|
||||
.ToList();
|
||||
|
||||
var userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).Where(m => m is IHasMusicGenres).ToList()))
|
||||
.ToList();
|
||||
|
||||
var allLibraryItems = allItems;
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(null, allLibraryItems, masterDictionary);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var names = masterDictionary.Keys.ToList();
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= names.Count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
|
||||
{
|
||||
var itemByName = await _libraryManager.GetMusicGenre(name, cancellationToken, true, true).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys.ToList())
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
if (libraryId == Guid.Empty)
|
||||
{
|
||||
itemByName.ItemCounts = itemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemByName.UserItemCounts[libraryId] = itemCounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Genres
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
class PeoplePostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public PeoplePostScanTask(ILibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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 userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).ToList()))
|
||||
.ToList();
|
||||
|
||||
var allLibraryItems = allItems;
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(null, allLibraryItems, masterDictionary);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var names = masterDictionary.Keys.ToList();
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, masterDictionary[name]).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= names.Count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task UpdateItemByNameCounts(string name, Dictionary<Guid, Dictionary<string, int>> counts)
|
||||
{
|
||||
var itemByName = await _libraryManager.GetPerson(name).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys.ToList())
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
if (libraryId == Guid.Empty)
|
||||
{
|
||||
itemByName.ItemCounts = itemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemByName.UserItemCounts[libraryId] = itemCounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.People.Select(i => i.Name)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using MediaBrowser.Controller.Library;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MusicGenresPostScanTask
|
||||
/// </summary>
|
||||
public class StudiosPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userManager">The user manager.</param>
|
||||
public StudiosPostScanTask(ILibraryManager libraryManager, IUserManager userManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return _libraryManager.ValidateStudios(cancellationToken, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Validators
|
||||
{
|
||||
class StudiosValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly LibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger
|
||||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public StudiosValidator(LibraryManager libraryManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <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 userLibraries = _userManager.Users
|
||||
.Select(i => new Tuple<Guid, List<BaseItem>>(i.Id, i.RootFolder.GetRecursiveChildren(i).ToList()))
|
||||
.ToList();
|
||||
|
||||
var allLibraryItems = allItems;
|
||||
|
||||
var masterDictionary = new Dictionary<string, Dictionary<Guid, Dictionary<string, int>>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Populate counts of items
|
||||
SetItemCounts(null, allLibraryItems, masterDictionary);
|
||||
|
||||
progress.Report(2);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var lib in userLibraries)
|
||||
{
|
||||
SetItemCounts(lib.Item1, lib.Item2, masterDictionary);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= userLibraries.Count;
|
||||
percent *= 8;
|
||||
|
||||
progress.Report(percent);
|
||||
}
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var names = masterDictionary.Keys.ToList();
|
||||
numComplete = 0;
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateItemByNameCounts(name, cancellationToken, masterDictionary[name]).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error updating counts for {0}", ex, name);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= names.Count;
|
||||
percent *= 90;
|
||||
|
||||
progress.Report(percent + 10);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task UpdateItemByNameCounts(string name, CancellationToken cancellationToken, Dictionary<Guid, Dictionary<string, int>> counts)
|
||||
{
|
||||
var itemByName = await _libraryManager.GetStudio(name, cancellationToken, true, true).ConfigureAwait(false);
|
||||
|
||||
foreach (var libraryId in counts.Keys.ToList())
|
||||
{
|
||||
var itemCounts = CountHelpers.GetCounts(counts[libraryId]);
|
||||
|
||||
if (libraryId == Guid.Empty)
|
||||
{
|
||||
itemByName.ItemCounts = itemCounts;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemByName.UserItemCounts[libraryId] = itemCounts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemCounts(Guid? userId, IEnumerable<BaseItem> allItems, Dictionary<string, Dictionary<Guid, Dictionary<string, int>>> masterDictionary)
|
||||
{
|
||||
foreach (var media in allItems)
|
||||
{
|
||||
var names = media
|
||||
.Studios
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
CountHelpers.SetItemCounts(userId, media, names, masterDictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,18 @@
|
||||
<Compile Include="Library\Resolvers\TV\SeriesResolver.cs" />
|
||||
<Compile Include="Library\Resolvers\VideoResolver.cs" />
|
||||
<Compile Include="Library\UserManager.cs" />
|
||||
<Compile Include="Library\Validators\ArtistsPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\ArtistsValidator.cs" />
|
||||
<Compile Include="Library\Validators\CountHelpers.cs" />
|
||||
<Compile Include="Library\Validators\GameGenresPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\GameGenresValidator.cs" />
|
||||
<Compile Include="Library\Validators\GenresPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\GenresValidator.cs" />
|
||||
<Compile Include="Library\Validators\MusicGenresPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\MusicGenresValidator.cs" />
|
||||
<Compile Include="Library\Validators\PeoplePostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\StudiosPostScanTask.cs" />
|
||||
<Compile Include="Library\Validators\StudiosValidator.cs" />
|
||||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="MediaEncoder\MediaEncoder.cs" />
|
||||
<Compile Include="Persistence\SqliteChapterRepository.cs" />
|
||||
@@ -155,7 +167,6 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Providers\ImageSaver.cs" />
|
||||
<Compile Include="Providers\ProviderManager.cs" />
|
||||
<Compile Include="ScheduledTasks\ArtistValidationTask.cs" />
|
||||
<Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
|
||||
<Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
|
||||
<Compile Include="ScheduledTasks\PluginUpdateTask.cs" />
|
||||
|
||||
@@ -189,7 +189,11 @@ namespace MediaBrowser.Server.Implementations.Providers
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
_logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--");
|
||||
// Don't clog up the log with these providers
|
||||
if (!(provider is IDynamicInfoProvider))
|
||||
{
|
||||
_logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--");
|
||||
}
|
||||
|
||||
// This provides the ability to cancel just this one provider
|
||||
var innerCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,11 +85,6 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
get { return _activeConnections.Values.OrderByDescending(c => c.LastActivityDate).ToList(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The _true task result
|
||||
/// </summary>
|
||||
private readonly Task _trueTaskResult = Task.FromResult(true);
|
||||
|
||||
/// <summary>
|
||||
/// Logs the user activity.
|
||||
/// </summary>
|
||||
@@ -339,6 +334,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||
// If the client isn't able to report this, then we'll just have to make an assumption
|
||||
data.PlayCount++;
|
||||
data.Played = true;
|
||||
data.PlaybackPositionTicks = 0;
|
||||
}
|
||||
|
||||
await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
Reference in New Issue
Block a user