aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Reed <ebr@mediabrowser3.com>2013-04-22 11:27:23 -0400
committerEric Reed <ebr@mediabrowser3.com>2013-04-22 11:27:23 -0400
commit49cc12c4f56ceb51d1e03d405146ab2112411122 (patch)
treec0076d970df935a724c1ad1b7fbfb9800d0682e3
parent8aa9a5ec63ff6c744c456bd0a2bb11d9da5b74e6 (diff)
parenta55999b780367dfa344bb0dfc754b5172b0b195a (diff)
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs25
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs137
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj1
-rw-r--r--MediaBrowser.Api/UserLibrary/ArtistsService.cs187
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs66
-rw-r--r--MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs7
-rw-r--r--MediaBrowser.Api/UserLibrary/GenresService.cs110
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs166
-rw-r--r--MediaBrowser.Api/UserLibrary/ItemsService.cs9
-rw-r--r--MediaBrowser.Api/UserLibrary/PersonsService.cs74
-rw-r--r--MediaBrowser.Api/UserLibrary/StudiosService.cs76
-rw-r--r--MediaBrowser.Api/UserLibrary/YearsService.cs70
-rw-r--r--MediaBrowser.Controller/Dto/DtoBuilder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Artist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs10
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs8
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs16
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs2
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs8
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj9
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs3
-rw-r--r--MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs10
-rw-r--r--MediaBrowser.Controller/Providers/Movies/MovieDbProvider.cs11
-rw-r--r--MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtAlbumProvider.cs106
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtArtistByNameProvider.cs48
-rw-r--r--MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs76
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmAlbumProvider.cs85
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmArtistByNameProvider.cs50
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs21
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmBaseProvider.cs79
-rw-r--r--MediaBrowser.Controller/Providers/Music/LastfmHelper.cs20
-rw-r--r--MediaBrowser.Controller/Providers/TV/FanArtTVProvider.cs6
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs2
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs8
-rw-r--r--MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs8
-rw-r--r--MediaBrowser.Controller/packages.config4
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs108
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj1
-rw-r--r--MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs4
-rw-r--r--MediaBrowser.Server.Implementations/Providers/ProviderManager.cs7
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs81
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs4
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs5
-rw-r--r--MediaBrowser.WebDashboard/ApiClient.js364
-rw-r--r--MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj30
-rw-r--r--MediaBrowser.WebDashboard/packages.config2
52 files changed, 1558 insertions, 582 deletions
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 1f69183cc..19cb14bbd 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
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "Artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+ }
+
/// <summary>
/// Class GetStudioImage
/// </summary>
@@ -238,6 +251,18 @@ namespace MediaBrowser.Api.Images
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
+ public object Get(GetArtistImage request)
+ {
+ var item = _libraryManager.GetArtist(request.Name).Result;
+
+ return GetImage(request, item);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
public object Get(GetGenreImage request)
{
var item = _libraryManager.GetGenre(request.Name).Result;
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 5b34119de..c7b4fae5f 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;
@@ -37,66 +33,6 @@ namespace MediaBrowser.Api.Library
}
/// <summary>
- /// Class GetPerson
- /// </summary>
- [Route("/Persons/{Name}", "GET")]
- [Api(Description = "Gets a person, by name")]
- public class GetPerson : IReturn<BaseItemDto>
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- /// <summary>
- /// Class GetStudio
- /// </summary>
- [Route("/Studios/{Name}", "GET")]
- [Api(Description = "Gets a studio, by name")]
- public class GetStudio : IReturn<BaseItemDto>
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- /// <summary>
- /// Class GetGenre
- /// </summary>
- [Route("/Genres/{Name}", "GET")]
- [Api(Description = "Gets a genre, by name")]
- public class GetGenre : IReturn<BaseItemDto>
- {
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- /// <summary>
- /// Class GetYear
- /// </summary>
- [Route("/Years/{Year}", "GET")]
- [Api(Description = "Gets a year")]
- public class GetYear : IReturn<BaseItemDto>
- {
- /// <summary>
- /// Gets or sets the year.
- /// </summary>
- /// <value>The year.</value>
- [ApiMember(Name = "Year", Description = "The year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
- public int Year { get; set; }
- }
-
- /// <summary>
/// Class LibraryService
/// </summary>
public class LibraryService : BaseApiService
@@ -106,16 +42,14 @@ namespace MediaBrowser.Api.Library
/// </summary>
private readonly IApplicationHost _appHost;
private readonly ILibraryManager _libraryManager;
- private readonly IUserDataRepository _userDataRepository;
/// <summary>
/// Initializes a new instance of the <see cref="LibraryService" /> class.
/// </summary>
/// <param name="appHost">The app host.</param>
/// <param name="libraryManager">The library manager.</param>
- /// <param name="userDataRepository">The user data repository.</param>
/// <exception cref="System.ArgumentNullException">appHost</exception>
- 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;
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- 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);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- 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);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- 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);
- }
-
- /// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- 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);
}
/// <summary>
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 710c159e7..32c1bfaf5 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -87,6 +87,7 @@
<Compile Include="ScheduledTasks\ScheduledTasksWebSocketListener.cs" />
<Compile Include="ApiEntryPoint.cs" />
<Compile Include="SystemService.cs" />
+ <Compile Include="UserLibrary\ArtistsService.cs" />
<Compile Include="UserLibrary\BaseItemsByNameService.cs" />
<Compile Include="UserLibrary\BaseItemsRequest.cs" />
<Compile Include="UserLibrary\GenresService.cs" />
diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs
new file mode 100644
index 000000000..2622f0bd1
--- /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
+{
+ /// <summary>
+ /// Class GetArtists
+ /// </summary>
+ [Route("/Artists", "GET")]
+ [Api(Description = "Gets all artists from a given item, folder, or the entire library")]
+ public class GetArtists : GetItemsByName
+ {
+ }
+
+ /// <summary>
+ /// Class GetArtistsItemCounts
+ /// </summary>
+ [Route("/Artists/{Name}/Counts", "GET")]
+ [Api(Description = "Gets item counts of library items that an artist appears in")]
+ public class GetArtistsItemCounts : IReturn<ItemByNameCounts>
+ {
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid UserId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+ }
+
+ [Route("/Artists/{Name}", "GET")]
+ [Api(Description = "Gets an artist, by name")]
+ public class GetArtist : IReturn<BaseItemDto>
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "The artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+ }
+
+ /// <summary>
+ /// Class ArtistsService
+ /// </summary>
+ public class ArtistsService : BaseItemsByNameService<Artist>
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ArtistsService"/> class.
+ /// </summary>
+ /// <param name="userManager">The user manager.</param>
+ /// <param name="libraryManager">The library manager.</param>
+ /// <param name="userDataRepository">The user data repository.</param>
+ public ArtistsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
+ : base(userManager, libraryManager, userDataRepository)
+ {
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetArtist request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ /// <summary>
+ /// Gets the item.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task{BaseItemDto}.</returns>
+ private async Task<BaseItemDto> 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);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetArtistsItemCounts request)
+ {
+ var items = GetItems(request.UserId).OfType<Audio>().Where(i => i.HasArtist(request.Name)).ToList();
+
+ var counts = new ItemByNameCounts
+ {
+ TotalCount = items.Count,
+
+ SongCount = items.Count(),
+
+ AlbumCount = items.Select(i => i.Parent).OfType<MusicAlbum>().Distinct().Count()
+ };
+
+ return ToOptimizedResult(counts);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetArtists request)
+ {
+ var result = GetResult(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ /// <summary>
+ /// Gets all items.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <param name="items">The items.</param>
+ /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
+ protected override IEnumerable<IbnStub<Artist>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
+ {
+ var itemsList = items.OfType<Audio>().ToList();
+
+ return itemsList
+ .SelectMany(i =>
+ {
+ var list = i.Artists.ToList();
+
+ if (!string.IsNullOrEmpty(i.AlbumArtist))
+ {
+ list.Add(i.AlbumArtist);
+ }
+
+ return list;
+ })
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .Select(name => new IbnStub<Artist>(name, () => itemsList.Where(i => i.HasArtist(name)), GetEntity));
+ }
+
+ /// <summary>
+ /// Gets the entity.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns>Task{Artist}.</returns>
+ protected Task<Artist> GetEntity(string name)
+ {
+ return LibraryManager.GetArtist(name);
+ }
+ }
+}
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 0a2d6453a..8f2264c6a 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -50,9 +50,18 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>Task{ItemsResult}.</returns>
protected async Task<ItemsResult> GetResult(GetItemsByName request)
{
- var user = UserManager.GetUserById(request.UserId);
+ User user = null;
+ BaseItem item;
- var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
+ if (request.UserId.HasValue)
+ {
+ user = UserManager.GetUserById(request.UserId.Value);
+ item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
+ }
+ else
+ {
+ item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager);
+ }
IEnumerable<BaseItem> items;
@@ -60,16 +69,23 @@ namespace MediaBrowser.Api.UserLibrary
{
var folder = (Folder)item;
- items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user);
+ if (request.UserId.HasValue)
+ {
+ items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user);
+ }
+ else
+ {
+ items = request.Recursive ? folder.RecursiveChildren: folder.Children;
+ }
}
else
{
items = new[] { item };
}
- items = FilterItems(request, items, user);
+ items = FilterItems(request, items);
- var extractedItems = GetAllItems(request, items, user);
+ var extractedItems = GetAllItems(request, items);
extractedItems = FilterItems(request, extractedItems, user);
extractedItems = SortItems(request, extractedItems);
@@ -187,9 +203,8 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
- private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
+ private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
// Exclude item types
if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
@@ -213,9 +228,8 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected abstract IEnumerable<IbnStub<TItemType>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user);
+ protected abstract IEnumerable<IbnStub<TItemType>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
/// <summary>
/// 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;
}
+
+ /// <summary>
+ /// Gets the items.
+ /// </summary>
+ /// <param name="userId">The user id.</param>
+ /// <returns>IEnumerable{BaseItem}.</returns>
+ protected IEnumerable<BaseItem> GetItems(Guid? userId)
+ {
+ if (userId.HasValue)
+ {
+ var user = UserManager.GetUserById(userId.Value);
+
+ return UserManager.GetUserById(userId.Value).RootFolder.GetRecursiveChildren(user);
+ }
+
+ return LibraryManager.RootFolder.RecursiveChildren;
+ }
}
/// <summary>
@@ -258,11 +290,23 @@ namespace MediaBrowser.Api.UserLibrary
public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
{
/// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+
+ /// <summary>
/// What to sort the results by
/// </summary>
/// <value>The sort by.</value>
[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<T>
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
index afe93a086..7dcce53b2 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs
@@ -10,13 +10,6 @@ namespace MediaBrowser.Api.UserLibrary
public abstract class BaseItemsRequest
{
/// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
- /// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
/// <value>The start index.</value>
diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs
index 4f87b154e..30094d4f3 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
/// <summary>
/// Class GetGenres
/// </summary>
- [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
{
}
- /// <summary>
- /// Class GetGenreItemCounts
- /// </summary>
- [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<ItemByNameCounts>
{
@@ -35,8 +32,8 @@ namespace MediaBrowser.Api.UserLibrary
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public Guid? UserId { get; set; }
/// <summary>
/// Gets or sets the name.
@@ -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; }
}
+
+ /// <summary>
+ /// Class GetGenre
+ /// </summary>
+ [Route("/Genres/{Name}", "GET")]
+ [Api(Description = "Gets a genre, by name")]
+ public class GetGenre : IReturn<BaseItemDto>
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+ }
/// <summary>
/// Class GenresService
@@ -61,32 +80,37 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- 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<Trailer>().Count(),
+ return ToOptimizedResult(result);
+ }
- MovieCount = items.OfType<Movie>().Count(),
+ /// <summary>
+ /// Gets the item.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task{BaseItemDto}.</returns>
+ private async Task<BaseItemDto> GetItem(GetGenre request)
+ {
+ var item = await LibraryManager.GetGenre(request.Name).ConfigureAwait(false);
- SeriesCount = items.OfType<Series>().Count(),
+ // Get everything
+ var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
- GameCount = items.OfType<BaseGame>().Count(),
+ var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository);
- SongCount = items.OfType<Audio>().Count(),
+ if (request.UserId.HasValue)
+ {
+ var user = UserManager.GetUserById(request.UserId.Value);
- AlbumCount = items.OfType<MusicAlbum>().Count()
- };
+ return await builder.GetBaseItemDto(item, user, fields.ToList()).ConfigureAwait(false);
+ }
- return ToOptimizedResult(counts);
+ return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
}
-
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -104,9 +128,8 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<IbnStub<Genre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
+ protected override IEnumerable<IbnStub<Genre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.Where(i => i.Genres != null).ToList();
@@ -125,5 +148,34 @@ namespace MediaBrowser.Api.UserLibrary
{
return LibraryManager.GetGenre(name);
}
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ public object Get(GetGenreItemCounts request)
+ {
+ var 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<Trailer>().Count(),
+
+ MovieCount = items.OfType<Movie>().Count(),
+
+ SeriesCount = items.OfType<Series>().Count(),
+
+ GameCount = items.OfType<BaseGame>().Count(),
+
+ SongCount = items.OfType<Audio>().Count(),
+
+ AlbumCount = items.OfType<MusicAlbum>().Count()
+ };
+
+ return ToOptimizedResult(counts);
+ }
}
}
diff --git a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
index e068eb216..a3f36afe9 100644
--- a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
@@ -1,6 +1,8 @@
-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;
@@ -8,31 +10,12 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
/// <summary>
- /// Class GetItemByNameUserData
- /// </summary>
- [Route("/Users/{UserId}/ItemsByName/{Name}/UserData", "GET")]
- [Api(Description = "Gets user data for an item")]
- public class GetItemByNameUserData : IReturnVoid
- {
- /// <summary>
- /// Gets or sets the user id.
- /// </summary>
- /// <value>The user id.</value>
- [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public Guid UserId { get; set; }
-
- /// <summary>
- /// Gets or sets the name.
- /// </summary>
- /// <value>The name.</value>
- [ApiMember(Name = "Name", Description = "The item name (genre, person, year, studio, artist, album)", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
- public string Name { get; set; }
- }
-
- /// <summary>
/// Class MarkItemByNameFavorite
/// </summary>
- [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.
/// </summary>
/// <value>The name.</value>
- [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; }
}
/// <summary>
/// Class UnmarkItemByNameFavorite
/// </summary>
- [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.
/// </summary>
/// <value>The name.</value>
- [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")]
+ /// <summary>
+ /// Class UpdateItemByNameRating
+ /// </summary>
+ [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.
/// </summary>
/// <value>The name.</value>
- [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; }
/// <summary>
@@ -99,7 +91,13 @@ namespace MediaBrowser.Api.UserLibrary
public bool Likes { get; set; }
}
- [Route("/Users/{UserId}/ItemsByName/{Name}/Rating", "DELETE")]
+ /// <summary>
+ /// Class DeleteItemByNameRating
+ /// </summary>
+ [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.
/// </summary>
/// <value>The name.</value>
- [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; }
}
-
+
/// <summary>
/// Class ItemByNameUserDataService
/// </summary>
@@ -129,34 +127,31 @@ namespace MediaBrowser.Api.UserLibrary
protected readonly IUserDataRepository UserDataRepository;
/// <summary>
+ /// The library manager
+ /// </summary>
+ protected readonly ILibraryManager LibraryManager;
+
+ /// <summary>
/// Initializes a new instance of the <see cref="ItemByNameUserDataService" /> class.
/// </summary>
/// <param name="userDataRepository">The user data repository.</param>
- public ItemByNameUserDataService(IUserDataRepository userDataRepository)
+ /// <param name="libraryManager">The library manager.</param>
+ public ItemByNameUserDataService(IUserDataRepository userDataRepository, ILibraryManager libraryManager)
{
UserDataRepository = userDataRepository;
+ LibraryManager = libraryManager;
}
/// <summary>
- /// Gets the specified request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>System.Object.</returns>
- 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));
- }
-
- /// <summary>
/// Posts the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Post(MarkItemByNameFavorite request)
{
- var task = MarkFavorite(request.UserId, request.Name, true);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue<string>(3);
+
+ var task = MarkFavorite(request.UserId, type, request.Name, true);
Task.WaitAll(task);
}
@@ -167,18 +162,24 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public void Post(UpdateItemByNameRating request)
{
- var task = MarkLike(request.UserId, request.Name, request.Likes);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue<string>(3);
+
+ var task = MarkLike(request.UserId, type, request.Name, request.Likes);
Task.WaitAll(task);
}
-
+
/// <summary>
/// Deletes the specified request.
/// </summary>
/// <param name="request">The request.</param>
public void Delete(UnmarkItemByNameFavorite request)
{
- var task = MarkFavorite(request.UserId, request.Name, false);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue<string>(3);
+
+ var task = MarkFavorite(request.UserId, type, request.Name, false);
Task.WaitAll(task);
}
@@ -189,7 +190,10 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
public void Delete(DeleteItemByNameRating request)
{
- var task = MarkLike(request.UserId, request.Name, null);
+ var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+ var type = pathInfo.GetArgumentValue<string>(3);
+
+ var task = MarkLike(request.UserId, type, request.Name, null);
Task.WaitAll(task);
}
@@ -198,11 +202,37 @@ namespace MediaBrowser.Api.UserLibrary
/// Marks the favorite.
/// </summary>
/// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
+ /// <param name="type">The type.</param>
+ /// <param name="name">The name.</param>
/// <param name="isFavorite">if set to <c>true</c> [is favorite].</param>
/// <returns>Task.</returns>
- 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.
/// </summary>
/// <param name="userId">The user id.</param>
- /// <param name="key">The key.</param>
+ /// <param name="type">The type.</param>
+ /// <param name="name">The name.</param>
/// <param name="likes">if set to <c>true</c> [likes].</param>
/// <returns>Task.</returns>
- 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 79e00998f..7d3581846 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -22,6 +22,13 @@ namespace MediaBrowser.Api.UserLibrary
public class GetItems : BaseItemsRequest, IReturn<ItemsResult>
{
/// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public Guid UserId { get; set; }
+
+ /// <summary>
/// Limit results to items containing a specific person
/// </summary>
/// <value>The person.</value>
@@ -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 fb623e953..ee16a986e 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
/// <summary>
/// Class GetPersons
/// </summary>
- [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
/// <summary>
/// Class GetPersonItemCounts
/// </summary>
- [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<ItemByNameCounts>
{
@@ -52,6 +53,28 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <summary>
+ /// Class GetPerson
+ /// </summary>
+ [Route("/Persons/{Name}", "GET")]
+ [Api(Description = "Gets a person, by name")]
+ public class GetPerson : IReturn<BaseItemDto>
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "The person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+ }
+
+ /// <summary>
/// Class PersonsService
/// </summary>
public class PersonsService : BaseItemsByNameService<Person>
@@ -72,6 +95,42 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
+ public object Get(GetPerson request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ /// <summary>
+ /// Gets the item.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task{BaseItemDto}.</returns>
+ private async Task<BaseItemDto> 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);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
public object Get(GetPersons request)
{
var result = GetResult(request).Result;
@@ -86,9 +145,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <returns>System.Object.</returns>
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
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<IbnStub<Person>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
+ protected override IEnumerable<IbnStub<Person>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> 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 94c604685..4e3a2d42a 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
/// <summary>
/// Class GetStudios
/// </summary>
- [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<ItemByNameCounts>
{
@@ -43,6 +44,28 @@ namespace MediaBrowser.Api.UserLibrary
}
/// <summary>
+ /// Class GetStudio
+ /// </summary>
+ [Route("/Studios/{Name}", "GET")]
+ [Api(Description = "Gets a studio, by name")]
+ public class GetStudio : IReturn<BaseItemDto>
+ {
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ /// <value>The name.</value>
+ [ApiMember(Name = "Name", Description = "The studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+ }
+
+ /// <summary>
/// Class StudiosService
/// </summary>
public class StudiosService : BaseItemsByNameService<Studio>
@@ -57,11 +80,45 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
- public object Get(GetStudioItemCounts request)
+ public object Get(GetStudio request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ /// <summary>
+ /// Gets the item.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task{BaseItemDto}.</returns>
+ private async Task<BaseItemDto> 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);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
+ 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);
}
-
+
/// <summary>
/// Gets all items.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<IbnStub<Studio>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
+ protected override IEnumerable<IbnStub<Studio>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> 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 b22a8dac3..79cb08ef9 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,14 +16,35 @@ namespace MediaBrowser.Api.UserLibrary
/// <summary>
/// Class GetYears
/// </summary>
- [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
{
}
/// <summary>
+ /// Class GetYear
+ /// </summary>
+ [Route("/Years/{Year}", "GET")]
+ [Api(Description = "Gets a year")]
+ public class GetYear : IReturn<BaseItemDto>
+ {
+ /// <summary>
+ /// Gets or sets the year.
+ /// </summary>
+ /// <value>The year.</value>
+ [ApiMember(Name = "Year", Description = "The year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
+ public int Year { get; set; }
+
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ /// <value>The user id.</value>
+ [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; }
+ }
+
+ /// <summary>
/// Class YearsService
/// </summary>
public class YearsService : BaseItemsByNameService<Year>
@@ -39,6 +64,42 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
+ public object Get(GetYear request)
+ {
+ var result = GetItem(request).Result;
+
+ return ToOptimizedResult(result);
+ }
+
+ /// <summary>
+ /// Gets the item.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>Task{BaseItemDto}.</returns>
+ private async Task<BaseItemDto> 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);
+ }
+
+ /// <summary>
+ /// Gets the specified request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>System.Object.</returns>
public object Get(GetYears request)
{
var result = GetResult(request).Result;
@@ -51,9 +112,8 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
- /// <param name="user">The user.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
- protected override IEnumerable<IbnStub<Year>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
+ protected override IEnumerable<IbnStub<Year>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> 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 2631488a5..371241d1b 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 dcd6af92d..567b67868 100644
--- a/MediaBrowser.Controller/Entities/Audio/Artist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Artist.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <returns>System.String.</returns>
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 9deb8241d..01bdd84ac 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;
}
+
+ /// <summary>
+ /// Determines whether the specified name has artist.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
+ 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 7b64c0e85..7d6577b4e 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -40,7 +40,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary>
/// The unknwon artist
/// </summary>
- private static readonly MusicArtist UnknwonArtist = new MusicArtist {Name = "<Unknown>"};
+ private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "<Unknown>" };
/// <summary>
/// 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 b5627e061..1f1d5e083 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
{
/// <summary>
@@ -8,12 +6,6 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicArtist : Folder
{
- public Dictionary<string, string> 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 f7963c6e6..1d803ea45 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -23,6 +23,14 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public abstract class BaseItem : IHasProviderIds
{
+ protected BaseItem()
+ {
+ Genres = new List<string>();
+ TrailerUrls = new List<string>();
+ Studios = new List<string>();
+ People = new List<PersonInfo>();
+ }
+
/// <summary>
/// The trailer folder name
/// </summary>
@@ -925,16 +933,10 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Determines if the item is considered new based on user settings
/// </summary>
- /// <param name="user">The user.</param>
/// <returns><c>true</c> if [is recently added] [the specified user]; otherwise, <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException"></exception>
- 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 619c7a12b..b2b465353 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
- return Name;
+ return "Genre-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index f5570448d..0f2803744 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
- return Name;
+ return "Person-" + Name;
}
}
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 06511d959..0dec024f8 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
- return Name;
+ return "Studio-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index 1e4e6cb06..307ce306b 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
/// <returns>System.String.</returns>
public override string GetUserDataKey()
{
- return Name;
+ return "Year-" + Name;
}
}
}
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 86fd25e66..060f52e37 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -213,5 +213,13 @@ namespace MediaBrowser.Controller.Library
/// <param name="parent">The parent.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
IEnumerable<BaseItem> RetrieveChildren(Folder parent);
+
+ /// <summary>
+ /// Validates the artists.
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 926639d0c..09a59286e 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -53,8 +53,12 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="MoreLinq">
+ <HintPath>..\packages\morelinq.1.0.15631-beta\lib\net35\MoreLinq.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net" />
<Reference Include="System.Runtime.Serialization" />
@@ -111,9 +115,11 @@
<Compile Include="Providers\IProviderManager.cs" />
<Compile Include="Providers\MediaInfo\MediaEncoderHelpers.cs" />
<Compile Include="Providers\MetadataProviderPriority.cs" />
+ <Compile Include="Providers\Music\FanArtArtistByNameProvider.cs" />
<Compile Include="Providers\Music\LastfmAlbumProvider.cs" />
<Compile Include="Providers\Music\FanArtAlbumProvider.cs" />
<Compile Include="Providers\Music\FanArtArtistProvider.cs" />
+ <Compile Include="Providers\Music\LastfmArtistByNameProvider.cs" />
<Compile Include="Providers\Music\LastfmArtistProvider.cs" />
<Compile Include="Providers\Music\LastfmHelper.cs" />
<Compile Include="Providers\Music\MusicArtistProviderFromJson.cs" />
@@ -197,6 +203,9 @@
<Name>MediaBrowser.Model</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>if $(ConfigurationName) == Release (
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index cb7237a9d..fa10c8585 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -14,11 +14,12 @@ namespace MediaBrowser.Controller.Providers
/// <param name="item">The item.</param>
/// <param name="source">The source.</param>
/// <param name="targetName">Name of the target.</param>
+ /// <param name="saveLocally">if set to <c>true</c> [save locally].</param>
/// <param name="resourcePool">The resource pool.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.String}.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, SemaphoreSlim resourcePool, CancellationToken cancellationToken);
+ Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken);
/// <summary>
/// Saves to library filesystem.
diff --git a/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs b/MediaBrowser.Controller/Providers/Movies/FanArtMovieProvider.cs
index 94fe38680..b6155f612 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 c086aab77..69023c339 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(@"(?<name>.*)") // 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 583e0bb97..affd4757a 100644
--- a/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
+++ b/MediaBrowser.Controller/Providers/Movies/TmdbPersonProvider.cs
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Providers.Movies
/// <summary>
/// The meta file name
/// </summary>
- 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 f850722d1..4d7f78413 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;
}
/// <summary>
@@ -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();
- /// <summary>
- /// Helper method for Dictionaries since they throw on not-found keys
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <typeparam name="U"></typeparam>
- /// <param name="dictionary">The dictionary.</param>
- /// <param name="key">The key.</param>
- /// <param name="defaultValue">The default value.</param>
- /// <returns>``1.</returns>
- private static U GetValueOrDefault<T, U>(Dictionary<T, U> 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 000000000..58200a458
--- /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
+{
+ /// <summary>
+ /// Class FanArtArtistByNameProvider
+ /// </summary>
+ public class FanArtArtistByNameProvider : FanArtArtistProvider
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class.
+ /// </summary>
+ /// <param name="httpClient">The HTTP client.</param>
+ /// <param name="logManager">The log manager.</param>
+ /// <param name="configurationManager">The configuration manager.</param>
+ /// <param name="providerManager">The provider manager.</param>
+ public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+ : base(httpClient, logManager, configurationManager, providerManager)
+ {
+ }
+
+ /// <summary>
+ /// Supportses the specified item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ public override bool Supports(BaseItem item)
+ {
+ return item is Artist;
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether [save local meta].
+ /// </summary>
+ /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
+ protected override bool SaveLocalMeta
+ {
+ get
+ {
+ return true;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
index 1dd5c7cd2..ec99a78a7 100644
--- a/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
+++ b/MediaBrowser.Controller/Providers/Music/FanArtArtistProvider.cs
@@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Providers.Music
/// <summary>
/// Class FanArtArtistProvider
/// </summary>
- class FanArtArtistProvider : FanartBaseProvider
+ public class FanArtArtistProvider : FanartBaseProvider
{
/// <summary>
/// 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; }
+ }
+
/// <summary>
/// Shoulds the fetch.
/// </summary>
@@ -62,16 +67,11 @@ namespace MediaBrowser.Controller.Providers.Music
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
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);
}
/// <summary>
@@ -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<string>();
+ item.BackdropImagePaths = new List<string>();
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<string, string>();
- 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 697a6604c..b48999176 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<LastfmGetAlbumResult>(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<LastfmGetAlbumResult> 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<Audio>().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<LastfmGetAlbumResult> 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<LastfmGetAlbumResult>(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 000000000..f9ec2cc74
--- /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
+{
+ /// <summary>
+ /// Class LastfmArtistByNameProvider
+ /// </summary>
+ public class LastfmArtistByNameProvider : LastfmArtistProvider
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="LastfmArtistByNameProvider"/> class.
+ /// </summary>
+ /// <param name="jsonSerializer">The json serializer.</param>
+ /// <param name="httpClient">The HTTP client.</param>
+ /// <param name="logManager">The log manager.</param>
+ /// <param name="configurationManager">The configuration manager.</param>
+ /// <param name="providerManager">The provider manager.</param>
+ public LastfmArtistByNameProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+ : base(jsonSerializer, httpClient, logManager, configurationManager, providerManager)
+ {
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether [save local meta].
+ /// </summary>
+ /// <value><c>true</c> if [save local meta]; otherwise, <c>false</c>.</value>
+ protected override bool SaveLocalMeta
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Supportses the specified item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+ public override bool Supports(BaseItem item)
+ {
+ return item is Artist;
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs b/MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
index 8a17bcbf6..165b996f6 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<LastfmGetArtistResult>(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<LastfmGetArtistResult>(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 f7e0eef48..dc586cb51 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)
- {
- }
-
- }
/// <summary>
/// Class MovieDbProvider
/// </summary>
@@ -84,6 +75,14 @@ namespace MediaBrowser.Controller.Providers.Music
/// </summary>
protected string LocalMetaFileName { get; set; }
+ protected virtual bool SaveLocalMeta
+ {
+ get
+ {
+ return ConfigurationManager.Configuration.SaveLocalMeta;
+ }
+ }
+
/// <summary>
/// If we save locally, refresh if they delete something
/// </summary>
@@ -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;
}
/// <summary>
@@ -221,36 +207,9 @@ namespace MediaBrowser.Controller.Providers.Music
/// <returns>Task{System.Boolean}.</returns>
public override async Task<bool> 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 842d10e4d..442dd4b69 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 a7fc4586f..cdbfb0883 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 b5c6df7ec..74cb1bfd4 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 f39e91834..9d1a7c256 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<string>();
- 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 89cb89289..5a68981bf 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 000000000..44996f0e8
--- /dev/null
+++ b/MediaBrowser.Controller/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="morelinq" version="1.0.15631-beta" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 4d66d1422..692176efc 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -103,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Library
private readonly IUserManager _userManager;
private readonly IUserDataRepository _userDataRepository;
-
+
/// <summary>
/// Gets or sets the configuration manager.
/// </summary>
@@ -244,7 +245,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
// Any number of configuration settings could change the way the library is refreshed, so do that now
_taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
-
+
if (refreshPeopleAfterUpdate)
{
_taskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
@@ -285,7 +286,7 @@ namespace MediaBrowser.Server.Implementations.Library
items.AddRange(userFolders);
- return new ConcurrentDictionary<Guid,BaseItem>(items.ToDictionary(i => i.Id));
+ return new ConcurrentDictionary<Guid, BaseItem>(items.ToDictionary(i => i.Id));
}
/// <summary>
@@ -505,7 +506,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
return _userRootFolders.GetOrAdd(userRootPath, key => RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(userRootPath));
}
-
+
/// <summary>
/// Gets a Person
/// </summary>
@@ -560,7 +561,20 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task{Genre}.</returns>
public Task<Artist> GetArtist(string name, bool allowSlowProviders = false)
{
- return GetImagesByNameItem<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, CancellationToken.None, allowSlowProviders);
+ return GetArtist(name, CancellationToken.None, allowSlowProviders);
+ }
+
+ /// <summary>
+ /// Gets the artist.
+ /// </summary>
+ /// <param name="name">The name.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>
+ /// <param name="forceCreation">if set to <c>true</c> [force creation].</param>
+ /// <returns>Task{Artist}.</returns>
+ private Task<Artist> GetArtist(string name, CancellationToken cancellationToken, bool allowSlowProviders = false, bool forceCreation = false)
+ {
+ return GetImagesByNameItem<Artist>(ConfigurationManager.ApplicationPaths.ArtistsPath, name, cancellationToken, allowSlowProviders, forceCreation);
}
/// <summary>
@@ -764,6 +778,76 @@ namespace MediaBrowser.Server.Implementations.Library
_logger.Info("People validation complete");
}
+ public async Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ const int maxTasks = 25;
+
+ var tasks = new List<Task>();
+
+ var artists = RootFolder.RecursiveChildren
+ .OfType<Audio>()
+ .SelectMany(c =>
+ {
+ var list = c.Artists.ToList();
+
+ if (!string.IsNullOrEmpty(c.AlbumArtist))
+ {
+ list.Add(c.AlbumArtist);
+ }
+
+ return list;
+ })
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
+
+ var numComplete = 0;
+
+ foreach (var artist in artists)
+ {
+ if (tasks.Count > maxTasks)
+ {
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+ tasks.Clear();
+
+ // Safe cancellation point, when there are no pending tasks
+ cancellationToken.ThrowIfCancellationRequested();
+ }
+
+ // Avoid accessing the foreach variable within the closure
+ var currentArtist = artist;
+
+ tasks.Add(Task.Run(async () =>
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ await GetArtist(currentArtist, cancellationToken, true, true).ConfigureAwait(false);
+ }
+ catch (IOException ex)
+ {
+ _logger.ErrorException("Error validating Artist {0}", ex, currentArtist);
+ }
+
+ // Update progress
+ lock (progress)
+ {
+ numComplete++;
+ double percent = numComplete;
+ percent /= artists.Count;
+
+ progress.Report(100 * percent);
+ }
+ }));
+ }
+
+ await Task.WhenAll(tasks).ConfigureAwait(false);
+
+ progress.Report(100);
+
+ _logger.Info("Artist validation complete");
+ }
+
/// <summary>
/// Reloads the root media folder
/// </summary>
@@ -796,8 +880,20 @@ namespace MediaBrowser.Server.Implementations.Library
await ValidateCollectionFolders(folder, cancellationToken).ConfigureAwait(false);
}
+ var innerProgress = new ActionableProgress<double>();
+
+ innerProgress.RegisterAction(pct => progress.Report(pct * .8));
+
// Now validate the entire media library
- await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false);
+ await RootFolder.ValidateChildren(innerProgress, cancellationToken, recursive: true).ConfigureAwait(false);
+
+ innerProgress = new ActionableProgress<double>();
+
+ innerProgress.RegisterAction(pct => progress.Report(80 + pct * .2));
+
+ await ValidateArtists(cancellationToken, innerProgress);
+
+ progress.Report(100);
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 79aee7ad2..6d278bb18 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -145,6 +145,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\ProviderManager.cs" />
<Compile Include="Reflection\TypeMapper.cs" />
+ <Compile Include="ScheduledTasks\ArtistValidationTask.cs" />
<Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
<Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
<Compile Include="ScheduledTasks\ImageCleanupTask.cs" />
diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
index 8c74b8aed..8bdf597a1 100644
--- a/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
+++ b/MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
@@ -757,8 +757,8 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
throw new ArgumentNullException("outputPath");
}
- var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath) :
- string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih\" -f image2 \"{1}\"", inputPath, outputPath);
+ var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -filter:v select=\\'eq(pict_type\\,I)\\' -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath) :
+ string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"scale=iw*sar:ih, scale=600:-1\" -f image2 \"{1}\"", inputPath, outputPath);
var probeSize = GetProbeSizeArgument(type);
diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
index e4f57e8d9..4d5123cc5 100644
--- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
@@ -330,11 +330,12 @@ namespace MediaBrowser.Server.Implementations.Providers
/// <param name="item">The item.</param>
/// <param name="source">The source.</param>
/// <param name="targetName">Name of the target.</param>
+ /// <param name="saveLocally">if set to <c>true</c> [save locally].</param>
/// <param name="resourcePool">The resource pool.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.String}.</returns>
/// <exception cref="System.ArgumentNullException">item</exception>
- public async Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
+ public async Task<string> DownloadAndSaveImage(BaseItem item, string source, string targetName, bool saveLocally, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
if (item == null)
{
@@ -354,13 +355,13 @@ namespace MediaBrowser.Server.Implementations.Providers
}
//download and save locally
- var localPath = (ConfigurationManager.Configuration.SaveLocalMeta && item.MetaLocation != null) ?
+ var localPath = (saveLocally && item.MetaLocation != null) ?
Path.Combine(item.MetaLocation, targetName) :
_remoteImageCache.GetResourcePath(item.GetType().FullName + item.Path.ToLower(), targetName);
var img = await _httpClient.Get(source, resourcePool, cancellationToken).ConfigureAwait(false);
- if (ConfigurationManager.Configuration.SaveLocalMeta) // queue to media directories
+ if (saveLocally) // queue to media directories
{
await SaveToLibraryFilesystem(item, localPath, img, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs
new file mode 100644
index 000000000..a67db1b2d
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ArtistValidationTask.cs
@@ -0,0 +1,81 @@
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller.Library;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.ScheduledTasks
+{
+ public class ArtistValidationTask
+ {
+ /// <summary>
+ /// The _library manager
+ /// </summary>
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PeopleValidationTask" /> class.
+ /// </summary>
+ /// <param name="libraryManager">The library manager.</param>
+ public ArtistValidationTask(ILibraryManager libraryManager)
+ {
+ _libraryManager = libraryManager;
+ }
+
+ /// <summary>
+ /// Creates the triggers that define when the task will run
+ /// </summary>
+ /// <returns>IEnumerable{BaseTaskTrigger}.</returns>
+ public IEnumerable<ITaskTrigger> GetDefaultTriggers()
+ {
+ return new ITaskTrigger[]
+ {
+ new DailyTrigger { TimeOfDay = TimeSpan.FromHours(5) },
+
+ new IntervalTrigger{ Interval = TimeSpan.FromHours(12)}
+ };
+ }
+
+ /// <summary>
+ /// Returns the task to be executed
+ /// </summary>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <param name="progress">The progress.</param>
+ /// <returns>Task.</returns>
+ public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+ {
+ return _libraryManager.ValidateArtists(cancellationToken, progress);
+ }
+
+ /// <summary>
+ /// Gets the name of the task
+ /// </summary>
+ /// <value>The name.</value>
+ public string Name
+ {
+ get { return "Refresh music artists"; }
+ }
+
+ /// <summary>
+ /// Gets the description.
+ /// </summary>
+ /// <value>The description.</value>
+ public string Description
+ {
+ get { return "Updates metadata for music artists in your media library."; }
+ }
+
+ /// <summary>
+ /// Gets the category.
+ /// </summary>
+ /// <value>The category.</value>
+ public string Category
+ {
+ get
+ {
+ return "Library";
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
index 6b8113480..ce15f5606 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
@@ -66,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <value>The description.</value>
public string Description
{
- get { return "Updates metadata for actors, artists and directors in your media library."; }
+ get { return "Updates metadata for actors and directors in your media library."; }
}
/// <summary>
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
index 575cd81ba..897ece764 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
@@ -150,6 +150,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite
GC.SuppressFinalize(this);
}
+ private readonly object _disposeLock = new object();
+
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
@@ -160,7 +162,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
{
try
{
- lock (this)
+ lock (_disposeLock)
{
if (connection != null)
{
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 1b22557c8..9f49c83a8 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 fe676abaf..759fb0dc4 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",
@@ -1132,6 +1180,41 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
};
/**
+ * 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
* @param {Object} options
@@ -1525,6 +1608,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
*/
self.getGenres = function (userId, options) {
@@ -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 68836a245..f7cd271ef 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -84,9 +84,6 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ApiClient.js" />
- <Content Include="dashboard-ui\boxset.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\boxsets.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -237,6 +234,12 @@
<Content Include="dashboard-ui\movietrailers.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\musicalbums.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\musicartists.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\musicgenres.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -246,9 +249,6 @@
<Content Include="dashboard-ui\playlist.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\boxset.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\boxsets.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -288,6 +288,12 @@
<Content Include="dashboard-ui\scripts\movietrailers.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\musicalbums.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\scripts\musicartists.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\musicgenres.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -335,12 +341,6 @@
<Content Include="dashboard-ui\scripts\tvrecommended.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\scripts\tvseason.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\scripts\tvseries.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\scripts\tvshows.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -383,12 +383,6 @@
<Content Include="dashboard-ui\tvrecommended.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\tvseason.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\tvseries.html">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\tvshows.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
diff --git a/MediaBrowser.WebDashboard/packages.config b/MediaBrowser.WebDashboard/packages.config
index c84847e3e..56ea6b5c9 100644
--- a/MediaBrowser.WebDashboard/packages.config
+++ b/MediaBrowser.WebDashboard/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.ApiClient.Javascript" version="3.0.80" targetFramework="net45" />
+ <package id="MediaBrowser.ApiClient.Javascript" version="3.0.85" targetFramework="net45" />
<package id="ServiceStack.Common" version="3.9.43" targetFramework="net45" />
<package id="ServiceStack.Text" version="3.9.43" targetFramework="net45" />
</packages> \ No newline at end of file