浏览代码

added methods to edit ibn images

Luke Pulverenti 12 年之前
父节点
当前提交
c411fdc93a

+ 48 - 0
MediaBrowser.Api/BaseApiService.cs

@@ -238,6 +238,54 @@ namespace MediaBrowser.Api
 
                 }) ?? name;
         }
+
+        /// <summary>
+        /// Gets the name of the item by.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="libraryManager">The library manager.</param>
+        /// <returns>Task{BaseItem}.</returns>
+        /// <exception cref="System.ArgumentException"></exception>
+        protected async Task<BaseItem> GetItemByName(string name, string type, ILibraryManager libraryManager)
+        {
+            BaseItem item;
+
+            if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetPerson(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetArtist(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetGenre(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetMusicGenre(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetGameGenre(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await GetStudio(name, libraryManager).ConfigureAwait(false);
+            }
+            else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+                item = await libraryManager.GetYear(int.Parse(name)).ConfigureAwait(false);
+            }
+            else
+            {
+                throw new ArgumentException();
+            }
+
+            return item;
+        }
     }
 
     /// <summary>

+ 196 - 160
MediaBrowser.Api/Images/ImageService.cs

@@ -1,12 +1,9 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
@@ -39,6 +36,23 @@ namespace MediaBrowser.Api.Images
         public string Id { get; set; }
     }
 
+    [Route("/Artists/{Name}/Images", "GET")]
+    [Route("/Genres/{Name}/Images", "GET")]
+    [Route("/GameGenres/{Name}/Images", "GET")]
+    [Route("/MusicGenres/{Name}/Images", "GET")]
+    [Route("/Persons/{Name}/Images", "GET")]
+    [Route("/Studios/{Name}/Images", "GET")]
+    [Api(Description = "Gets information about an item's images")]
+    public class GetItemByNameImageInfos : IReturn<List<ImageInfo>>
+    {
+        /// <summary>
+        /// Gets or sets the id.
+        /// </summary>
+        /// <value>The id.</value>
+        [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Name { get; set; }
+    }
+
     [Route("/Items/{Id}/Images/{Type}", "GET")]
     [Route("/Items/{Id}/Images/{Type}/{Index}", "GET")]
     [Api(Description = "Gets an item image")]
@@ -88,142 +102,128 @@ namespace MediaBrowser.Api.Images
         public int NewIndex { get; set; }
     }
 
-    /// <summary>
-    /// Class DeleteItemImage
-    /// </summary>
-    [Route("/Items/{Id}/Images/{Type}", "DELETE")]
-    [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")]
-    [Api(Description = "Deletes an item image")]
-    public class DeleteItemImage : DeleteImageRequest, IReturnVoid
+    [Route("/Artists/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/Genres/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/GameGenres/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/MusicGenres/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/Persons/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/Studios/{Name}/Images/{Type}/{Index}/Index", "POST")]
+    [Route("/Years/{Year}/Images/{Type}/{Index}/Index", "POST")]
+    [Api(Description = "Updates the index for an item image")]
+    public class UpdateItemByNameImageIndex : IReturnVoid
     {
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
         /// <value>The id.</value>
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public Guid Id { get; set; }
-    }
+        [ApiMember(Name = "Name", Description = "Item name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public string Name { get; set; }
 
-    /// <summary>
-    /// Class GetPersonImage
-    /// </summary>
-    [Route("/Persons/{Name}/Images/{Type}", "GET")]
-    [Route("/Persons/{Name}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a person image")]
-    public class GetPersonImage : ImageRequest
-    {
         /// <summary>
-        /// Gets or sets the name.
+        /// Gets or sets the type of the image.
         /// </summary>
-        /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Person name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Name { get; set; }
-    }
+        /// <value>The type of the image.</value>
+        [ApiMember(Name = "Type", Description = "Image Type", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public ImageType Type { get; set; }
 
-    /// <summary>
-    /// Class GetArtistImage
-    /// </summary>
-    [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.
+        /// Gets or sets the index.
         /// </summary>
-        /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Artist name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Name { get; set; }
-    }
+        /// <value>The index.</value>
+        [ApiMember(Name = "Index", Description = "Image Index", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")]
+        public int Index { get; set; }
 
-    /// <summary>
-    /// Class GetStudioImage
-    /// </summary>
-    [Route("/Studios/{Name}/Images/{Type}", "GET")]
-    [Route("/Studios/{Name}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a studio image")]
-    public class GetStudioImage : ImageRequest
-    {
         /// <summary>
-        /// Gets or sets the name.
+        /// Gets or sets the new index.
         /// </summary>
-        /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Studio name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Name { get; set; }
+        /// <value>The new index.</value>
+        [ApiMember(Name = "NewIndex", Description = "The new image index", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public int NewIndex { get; set; }
     }
-
+    
     /// <summary>
-    /// Class GetGenreImage
+    /// Class GetPersonImage
     /// </summary>
+    [Route("/Artists/{Name}/Images/{Type}", "GET")]
+    [Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")]
     [Route("/Genres/{Name}/Images/{Type}", "GET")]
     [Route("/Genres/{Name}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a genre image")]
-    public class GetGenreImage : ImageRequest
-    {
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Name { get; set; }
-    }
-
+    [Route("/GameGenres/{Name}/Images/{Type}", "GET")]
+    [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "GET")]
     [Route("/MusicGenres/{Name}/Images/{Type}", "GET")]
     [Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a genre image")]
-    public class GetMusicGenreImage : ImageRequest
+    [Route("/Persons/{Name}/Images/{Type}", "GET")]
+    [Route("/Persons/{Name}/Images/{Type}/{Index}", "GET")]
+    [Route("/Studios/{Name}/Images/{Type}", "GET")]
+    [Route("/Studios/{Name}/Images/{Type}/{Index}", "GET")]
+    [Route("/Years/{Year}/Images/{Type}", "GET")]
+    [Route("/Years/{Year}/Images/{Type}/{Index}", "GET")]
+    [Api(Description = "Gets an item by name image")]
+    public class GetItemByNameImage : ImageRequest
     {
         /// <summary>
         /// Gets or sets the name.
         /// </summary>
         /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        [ApiMember(Name = "Name", Description = "Item name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
         public string Name { get; set; }
     }
 
-    [Route("/GameGenres/{Name}/Images/{Type}", "GET")]
-    [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a genre image")]
-    public class GetGameGenreImage : ImageRequest
+    /// <summary>
+    /// Class GetUserImage
+    /// </summary>
+    [Route("/Users/{Id}/Images/{Type}", "GET")]
+    [Route("/Users/{Id}/Images/{Type}/{Index}", "GET")]
+    [Api(Description = "Gets a user image")]
+    public class GetUserImage : ImageRequest
     {
         /// <summary>
-        /// Gets or sets the name.
+        /// Gets or sets the id.
         /// </summary>
-        /// <value>The name.</value>
-        [ApiMember(Name = "Name", Description = "Genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Name { get; set; }
+        /// <value>The id.</value>
+        [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public Guid Id { get; set; }
     }
 
     /// <summary>
-    /// Class GetYearImage
+    /// Class DeleteItemImage
     /// </summary>
-    [Route("/Years/{Year}/Images/{Type}", "GET")]
-    [Route("/Years/{Year}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a year image")]
-    public class GetYearImage : ImageRequest
+    [Route("/Items/{Id}/Images/{Type}", "DELETE")]
+    [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")]
+    [Api(Description = "Deletes an item image")]
+    public class DeleteItemImage : DeleteImageRequest, IReturnVoid
     {
         /// <summary>
-        /// Gets or sets the year.
+        /// Gets or sets the id.
         /// </summary>
-        /// <value>The year.</value>
-        [ApiMember(Name = "Year", Description = "Year", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
-        public int Year { get; set; }
+        /// <value>The id.</value>
+        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+        public Guid Id { get; set; }
     }
 
-    /// <summary>
-    /// Class GetUserImage
-    /// </summary>
-    [Route("/Users/{Id}/Images/{Type}", "GET")]
-    [Route("/Users/{Id}/Images/{Type}/{Index}", "GET")]
-    [Api(Description = "Gets a user image")]
-    public class GetUserImage : ImageRequest
+    [Route("/Artists/{Name}/Images/{Type}", "DELETE")]
+    [Route("/Artists/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/Genres/{Name}/Images/{Type}", "DELETE")]
+    [Route("/Genres/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/GameGenres/{Name}/Images/{Type}", "DELETE")]
+    [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/MusicGenres/{Name}/Images/{Type}", "DELETE")]
+    [Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/Persons/{Name}/Images/{Type}", "DELETE")]
+    [Route("/Persons/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/Studios/{Name}/Images/{Type}", "DELETE")]
+    [Route("/Studios/{Name}/Images/{Type}/{Index}", "DELETE")]
+    [Route("/Years/{Year}/Images/{Type}", "DELETE")]
+    [Route("/Years/{Year}/Images/{Type}/{Index}", "DELETE")]
+    [Api(Description = "Deletes an item image")]
+    public class DeleteItemByNameImage : DeleteImageRequest, IReturnVoid
     {
         /// <summary>
         /// Gets or sets the id.
         /// </summary>
         /// <value>The id.</value>
-        [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public Guid Id { get; set; }
+        [ApiMember(Name = "Name", Description = "Item name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
+        public string Name { get; set; }
     }
 
     /// <summary>
@@ -286,6 +286,37 @@ namespace MediaBrowser.Api.Images
         public Stream RequestStream { get; set; }
     }
 
+    [Route("/Artists/{Name}/Images/{Type}", "POST")]
+    [Route("/Artists/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/Genres/{Name}/Images/{Type}", "POST")]
+    [Route("/Genres/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/GameGenres/{Name}/Images/{Type}", "POST")]
+    [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/MusicGenres/{Name}/Images/{Type}", "POST")]
+    [Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/Persons/{Name}/Images/{Type}", "POST")]
+    [Route("/Persons/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/Studios/{Name}/Images/{Type}", "POST")]
+    [Route("/Studios/{Name}/Images/{Type}/{Index}", "POST")]
+    [Route("/Years/{Year}/Images/{Type}", "POST")]
+    [Route("/Years/{Year}/Images/{Type}/{Index}", "POST")]
+    [Api(Description = "Posts an item image")]
+    public class PostItemByNameImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
+    {
+        /// <summary>
+        /// Gets or sets the id.
+        /// </summary>
+        /// <value>The id.</value>
+        [ApiMember(Name = "Name", Description = "Item name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// The raw Http Request Input Stream
+        /// </summary>
+        /// <value>The request stream.</value>
+        public Stream RequestStream { get; set; }
+    }
+
     /// <summary>
     /// Class ImageService
     /// </summary>
@@ -306,7 +337,7 @@ namespace MediaBrowser.Api.Images
         private readonly IProviderManager _providerManager;
 
         private readonly IItemRepository _itemRepo;
-        
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageService" /> class.
         /// </summary>
@@ -337,6 +368,28 @@ namespace MediaBrowser.Api.Images
             return ToOptimizedResult(result);
         }
 
+        public object Get(GetItemByNameImageInfos request)
+        {
+            var result = GetItemByNameImageInfos(request).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        /// <summary>
+        /// Gets the item by name image infos.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        /// <returns>Task{List{ImageInfo}}.</returns>
+        public async Task<List<ImageInfo>> GetItemByNameImageInfos(GetItemByNameImageInfos request)
+        {
+            var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+            var type = pathInfo.GetArgumentValue<string>(0);
+
+            var item = await GetItemByName(request.Name, type, _libraryManager).ConfigureAwait(false);
+
+            return await GetItemImageInfos(item).ConfigureAwait(false);
+        }
+
         /// <summary>
         /// Gets the item image infos.
         /// </summary>
@@ -476,98 +529,49 @@ namespace MediaBrowser.Api.Images
             return GetImage(request, item);
         }
 
-        /// <summary>
-        /// Gets the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetYearImage request)
-        {
-            var item = _libraryManager.GetYear(request.Year).Result;
-
-            return GetImage(request, item);
-        }
-
-        /// <summary>
-        /// Gets the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetStudioImage request)
+        public object Get(GetItemByNameImage request)
         {
-            var item = GetStudio(request.Name, _libraryManager).Result;
-
-            return GetImage(request, item);
-        }
+            var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+            var type = pathInfo.GetArgumentValue<string>(0);
 
-        /// <summary>
-        /// Gets the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetPersonImage request)
-        {
-            var item = GetPerson(request.Name, _libraryManager).Result;
+            var item = GetItemByName(request.Name, type, _libraryManager).Result;
 
             return GetImage(request, item);
         }
 
         /// <summary>
-        /// Gets the specified request.
+        /// Posts the specified request.
         /// </summary>
         /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetArtistImage request)
+        public void Post(PostUserImage request)
         {
-            var item = GetArtist(request.Name, _libraryManager).Result;
-
-            return GetImage(request, item);
-        }
+            var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+            var id = new Guid(pathInfo.GetArgumentValue<string>(1));
 
-        /// <summary>
-        /// Gets the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>System.Object.</returns>
-        public object Get(GetGenreImage request)
-        {
-            var item = GetGenre(request.Name, _libraryManager).Result;
+            request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
 
-            return GetImage(request, item);
-        }
+            var item = _userManager.Users.First(i => i.Id == id);
 
-        public object Get(GetMusicGenreImage request)
-        {
-            var item = GetMusicGenre(request.Name, _libraryManager).Result;
+            var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType);
 
-            return GetImage(request, item);
+            Task.WaitAll(task);
         }
 
-        public object Get(GetGameGenreImage request)
-        {
-            var item = GetGameGenre(request.Name, _libraryManager).Result;
-
-            return GetImage(request, item);
-        }
-        
-        /// <summary>
-        /// Posts the specified request.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        public void Post(PostUserImage request)
+        public void Post(PostItemByNameImage request)
         {
             var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
-            var id = new Guid(pathInfo.GetArgumentValue<string>(1));
+            var type = pathInfo.GetArgumentValue<string>(0);
+            var name = pathInfo.GetArgumentValue<string>(1);
 
             request.Type = (ImageType)Enum.Parse(typeof(ImageType), pathInfo.GetArgumentValue<string>(3), true);
 
-            var item = _userManager.Users.First(i => i.Id == id);
+            var item = GetItemByName(name, type, _libraryManager).Result;
 
             var task = PostImage(item, request.RequestStream, request.Type, RequestContext.ContentType);
 
             Task.WaitAll(task);
         }
-
+        
         /// <summary>
         /// Posts the specified request.
         /// </summary>
@@ -612,6 +616,22 @@ namespace MediaBrowser.Api.Images
             Task.WaitAll(task);
         }
 
+        /// <summary>
+        /// Deletes the specified request.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        public void Delete(DeleteItemByNameImage request)
+        {
+            var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+            var type = pathInfo.GetArgumentValue<string>(0);
+
+            var item = GetItemByName(request.Name, type, _libraryManager).Result;
+
+            var task = item.DeleteImage(request.Type, request.Index);
+
+            Task.WaitAll(task);
+        }
+
         /// <summary>
         /// Posts the specified request.
         /// </summary>
@@ -625,6 +645,22 @@ namespace MediaBrowser.Api.Images
             Task.WaitAll(task);
         }
 
+        /// <summary>
+        /// Posts the specified request.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        public void Post(UpdateItemByNameImageIndex request)
+        {
+            var pathInfo = PathInfo.Parse(RequestContext.PathInfo);
+            var type = pathInfo.GetArgumentValue<string>(0);
+
+            var item = GetItemByName(request.Name, type, _libraryManager).Result;
+
+            var task = UpdateItemIndex(item, request.Type, request.Index, request.NewIndex);
+
+            Task.WaitAll(task);
+        }
+
         /// <summary>
         /// Updates the index of the item.
         /// </summary>

+ 3 - 62
MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using ServiceStack.ServiceHost;
 using ServiceStack.Text.Controller;
@@ -215,36 +214,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// <returns>Task.</returns>
         protected async Task MarkFavorite(Guid userId, string type, string name, bool isFavorite)
         {
-            BaseItem item;
-
-            if (string.Equals(type, "Persons"))
-            {
-                item = await GetPerson(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Artists"))
-            {
-                item = await GetArtist(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Genres"))
-            {
-                item = await GetGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "MusicGenres"))
-            {
-                item = await GetMusicGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "GameGenres"))
-            {
-                item = await GetGameGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Studios"))
-            {
-                item = await GetStudio(name, LibraryManager).ConfigureAwait(false);
-            }
-            else
-            {
-                throw new ArgumentException();
-            }
+            var item = await GetItemByName(name, type, LibraryManager).ConfigureAwait(false);
 
             var key = item.GetUserDataKey();
 
@@ -267,36 +237,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// <returns>Task.</returns>
         protected async Task MarkLike(Guid userId, string type, string name, bool? likes)
         {
-            BaseItem item;
-
-            if (string.Equals(type, "Persons"))
-            {
-                item = await GetPerson(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Artists"))
-            {
-                item = await GetArtist(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Genres"))
-            {
-                item = await GetGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "MusicGenres"))
-            {
-                item = await GetMusicGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "GameGenres"))
-            {
-                item = await GetGameGenre(name, LibraryManager).ConfigureAwait(false);
-            }
-            else if (string.Equals(type, "Studios"))
-            {
-                item = await GetStudio(name, LibraryManager).ConfigureAwait(false);
-            }
-            else
-            {
-                throw new ArgumentException();
-            }
+            var item = await GetItemByName(name, type, LibraryManager).ConfigureAwait(false);
 
             var key = item.GetUserDataKey();
 

+ 8 - 0
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -73,6 +73,10 @@ namespace MediaBrowser.Controller.Entities.TV
             }
         }
 
+        /// <summary>
+        /// Gets all genres.
+        /// </summary>
+        /// <value>All genres.</value>
         [IgnoreDataMember]
         public override IEnumerable<string> AllGenres
         {
@@ -83,6 +87,10 @@ namespace MediaBrowser.Controller.Entities.TV
             }
         }
 
+        /// <summary>
+        /// Gets all studios.
+        /// </summary>
+        /// <value>All studios.</value>
         [IgnoreDataMember]
         public override IEnumerable<string> AllStudios
         {

+ 149 - 38
MediaBrowser.WebDashboard/ApiClient.js

@@ -80,18 +80,15 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             else if ($.browser.firefox || $.browser.mozilla) {
                 name = "Firefox";
             }
-			
-			if (name)
-			{
-				if ($.browser.version)
-				{
-					name += " " + $.browser.version;
-				}
-			}
-			else			
-			{
-				name = "Web Browser";
-			}
+
+            if (name) {
+                if ($.browser.version) {
+                    name += " " + $.browser.version;
+                }
+            }
+            else {
+                name = "Web Browser";
+            }
 
             if ($.browser.ipad) {
                 name += " Ipad";
@@ -1046,17 +1043,41 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             });
         };
 
-        self.deleteItemImage = function (itemId, imageType, imageIndex) {
-
-            if (!itemId) {
-                throw new Error("null itemId");
-            }
+        self.deleteItemImage = function (itemId, itemType, itemName, imageType, imageIndex) {
 
             if (!imageType) {
                 throw new Error("null imageType");
             }
 
-            var url = self.getUrl("Items/" + itemId + "/Images/" + imageType);
+            if (!itemType) {
+                throw new Error("null itemType");
+            }
+
+            var url;
+
+            if (itemType == "Artist") {
+                url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Genre") {
+                url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "GameGenre") {
+                url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "MusicGenre") {
+                url = self.getUrl("MusicGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Person") {
+                url = self.getUrl("Persons/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Studio") {
+                url = self.getUrl("Studios/" + self.encodeName(itemName) + "/Images");
+            }
+            else {
+                url = self.getUrl("Items/" + itemId + "/Images");
+            }
+
+            url += "/" + imageType;
 
             if (imageIndex != null) {
                 url += "/" + imageIndex;
@@ -1068,17 +1089,41 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             });
         };
 
-        self.updateItemImageIndex = function (itemId, imageType, imageIndex, newIndex) {
-
-            if (!itemId) {
-                throw new Error("null itemId");
-            }
+        self.updateItemImageIndex = function (itemId, itemType, itemName, imageType, imageIndex, newIndex) {
 
             if (!imageType) {
                 throw new Error("null imageType");
             }
 
-            var url = self.getUrl("Items/" + itemId + "/Images/" + imageType + "/" + imageIndex + "/Index", { newIndex: newIndex });
+            if (!itemType) {
+                throw new Error("null itemType");
+            }
+
+            var url;
+
+            var options = { newIndex: newIndex };
+
+            if (itemType == "Artist") {
+                url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else if (itemType == "Genre") {
+                url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else if (itemType == "GameGenre") {
+                url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else if (itemType == "MusicGenre") {
+                url = self.getUrl("MusicGenres/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else if (itemType == "Person") {
+                url = self.getUrl("Persons/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else if (itemType == "Studio") {
+                url = self.getUrl("Studios/" + self.encodeName(itemName) + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
+            else {
+                url = self.getUrl("Items/" + itemId + "/Images/" + imageType + "/" + imageIndex + "/Index", options);
+            }
 
             return self.ajax({
                 type: "POST",
@@ -1086,13 +1131,35 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             });
         };
 
-        self.getItemImageInfos = function (itemId) {
+        self.getItemImageInfos = function (itemId, itemType, itemName) {
 
-            if (!itemId) {
-                throw new Error("null itemId");
+            if (!itemType) {
+                throw new Error("null itemType");
             }
 
-            var url = self.getUrl("Items/" + itemId + "/Images");
+            var url;
+
+            if (itemType == "Artist") {
+                url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Genre") {
+                url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "GameGenre") {
+                url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "MusicGenre") {
+                url = self.getUrl("MusicGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Person") {
+                url = self.getUrl("Persons/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Studio") {
+                url = self.getUrl("Studios/" + self.encodeName(itemName) + "/Images");
+            }
+            else {
+                url = self.getUrl("Items/" + itemId + "/Images");
+            }
 
             return self.ajax({
                 type: "GET",
@@ -1191,7 +1258,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             return deferred.promise();
         };
 
-        self.uploadItemImage = function (itemId, imageType, file) {
+        self.uploadItemImage = function (itemId, itemType, itemName, imageType, file) {
 
             if (!itemId) {
                 throw new Error("null itemId");
@@ -1209,6 +1276,32 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
                 throw new Error("File must be an image.");
             }
 
+            var url;
+
+            if (itemType == "Artist") {
+                url = self.getUrl("Artists/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Genre") {
+                url = self.getUrl("Genres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "GameGenre") {
+                url = self.getUrl("GameGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "MusicGenre") {
+                url = self.getUrl("MusicGenres/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Person") {
+                url = self.getUrl("Persons/" + self.encodeName(itemName) + "/Images");
+            }
+            else if (itemType == "Studio") {
+                url = self.getUrl("Studios/" + self.encodeName(itemName) + "/Images");
+            }
+            else {
+                url = self.getUrl("Items/" + itemId + "/Images");
+            }
+
+            url += "/" + imageType;
+
             var deferred = $.Deferred();
 
             var reader = new FileReader();
@@ -1227,8 +1320,6 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
                 // Split by a comma to remove the url: prefix
                 var data = e.target.result.split(',')[1];
 
-                var url = self.getUrl("Items/" + itemId + "/Images/" + imageType);
-
                 self.ajax({
                     type: "POST",
                     url: url,
@@ -2243,6 +2334,27 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout) {
             });
         };
 
+        self.getAncestorItems = function (itemId, userId) {
+
+            if (!itemId) {
+                throw new Error("null itemId");
+            }
+
+            var options = {};
+
+            if (userId) {
+                options.userId = userId;
+            }
+
+            var url = self.getUrl("Items/" + itemId + "/Ancestors", options);
+
+            return self.ajax({
+                type: "GET",
+                url: url,
+                dataType: "json"
+            });
+        };
+
         /**
          * Gets items based on a query, typically for children of a folder
          * @param {String} userId
@@ -3509,13 +3621,12 @@ MediaBrowser.SHA1 = function (msg) {
             /(iphone)/.exec(ua) ||
             /(android)/.exec(ua) ||
             [];
-			
-		var browser = match[1] || "";
-		
-		if (ua.indexOf("like gecko") != -1 && ua.indexOf('webkit') == -1 && ua.indexOf('opera') == -1)
-		{
-			browser = "msie";
-		}
+
+        var browser = match[1] || "";
+
+        if (ua.indexOf("like gecko") != -1 && ua.indexOf('webkit') == -1 && ua.indexOf('opera') == -1) {
+            browser = "msie";
+        }
 
         return {
             browser: browser,

+ 1 - 1
MediaBrowser.WebDashboard/packages.config

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.155" targetFramework="net45" />
+  <package id="MediaBrowser.ApiClient.Javascript" version="3.0.159" targetFramework="net45" />
   <package id="ServiceStack.Common" version="3.9.56" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.55" targetFramework="net45" />
 </packages>