de-normalize item by name data. create counts during library scan for fast access.
This commit is contained in:
parent
d078edfb96
commit
740a10a4e3
|
@ -22,28 +22,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetArtistsItemCounts
|
||||
/// </summary>
|
||||
[Route("/Artists/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that an artist appears in")]
|
||||
public class GetArtistsItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Route("/Artists/{Name}", "GET")]
|
||||
[Api(Description = "Gets an artist, by name")]
|
||||
public class GetArtist : IReturn<BaseItemDto>
|
||||
|
@ -114,49 +92,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetArtistsItemCounts request)
|
||||
{
|
||||
var name = DeSlugArtistName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i =>
|
||||
{
|
||||
var song = i as Audio;
|
||||
|
||||
if (song != null)
|
||||
{
|
||||
return song.HasArtist(name);
|
||||
}
|
||||
|
||||
var musicVideo = i as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
return musicVideo.HasArtist(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.Select(i => i.Parent).OfType<MusicAlbum>().Distinct().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count(i => i.HasArtist(name))
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -193,7 +128,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<Artist>(name, () => itemsList.Where(i => i.HasArtist(name)), GetEntity));
|
||||
.Select(name => new IbnStub<Artist>(name, GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// </summary>
|
||||
/// <typeparam name="TItemType">The type of the T item type.</typeparam>
|
||||
public abstract class BaseItemsByNameService<TItemType> : BaseApiService
|
||||
where TItemType : BaseItem
|
||||
where TItemType : BaseItem, IItemByName
|
||||
{
|
||||
/// <summary>
|
||||
/// The _user manager
|
||||
|
@ -38,6 +38,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <param name="userManager">The user manager.</param>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
/// <param name="userDataRepository">The user data repository.</param>
|
||||
/// <param name="itemRepository">The item repository.</param>
|
||||
/// <param name="dtoService">The dto service.</param>
|
||||
protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepository, IDtoService dtoService)
|
||||
{
|
||||
UserManager = userManager;
|
||||
|
@ -292,7 +294,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// <returns>Task{DtoBaseItem}.</returns>
|
||||
private async Task<BaseItemDto> GetDto(IbnStub<TItemType> stub, User user, List<ItemFields> fields)
|
||||
{
|
||||
BaseItem item;
|
||||
TItemType item;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -307,14 +309,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
var dto = user == null ? await DtoService.GetBaseItemDto(item, fields).ConfigureAwait(false) :
|
||||
await DtoService.GetBaseItemDto(item, fields, user).ConfigureAwait(false);
|
||||
|
||||
if (fields.Contains(ItemFields.ItemCounts))
|
||||
{
|
||||
var items = stub.Items;
|
||||
|
||||
dto.ChildCount = items.Count;
|
||||
dto.RecentlyAddedItemCount = items.Count(i => i.IsRecentlyAdded());
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
|
@ -367,9 +361,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
public class IbnStub<T>
|
||||
where T : BaseItem
|
||||
{
|
||||
private readonly Func<IEnumerable<BaseItem>> _childItemsFunction;
|
||||
private List<BaseItem> _childItems;
|
||||
|
||||
private readonly Func<string,Task<T>> _itemFunction;
|
||||
private Task<T> _itemTask;
|
||||
|
||||
|
@ -377,11 +368,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
private UserItemData _userData;
|
||||
|
||||
public List<BaseItem> Items
|
||||
{
|
||||
get { return _childItems ?? (_childItems = _childItemsFunction().ToList()); }
|
||||
}
|
||||
|
||||
public Task<T> GetItem()
|
||||
{
|
||||
return _itemTask ?? (_itemTask = _itemFunction(Name));
|
||||
|
@ -394,10 +380,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return _userData ?? (_userData = repo.GetUserData(userId, item.GetUserDataKey()));
|
||||
}
|
||||
|
||||
public IbnStub(string name, Func<IEnumerable<BaseItem>> childItems, Func<string,Task<T>> item)
|
||||
public IbnStub(string name, Func<string,Task<T>> item)
|
||||
{
|
||||
Name = name;
|
||||
_childItemsFunction = childItems;
|
||||
_itemFunction = item;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,25 +23,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
}
|
||||
}
|
||||
|
||||
[Route("/GameGenres/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that a genre appears in")]
|
||||
public class GetGameGenreItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Route("/GameGenres/{Name}", "GET")]
|
||||
[Api(Description = "Gets a Game genre, by name")]
|
||||
public class GetGameGenre : IReturn<BaseItemDto>
|
||||
|
@ -127,7 +108,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return itemsList
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<GameGenre>(name, () => itemsList.Where(i => i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)), GetEntity));
|
||||
.Select(name => new IbnStub<GameGenre>(name, GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -139,26 +120,5 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
return LibraryManager.GetGameGenre(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetGameGenreItemCounts request)
|
||||
{
|
||||
var name = DeSlugGameGenreName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i => i.Genres != null && i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
GameCount = items.OfType<Game>().Count()
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
@ -23,25 +21,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
}
|
||||
|
||||
[Route("/Genres/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that a genre appears in")]
|
||||
public class GetGenreItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetGenre
|
||||
/// </summary>
|
||||
|
@ -133,7 +112,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return itemsList
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<Genre>(name, () => itemsList.Where(i => i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)), GetEntity));
|
||||
.Select(name => new IbnStub<Genre>(name, GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -145,34 +124,5 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
return LibraryManager.GetGenre(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetGenreItemCounts request)
|
||||
{
|
||||
var name = DeSlugGenreName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i => i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
TrailerCount = items.OfType<Trailer>().Count(),
|
||||
|
||||
MovieCount = items.OfType<Movie>().Count(),
|
||||
|
||||
SeriesCount = items.OfType<Series>().Count(),
|
||||
|
||||
GameCount = items.OfType<Game>().Count(),
|
||||
|
||||
AdultVideoCount = items.OfType<AdultVideo>().Count()
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,28 +427,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
items = items.Where(i =>
|
||||
{
|
||||
var audio = i as Audio;
|
||||
var audio = i as IHasArtist;
|
||||
|
||||
if (audio != null)
|
||||
{
|
||||
return artists.Any(audio.HasArtist);
|
||||
}
|
||||
|
||||
var album = i as MusicAlbum;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
return artists.Any(album.HasArtist);
|
||||
}
|
||||
|
||||
var musicVideo = i as MusicVideo;
|
||||
|
||||
if (musicVideo != null)
|
||||
{
|
||||
return artists.Any(musicVideo.HasArtist);
|
||||
}
|
||||
|
||||
return false;
|
||||
return audio != null && artists.Any(audio.HasArtist);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -23,25 +23,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
}
|
||||
}
|
||||
|
||||
[Route("/MusicGenres/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that a genre appears in")]
|
||||
public class GetMusicGenreItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
[Route("/MusicGenres/{Name}", "GET")]
|
||||
[Api(Description = "Gets a music genre, by name")]
|
||||
public class GetMusicGenre : IReturn<BaseItemDto>
|
||||
|
@ -127,7 +108,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return itemsList
|
||||
.SelectMany(i => i.Genres)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<MusicGenre>(name, () => itemsList.Where(i => i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)), GetEntity));
|
||||
.Select(name => new IbnStub<MusicGenre>(name, GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -139,30 +120,5 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
return LibraryManager.GetMusicGenre(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetMusicGenreItemCounts request)
|
||||
{
|
||||
var name = DeSlugGenreName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i => i.Genres != null && i.Genres.Contains(name, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.OfType<MusicAlbum>().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count()
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
@ -29,28 +26,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
public string PersonTypes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetPersonItemCounts
|
||||
/// </summary>
|
||||
[Route("/Persons/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that a person appears in")]
|
||||
public class GetPersonItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetPerson
|
||||
/// </summary>
|
||||
|
@ -136,43 +111,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetPersonItemCounts request)
|
||||
{
|
||||
var name = DeSlugPersonName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i => i.People != null && i.People.Any(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase))).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
TrailerCount = items.OfType<Trailer>().Count(),
|
||||
|
||||
MovieCount = items.OfType<Movie>().Count(),
|
||||
|
||||
SeriesCount = items.OfType<Series>().Count(),
|
||||
|
||||
GameCount = items.OfType<Game>().Count(),
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.OfType<MusicAlbum>().Count(),
|
||||
|
||||
EpisodeCount = items.OfType<Episode>().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count(),
|
||||
|
||||
AdultVideoCount = items.OfType<AdultVideo>().Count()
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all items.
|
||||
/// </summary>
|
||||
|
@ -193,15 +131,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
.Select(i => i.Name)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
|
||||
.Select(name => new IbnStub<Person>(name, () =>
|
||||
{
|
||||
if (personTypes.Length == 0)
|
||||
{
|
||||
return itemsList.Where(i => i.People.Any(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
|
||||
return itemsList.Where(i => i.People.Any(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && (personTypes.Contains(p.Type ?? string.Empty, StringComparer.OrdinalIgnoreCase) || personTypes.Contains(p.Role ?? string.Empty, StringComparer.OrdinalIgnoreCase))));
|
||||
}, GetEntity)
|
||||
.Select(name => new IbnStub<Person>(name, GetEntity)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
@ -24,25 +21,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
{
|
||||
}
|
||||
|
||||
[Route("/Studios/{Name}/Counts", "GET")]
|
||||
[Api(Description = "Gets item counts of library items that a studio appears in")]
|
||||
public class GetStudioItemCounts : IReturn<ItemByNameCounts>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
[ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class GetStudio
|
||||
/// </summary>
|
||||
|
@ -109,41 +87,6 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetStudioItemCounts request)
|
||||
{
|
||||
var name = DeSlugStudioName(request.Name, LibraryManager);
|
||||
|
||||
var items = GetItems(request.UserId).Where(i => i.Studios != null && i.Studios.Contains(name, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
var counts = new ItemByNameCounts
|
||||
{
|
||||
TotalCount = items.Count,
|
||||
|
||||
TrailerCount = items.OfType<Trailer>().Count(),
|
||||
|
||||
MovieCount = items.OfType<Movie>().Count(),
|
||||
|
||||
SeriesCount = items.OfType<Series>().Count(),
|
||||
|
||||
GameCount = items.OfType<Game>().Count(),
|
||||
|
||||
SongCount = items.OfType<Audio>().Count(),
|
||||
|
||||
AlbumCount = items.OfType<MusicAlbum>().Count(),
|
||||
|
||||
MusicVideoCount = items.OfType<MusicVideo>().Count(),
|
||||
|
||||
AdultVideoCount = items.OfType<AdultVideo>().Count()
|
||||
};
|
||||
|
||||
return ToOptimizedResult(counts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified request.
|
||||
/// </summary>
|
||||
|
@ -169,7 +112,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return itemsList
|
||||
.SelectMany(i => i.Studios)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(name => new IbnStub<Studio>(name, () => itemsList.Where(i => i.Studios.Contains(name, StringComparer.OrdinalIgnoreCase)), GetEntity));
|
||||
.Select(name => new IbnStub<Studio>(name, GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return itemsList
|
||||
.Select(i => i.ProductionYear.Value)
|
||||
.Distinct()
|
||||
.Select(year => new IbnStub<Year>(year.ToString(UsCulture), () => itemsList.Where(i => i.ProductionYear.HasValue && i.ProductionYear.Value == year), GetEntity));
|
||||
.Select(year => new IbnStub<Year>(year.ToString(UsCulture), GetEntity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Class Artist
|
||||
/// </summary>
|
||||
public class Artist : BaseItem, IItemByName
|
||||
public class Artist : BaseItem, IItemByName, IHasMusicGenres
|
||||
{
|
||||
public Artist()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
public string LastFmImageUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -17,5 +26,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
return "Artist-" + Name;
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <summary>
|
||||
/// Class Audio
|
||||
/// </summary>
|
||||
public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist
|
||||
public class Audio : BaseItem, IHasMediaStreams, IHasAlbumArtist, IHasArtist, IHasMusicGenres
|
||||
{
|
||||
public Audio()
|
||||
{
|
||||
|
|
|
@ -5,4 +5,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
string AlbumArtist { get; }
|
||||
}
|
||||
|
||||
public interface IHasArtist
|
||||
{
|
||||
bool HasArtist(string name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
public interface IHasMusicGenres
|
||||
{
|
||||
List<string> Genres { get; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
|
@ -6,10 +7,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <summary>
|
||||
/// Class MusicAlbum
|
||||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres
|
||||
{
|
||||
public MusicAlbum()
|
||||
{
|
||||
Artists = new string[] { };
|
||||
}
|
||||
|
||||
public string LastFmImageUrl { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Songs will group into us so don't also include us in the index
|
||||
/// </summary>
|
||||
|
@ -60,23 +66,17 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <returns><c>true</c> if the specified artist has artist; otherwise, <c>false</c>.</returns>
|
||||
public bool HasArtist(string artist)
|
||||
{
|
||||
return RecursiveChildren.OfType<Audio>().Any(i => i.HasArtist(artist));
|
||||
return string.Equals(AlbumArtist, artist, StringComparison.OrdinalIgnoreCase)
|
||||
|| Artists.Contains(artist, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public string AlbumArtist
|
||||
{
|
||||
get
|
||||
{
|
||||
return RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.Select(i => i.AlbumArtist)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
}
|
||||
}
|
||||
public string AlbumArtist { get; set; }
|
||||
|
||||
public string[] Artists { get; set; }
|
||||
}
|
||||
|
||||
public class MusicAlbumDisc : Folder
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +9,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// </summary>
|
||||
public class MusicGenre : BaseItem, IItemByName
|
||||
{
|
||||
public MusicGenre()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
@ -14,5 +23,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
return "MusicGenre-" + Name;
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1537,5 +1537,58 @@ namespace MediaBrowser.Controller.Entities
|
|||
// Refresh metadata
|
||||
return RefreshMetadata(CancellationToken.None, forceSave: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that images within the item are still on the file system
|
||||
/// </summary>
|
||||
public void ValidateImages()
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedKeys = Images
|
||||
.ToList()
|
||||
.Where(image => !File.Exists(image.Value))
|
||||
.Select(i => i.Key)
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var key in deletedKeys)
|
||||
{
|
||||
Images.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that backdrops within the item are still on the file system
|
||||
/// </summary>
|
||||
public void ValidateBackdrops()
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedImages = BackdropImagePaths
|
||||
.Where(path => !File.Exists(path))
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var path in deletedImages)
|
||||
{
|
||||
BackdropImagePaths.Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the screenshots.
|
||||
/// </summary>
|
||||
public void ValidateScreenshots()
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedImages = ScreenshotImagePaths
|
||||
.Where(path => !File.Exists(path))
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var path in deletedImages)
|
||||
{
|
||||
ScreenshotImagePaths.Remove(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class GameGenre : BaseItem, IItemByName
|
||||
{
|
||||
public GameGenre()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
@ -11,5 +20,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return "GameGenre-" + Name;
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +9,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public class Genre : BaseItem, IItemByName
|
||||
{
|
||||
public Genre()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
@ -14,5 +23,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return "Genre-" + Name;
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,5 +9,8 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public interface IItemByName
|
||||
{
|
||||
ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class MusicVideo : Video
|
||||
public class MusicVideo : Video, IHasArtist, IHasMusicGenres
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the artist.
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +9,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public class Person : BaseItem, IItemByName
|
||||
{
|
||||
public Person()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +9,12 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public class Studio : BaseItem, IItemByName
|
||||
{
|
||||
public Studio()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
@ -14,5 +23,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
return "Studio-" + Name;
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,6 +136,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
get { return Video3DFormat.HasValue; }
|
||||
}
|
||||
|
||||
public bool IsHd
|
||||
{
|
||||
get { return MediaStreams != null && MediaStreams.Any(i => i.Type == MediaStreamType.Video && i.Width.HasValue && i.Width.Value >= 1280); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -6,6 +9,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// </summary>
|
||||
public class Year : BaseItem, IItemByName
|
||||
{
|
||||
public Year()
|
||||
{
|
||||
ItemCounts = new ItemByNameCounts();
|
||||
UserItemCounts = new Dictionary<Guid, ItemByNameCounts>();
|
||||
}
|
||||
|
||||
public ItemByNameCounts ItemCounts { get; set; }
|
||||
|
||||
public Dictionary<Guid, ItemByNameCounts> UserItemCounts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
|
|
@ -235,6 +235,38 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <returns>Task.</returns>
|
||||
Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the music genres.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the game genres.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the genres.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the studios.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item added].
|
||||
/// </summary>
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<Compile Include="Dto\IDtoService.cs" />
|
||||
<Compile Include="Entities\AdultVideo.cs" />
|
||||
<Compile Include="Entities\Audio\IHasAlbumArtist.cs" />
|
||||
<Compile Include="Entities\Audio\IHasMusicGenres.cs" />
|
||||
<Compile Include="Entities\Book.cs" />
|
||||
<Compile Include="Configuration\IServerConfigurationManager.cs" />
|
||||
<Compile Include="Entities\Audio\MusicGenre.cs" />
|
||||
|
@ -90,6 +91,7 @@
|
|||
<Compile Include="Localization\ILocalizationManager.cs" />
|
||||
<Compile Include="Notifications\INotificationsRepository.cs" />
|
||||
<Compile Include="Notifications\NotificationUpdateEventArgs.cs" />
|
||||
<Compile Include="Providers\IDynamicInfoProvider.cs" />
|
||||
<Compile Include="Session\ISessionManager.cs" />
|
||||
<Compile Include="Drawing\ImageExtensions.cs" />
|
||||
<Compile Include="Drawing\ImageHeader.cs" />
|
||||
|
|
10
MediaBrowser.Controller/Providers/IDynamicInfoProvider.cs
Normal file
10
MediaBrowser.Controller/Providers/IDynamicInfoProvider.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for a provider that always runs
|
||||
/// </summary>
|
||||
public interface IDynamicInfoProvider
|
||||
{
|
||||
}
|
||||
}
|
|
@ -28,6 +28,8 @@ namespace MediaBrowser.Model.ApiClient
|
|||
/// </summary>
|
||||
event EventHandler<HttpResponseEventArgs> HttpResponseReceived;
|
||||
|
||||
Task<T> GetAsync<T>(string url, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the critic reviews.
|
||||
/// </summary>
|
||||
|
|
|
@ -36,8 +36,6 @@ namespace MediaBrowser.Model.Dto
|
|||
/// <value>The name of the sort.</value>
|
||||
public string SortName { get; set; }
|
||||
|
||||
public string MainFeaturePlaylistName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the video3 D format.
|
||||
/// </summary>
|
||||
|
@ -521,6 +519,48 @@ namespace MediaBrowser.Model.Dto
|
|||
/// <value>The locked fields.</value>
|
||||
public List<MetadataFields> LockedFields { get; set; }
|
||||
|
||||
public int? AdultVideoCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the movie count.
|
||||
/// </summary>
|
||||
/// <value>The movie count.</value>
|
||||
public int? MovieCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the series count.
|
||||
/// </summary>
|
||||
/// <value>The series count.</value>
|
||||
public int? SeriesCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the episode count.
|
||||
/// </summary>
|
||||
/// <value>The episode count.</value>
|
||||
public int? EpisodeCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the game count.
|
||||
/// </summary>
|
||||
/// <value>The game count.</value>
|
||||
public int? GameCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the trailer count.
|
||||
/// </summary>
|
||||
/// <value>The trailer count.</value>
|
||||
public int? TrailerCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the song count.
|
||||
/// </summary>
|
||||
/// <value>The song count.</value>
|
||||
public int? SongCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the album count.
|
||||
/// </summary>
|
||||
/// <value>The album count.</value>
|
||||
public int? AlbumCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the music video count.
|
||||
/// </summary>
|
||||
/// <value>The music video count.</value>
|
||||
public int? MusicVideoCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable internet providers].
|
||||
/// </summary>
|
||||
|
|
|
@ -11,6 +11,10 @@ namespace MediaBrowser.Model.Dto
|
|||
/// </summary>
|
||||
/// <value>The total count.</value>
|
||||
public int TotalCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the adult video count.
|
||||
/// </summary>
|
||||
/// <value>The adult video count.</value>
|
||||
public int AdultVideoCount { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the movie count.
|
||||
|
|
|
@ -98,13 +98,13 @@ namespace MediaBrowser.Providers
|
|||
var args = GetResolveArgsContainingImages(item);
|
||||
|
||||
// Make sure current image paths still exist
|
||||
ValidateImages(item);
|
||||
item.ValidateImages();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// Make sure current backdrop paths still exist
|
||||
ValidateBackdrops(item);
|
||||
ValidateScreenshots(item, args);
|
||||
item.ValidateBackdrops();
|
||||
item.ValidateScreenshots();
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
|
@ -128,74 +128,6 @@ namespace MediaBrowser.Providers
|
|||
return item.ResolveArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that images within the item are still on the file system
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
internal static void ValidateImages(BaseItem item)
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedKeys = item.Images
|
||||
.ToList()
|
||||
.Where(image => !File.Exists(image.Value))
|
||||
.Select(i => i.Key)
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var key in deletedKeys)
|
||||
{
|
||||
item.Images.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that backdrops within the item are still on the file system
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
internal static void ValidateBackdrops(BaseItem item)
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedImages = item.BackdropImagePaths
|
||||
.Where(path => !File.Exists(path))
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var path in deletedImages)
|
||||
{
|
||||
item.BackdropImagePaths.Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the screenshots.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="args">The args.</param>
|
||||
private void ValidateScreenshots(BaseItem item, ItemResolveArgs args)
|
||||
{
|
||||
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
|
||||
var deletedImages = item.ScreenshotImagePaths
|
||||
.Where(path => !File.Exists(path))
|
||||
.ToList();
|
||||
|
||||
// Now remove them from the dictionary
|
||||
foreach (var path in deletedImages)
|
||||
{
|
||||
item.ScreenshotImagePaths.Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is in same directory] [the specified item].
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is in same directory] [the specified item]; otherwise, <c>false</c>.</returns>
|
||||
private bool IsInMetaLocation(BaseItem item, string path)
|
||||
{
|
||||
return string.Equals(Path.GetDirectoryName(path), item.MetaLocation, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image.
|
||||
/// </summary>
|
||||
|
|
|
@ -70,7 +70,6 @@
|
|||
<Compile Include="Music\AlbumInfoFromSongProvider.cs" />
|
||||
<Compile Include="Music\ArtistInfoFromSongProvider.cs" />
|
||||
<Compile Include="Music\ArtistProviderFromXml.cs" />
|
||||
<Compile Include="Music\ArtistsPostScanTask.cs" />
|
||||
<Compile Include="Music\FanArtAlbumProvider.cs" />
|
||||
<Compile Include="Music\FanArtArtistByNameProvider.cs" />
|
||||
<Compile Include="Music\FanArtArtistProvider.cs" />
|
||||
|
@ -81,6 +80,7 @@
|
|||
<Compile Include="Music\LastfmArtistProvider.cs" />
|
||||
<Compile Include="Music\LastfmBaseProvider.cs" />
|
||||
<Compile Include="Music\LastfmHelper.cs" />
|
||||
<Compile Include="Music\MusicAlbumDynamicInfoProvider.cs" />
|
||||
<Compile Include="Music\MusicVideoXmlParser.cs" />
|
||||
<Compile Include="Music\SoundtrackPostScanTask.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -106,9 +106,9 @@
|
|||
<Compile Include="TV\RemoteSeasonProvider.cs" />
|
||||
<Compile Include="TV\RemoteSeriesProvider.cs" />
|
||||
<Compile Include="TV\SeasonProviderFromXml.cs" />
|
||||
<Compile Include="TV\SeriesPostScanTask.cs" />
|
||||
<Compile Include="TV\SeriesProviderFromXml.cs" />
|
||||
<Compile Include="TV\SeriesXmlParser.cs" />
|
||||
<Compile Include="TV\SeriesPostScanTask.cs" />
|
||||
<Compile Include="TV\TvdbPersonImageProvider.cs" />
|
||||
<Compile Include="TV\TvdbPrescanTask.cs" />
|
||||
<Compile Include="TV\TvdbSeriesImageProvider.cs" />
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
/// <summary>
|
||||
/// Class ArtistsPostScanTask
|
||||
/// </summary>
|
||||
public class ArtistsPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The _library manager
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArtistsPostScanTask"/> class.
|
||||
/// </summary>
|
||||
/// <param name="libraryManager">The library manager.</param>
|
||||
public ArtistsPostScanTask(ILibraryManager libraryManager)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the specified progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
|
||||
|
||||
var allArtists = await GetAllArtists(allItems).ConfigureAwait(false);
|
||||
|
||||
progress.Report(10);
|
||||
|
||||
var allMusicArtists = allItems.OfType<MusicArtist>().ToList();
|
||||
var allSongs = allItems.OfType<Audio>().ToList();
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var artist in allArtists)
|
||||
{
|
||||
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();
|
||||
|
||||
ImageFromMediaLocationProvider.ValidateImages(artist);
|
||||
ImageFromMediaLocationProvider.ValidateBackdrops(artist);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= allArtists.Length;
|
||||
percent *= 5;
|
||||
|
||||
progress.Report(10 + percent);
|
||||
}
|
||||
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
|
||||
innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85));
|
||||
|
||||
await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
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="allItems">All items.</param>
|
||||
/// <returns>Task{Artist[]}.</returns>
|
||||
private Task<Artist[]> GetAllArtists(IEnumerable<BaseItem> allItems)
|
||||
{
|
||||
var itemsList = allItems.OfType<Audio>().ToList();
|
||||
|
||||
var tasks = itemsList
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(i.AlbumArtist))
|
||||
{
|
||||
list.Add(i.AlbumArtist);
|
||||
}
|
||||
list.AddRange(i.Artists);
|
||||
|
||||
return list;
|
||||
})
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(i => _libraryManager.GetArtist(i));
|
||||
|
||||
return Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the music artist.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <param name="allMusicArtists">All music artists.</param>
|
||||
/// <returns>MusicArtist.</returns>
|
||||
private static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists)
|
||||
{
|
||||
var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
|
||||
|
||||
return allMusicArtists.FirstOrDefault(i =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Providers.Music
|
||||
{
|
||||
/// <summary>
|
||||
/// Class MusicAlbumDynamicInfoProvider
|
||||
/// </summary>
|
||||
public class MusicAlbumDynamicInfoProvider : BaseMetadataProvider, IDynamicInfoProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logManager">The log manager.</param>
|
||||
/// <param name="configurationManager">The configuration manager.</param>
|
||||
public MusicAlbumDynamicInfoProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
|
||||
: base(logManager, configurationManager)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supportses the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
public override bool Supports(BaseItem item)
|
||||
{
|
||||
return item is MusicAlbum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Needses the refresh internal.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="providerInfo">The provider info.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="force">if set to <c>true</c> [force].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{System.Boolean}.</returns>
|
||||
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
|
||||
{
|
||||
var album = (MusicAlbum)item;
|
||||
|
||||
var songs = album.RecursiveChildren
|
||||
.OfType<Audio>()
|
||||
.ToList();
|
||||
|
||||
album.AlbumArtist = songs
|
||||
.Select(i => i.AlbumArtist)
|
||||
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
|
||||
|
||||
album.Artists = songs.SelectMany(i => i.Artists)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
// Don't save to the db
|
||||
return FalseTaskResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
public override MetadataProviderPriority Priority
|
||||
{
|
||||
get { return MetadataProviderPriority.Last; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -336,11 +336,6 @@
|
|||
<ItemGroup>
|
||||
<Resource Include="Resources\Images\audio.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Images\starEmpty.png" />
|
||||
<Resource Include="Resources\Images\starFull.png" />
|
||||
<Resource Include="Resources\Images\starHalf.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Images\artist.png" />
|
||||
</ItemGroup>
|
||||
|
@ -358,8 +353,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Images\folder.jpg" />
|
||||
<Resource Include="Resources\Images\mblogoblackfull.png" />
|
||||
<Resource Include="Resources\Images\mblogowhitefull.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
|
@ -3171,144 +3171,6 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Gets a variety of item counts that a person appears in
|
||||
*/
|
||||
self.getPersonItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("Persons/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Gets a variety of item counts that a genre appears in
|
||||
*/
|
||||
self.getGenreItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("Genres/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
self.getMusicGenreItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("MusicGenres/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
self.getGameGenreItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("GameGenres/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Gets a variety of item counts that an artist appears in
|
||||
*/
|
||||
self.getArtistItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("Artists/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
Gets a variety of item counts that a studio appears in
|
||||
*/
|
||||
self.getStudioItemCounts = function (userId, name) {
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("null userId");
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
throw new Error("null name");
|
||||
}
|
||||
|
||||
var url = self.getUrl("Studios/" + self.encodeName(name) + "/Counts", {
|
||||
userId: userId
|
||||
});
|
||||
|
||||
return self.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears a user's personal rating for an item
|
||||
* @param {String} userId
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.174" targetFramework="net45" />
|
||||
<package id="MediaBrowser.ApiClient.Javascript" version="3.0.175" targetFramework="net45" />
|
||||
<package id="ServiceStack.Common" version="3.9.58" targetFramework="net45" />
|
||||
<package id="ServiceStack.Text" version="3.9.58" targetFramework="net45" />
|
||||
</packages>
|
|
@ -237,4 +237,7 @@ Global
|
|||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Reference in New Issue
Block a user