diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 1f69183cc8..19cb14bbd5 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -48,6 +48,19 @@ namespace MediaBrowser.Api.Images
public string Name { get; set; }
}
+ [Route("/Artists/{Name}/Images/{Type}", "GET")]
+ [Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")]
+ [Api(Description = "Gets an artist image")]
+ public class GetArtistImage : ImageRequest
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [ApiMember(Name = "Name", Description = "Artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+ }
+
///
/// Class GetStudioImage
///
@@ -233,6 +246,18 @@ namespace MediaBrowser.Api.Images
return GetImage(request, item);
}
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetArtistImage request)
+ {
+ var item = _libraryManager.GetArtist(request.Name).Result;
+
+ return GetImage(request, item);
+ }
+
///
/// Gets the specified request.
///
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 5b34119dea..c7b4fae5f5 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -1,10 +1,6 @@
using MediaBrowser.Common;
-using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@@ -36,66 +32,6 @@ namespace MediaBrowser.Api.Library
public bool HasInternetProvider { get; set; }
}
- ///
- /// Class GetPerson
- ///
- [Route("/Persons/{Name}", "GET")]
- [Api(Description = "Gets a person, by name")]
- public class GetPerson : IReturn
- {
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- ///
- /// Class GetStudio
- ///
- [Route("/Studios/{Name}", "GET")]
- [Api(Description = "Gets a studio, by name")]
- public class GetStudio : IReturn
- {
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- ///
- /// Class GetGenre
- ///
- [Route("/Genres/{Name}", "GET")]
- [Api(Description = "Gets a genre, by name")]
- public class GetGenre : IReturn
- {
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- ///
- /// Class GetYear
- ///
- [Route("/Years/{Year}", "GET")]
- [Api(Description = "Gets a year")]
- public class GetYear : IReturn
- {
- ///
- /// Gets or sets the year.
- ///
- /// The year.
- [ApiMember(Name = "Year", Description = "The year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Year { get; set; }
- }
-
///
/// Class LibraryService
///
@@ -106,16 +42,14 @@ namespace MediaBrowser.Api.Library
///
private readonly IApplicationHost _appHost;
private readonly ILibraryManager _libraryManager;
- private readonly IUserDataRepository _userDataRepository;
///
/// Initializes a new instance of the class.
///
/// The app host.
/// The library manager.
- /// The user data repository.
/// appHost
- public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
+ public LibraryService(IApplicationHost appHost, ILibraryManager libraryManager)
{
if (appHost == null)
{
@@ -124,75 +58,6 @@ namespace MediaBrowser.Api.Library
_appHost = appHost;
_libraryManager = libraryManager;
- _userDataRepository = userDataRepository;
- }
-
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetPerson request)
- {
- var item = _libraryManager.GetPerson(request.Name).Result;
-
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
- var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result;
-
- return ToOptimizedResult(result);
- }
-
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetGenre request)
- {
- var item = _libraryManager.GetGenre(request.Name).Result;
-
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
- var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result;
-
- return ToOptimizedResult(result);
- }
-
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetStudio request)
- {
- var item = _libraryManager.GetStudio(request.Name).Result;
-
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
- var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result;
-
- return ToOptimizedResult(result);
- }
-
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetYear request)
- {
- var item = _libraryManager.GetYear(request.Year).Result;
-
- // Get everything
- var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
- var result = new DtoBuilder(Logger, _libraryManager, _userDataRepository).GetBaseItemDto(item, fields.ToList()).Result;
-
- return ToOptimizedResult(result);
}
///
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 710c159e7f..32c1bfaf5c 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -87,6 +87,7 @@
+
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
new file mode 100644
index 0000000000..2622f0bd15
--- /dev/null
+++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
@@ -0,0 +1,187 @@
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
+using ServiceStack.ServiceHost;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.UserLibrary
+{
+ ///
+ /// Class GetArtists
+ ///
+ [Route("/Artists", "GET")]
+ [Api(Description = "Gets all artists from a given item, folder, or the entire library")]
+ public class GetArtists : GetItemsByName
+ {
+ }
+
+ ///
+ /// Class GetArtistsItemCounts
+ ///
+ [Route("/Artists/{Name}/Counts", "GET")]
+ [Api(Description = "Gets item counts of library items that an artist appears in")]
+ public class GetArtistsItemCounts : IReturn
+ {
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid UserId { get; set; }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [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
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
+
+ ///
+ /// Class ArtistsService
+ ///
+ public class ArtistsService : BaseItemsByNameService
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The user manager.
+ /// The library manager.
+ /// The user data repository.
+ public ArtistsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
+ : base(userManager, libraryManager, userDataRepository)
+ {
+ }
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetArtist request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ ///
+ /// Gets the item.
+ ///
+ /// The request.
+ /// Task{BaseItemDto}.
+ private async Task GetItem(GetArtist request)
+ {
+ var item = await LibraryManager.GetArtist(request.Name).ConfigureAwait(false);
+
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
+
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
+
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
+
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+ }
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetArtistsItemCounts request)
+ {
+ var items = GetItems(request.UserId).OfType
/// The request.
/// The items.
- /// The user.
/// IEnumerable{BaseItem}.
- private IEnumerable FilterItems(GetItemsByName request, IEnumerable items, User user)
+ private IEnumerable FilterItems(GetItemsByName request, IEnumerable items)
{
// Exclude item types
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
@@ -213,9 +228,8 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// The items.
- /// The user.
/// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
- protected abstract IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items, User user);
+ protected abstract IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items);
///
/// Gets the dto.
@@ -238,18 +252,36 @@ namespace MediaBrowser.Api.UserLibrary
return null;
}
- var dto = await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, user, fields).ConfigureAwait(false);
+ var dto = user == null ? await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, fields).ConfigureAwait(false) :
+ await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, user, fields).ConfigureAwait(false);
if (fields.Contains(ItemFields.ItemCounts))
{
var items = stub.Items;
dto.ChildCount = items.Count;
- dto.RecentlyAddedItemCount = items.Count(i => i.IsRecentlyAdded(user));
+ dto.RecentlyAddedItemCount = items.Count(i => i.IsRecentlyAdded());
}
return dto;
}
+
+ ///
+ /// Gets the items.
+ ///
+ /// The user id.
+ /// IEnumerable{BaseItem}.
+ protected IEnumerable GetItems(Guid? userId)
+ {
+ if (userId.HasValue)
+ {
+ var user = UserManager.GetUserById(userId.Value);
+
+ return UserManager.GetUserById(userId.Value).RootFolder.GetRecursiveChildren(user);
+ }
+
+ return LibraryManager.RootFolder.RecursiveChildren;
+ }
}
///
@@ -257,12 +289,24 @@ namespace MediaBrowser.Api.UserLibrary
///
public class GetItemsByName : BaseItemsRequest, IReturn
{
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+
///
/// What to sort the results by
///
/// The sort by.
[ApiMember(Name = "SortBy", Description = "Optional. Options: SortName", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string SortBy { get; set; }
+
+ public GetItemsByName()
+ {
+ Recursive = true;
+ }
}
public class IbnStub
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index afe93a0865..7dcce53b2c 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -9,13 +9,6 @@ namespace MediaBrowser.Api.UserLibrary
{
public abstract class BaseItemsRequest
{
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
///
/// Skips over a given number of items within the results. Use for paging.
///
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 4f87b154e5..30094d4f32 100644
--- a/MediaBrowser.Api/UserLibrary/GenresService.cs
+++ b/MediaBrowser.Api/UserLibrary/GenresService.cs
@@ -1,11 +1,12 @@
-using MediaBrowser.Controller.Entities;
+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;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@@ -17,17 +18,13 @@ namespace MediaBrowser.Api.UserLibrary
///
/// Class GetGenres
///
- [Route("/Users/{UserId}/Items/{ParentId}/Genres", "GET")]
- [Route("/Users/{UserId}/Items/Root/Genres", "GET")]
+ [Route("/Genres", "GET")]
[Api(Description = "Gets all genres from a given item, folder, or the entire library")]
public class GetGenres : GetItemsByName
{
}
- ///
- /// Class GetGenreItemCounts
- ///
- [Route("/Users/{UserId}/Genres/{Name}/Counts", "GET")]
+ [Route("/Genres/{Name}/Counts", "GET")]
[Api(Description = "Gets item counts of library items that a genre appears in")]
public class GetGenreItemCounts : IReturn
{
@@ -35,8 +32,8 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the user id.
///
/// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
///
/// Gets or sets the name.
@@ -45,6 +42,28 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Name { get; set; }
}
+
+ ///
+ /// Class GetGenre
+ ///
+ [Route("/Genres/{Name}", "GET")]
+ [Api(Description = "Gets a genre, by name")]
+ public class GetGenre : IReturn
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
///
/// Class GenresService
@@ -61,32 +80,37 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// System.Object.
- public object Get(GetGenreItemCounts request)
+ public object Get(GetGenre request)
{
- var user = UserManager.GetUserById(request.UserId);
-
- var items = user.RootFolder.GetRecursiveChildren(user).Where(i => i.Genres != null && i.Genres.Contains(request.Name, StringComparer.OrdinalIgnoreCase)).ToList();
+ var result = GetItem(request).Result;
- var counts = new ItemByNameCounts
- {
- TotalCount = items.Count,
-
- TrailerCount = items.OfType().Count(),
+ return ToOptimizedResult(result);
+ }
- MovieCount = items.OfType().Count(),
+ ///
+ /// Gets the item.
+ ///
+ /// The request.
+ /// Task{BaseItemDto}.
+ private async Task GetItem(GetGenre request)
+ {
+ var item = await LibraryManager.GetGenre(request.Name).ConfigureAwait(false);
- SeriesCount = items.OfType().Count(),
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
- GameCount = items.OfType().Count(),
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
- SongCount = items.OfType().Count(),
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
- AlbumCount = items.OfType().Count()
- };
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
- return ToOptimizedResult(counts);
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
}
-
+
///
/// Gets the specified request.
///
@@ -104,9 +128,8 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// The items.
- /// The user.
/// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
- protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items, User user)
+ protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items)
{
var itemsList = items.Where(i => i.Genres != null).ToList();
@@ -125,5 +148,34 @@ namespace MediaBrowser.Api.UserLibrary
{
return LibraryManager.GetGenre(name);
}
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetGenreItemCounts request)
+ {
+ var items = GetItems(request.UserId).Where(i => i.Genres != null && i.Genres.Contains(request.Name, StringComparer.OrdinalIgnoreCase)).ToList();
+
+ var counts = new ItemByNameCounts
+ {
+ TotalCount = items.Count,
+
+ TrailerCount = items.OfType().Count(),
+
+ MovieCount = items.OfType().Count(),
+
+ SeriesCount = items.OfType().Count(),
+
+ GameCount = items.OfType().Count(),
+
+ SongCount = items.OfType().Count(),
+
+ AlbumCount = items.OfType().Count()
+ };
+
+ return ToOptimizedResult(counts);
+ }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
index e068eb2163..a3f36afe9d 100644
--- a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
@@ -1,38 +1,21 @@
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using ServiceStack.ServiceHost;
+using ServiceStack.Text.Controller;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
- ///
- /// Class GetItemByNameUserData
- ///
- [Route("/Users/{UserId}/ItemsByName/{Name}/UserData", "GET")]
- [Api(Description = "Gets user data for an item")]
- public class GetItemByNameUserData : IReturnVoid
- {
- ///
- /// Gets or sets the user id.
- ///
- /// The user id.
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
///
/// Class MarkItemByNameFavorite
///
- [Route("/Users/{UserId}/ItemsByName/Favorites/{Name}", "POST")]
+ [Route("/Users/{UserId}/Favorites/Artists/{Name}", "POST")]
+ [Route("/Users/{UserId}/Favorites/Persons/{Name}", "POST")]
+ [Route("/Users/{UserId}/Favorites/Studios/{Name}", "POST")]
+ [Route("/Users/{UserId}/Favorites/Genres/{Name}", "POST")]
[Api(Description = "Marks something as a favorite")]
public class MarkItemByNameFavorite : IReturnVoid
{
@@ -47,14 +30,17 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the name.
///
/// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Name { get; set; }
}
///
/// Class UnmarkItemByNameFavorite
///
- [Route("/Users/{UserId}/ItemsByName/Favorites/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Favorites/Artists/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Favorites/Persons/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Favorites/Studios/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Favorites/Genres/{Name}", "DELETE")]
[Api(Description = "Unmarks something as a favorite")]
public class UnmarkItemByNameFavorite : IReturnVoid
{
@@ -69,11 +55,17 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the name.
///
/// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public string Name { get; set; }
}
- [Route("/Users/{UserId}/ItemsByName/{Name}/Rating", "POST")]
+ ///
+ /// Class UpdateItemByNameRating
+ ///
+ [Route("/Users/{UserId}/Ratings/Artists/{Name}", "POST")]
+ [Route("/Users/{UserId}/Ratings/Persons/{Name}", "POST")]
+ [Route("/Users/{UserId}/Ratings/Studios/{Name}", "POST")]
+ [Route("/Users/{UserId}/Ratings/Genres/{Name}", "POST")]
[Api(Description = "Updates a user's rating for an item")]
public class UpdateItemByNameRating : IReturnVoid
{
@@ -88,7 +80,7 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the name.
///
/// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+ [ApiMember(Name = "Name", Description = "The name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
public string Name { get; set; }
///
@@ -99,7 +91,13 @@ namespace MediaBrowser.Api.UserLibrary
public bool Likes { get; set; }
}
- [Route("/Users/{UserId}/ItemsByName/{Name}/Rating", "DELETE")]
+ ///
+ /// Class DeleteItemByNameRating
+ ///
+ [Route("/Users/{UserId}/Ratings/Artists/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Ratings/Persons/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Ratings/Studios/{Name}", "DELETE")]
+ [Route("/Users/{UserId}/Ratings/Genres/{Name}", "DELETE")]
[Api(Description = "Deletes a user's saved personal rating for an item")]
public class DeleteItemByNameRating : IReturnVoid
{
@@ -114,10 +112,10 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the name.
///
/// The name.
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+ [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
public string Name { get; set; }
}
-
+
///
/// Class ItemByNameUserDataService
///
@@ -128,35 +126,32 @@ namespace MediaBrowser.Api.UserLibrary
///
protected readonly IUserDataRepository UserDataRepository;
+ ///
+ /// The library manager
+ ///
+ protected readonly ILibraryManager LibraryManager;
+
///
/// Initializes a new instance of the class.
///
/// The user data repository.
- public ItemByNameUserDataService(IUserDataRepository userDataRepository)
+ /// The library manager.
+ public ItemByNameUserDataService(IUserDataRepository userDataRepository, ILibraryManager libraryManager)
{
UserDataRepository = userDataRepository;
+ LibraryManager = libraryManager;
}
- ///
- /// Gets the specified request.
- ///
- /// The request.
- /// System.Object.
- public object Get(GetItemByNameUserData request)
- {
- // Get the user data for this item
- var data = UserDataRepository.GetUserData(request.UserId, request.Name).Result;
-
- return ToOptimizedResult(DtoBuilder.GetUserItemDataDto(data));
- }
-
///
/// Posts the specified request.
///
/// The request.
public void Post(MarkItemByNameFavorite request)
{
- var task = MarkFavorite(request.UserId, request.Name, true);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue(3);
+
+ var task = MarkFavorite(request.UserId, type, request.Name, true);
Task.WaitAll(task);
}
@@ -167,18 +162,24 @@ namespace MediaBrowser.Api.UserLibrary
/// The request.
public void Post(UpdateItemByNameRating request)
{
- var task = MarkLike(request.UserId, request.Name, request.Likes);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue(3);
+
+ var task = MarkLike(request.UserId, type, request.Name, request.Likes);
Task.WaitAll(task);
}
-
+
///
/// Deletes the specified request.
///
/// The request.
public void Delete(UnmarkItemByNameFavorite request)
{
- var task = MarkFavorite(request.UserId, request.Name, false);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue(3);
+
+ var task = MarkFavorite(request.UserId, type, request.Name, false);
Task.WaitAll(task);
}
@@ -189,7 +190,10 @@ namespace MediaBrowser.Api.UserLibrary
/// The request.
public void Delete(DeleteItemByNameRating request)
{
- var task = MarkLike(request.UserId, request.Name, null);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue(3);
+
+ var task = MarkLike(request.UserId, type, request.Name, null);
Task.WaitAll(task);
}
@@ -198,11 +202,37 @@ namespace MediaBrowser.Api.UserLibrary
/// Marks the favorite.
///
/// The user id.
- /// The key.
+ /// The type.
+ /// The name.
/// if set to true [is favorite].
/// Task.
- protected async Task MarkFavorite(Guid userId, string key, bool isFavorite)
+ protected async Task MarkFavorite(Guid userId, string type, string name, bool isFavorite)
{
+ BaseItem item;
+
+ if (string.Equals(type, "Persons"))
+ {
+ item = await LibraryManager.GetPerson(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Artists"))
+ {
+ item = await LibraryManager.GetArtist(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Genres"))
+ {
+ item = await LibraryManager.GetGenre(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Studios"))
+ {
+ item = await LibraryManager.GetStudio(name).ConfigureAwait(false);
+ }
+ else
+ {
+ throw new ArgumentException();
+ }
+
+ var key = item.GetUserDataKey();
+
// Get the user data for this item
var data = await UserDataRepository.GetUserData(userId, key).ConfigureAwait(false);
@@ -216,11 +246,37 @@ namespace MediaBrowser.Api.UserLibrary
/// Marks the like.
///
/// The user id.
- /// The key.
+ /// The type.
+ /// The name.
/// if set to true [likes].
/// Task.
- protected async Task MarkLike(Guid userId, string key, bool? likes)
+ protected async Task MarkLike(Guid userId, string type, string name, bool? likes)
{
+ BaseItem item;
+
+ if (string.Equals(type, "Persons"))
+ {
+ item = await LibraryManager.GetPerson(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Artists"))
+ {
+ item = await LibraryManager.GetArtist(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Genres"))
+ {
+ item = await LibraryManager.GetGenre(name).ConfigureAwait(false);
+ }
+ else if (string.Equals(type, "Studios"))
+ {
+ item = await LibraryManager.GetStudio(name).ConfigureAwait(false);
+ }
+ else
+ {
+ throw new ArgumentException();
+ }
+
+ var key = item.GetUserDataKey();
+
// Get the user data for this item
var data = await UserDataRepository.GetUserData(userId, key).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 79e00998f5..7d3581846d 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -21,6 +21,13 @@ namespace MediaBrowser.Api.UserLibrary
[Api(Description = "Gets items based on a query.")]
public class GetItems : BaseItemsRequest, IReturn
{
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid UserId { get; set; }
+
///
/// Limit results to items containing a specific person
///
@@ -328,7 +335,7 @@ namespace MediaBrowser.Api.UserLibrary
});
case ItemFilter.IsRecentlyAdded:
- return items.Where(item => item.IsRecentlyAdded(currentUser));
+ return items.Where(item => item.IsRecentlyAdded());
case ItemFilter.IsResumable:
return items.Where(item =>
diff --git a/MediaBrowser.Api/UserLibrary/PersonsService.cs b/MediaBrowser.Api/UserLibrary/PersonsService.cs
index fb623e953e..ee16a986e2 100644
--- a/MediaBrowser.Api/UserLibrary/PersonsService.cs
+++ b/MediaBrowser.Api/UserLibrary/PersonsService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
@@ -6,6 +7,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@@ -17,8 +19,7 @@ namespace MediaBrowser.Api.UserLibrary
///
/// Class GetPersons
///
- [Route("/Users/{UserId}/Items/{ParentId}/Persons", "GET")]
- [Route("/Users/{UserId}/Items/Root/Persons", "GET")]
+ [Route("/Persons", "GET")]
[Api(Description = "Gets all persons from a given item, folder, or the entire library")]
public class GetPersons : GetItemsByName
{
@@ -32,7 +33,7 @@ namespace MediaBrowser.Api.UserLibrary
///
/// Class GetPersonItemCounts
///
- [Route("/Users/{UserId}/Persons/{Name}/Counts", "GET")]
+ [Route("/Persons/{Name}/Counts", "GET")]
[Api(Description = "Gets item counts of library items that a person appears in")]
public class GetPersonItemCounts : IReturn
{
@@ -51,6 +52,28 @@ namespace MediaBrowser.Api.UserLibrary
public string Name { get; set; }
}
+ ///
+ /// Class GetPerson
+ ///
+ [Route("/Persons/{Name}", "GET")]
+ [Api(Description = "Gets a person, by name")]
+ public class GetPerson : IReturn
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [ApiMember(Name = "Name", Description = "The person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
+
///
/// Class PersonsService
///
@@ -67,6 +90,42 @@ namespace MediaBrowser.Api.UserLibrary
{
}
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetPerson request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ ///
+ /// Gets the item.
+ ///
+ /// The request.
+ /// Task{BaseItemDto}.
+ private async Task GetItem(GetPerson request)
+ {
+ var item = await LibraryManager.GetPerson(request.Name).ConfigureAwait(false);
+
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
+
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
+
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
+
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+ }
+
///
/// Gets the specified request.
///
@@ -86,9 +145,7 @@ namespace MediaBrowser.Api.UserLibrary
/// System.Object.
public object Get(GetPersonItemCounts request)
{
- var user = UserManager.GetUserById(request.UserId);
-
- var items = user.RootFolder.GetRecursiveChildren(user).Where(i => i.People != null && i.People.Any(p => string.Equals(p.Name, request.Name, StringComparison.OrdinalIgnoreCase))).ToList();
+ var items = GetItems(request.UserId).Where(i => i.People != null && i.People.Any(p => string.Equals(p.Name, request.Name, StringComparison.OrdinalIgnoreCase))).ToList();
var counts = new ItemByNameCounts
{
@@ -117,9 +174,8 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// The items.
- /// The user.
/// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
- protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items, User user)
+ protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items)
{
var inputPersonTypes = ((GetPersons)request).PersonTypes;
var personTypes = string.IsNullOrEmpty(inputPersonTypes) ? new string[] { } : inputPersonTypes.Split(',');
diff --git a/MediaBrowser.Api/UserLibrary/StudiosService.cs b/MediaBrowser.Api/UserLibrary/StudiosService.cs
index 94c6046854..4e3a2d42aa 100644
--- a/MediaBrowser.Api/UserLibrary/StudiosService.cs
+++ b/MediaBrowser.Api/UserLibrary/StudiosService.cs
@@ -1,10 +1,12 @@
-using MediaBrowser.Controller.Entities;
+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;
+using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
@@ -16,14 +18,13 @@ namespace MediaBrowser.Api.UserLibrary
///
/// Class GetStudios
///
- [Route("/Users/{UserId}/Items/{ParentId}/Studios", "GET")]
- [Route("/Users/{UserId}/Items/Root/Studios", "GET")]
+ [Route("/Studios", "GET")]
[Api(Description = "Gets all studios from a given item, folder, or the entire library")]
public class GetStudios : GetItemsByName
{
}
- [Route("/Users/{UserId}/Studios/{Name}/Counts", "GET")]
+ [Route("/Studios/{Name}/Counts", "GET")]
[Api(Description = "Gets item counts of library items that a studio appears in")]
public class GetStudioItemCounts : IReturn
{
@@ -42,6 +43,28 @@ namespace MediaBrowser.Api.UserLibrary
public string Name { get; set; }
}
+ ///
+ /// Class GetStudio
+ ///
+ [Route("/Studios/{Name}", "GET")]
+ [Api(Description = "Gets a studio, by name")]
+ public class GetStudio : IReturn
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ /// The name.
+ [ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
+
///
/// Class StudiosService
///
@@ -57,11 +80,45 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// System.Object.
- public object Get(GetStudioItemCounts request)
+ public object Get(GetStudio request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ ///
+ /// Gets the item.
+ ///
+ /// The request.
+ /// Task{BaseItemDto}.
+ private async Task GetItem(GetStudio request)
{
- var user = UserManager.GetUserById(request.UserId);
+ var item = await LibraryManager.GetStudio(request.Name).ConfigureAwait(false);
+
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
+
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
+
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
- var items = user.RootFolder.GetRecursiveChildren(user).Where(i => i.Studios != null && i.Studios.Contains(request.Name, StringComparer.OrdinalIgnoreCase)).ToList();
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+ }
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetStudioItemCounts request)
+ {
+ var items = GetItems(request.UserId).Where(i => i.Studios != null && i.Studios.Contains(request.Name, StringComparer.OrdinalIgnoreCase)).ToList();
var counts = new ItemByNameCounts
{
@@ -94,15 +151,14 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(result);
}
-
+
///
/// Gets all items.
///
/// The request.
/// The items.
- /// The user.
/// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
- protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items, User user)
+ protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items)
{
var itemsList = items.Where(i => i.Studios != null).ToList();
diff --git a/MediaBrowser.Api/UserLibrary/YearsService.cs b/MediaBrowser.Api/UserLibrary/YearsService.cs
index b22a8dac35..79cb08ef92 100644
--- a/MediaBrowser.Api/UserLibrary/YearsService.cs
+++ b/MediaBrowser.Api/UserLibrary/YearsService.cs
@@ -1,7 +1,11 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -12,13 +16,34 @@ namespace MediaBrowser.Api.UserLibrary
///
/// Class GetYears
///
- [Route("/Users/{UserId}/Items/{ParentId}/Years", "GET")]
- [Route("/Users/{UserId}/Items/Root/Years", "GET")]
+ [Route("/Years", "GET")]
[Api(Description = "Gets all years from a given item, folder, or the entire library")]
public class GetYears : GetItemsByName
{
}
+ ///
+ /// Class GetYear
+ ///
+ [Route("/Years/{Year}", "GET")]
+ [Api(Description = "Gets a year")]
+ public class GetYear : IReturn
+ {
+ ///
+ /// Gets or sets the year.
+ ///
+ /// The year.
+ [ApiMember(Name = "Year", Description = "The year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
+ public int Year { get; set; }
+
+ ///
+ /// Gets or sets the user id.
+ ///
+ /// The user id.
+ [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
+ }
+
///
/// Class YearsService
///
@@ -34,6 +59,42 @@ namespace MediaBrowser.Api.UserLibrary
{
}
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetYear request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ ///
+ /// Gets the item.
+ ///
+ /// The request.
+ /// Task{BaseItemDto}.
+ private async Task GetItem(GetYear request)
+ {
+ var item = await LibraryManager.GetYear(request.Year).ConfigureAwait(false);
+
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
+
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
+
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
+
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
+
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+ }
+
///
/// Gets the specified request.
///
@@ -51,9 +112,8 @@ namespace MediaBrowser.Api.UserLibrary
///
/// The request.
/// The items.
- /// The user.
/// IEnumerable{Tuple{System.StringFunc{System.Int32}}}.
- protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items, User user)
+ protected override IEnumerable> GetAllItems(GetItemsByName request, IEnumerable items)
{
var itemsList = items.Where(i => i.ProductionYear != null).ToList();
diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs
index 2631488a58..371241d1ba 100644
--- a/MediaBrowser.Controller/Dto/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs
@@ -528,7 +528,7 @@ namespace MediaBrowser.Controller.Dto
recursiveItemCount++;
// Check is recently added
- if (child.IsRecentlyAdded(user))
+ if (child.IsRecentlyAdded())
{
rcentlyAddedItemCount++;
}
diff --git a/MediaBrowser.Controller/Entities/Audio/Artist.cs b/MediaBrowser.Controller/Entities/Audio/Artist.cs
index dcd6af92d3..567b678685 100644
--- a/MediaBrowser.Controller/Entities/Audio/Artist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Artist.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// System.String.
public override string GetUserDataKey()
{
- return Name;
+ return "Artist-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 9deb8241de..01bdd84aca 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -113,5 +113,15 @@ namespace MediaBrowser.Controller.Entities.Audio
return (ProductionYear != null ? ProductionYear.Value.ToString("000-") : "")
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
}
+
+ ///
+ /// Determines whether the specified name has artist.
+ ///
+ /// The name.
+ /// true if the specified name has artist; otherwise, false.
+ public bool HasArtist(string name)
+ {
+ return Artists.Contains(name, StringComparer.OrdinalIgnoreCase) || string.Equals(AlbumArtist, name, StringComparison.OrdinalIgnoreCase);
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 7b64c0e854..7d6577b4ec 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Entities.Audio
///
/// The unknwon artist
///
- private static readonly MusicArtist UnknwonArtist = new MusicArtist {Name = ""};
+ private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "" };
///
/// Override this to return the folder that should be used to construct a container
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index b5627e061f..1f1d5e0837 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-
namespace MediaBrowser.Controller.Entities.Audio
{
///
@@ -8,12 +6,6 @@ namespace MediaBrowser.Controller.Entities.Audio
///
public class MusicArtist : Folder
{
- public Dictionary AlbumCovers { get; set; }
- public override void ClearMetaValues()
- {
- AlbumCovers = null;
- base.ClearMetaValues();
- }
}
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index f7963c6e69..1d803ea455 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -23,6 +23,14 @@ namespace MediaBrowser.Controller.Entities
///
public abstract class BaseItem : IHasProviderIds
{
+ protected BaseItem()
+ {
+ Genres = new List();
+ TrailerUrls = new List();
+ Studios = new List();
+ People = new List();
+ }
+
///
/// The trailer folder name
///
@@ -925,16 +933,10 @@ namespace MediaBrowser.Controller.Entities
///
/// Determines if the item is considered new based on user settings
///
- /// The user.
/// true if [is recently added] [the specified user]; otherwise, false.
///
- public bool IsRecentlyAdded(User user)
+ public bool IsRecentlyAdded()
{
- if (user == null)
- {
- throw new ArgumentNullException();
- }
-
return (DateTime.UtcNow - DateCreated).TotalDays < ConfigurationManager.Configuration.RecentItemDays;
}
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index 619c7a12b6..b2b4653532 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// System.String.
public override string GetUserDataKey()
{
- return Name;
+ return "Genre-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index f5570448da..0f2803744e 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// System.String.
public override string GetUserDataKey()
{
- return Name;
+ return "Person-" + Name;
}
}
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 06511d959e..0dec024f86 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// System.String.
public override string GetUserDataKey()
{
- return Name;
+ return "Studio-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 1e4e6cb06b..307ce306bf 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// System.String.
public override string GetUserDataKey()
{
- return Name;
+ return "Year-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 86fd25e661..060f52e37e 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -213,5 +213,13 @@ namespace MediaBrowser.Controller.Library
/// The parent.
/// IEnumerable{BaseItem}.
IEnumerable RetrieveChildren(Folder parent);
+
+ ///
+ /// Validates the artists.
+ ///
+ /// The cancellation token.
+ /// The progress.
+ /// Task.
+ Task ValidateArtists(CancellationToken cancellationToken, IProgress progress);
}
}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 926639d0c7..09a59286ee 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -53,8 +53,12 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\morelinq.1.0.15631-beta\lib\net35\MoreLinq.dll
+
+
@@ -111,9 +115,11 @@
+
+
@@ -197,6 +203,9 @@
MediaBrowser.Model
+
+
+
if $(ConfigurationName) == Release (
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index cb7237a9df..fa10c85855 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -14,11 +14,12 @@ namespace MediaBrowser.Controller.Providers
/// The item.
/// The source.
/// Name of the target.
+ /// if set to true [save locally].
/// The resource pool.
/// The cancellation token.
/// Task{System.String}.
/// item
- Task DownloadAndSaveImage(BaseItem item, string source, string targetName, SemaphoreSlim resourcePool, CancellationToken cancellationToken);
+ Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken);
///
/// Saves to library filesystem.
diff --git a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
index 94fe386806..b6155f6129 100644
--- a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
+++ b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
@@ -150,7 +150,7 @@ namespace MediaBrowser.Controller.Providers.Movies
Logger.Debug("FanArtProvider getting ClearLogo for " + movie.Name);
try
{
- movie.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(movie, path, LOGO_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ movie.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(movie, path, LOGO_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -176,7 +176,7 @@ namespace MediaBrowser.Controller.Providers.Movies
Logger.Debug("FanArtProvider getting ClearArt for " + movie.Name);
try
{
- movie.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(movie, path, ART_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ movie.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(movie, path, ART_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -199,7 +199,7 @@ namespace MediaBrowser.Controller.Providers.Movies
Logger.Debug("FanArtProvider getting DiscArt for " + movie.Name);
try
{
- movie.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(movie, path, DISC_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ movie.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(movie, path, DISC_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -223,7 +223,7 @@ namespace MediaBrowser.Controller.Providers.Movies
Logger.Debug("FanArtProvider getting Banner for " + movie.Name);
try
{
- movie.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(movie, path, BANNER_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ movie.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(movie, path, BANNER_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -247,7 +247,7 @@ namespace MediaBrowser.Controller.Providers.Movies
Logger.Debug("FanArtProvider getting Banner for " + movie.Name);
try
{
- movie.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(movie, path, THUMB_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ movie.SetImage(ImageType.Thumb, await _providerManager.DownloadAndSaveImage(movie, path, THUMB_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
diff --git a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
index c086aab779..69023c339c 100644
--- a/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs
@@ -253,7 +253,7 @@ namespace MediaBrowser.Controller.Providers.Movies
new Regex(@"(?.*)") // last resort matches the whole string as the name
};
- public const string LOCAL_META_FILE_NAME = "MBMovie.json";
+ public const string LOCAL_META_FILE_NAME = "mbmovie.js";
public const string ALT_META_FILE_NAME = "movie.xml";
protected string ItemType = "movie";
@@ -270,7 +270,7 @@ namespace MediaBrowser.Controller.Providers.Movies
}
- if (providerInfo.LastRefreshStatus == ProviderRefreshStatus.CompletedWithErrors)
+ if (providerInfo.LastRefreshStatus != ProviderRefreshStatus.Success)
{
Logger.Debug("MovieProvider for {0} - last attempt had errors. Will try again.", item.Path);
return true;
@@ -283,9 +283,6 @@ namespace MediaBrowser.Controller.Providers.Movies
return false;
}
- if (DateTime.Today.Subtract(item.DateCreated).TotalDays > 180 && downloadDate != DateTime.MinValue)
- return false; // don't trigger a refresh data for item that are more than 6 months old and have been refreshed before
-
if (DateTime.Today.Subtract(downloadDate).TotalDays < ConfigurationManager.Configuration.MetadataRefreshDays) // only refresh every n days
return false;
@@ -1028,7 +1025,7 @@ namespace MediaBrowser.Controller.Providers.Movies
{
try
{
- item.PrimaryImagePath = await ProviderManager.DownloadAndSaveImage(item, tmdbImageUrl + poster.file_path, "folder" + Path.GetExtension(poster.file_path), MovieDbResourcePool, cancellationToken).ConfigureAwait(false);
+ item.PrimaryImagePath = await ProviderManager.DownloadAndSaveImage(item, tmdbImageUrl + poster.file_path, "folder" + Path.GetExtension(poster.file_path), ConfigurationManager.Configuration.SaveLocalMeta, MovieDbResourcePool, cancellationToken).ConfigureAwait(false);
}
catch (HttpException)
{
@@ -1060,7 +1057,7 @@ namespace MediaBrowser.Controller.Providers.Movies
{
try
{
- item.BackdropImagePaths.Add(await ProviderManager.DownloadAndSaveImage(item, tmdbImageUrl + images.backdrops[i].file_path, bdName + Path.GetExtension(images.backdrops[i].file_path), MovieDbResourcePool, cancellationToken).ConfigureAwait(false));
+ item.BackdropImagePaths.Add(await ProviderManager.DownloadAndSaveImage(item, tmdbImageUrl + images.backdrops[i].file_path, bdName + Path.GetExtension(images.backdrops[i].file_path), ConfigurationManager.Configuration.SaveLocalMeta, MovieDbResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
diff --git a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
index 583e0bb97b..affd4757a3 100644
--- a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
+++ b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Providers.Movies
///
/// The meta file name
///
- protected const string MetaFileName = "MBPerson.json";
+ protected const string MetaFileName = "mbperson.js";
protected readonly IProviderManager ProviderManager;
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs
index f850722d1a..4d7f78413d 100644
--- a/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs
@@ -1,29 +1,34 @@
-using System.Collections.Generic;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
using System;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using System.Xml;
namespace MediaBrowser.Controller.Providers.Music
{
public class FanArtAlbumProvider : FanartBaseProvider
{
private readonly IProviderManager _providerManager;
-
- public FanArtAlbumProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+
+ protected IHttpClient HttpClient { get; private set; }
+
+ public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
: base(logManager, configurationManager)
{
_providerManager = providerManager;
+ HttpClient = httpClient;
}
public override bool Supports(BaseItem item)
{
- return item is MusicAlbum && item.Parent is MusicArtist;
+ return item is MusicAlbum;
}
///
@@ -35,7 +40,7 @@ namespace MediaBrowser.Controller.Providers.Music
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
{
//we fetch if image needed and haven't already tried recently
- return string.IsNullOrEmpty(item.PrimaryImagePath) &&
+ return (string.IsNullOrEmpty(item.PrimaryImagePath) || !item.HasImage(ImageType.Disc)) &&
DateTime.Today.Subtract(providerInfo.LastRefreshed).TotalDays > ConfigurationManager.Configuration.MetadataRefreshDays;
}
@@ -45,46 +50,81 @@ namespace MediaBrowser.Controller.Providers.Music
if (mbid == null)
{
Logger.Warn("No Musicbrainz id associated with album {0}", item.Name);
- SetLastRefreshed(item, DateTime.UtcNow, ProviderRefreshStatus.CompletedWithErrors);
- return false;
+ SetLastRefreshed(item, DateTime.UtcNow);
+ return true;
}
cancellationToken.ThrowIfCancellationRequested();
- //Look at our parent for our album cover
- var artist = (MusicArtist)item.Parent;
+ var url = string.Format("http://api.fanart.tv/webservice/album/{0}/{1}/xml/all/1/1", APIKey, item.GetProviderId(MetadataProviders.Musicbrainz));
- var cover = artist.AlbumCovers != null ? GetValueOrDefault(artist.AlbumCovers, mbid, null) : null;
+ var doc = new XmlDocument();
- if (cover == null)
+ try
+ {
+ using (var xml = await HttpClient.Get(url, FanArtResourcePool, cancellationToken).ConfigureAwait(false))
+ {
+ doc.Load(xml);
+ }
+ }
+ catch (HttpException)
{
- Logger.Warn("Unable to find cover art for {0}", item.Name);
- SetLastRefreshed(item, DateTime.UtcNow, ProviderRefreshStatus.CompletedWithErrors);
- return false;
}
- item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, cover, "folder.jpg", FanArtResourcePool, cancellationToken).ConfigureAwait(false));
- return true;
- }
+ cancellationToken.ThrowIfCancellationRequested();
- ///
- /// Helper method for Dictionaries since they throw on not-found keys
- ///
- ///
- ///
- /// The dictionary.
- /// The key.
- /// The default value.
- /// ``1.
- private static U GetValueOrDefault(Dictionary dictionary, T key, U defaultValue)
- {
- U val;
- if (!dictionary.TryGetValue(key, out val))
+ if (doc.HasChildNodes)
{
- val = defaultValue;
+ if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc && !item.ResolveArgs.ContainsMetaFileByName(DISC_FILE))
+ {
+ var node = doc.SelectSingleNode("//fanart/music/albums/album//cdart/@url");
+
+ var path = node != null ? node.Value : null;
+
+ if (!string.IsNullOrEmpty(path))
+ {
+ Logger.Debug("FanArtProvider getting Disc for " + item.Name);
+ try
+ {
+ item.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(item, path, DISC_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ }
+ catch (HttpException)
+ {
+ }
+ catch (IOException)
+ {
+
+ }
+ }
+ }
+
+ if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary && !item.ResolveArgs.ContainsMetaFileByName(PRIMARY_FILE))
+ {
+ var node = doc.SelectSingleNode("//fanart/music/albums/album//albumcover/@url");
+
+ var path = node != null ? node.Value : null;
+
+ if (!string.IsNullOrEmpty(path))
+ {
+ Logger.Debug("FanArtProvider getting albumcover for " + item.Name);
+ try
+ {
+ item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PRIMARY_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ }
+ catch (HttpException)
+ {
+ }
+ catch (IOException)
+ {
+
+ }
+ }
+ }
}
- return val;
+ SetLastRefreshed(item, DateTime.UtcNow);
+
+ return true;
}
}
}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs
new file mode 100644
index 0000000000..58200a458c
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs
@@ -0,0 +1,48 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.Controller.Providers.Music
+{
+ ///
+ /// Class FanArtArtistByNameProvider
+ ///
+ public class FanArtArtistByNameProvider : FanArtArtistProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The HTTP client.
+ /// The log manager.
+ /// The configuration manager.
+ /// The provider manager.
+ public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+ : base(httpClient, logManager, configurationManager, providerManager)
+ {
+ }
+
+ ///
+ /// Supportses the specified item.
+ ///
+ /// The item.
+ /// true if XXXX, false otherwise
+ public override bool Supports(BaseItem item)
+ {
+ return item is Artist;
+ }
+
+ ///
+ /// Gets a value indicating whether [save local meta].
+ ///
+ /// true if [save local meta]; otherwise, false.
+ protected override bool SaveLocalMeta
+ {
+ get
+ {
+ return true;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
index 1dd5c7cd25..ec99a78a7b 100644
--- a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Providers.Music
///
/// Class FanArtArtistProvider
///
- class FanArtArtistProvider : FanartBaseProvider
+ public class FanArtArtistProvider : FanartBaseProvider
{
///
/// Gets the HTTP client.
@@ -54,6 +54,11 @@ namespace MediaBrowser.Controller.Providers.Music
return item is MusicArtist;
}
+ protected virtual bool SaveLocalMeta
+ {
+ get { return ConfigurationManager.Configuration.SaveLocalMeta; }
+ }
+
///
/// Shoulds the fetch.
///
@@ -62,16 +67,11 @@ namespace MediaBrowser.Controller.Providers.Music
/// true if XXXX, false otherwise
protected override bool ShouldFetch(BaseItem item, BaseProviderInfo providerInfo)
{
- var artist = (MusicArtist)item;
- if (item.Path == null || item.DontFetchMeta || string.IsNullOrEmpty(artist.GetProviderId(MetadataProviders.Musicbrainz))) return false; //nothing to do
- var artExists = item.ResolveArgs.ContainsMetaFileByName(ART_FILE);
- var logoExists = item.ResolveArgs.ContainsMetaFileByName(LOGO_FILE);
- var discExists = item.ResolveArgs.ContainsMetaFileByName(DISC_FILE);
+ if (item.Path == null || item.DontFetchMeta || string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz))) return false; //nothing to do
- return (!artExists && ConfigurationManager.Configuration.DownloadMusicArtistImages.Art)
- || (!logoExists && ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo)
- || (!discExists && ConfigurationManager.Configuration.DownloadMusicArtistImages.Disc)
- || ((artist.AlbumCovers == null || artist.AlbumCovers.Count == 0) && ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary);
+ return (!item.ResolveArgs.ContainsMetaFileByName(ART_FILE) && ConfigurationManager.Configuration.DownloadMusicArtistImages.Art)
+ || (!item.ResolveArgs.ContainsMetaFileByName(LOGO_FILE) && ConfigurationManager.Configuration.DownloadMusicArtistImages.Logo)
+ || (!item.ResolveArgs.ContainsMetaFileByName(DISC_FILE) && ConfigurationManager.Configuration.DownloadMusicArtistImages.Disc);
}
///
@@ -85,7 +85,7 @@ namespace MediaBrowser.Controller.Providers.Music
{
cancellationToken.ThrowIfCancellationRequested();
- var artist = (MusicArtist)item;
+ //var artist = item;
BaseProviderInfo providerData;
@@ -94,9 +94,9 @@ namespace MediaBrowser.Controller.Providers.Music
providerData = new BaseProviderInfo();
}
- if (ShouldFetch(artist, providerData))
+ if (ShouldFetch(item, providerData))
{
- var url = string.Format(FanArtBaseUrl, APIKey, artist.GetProviderId(MetadataProviders.Musicbrainz));
+ var url = string.Format(FanArtBaseUrl, APIKey, item.GetProviderId(MetadataProviders.Musicbrainz));
var doc = new XmlDocument();
try
@@ -124,10 +124,10 @@ namespace MediaBrowser.Controller.Providers.Music
path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path))
{
- Logger.Debug("FanArtProvider getting ClearLogo for " + artist.Name);
+ Logger.Debug("FanArtProvider getting ClearLogo for " + item.Name);
try
{
- artist.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(artist, path, LOGO_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ item.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(item, path, LOGO_FILE, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -146,16 +146,16 @@ namespace MediaBrowser.Controller.Providers.Music
if (nodes != null)
{
var numBackdrops = 0;
- artist.BackdropImagePaths = new List();
+ item.BackdropImagePaths = new List();
foreach (XmlNode node in nodes)
{
path = node.Value;
if (!string.IsNullOrEmpty(path))
{
- Logger.Debug("FanArtProvider getting Backdrop for " + artist.Name);
+ Logger.Debug("FanArtProvider getting Backdrop for " + item.Name);
try
{
- artist.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(artist, path, ("Backdrop" + (numBackdrops > 0 ? numBackdrops.ToString() : "") + ".jpg"), FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ item.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(item, path, ("Backdrop" + (numBackdrops > 0 ? numBackdrops.ToString() : "") + ".jpg"), SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
numBackdrops++;
if (numBackdrops >= ConfigurationManager.Configuration.MaxBackdrops) break;
}
@@ -175,32 +175,6 @@ namespace MediaBrowser.Controller.Providers.Music
cancellationToken.ThrowIfCancellationRequested();
- if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary)
- {
- var nodes = doc.SelectNodes("//fanart/music/albums/*");
- if (nodes != null)
- {
- artist.AlbumCovers = new Dictionary();
- foreach (XmlNode node in nodes)
- {
-
- var key = node.Attributes["id"] != null ? node.Attributes["id"].Value : null;
- var cover = node.SelectSingleNode("albumcover/@url");
- path = cover != null ? cover.Value : null;
-
- if (!string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(key))
- {
- Logger.Debug("FanArtProvider getting Album Cover for " + artist.Name);
- artist.AlbumCovers[key] = path;
- }
- }
-
- }
-
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
if (ConfigurationManager.Configuration.DownloadMusicArtistImages.Art && !item.ResolveArgs.ContainsMetaFileByName(ART_FILE))
{
var node =
@@ -209,10 +183,10 @@ namespace MediaBrowser.Controller.Providers.Music
path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path))
{
- Logger.Debug("FanArtProvider getting ClearArt for " + artist.Name);
+ Logger.Debug("FanArtProvider getting ClearArt for " + item.Name);
try
{
- artist.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(artist, path, ART_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ item.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(item, path, ART_FILE, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -232,10 +206,10 @@ namespace MediaBrowser.Controller.Providers.Music
path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path))
{
- Logger.Debug("FanArtProvider getting Banner for " + artist.Name);
+ Logger.Debug("FanArtProvider getting Banner for " + item.Name);
try
{
- artist.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(artist, path, BANNER_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ item.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(item, path, BANNER_FILE, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -256,10 +230,10 @@ namespace MediaBrowser.Controller.Providers.Music
path = node != null ? node.Value : null;
if (!string.IsNullOrEmpty(path))
{
- Logger.Debug("FanArtProvider getting Primary image for " + artist.Name);
+ Logger.Debug("FanArtProvider getting Primary image for " + item.Name);
try
{
- artist.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(artist, path, PRIMARY_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ item.SetImage(ImageType.Primary, await _providerManager.DownloadAndSaveImage(item, path, PRIMARY_FILE, SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -272,7 +246,7 @@ namespace MediaBrowser.Controller.Providers.Music
}
}
}
- SetLastRefreshed(artist, DateTime.UtcNow);
+ SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs
index 697a6604cb..b489991762 100644
--- a/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs
@@ -1,14 +1,15 @@
-using System.IO;
-using System.Net;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
+using MoreLinq;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers.Music
{
@@ -33,26 +34,7 @@ namespace MediaBrowser.Controller.Providers.Music
protected override async Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken)
{
- // Get albu info using artist and album name
- var url = RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(item.Parent.Name), UrlEncode(item.Name), ApiKey);
-
- LastfmGetAlbumResult result;
-
- try
- {
- using (var json = await HttpClient.Get(url, LastfmResourcePool, cancellationToken).ConfigureAwait(false))
- {
- result = JsonSerializer.DeserializeFromStream(json);
- }
- }
- catch (HttpException e)
- {
- if (e.StatusCode == HttpStatusCode.NotFound)
- {
- throw new LastfmProviderException(string.Format("Unable to retrieve album info for {0} with artist {1}", item.Name, item.Parent.Name));
- }
- throw;
- }
+ var result = await GetAlbumResult(item, cancellationToken).ConfigureAwait(false);
if (result != null && result.album != null)
{
@@ -71,9 +53,60 @@ namespace MediaBrowser.Controller.Providers.Music
}
}
+ private async Task GetAlbumResult(BaseItem item, CancellationToken cancellationToken)
+ {
+ var result = await GetAlbumResult(item.Parent.Name, item.Name, cancellationToken);
+
+ if (result != null && result.album != null)
+ {
+ return result;
+ }
+
+ var folder = (Folder)item;
+
+ // Get each song, distinct by the combination of AlbumArtist and Album
+ var songs = folder.Children.OfType().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
+
+ foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
+ {
+ result = await GetAlbumResult(song.AlbumArtist, song.Album, cancellationToken).ConfigureAwait(false);
+
+ if (result != null && result.album != null)
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ private async Task GetAlbumResult(string artist, string album, CancellationToken cancellationToken)
+ {
+ // Get albu info using artist and album name
+ var url = RootUrl + string.Format("method=album.getInfo&artist={0}&album={1}&api_key={2}&format=json", UrlEncode(artist), UrlEncode(album), ApiKey);
+
+ using (var json = await HttpClient.Get(url, LastfmResourcePool, cancellationToken).ConfigureAwait(false))
+ {
+ return JsonSerializer.DeserializeFromStream(json);
+ }
+ }
+
+ protected override Task FetchData(BaseItem item, CancellationToken cancellationToken)
+ {
+ return FetchLastfmData(item, string.Empty, cancellationToken);
+ }
+
public override bool Supports(BaseItem item)
{
return item is MusicAlbum;
}
+
+ protected override bool RefreshOnFileSystemStampChange
+ {
+ get
+ {
+ return true;
+ }
+ }
}
}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs
new file mode 100644
index 0000000000..f9ec2cc748
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs
@@ -0,0 +1,50 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+
+namespace MediaBrowser.Controller.Providers.Music
+{
+ ///
+ /// Class LastfmArtistByNameProvider
+ ///
+ public class LastfmArtistByNameProvider : LastfmArtistProvider
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The json serializer.
+ /// The HTTP client.
+ /// The log manager.
+ /// The configuration manager.
+ /// The provider manager.
+ public LastfmArtistByNameProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+ : base(jsonSerializer, httpClient, logManager, configurationManager, providerManager)
+ {
+ }
+
+ ///
+ /// Gets a value indicating whether [save local meta].
+ ///
+ /// true if [save local meta]; otherwise, false.
+ protected override bool SaveLocalMeta
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ ///
+ /// Supportses the specified item.
+ ///
+ /// The item.
+ /// true if XXXX, false otherwise
+ public override bool Supports(BaseItem item)
+ {
+ return item is Artist;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
index 8a17bcbf6e..165b996f6b 100644
--- a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Providers.Music
//Execute the Artist search against our name and assume first one is the one we want
var url = RootUrl + string.Format("method=artist.search&artist={0}&api_key={1}&format=json", UrlEncode(item.Name), ApiKey);
- LastfmArtistSearchResults searchResult = null;
+ LastfmArtistSearchResults searchResult;
try
{
@@ -60,29 +60,18 @@ namespace MediaBrowser.Controller.Providers.Music
// Get artist info with provided id
var url = RootUrl + string.Format("method=artist.getInfo&mbid={0}&api_key={1}&format=json", UrlEncode(id), ApiKey);
- LastfmGetArtistResult result = null;
+ LastfmGetArtistResult result;
- try
+ using (var json = await HttpClient.Get(url, LastfmResourcePool, cancellationToken).ConfigureAwait(false))
{
- using (var json = await HttpClient.Get(url, LastfmResourcePool, cancellationToken).ConfigureAwait(false))
- {
- result = JsonSerializer.DeserializeFromStream(json);
- }
- }
- catch (HttpException e)
- {
- if (e.StatusCode == HttpStatusCode.NotFound)
- {
- throw new LastfmProviderException(string.Format("Unable to retrieve artist info for {0} with id {1}", item.Name, id));
- }
- throw;
+ result = JsonSerializer.DeserializeFromStream(json);
}
if (result != null && result.artist != null)
{
LastfmHelper.ProcessArtistData(item, result.artist);
//And save locally if indicated
- if (ConfigurationManager.Configuration.SaveLocalMeta)
+ if (SaveLocalMeta)
{
var ms = new MemoryStream();
JsonSerializer.SerializeToStream(result.artist, ms);
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs
index f7e0eef48d..dc586cb515 100644
--- a/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs
@@ -1,26 +1,17 @@
-using System.Collections.Generic;
-using System.Net;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
using System;
+using System.Collections.Generic;
+using System.Net;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Controller.Providers.Music
{
- class LastfmProviderException : ApplicationException
- {
- public LastfmProviderException(string msg)
- : base(msg)
- {
- }
-
- }
///
/// Class MovieDbProvider
///
@@ -84,6 +75,14 @@ namespace MediaBrowser.Controller.Providers.Music
///
protected string LocalMetaFileName { get; set; }
+ protected virtual bool SaveLocalMeta
+ {
+ get
+ {
+ return ConfigurationManager.Configuration.SaveLocalMeta;
+ }
+ }
+
///
/// If we save locally, refresh if they delete something
///
@@ -91,7 +90,7 @@ namespace MediaBrowser.Controller.Providers.Music
{
get
{
- return ConfigurationManager.Configuration.SaveLocalMeta;
+ return SaveLocalMeta;
}
}
@@ -173,16 +172,15 @@ namespace MediaBrowser.Controller.Providers.Music
{
if (item.DontFetchMeta) return false;
- if (ConfigurationManager.Configuration.SaveLocalMeta && HasFileSystemStampChanged(item, providerInfo))
+ if (RefreshOnFileSystemStampChange && HasFileSystemStampChanged(item, providerInfo))
{
//If they deleted something from file system, chances are, this item was mis-identified the first time
item.SetProviderId(MetadataProviders.Musicbrainz, null);
Logger.Debug("LastfmProvider reports file system stamp change...");
return true;
-
}
- if (providerInfo.LastRefreshStatus == ProviderRefreshStatus.CompletedWithErrors)
+ if (providerInfo.LastRefreshStatus != ProviderRefreshStatus.Success)
{
Logger.Debug("LastfmProvider for {0} - last attempt had errors. Will try again.", item.Path);
return true;
@@ -194,22 +192,10 @@ namespace MediaBrowser.Controller.Providers.Music
return true;
}
- var downloadDate = providerInfo.LastRefreshed;
-
- if (ConfigurationManager.Configuration.MetadataRefreshDays == -1 && downloadDate != DateTime.MinValue)
- {
- return false;
- }
-
- if (DateTime.Today.Subtract(item.DateCreated).TotalDays > 180 && downloadDate != DateTime.MinValue)
- return false; // don't trigger a refresh data for item that are more than 6 months old and have been refreshed before
-
- if (DateTime.Today.Subtract(downloadDate).TotalDays < ConfigurationManager.Configuration.MetadataRefreshDays) // only refresh every n days
- return false;
-
+ if (DateTime.UtcNow.Subtract(providerInfo.LastRefreshed).TotalDays > ConfigurationManager.Configuration.MetadataRefreshDays) // only refresh every n days
+ return true;
- Logger.Debug("LastfmProvider - " + item.Name + " needs refresh. Download date: " + downloadDate + " item created date: " + item.DateCreated + " Check for Update age: " + ConfigurationManager.Configuration.MetadataRefreshDays);
- return true;
+ return false;
}
///
@@ -221,36 +207,9 @@ namespace MediaBrowser.Controller.Providers.Music
/// Task{System.Boolean}.
public override async Task FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
- if (item.DontFetchMeta)
- {
- Logger.Info("LastfmProvider - Not fetching because requested to ignore " + item.Name);
- return false;
- }
-
cancellationToken.ThrowIfCancellationRequested();
- BaseProviderInfo providerData;
-
- if (!item.ProviderData.TryGetValue(Id, out providerData))
- {
- providerData = new BaseProviderInfo();
- }
-
- if (!ConfigurationManager.Configuration.SaveLocalMeta || !HasLocalMeta(item) || (force && !HasLocalMeta(item)) || (RefreshOnVersionChange && providerData.ProviderVersion != ProviderVersion))
- {
- try
- {
- await FetchData(item, cancellationToken).ConfigureAwait(false);
- SetLastRefreshed(item, DateTime.UtcNow);
- }
- catch (LastfmProviderException)
- {
- SetLastRefreshed(item, DateTime.UtcNow, ProviderRefreshStatus.CompletedWithErrors);
- }
-
- return true;
- }
- Logger.Debug("LastfmProvider not fetching because local meta exists for " + item.Name);
+ await FetchData(item, cancellationToken).ConfigureAwait(false);
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs b/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs
index 842d10e4d5..442dd4b694 100644
--- a/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs
+++ b/MediaBrowser.Controller/Providers/Music/LastfmHelper.cs
@@ -6,20 +6,23 @@ namespace MediaBrowser.Controller.Providers.Music
{
public static class LastfmHelper
{
- public static string LocalArtistMetaFileName = "MBArtist.json";
- public static string LocalAlbumMetaFileName = "MBAlbum.json";
+ public static string LocalArtistMetaFileName = "mbartist.js";
+ public static string LocalAlbumMetaFileName = "mbalbum.js";
public static void ProcessArtistData(BaseItem artist, LastfmArtist data)
{
- var overview = data.bio != null ? data.bio.content : null;
-
- artist.Overview = overview;
-
var yearFormed = 0;
if (data.bio != null)
{
Int32.TryParse(data.bio.yearformed, out yearFormed);
+
+ artist.Overview = data.bio.content;
+
+ if (!string.IsNullOrEmpty(data.bio.placeformed))
+ {
+ artist.AddProductionLocation(data.bio.placeformed);
+ }
}
artist.PremiereDate = yearFormed > 0 ? new DateTime(yearFormed, 1,1) : DateTime.MinValue;
@@ -52,7 +55,10 @@ namespace MediaBrowser.Controller.Providers.Music
{
foreach (var tag in tags.tag)
{
- item.AddGenre(tag.name);
+ if (!string.IsNullOrEmpty(tag.name))
+ {
+ item.AddGenre(tag.name);
+ }
}
}
}
diff --git a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs b/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs
index a7fc4586f1..cdbfb0883c 100644
--- a/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs
@@ -100,7 +100,7 @@ namespace MediaBrowser.Controller.Providers.TV
Logger.Debug("FanArtProvider getting ClearLogo for " + series.Name);
try
{
- series.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(series, path, LOGO_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ series.SetImage(ImageType.Logo, await _providerManager.DownloadAndSaveImage(series, path, LOGO_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -124,7 +124,7 @@ namespace MediaBrowser.Controller.Providers.TV
Logger.Debug("FanArtProvider getting ClearArt for " + series.Name);
try
{
- series.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(series, path, ART_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ series.SetImage(ImageType.Art, await _providerManager.DownloadAndSaveImage(series, path, ART_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -148,7 +148,7 @@ namespace MediaBrowser.Controller.Providers.TV
Logger.Debug("FanArtProvider getting ThumbArt for " + series.Name);
try
{
- series.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(series, path, THUMB_FILE, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
+ series.SetImage(ImageType.Disc, await _providerManager.DownloadAndSaveImage(series, path, THUMB_FILE, ConfigurationManager.Configuration.SaveLocalMeta, FanArtResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
index b5c6df7ecf..74cb1bfd4b 100644
--- a/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
@@ -233,7 +233,7 @@ namespace MediaBrowser.Controller.Providers.TV
try
{
- episode.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(episode, TVUtils.BannerUrl + p, Path.GetFileName(p), RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken);
+ episode.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(episode, TVUtils.BannerUrl + p, Path.GetFileName(p), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken);
}
catch (HttpException)
{
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
index f39e91834f..9d1a7c2566 100644
--- a/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
@@ -177,7 +177,7 @@ namespace MediaBrowser.Controller.Providers.TV
try
{
if (n != null)
- season.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false);
+ season.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false);
}
catch (HttpException)
{
@@ -204,7 +204,7 @@ namespace MediaBrowser.Controller.Providers.TV
TVUtils.BannerUrl + n.InnerText,
"banner" +
Path.GetExtension(n.InnerText),
- RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).
+ ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).
ConfigureAwait(false);
season.SetImage(ImageType.Banner, bannerImagePath);
@@ -231,7 +231,7 @@ namespace MediaBrowser.Controller.Providers.TV
try
{
if (season.BackdropImagePaths == null) season.BackdropImagePaths = new List();
- season.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "backdrop" + Path.GetExtension(n.InnerText), RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false));
+ season.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(season, TVUtils.BannerUrl + n.InnerText, "backdrop" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
@@ -265,7 +265,7 @@ namespace MediaBrowser.Controller.Providers.TV
"backdrop" +
Path.GetExtension(
n.InnerText),
- RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken)
+ ConfigurationManager.Configuration.SaveLocalMeta, RemoteSeriesProvider.Current.TvDbResourcePool, cancellationToken)
.ConfigureAwait(false));
}
catch (HttpException)
diff --git a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
index 89cb89289e..5a68981bf5 100644
--- a/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
+++ b/MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
@@ -228,7 +228,7 @@ namespace MediaBrowser.Controller.Providers.TV
string n = doc.SafeGetString("//banner");
if (!string.IsNullOrWhiteSpace(n))
{
- series.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n, "banner" + Path.GetExtension(n), TvDbResourcePool, cancellationToken).ConfigureAwait(false));
+ series.SetImage(ImageType.Banner, await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n, "banner" + Path.GetExtension(n), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false));
}
string s = doc.SafeGetString("//Network");
@@ -369,7 +369,7 @@ namespace MediaBrowser.Controller.Providers.TV
{
try
{
- series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), TvDbResourcePool, cancellationToken).ConfigureAwait(false);
+ series.PrimaryImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "folder" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false);
}
catch (HttpException)
{
@@ -392,7 +392,7 @@ namespace MediaBrowser.Controller.Providers.TV
{
try
{
- var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), TvDbResourcePool, cancellationToken);
+ var bannerImagePath = await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + n.InnerText, "banner" + Path.GetExtension(n.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken);
series.SetImage(ImageType.Banner, bannerImagePath);
}
@@ -421,7 +421,7 @@ namespace MediaBrowser.Controller.Providers.TV
{
try
{
- series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), TvDbResourcePool, cancellationToken).ConfigureAwait(false));
+ series.BackdropImagePaths.Add(await _providerManager.DownloadAndSaveImage(series, TVUtils.BannerUrl + p.InnerText, bdName + Path.GetExtension(p.InnerText), ConfigurationManager.Configuration.SaveLocalMeta, TvDbResourcePool, cancellationToken).ConfigureAwait(false));
}
catch (HttpException)
{
diff --git a/MediaBrowser.Controller/packages.config b/MediaBrowser.Controller/packages.config
new file mode 100644
index 0000000000..44996f0e82
--- /dev/null
+++ b/MediaBrowser.Controller/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 4d66d14227..692176efca 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -103,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
-
+
///
/// Gets or sets the configuration manager.
///
@@ -244,7 +245,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
// Any number of configuration settings could change the way the library is refreshed, so do that now
_taskManager.CancelIfRunningAndQueue();
-
+
if (refreshPeopleAfterUpdate)
{
_taskManager.CancelIfRunningAndQueue();
@@ -285,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.Library
items.AddRange(userFolders);
- return new ConcurrentDictionary(items.ToDictionary(i => i.Id));
+ return new ConcurrentDictionary(items.ToDictionary(i => i.Id));
}
///
@@ -505,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
return _userRootFolders.GetOrAdd(userRootPath, key => RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(userRootPath));
}
-
+
///
/// Gets a Person
///
@@ -560,7 +561,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// Task{Genre}.
public Task GetArtist(string name, bool allowSlowProviders = false)
{
- return GetImagesByNameItem(ConfigurationManager.ApplicationPaths.ArtistsPath, name, CancellationToken.None, allowSlowProviders);
+ return GetArtist(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ ///
+ /// Gets the artist.
+ ///
+ /// The name.
+ /// The cancellation token.
+ /// if set to true [allow slow providers].
+ /// if set to true [force creation].
+ /// Task{Artist}.
+ private Task GetArtist(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool forceCreation = false)
+ {
+ return GetImagesByNameItem(ConfigurationManager.ApplicationPaths.ArtistsPath, name, cancellationToken, allowSlowProviders, forceCreation);
}
///
@@ -764,6 +778,76 @@ namespace MediaBrowser.Server.Implementations.Library
_logger.Info("People validation complete");
}
+ public async Task ValidateArtists(CancellationToken cancellationToken, IProgress progress)
+ {
+ const int maxTasks = 25;
+
+ var tasks = new List();
+
+ var artists = RootFolder.RecursiveChildren
+ .OfType()
+ .SelectMany(c =>
+ {
+ var list = c.Artists.ToList();
+
+ if (!string.IsNullOrEmpty(c.AlbumArtist))
+ {
+ list.Add(c.AlbumArtist);
+ }
+
+ return list;
+ })
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ var numComplete = 0;
+
+ foreach (var artist in artists)
+ {
+ if (tasks.Count > maxTasks)
+ {
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+ tasks.Clear();
+
+ // Safe cancellation point, when there are no pending tasks
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+
+ // Avoid accessing the foreach variable within the closure
+ var currentArtist = artist;
+
+ tasks.Add(Task.Run(async () =>
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ await GetArtist(currentArtist, cancellationToken, true, true).ConfigureAwait(false);
+ }
+ catch (IOException ex)
+ {
+ _logger.ErrorException("Error validating Artist {0}", ex, currentArtist);
+ }
+
+ // Update progress
+ lock (progress)
+ {
+ numComplete++;
+ double percent = numComplete;
+ percent /= artists.Count;
+
+ progress.Report(100 * percent);
+ }
+ }));
+ }
+
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+
+ progress.Report(100);
+
+ _logger.Info("Artist validation complete");
+ }
+
///
/// Reloads the root media folder
///
@@ -796,8 +880,20 @@ namespace MediaBrowser.Server.Implementations.Library
await ValidateCollectionFolders(folder, cancellationToken).ConfigureAwait(false);
}
+ var innerProgress = new ActionableProgress();
+
+ innerProgress.RegisterAction(pct => progress.Report(pct * .8));
+
// Now validate the entire media library
- await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false);
+ await RootFolder.ValidateChildren(innerProgress, cancellationToken, recursive: true).ConfigureAwait(false);
+
+ innerProgress = new ActionableProgress();
+
+ innerProgress.RegisterAction(pct => progress.Report(80 + pct * .2));
+
+ await ValidateArtists(cancellationToken, innerProgress);
+
+ progress.Report(100);
}
///
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 79aee7ad25..6d278bb18b 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -145,6 +145,7 @@
+
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
index 8c74b8aeda..8bdf597a14 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
@@ -757,8 +757,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
throw new ArgumentNullException("outputPath");
}
- var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath) :
- string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath);
+ var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath) :
+ string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath);
var probeSize = GetProbeSizeArgument(type);
diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
index e4f57e8d94..4d5123cc50 100644
--- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
@@ -330,11 +330,12 @@ namespace MediaBrowser.Server.Implementations.Providers
/// The item.
/// The source.
/// Name of the target.
+ /// if set to true [save locally].
/// The resource pool.
/// The cancellation token.
/// Task{System.String}.
/// item
- public async Task DownloadAndSaveImage(BaseItem item, string source, string targetName, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
+ public async Task DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
if (item == null)
{
@@ -354,13 +355,13 @@ namespace MediaBrowser.Server.Implementations.Providers
}
//download and save locally
- var localPath = (ConfigurationManager.Configuration.SaveLocalMeta && item.MetaLocation != null) ?
+ var localPath = (saveLocally && item.MetaLocation != null) ?
Path.Combine(item.MetaLocation, targetName) :
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetName);
var img = await _httpClient.Get(source, resourcePool, cancellationToken).ConfigureAwait(false);
- if (ConfigurationManager.Configuration.SaveLocalMeta) // queue to media directories
+ if (saveLocally) // queue to media directories
{
await SaveToLibraryFilesystem(item, localPath, img, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs
new file mode 100644
index 0000000000..a67db1b2d7
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs
@@ -0,0 +1,81 @@
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Library;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.ScheduledTasks
+{
+ public class ArtistValidationTask
+ {
+ ///
+ /// The _library manager
+ ///
+ private readonly ILibraryManager _libraryManager;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The library manager.
+ public ArtistValidationTask(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ ///
+ /// Creates the triggers that define when the task will run
+ ///
+ /// IEnumerable{BaseTaskTrigger}.
+ public IEnumerable GetDefaultTriggers()
+ {
+ return new ITaskTrigger[]
+ {
+ new DailyTrigger { TimeOfDay = TimeSpan.FromHours(5) },
+
+ new IntervalTrigger{ Interval = TimeSpan.FromHours(12)}
+ };
+ }
+
+ ///
+ /// Returns the task to be executed
+ ///
+ /// The cancellation token.
+ /// The progress.
+ /// Task.
+ public Task Execute(CancellationToken cancellationToken, IProgress progress)
+ {
+ return _libraryManager.ValidateArtists(cancellationToken, progress);
+ }
+
+ ///
+ /// Gets the name of the task
+ ///
+ /// The name.
+ public string Name
+ {
+ get { return "Refresh music artists"; }
+ }
+
+ ///
+ /// Gets the description.
+ ///
+ /// The description.
+ public string Description
+ {
+ get { return "Updates metadata for music artists in your media library."; }
+ }
+
+ ///
+ /// Gets the category.
+ ///
+ /// The category.
+ public string Category
+ {
+ get
+ {
+ return "Library";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
index 6b81134806..ce15f56069 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
@@ -66,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// The description.
public string Description
{
- get { return "Updates metadata for actors, artists and directors in your media library."; }
+ get { return "Updates metadata for actors and directors in your media library."; }
}
///
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
index 575cd81ba1..897ece764b 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
@@ -150,6 +150,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite
GC.SuppressFinalize(this);
}
+ private readonly object _disposeLock = new object();
+
///
/// Releases unmanaged and - optionally - managed resources.
///
@@ -160,7 +162,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
{
try
{
- lock (this)
+ lock (_disposeLock)
{
if (connection != null)
{
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 1b22557c89..9f49c83a8c 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -449,7 +449,6 @@ namespace MediaBrowser.WebDashboard.Api
"addpluginpage.js",
"advancedconfigurationpage.js",
"advancedmetadataconfigurationpage.js",
- "boxset.js",
"boxsets.js",
"clientsettings.js",
"dashboardpage.js",
@@ -477,6 +476,8 @@ namespace MediaBrowser.WebDashboard.Api
"moviesrecommended.js",
"moviestudios.js",
"movietrailers.js",
+ "musicalbums.js",
+ "musicartists.js",
"musicgenres.js",
"playlist.js",
"plugincatalogpage.js",
@@ -488,8 +489,6 @@ namespace MediaBrowser.WebDashboard.Api
"supporterpage.js",
"tvgenres.js",
"tvpeople.js",
- "tvseason.js",
- "tvseries.js",
"tvrecommended.js",
"tvshows.js",
"tvstudios.js",
diff --git a/MediaBrowser.WebDashboard/ApiClient.js b/MediaBrowser.WebDashboard/ApiClient.js
index fe676abaf5..759fb0dc47 100644
--- a/MediaBrowser.WebDashboard/ApiClient.js
+++ b/MediaBrowser.WebDashboard/ApiClient.js
@@ -862,13 +862,19 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
/**
* Gets a studio
*/
- self.getStudio = function (name) {
+ self.getStudio = function (name, userId) {
if (!name) {
throw new Error("null name");
}
- var url = self.getUrl("Studios/" + encodeName(name));
+ var options = {};
+
+ if (userId) {
+ options.userId = userId;
+ }
+
+ var url = self.getUrl("Studios/" + encodeName(name), options);
return self.ajax({
type: "GET",
@@ -880,13 +886,43 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
/**
* Gets a genre
*/
- self.getGenre = function (name) {
+ self.getGenre = function (name, userId) {
if (!name) {
throw new Error("null name");
}
- var url = self.getUrl("Genres/" + encodeName(name));
+ var options = {};
+
+ if (userId) {
+ options.userId = userId;
+ }
+
+ var url = self.getUrl("Genres/" + encodeName(name), options);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
+ /**
+ * Gets an artist
+ */
+ self.getArtist = function (name, userId) {
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var options = {};
+
+ if (userId) {
+ options.userId = userId;
+ }
+
+ var url = self.getUrl("Artists/" + encodeName(name), options);
return self.ajax({
type: "GET",
@@ -898,13 +934,19 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
/**
* Gets a year
*/
- self.getYear = function (year) {
+ self.getYear = function (yea, userId) {
- if (!year) {
- throw new Error("null year");
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var options = {};
+
+ if (userId) {
+ options.userId = userId;
}
- var url = self.getUrl("Years/" + year);
+ var url = self.getUrl("Years/" + encodeName(name), options);
return self.ajax({
type: "GET",
@@ -916,13 +958,19 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
/**
* Gets a Person
*/
- self.getPerson = function (name) {
+ self.getPerson = function (name, userId) {
if (!name) {
throw new Error("null name");
}
- var url = self.getUrl("Persons/" + encodeName(name));
+ var options = {};
+
+ if (userId) {
+ options.userId = userId;
+ }
+
+ var url = self.getUrl("Persons/" + encodeName(name), options);
return self.ajax({
type: "GET",
@@ -1131,6 +1179,41 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
return self.getUrl(url, options);
};
+ /**
+ * Constructs a url for a artist image
+ * @param {String} name
+ * @param {Object} options
+ * Options supports the following properties:
+ * width - download the image at a fixed width
+ * height - download the image at a fixed height
+ * maxWidth - download the image at a maxWidth
+ * maxHeight - download the image at a maxHeight
+ * quality - A scale of 0-100. This should almost always be omitted as the default will suffice.
+ * For best results do not specify both width and height together, as aspect ratio might be altered.
+ */
+ self.getArtistImageUrl = function (name, options) {
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ options = options || {
+
+ };
+
+ var url = "Artists/" + encodeName(name) + "/Images/" + options.type;
+
+ if (options.index != null) {
+ url += "/" + options.index;
+ }
+
+ // Don't put these on the query string
+ delete options.type;
+ delete options.index;
+
+ return self.getUrl(url, options);
+ };
+
/**
* Constructs a url for a studio image
* @param {String} name
@@ -1524,6 +1607,27 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
});
};
+ /**
+ Gets artists from an item
+ */
+ self.getArtists = function (userId, options) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ options = options || {};
+ options.userId = userId;
+
+ var url = self.getUrl("Artists", options);
+
+ return self.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json"
+ });
+ };
+
/**
Gets genres from an item
*/
@@ -1533,12 +1637,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null userId");
}
- var parentId = options.parentId || "root";
-
- // Don't put these on the query string
- delete options.parentId;
+ options = options || {};
+ options.userId = userId;
- var url = self.getUrl("Users/" + userId + "/Items/" + parentId + "/Genres", options);
+ var url = self.getUrl("Genres", options);
return self.ajax({
type: "GET",
@@ -1556,12 +1658,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null userId");
}
- var parentId = options.parentId || "root";
-
- // Don't put these on the query string
- delete options.parentId;
+ options = options || {};
+ options.userId = userId;
- var url = self.getUrl("Users/" + userId + "/Items/" + parentId + "/Persons", options);
+ var url = self.getUrl("Persons", options);
return self.ajax({
type: "GET",
@@ -1579,12 +1679,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null userId");
}
- var parentId = options.parentId || "root";
-
- // Don't put these on the query string
- delete options.parentId;
+ options = options || {};
+ options.userId = userId;
- var url = self.getUrl("Users/" + userId + "/Items/" + parentId + "/Studios", options);
+ var url = self.getUrl("Studios", options);
return self.ajax({
type: "GET",
@@ -1722,7 +1820,67 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
* @param {String} name
* @param {Boolean} isFavorite
*/
- self.updateItemByNameFavoriteStatus = function (userId, name, isFavorite) {
+ self.updateFavoriteArtistStatus = function (userId, name, isFavorite) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Favorites/Artists/" + encodeName(name));
+
+ var method = isFavorite ? "POST" : "DELETE";
+
+ return self.ajax({
+ type: method,
+ url: url
+ });
+ };
+
+ self.updateFavoritePersonStatus = function (userId, name, isFavorite) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Favorites/Persons/" + encodeName(name));
+
+ var method = isFavorite ? "POST" : "DELETE";
+
+ return self.ajax({
+ type: method,
+ url: url
+ });
+ };
+
+ self.updateFavoriteStudioStatus = function (userId, name, isFavorite) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Favorites/Studios/" + encodeName(name));
+
+ var method = isFavorite ? "POST" : "DELETE";
+
+ return self.ajax({
+ type: method,
+ url: url
+ });
+ };
+
+ self.updateFavoriteGenreStatus = function (userId, name, isFavorite) {
if (!userId) {
throw new Error("null userId");
@@ -1732,7 +1890,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/ItemsByName/Favorites/" + encodeName(name));
+ var url = self.getUrl("Users/" + userId + "/Favorites/Genres/" + encodeName(name));
var method = isFavorite ? "POST" : "DELETE";
@@ -1748,7 +1906,27 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
* @param {String} name
* @param {Boolean} likes
*/
- self.updateItemByNameRating = function (userId, name, likes) {
+ self.updateArtistRating = function (userId, name, likes) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Artists/" + encodeName(name), {
+ likes: likes
+ });
+
+ return self.ajax({
+ type: "POST",
+ url: url
+ });
+ };
+
+ self.updatePersonRating = function (userId, name, likes) {
if (!userId) {
throw new Error("null userId");
@@ -1758,7 +1936,47 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/ItemsByName/" + encodeName(name) + "/Rating", {
+ var url = self.getUrl("Users/" + userId + "/Ratings/Persons/" + encodeName(name), {
+ likes: likes
+ });
+
+ return self.ajax({
+ type: "POST",
+ url: url
+ });
+ };
+
+ self.updateStudioRating = function (userId, name, likes) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Studios/" + encodeName(name), {
+ likes: likes
+ });
+
+ return self.ajax({
+ type: "POST",
+ url: url
+ });
+ };
+
+ self.updateGenreRating = function (userId, name, likes) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Genres/" + encodeName(name), {
likes: likes
});
@@ -1773,7 +1991,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
* @param {String} userId
* @param {String} name
*/
- self.clearItemByNameRating = function (userId, name) {
+ self.clearArtistRating = function (userId, name) {
if (!userId) {
throw new Error("null userId");
@@ -1783,7 +2001,61 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/ItemsByName/" + encodeName(name) + "/Rating");
+ var url = self.getUrl("Users/" + userId + "/Ratings/Artists/" + encodeName(name));
+
+ return self.ajax({
+ type: "DELETE",
+ url: url
+ });
+ };
+
+ self.clearPersonRating = function (userId, name) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Persons/" + encodeName(name));
+
+ return self.ajax({
+ type: "DELETE",
+ url: url
+ });
+ };
+
+ self.clearStudioRating = function (userId, name) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Studios/" + encodeName(name));
+
+ return self.ajax({
+ type: "DELETE",
+ url: url
+ });
+ };
+
+ self.clearGenreRating = function (userId, name) {
+
+ if (!userId) {
+ throw new Error("null userId");
+ }
+
+ if (!name) {
+ throw new Error("null name");
+ }
+
+ var url = self.getUrl("Users/" + userId + "/Ratings/Genres/" + encodeName(name));
return self.ajax({
type: "DELETE",
@@ -1792,11 +2064,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
- * Gets the full user data object for an item by name.
- * @param {String} userId
- * @param {String} name
+ Gets a variety of item counts that a person appears in
*/
- self.getItembyNameUserData = function (userId, name) {
+ self.getPersonItemCounts = function (userId, name) {
if (!userId) {
throw new Error("null userId");
@@ -1806,7 +2076,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/ItemsByName/" + encodeName(name) + "/UserData");
+ var url = self.getUrl("Persons/" + encodeName(name) + "/Counts", {
+ userId: userId
+ });
return self.ajax({
type: "GET",
@@ -1816,9 +2088,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
- Gets a variety of item counts that a person appears in
+ Gets a variety of item counts that a genre appears in
*/
- self.getPersonItemCounts = function (userId, name) {
+ self.getGenreItemCounts = function (userId, name) {
if (!userId) {
throw new Error("null userId");
@@ -1828,7 +2100,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/Persons/" + encodeName(name) + "/Counts");
+ var url = self.getUrl("Genres/" + encodeName(name) + "/Counts", {
+ userId: userId
+ });
return self.ajax({
type: "GET",
@@ -1838,9 +2112,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
- Gets a variety of item counts that a genre appears in
+ Gets a variety of item counts that an artist appears in
*/
- self.getGenreItemCounts = function (userId, name) {
+ self.getArtistItemCounts = function (userId, name) {
if (!userId) {
throw new Error("null userId");
@@ -1850,7 +2124,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/Genres/" + encodeName(name) + "/Counts");
+ var url = self.getUrl("Artists/" + encodeName(name) + "/Counts", {
+ userId: userId
+ });
return self.ajax({
type: "GET",
@@ -1872,7 +2148,9 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
throw new Error("null name");
}
- var url = self.getUrl("Users/" + userId + "/Studios/" + encodeName(name) + "/Counts");
+ var url = self.getUrl("Studios/" + encodeName(name) + "/Counts", {
+ userId: userId
+ });
return self.ajax({
type: "GET",
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 68836a2454..f7cd271ef5 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -84,9 +84,6 @@
-
- PreserveNewest
-
PreserveNewest
@@ -237,6 +234,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
@@ -246,9 +249,6 @@
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
@@ -288,6 +288,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
PreserveNewest
@@ -335,12 +341,6 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
@@ -383,12 +383,6 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index c84847e3ed..56ea6b5c94 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file