瀏覽代碼

Added some favorites api calls

LukePulverenti Luke Pulverenti luke pulverenti 12 年之前
父節點
當前提交
c1c4c85fc2

+ 21 - 1
MediaBrowser.Api/ApiService.cs

@@ -171,7 +171,7 @@ namespace MediaBrowser.Api
             dto.Type = item.GetType().Name;
             dto.UserRating = item.UserRating;
 
-            dto.UserData = item.GetUserData(user);
+            dto.UserData = GetDTOUserItemData(item.GetUserData(user));
 
             Folder folder = item as Folder;
 
@@ -394,6 +394,26 @@ namespace MediaBrowser.Api
             };
         }
 
+        /// <summary>
+        /// Converts a UserItemData to a DTOUserItemData
+        /// </summary>
+        public static DTOUserItemData GetDTOUserItemData(UserItemData data)
+        {
+            if (data == null)
+            {
+                return null;
+            }
+
+            return new DTOUserItemData()
+            {
+                IsFavorite = data.IsFavorite,
+                Likes = data.Likes,
+                PlaybackPositionTicks = data.PlaybackPositionTicks,
+                PlayCount = data.PlayCount,
+                Rating = data.Rating
+            };
+        }
+
         public static bool IsApiUrlMatch(string url, HttpListenerRequest request)
         {
             url = "/api/" + url;

+ 44 - 0
MediaBrowser.Api/HttpHandlers/FavoriteStatusHandler.cs

@@ -0,0 +1,44 @@
+using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Model.DTO;
+using MediaBrowser.Model.Entities;
+using System.ComponentModel.Composition;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+    /// <summary>
+    /// Provides a handler to set user favorite status for an item
+    /// </summary>
+    [Export(typeof(BaseHandler))]
+    public class FavoriteStatus : BaseSerializationHandler<DTOUserItemData>
+    {
+        public override bool HandlesRequest(HttpListenerRequest request)
+        {
+            return ApiService.IsApiUrlMatch("FavoriteStatus", request);
+        }
+
+        protected override Task<DTOUserItemData> GetObjectToSerialize()
+        {
+            // Get the item
+            BaseItem item = ApiService.GetItemById(QueryString["id"]);
+
+            // Get the user
+            User user = ApiService.GetUserById(QueryString["userid"], true);
+
+            // Get the user data for this item
+            UserItemData data = item.GetUserData(user);
+
+            if (data == null)
+            {
+                data = new UserItemData();
+                item.AddUserData(user, data);
+            }
+
+            // Set favorite status
+            data.IsFavorite = QueryString["isfavorite"] == "1";
+
+            return Task.FromResult<DTOUserItemData>(ApiService.GetDTOUserItemData(data));
+        }
+    }
+}

+ 4 - 9
MediaBrowser.Api/HttpHandlers/ItemHandler.cs

@@ -7,6 +7,9 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Api.HttpHandlers
 {
+    /// <summary>
+    /// Provides a handler to retrieve a single item
+    /// </summary>
     [Export(typeof(BaseHandler))]
     public class ItemHandler : BaseSerializationHandler<DTOBaseItem>
     {
@@ -19,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers
         {
             User user = ApiService.GetUserById(QueryString["userid"], true);
 
-            BaseItem item = ItemToSerialize;
+            BaseItem item = ApiService.GetItemById(QueryString["id"]);
 
             if (item == null)
             {
@@ -28,13 +31,5 @@ namespace MediaBrowser.Api.HttpHandlers
 
             return ApiService.GetDTOBaseItem(item, user);
         }
-
-        protected virtual BaseItem ItemToSerialize
-        {
-            get
-            {
-                return ApiService.GetItemById(QueryString["id"]);
-            }
-        }
     }
 }

+ 5 - 1
MediaBrowser.Api/HttpHandlers/ItemListHandler.cs

@@ -17,7 +17,7 @@ namespace MediaBrowser.Api.HttpHandlers
         {
             return ApiService.IsApiUrlMatch("itemlist", request);
         }
-        
+
         protected override Task<DTOBaseItem[]> GetObjectToSerialize()
         {
             User user = ApiService.GetUserById(QueryString["userid"], true);
@@ -60,6 +60,10 @@ namespace MediaBrowser.Api.HttpHandlers
             {
                 return parent.GetItemsWithPerson(QueryString["name"], null, user);
             }
+            else if (ListType.Equals("favorites", StringComparison.OrdinalIgnoreCase))
+            {
+                return parent.GetFavoriteItems(user);
+            }
 
             throw new InvalidOperationException();
         }

+ 1 - 0
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -60,6 +60,7 @@
     <Compile Include="ApiService.cs" />
     <Compile Include="HttpHandlers\AudioHandler.cs" />
     <Compile Include="HttpHandlers\BaseMediaHandler.cs" />
+    <Compile Include="HttpHandlers\FavoriteStatusHandler.cs" />
     <Compile Include="HttpHandlers\UserHandler.cs" />
     <Compile Include="HttpHandlers\GenreHandler.cs" />
     <Compile Include="HttpHandlers\GenresHandler.cs" />

+ 0 - 2
MediaBrowser.ApiInteraction.Metro/DataSerializer.cs

@@ -19,7 +19,6 @@ namespace MediaBrowser.ApiInteraction
         {
             if (format == ApiInteraction.SerializationFormats.Protobuf)
             {
-                //return Serializer.Deserialize<T>(stream);
                 return ProtobufModelSerializer.Deserialize(stream, null, typeof(T)) as T;
             }
             else if (format == ApiInteraction.SerializationFormats.Jsv)
@@ -44,7 +43,6 @@ namespace MediaBrowser.ApiInteraction
         {
             if (format == ApiInteraction.SerializationFormats.Protobuf)
             {
-                //throw new NotImplementedException();
                 return ProtobufModelSerializer.Deserialize(stream, null, type);
             }
             else if (format == ApiInteraction.SerializationFormats.Jsv)

+ 60 - 5
MediaBrowser.ApiInteraction.Portable/ApiClient.cs

@@ -113,6 +113,23 @@ namespace MediaBrowser.ApiInteraction.Portable
             GetDataAsync(url, callback);
         }
 
+        /// <summary>
+        /// Gets favorite items
+        /// </summary>
+        /// <param name="userId">The user id.</param>
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public void GetFavoriteItemsAsync(Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
+        {
+            string url = ApiUrl + "/itemlist?listtype=favorites&userId=" + userId.ToString();
+
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
+            GetDataAsync(url, callback);
+        }
+
         /// <summary>
         /// Gets recently added items that are unplayed.
         /// </summary>
@@ -143,40 +160,60 @@ namespace MediaBrowser.ApiInteraction.Portable
         /// <summary>
         /// Gets all items that contain a given Year
         /// </summary>
-        public void GetItemsWithYearAsync(string name, Guid userId, Action<DTOBaseItem[]> callback)
+        public void GetItemsWithYearAsync(string name, Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             GetDataAsync(url, callback);
         }
 
         /// <summary>
         /// Gets all items that contain a given Genre
         /// </summary>
-        public void GetItemsWithGenreAsync(string name, Guid userId, Action<DTOBaseItem[]> callback)
+        public void GetItemsWithGenreAsync(string name, Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             GetDataAsync(url, callback);
         }
 
         /// <summary>
         /// Gets all items that contain a given Person
         /// </summary>
-        public void GetItemsWithPersonAsync(string name, Guid userId, Action<DTOBaseItem[]> callback)
+        public void GetItemsWithPersonAsync(string name, Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+            
             GetDataAsync(url, callback);
         }
 
         /// <summary>
         /// Gets all items that contain a given Person
         /// </summary>
-        public void GetItemsWithPersonAsync(string name, string personType, Guid userId, Action<DTOBaseItem[]> callback)
+        public void GetItemsWithPersonAsync(string name, string personType, Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+            
             url += "&persontype=" + personType;
 
             GetDataAsync(url, callback);
@@ -195,10 +232,15 @@ namespace MediaBrowser.ApiInteraction.Portable
         /// <summary>
         /// Gets all items that contain a given Studio
         /// </summary>
-        public void GetItemsWithStudioAsync(string name, Guid userId, Action<DTOBaseItem[]> callback)
+        public void GetItemsWithStudioAsync(string name, Guid userId, Action<DTOBaseItem[]> callback, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             GetDataAsync(url, callback);
         }
 
@@ -344,6 +386,19 @@ namespace MediaBrowser.ApiInteraction.Portable
             PostDataAsync(url, formValues, callback, SerializationFormat);
         }
 
+        /// <summary>
+        /// Updates a user's favorite status for an item and returns the updated UserItemData object.
+        /// </summary>
+        public void UpdateFavoriteStatusAsync(Guid itemId, Guid userId, bool isFavorite, Action<DTOUserItemData> callback)
+        {
+            string url = ApiUrl + "/favoritestatus?id=" + itemId;
+
+            url += "&userid=" + userId;
+            url += "&isfavorite=" + (isFavorite ? "1" : "0");
+
+            GetDataAsync(url, callback);
+        }
+        
         /// <summary>
         /// Performs a GET request, and deserializes the response stream to an object of Type T
         /// </summary>

+ 72 - 5
MediaBrowser.ApiInteraction/BaseHttpApiClient.cs

@@ -8,6 +8,7 @@ using System.Net;
 using System.Net.Http;
 using System.Text;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.ApiInteraction
 {
@@ -118,6 +119,26 @@ namespace MediaBrowser.ApiInteraction
             }
         }
 
+        /// <summary>
+        /// Gets favorite items
+        /// </summary>
+        /// <param name="userId">The user id.</param>
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetFavoriteItemsAsync(Guid userId, Guid? folderId = null)
+        {
+            string url = ApiUrl + "/itemlist?listtype=favorites&userId=" + userId.ToString();
+
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
+            using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
+            {
+                return DeserializeFromStream<DTOBaseItem[]>(stream);
+            }
+        }
+
         /// <summary>
         /// Gets recently added items that are unplayed.
         /// </summary>
@@ -154,10 +175,16 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// Gets all items that contain a given Year
         /// </summary>
-        public async Task<DTOBaseItem[]> GetItemsWithYearAsync(string name, Guid userId)
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetItemsWithYearAsync(string name, Guid userId, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
             {
                 return DeserializeFromStream<DTOBaseItem[]>(stream);
@@ -167,10 +194,16 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// Gets all items that contain a given Genre
         /// </summary>
-        public async Task<DTOBaseItem[]> GetItemsWithGenreAsync(string name, Guid userId)
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetItemsWithGenreAsync(string name, Guid userId, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
             {
                 return DeserializeFromStream<DTOBaseItem[]>(stream);
@@ -180,10 +213,16 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// Gets all items that contain a given Person
         /// </summary>
-        public async Task<DTOBaseItem[]> GetItemsWithPersonAsync(string name, Guid userId)
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetItemsWithPersonAsync(string name, Guid userId, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
             {
                 return DeserializeFromStream<DTOBaseItem[]>(stream);
@@ -193,12 +232,18 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// Gets all items that contain a given Person
         /// </summary>
-        public async Task<DTOBaseItem[]> GetItemsWithPersonAsync(string name, string personType, Guid userId)
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetItemsWithPersonAsync(string name, string personType, Guid userId, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
 
             url += "&persontype=" + personType;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
             {
                 return DeserializeFromStream<DTOBaseItem[]>(stream);
@@ -221,10 +266,16 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// Gets all items that contain a given Studio
         /// </summary>
-        public async Task<DTOBaseItem[]> GetItemsWithStudioAsync(string name, Guid userId)
+        /// <param name="folderId">(Optional) Specify a folder Id to localize the search to a specific folder.</param>
+        public async Task<DTOBaseItem[]> GetItemsWithStudioAsync(string name, Guid userId, Guid? folderId = null)
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name;
 
+            if (folderId.HasValue)
+            {
+                url += "&id=" + folderId.ToString();
+            }
+
             using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
             {
                 return DeserializeFromStream<DTOBaseItem[]>(stream);
@@ -387,6 +438,22 @@ namespace MediaBrowser.ApiInteraction
             }
         }
 
+        /// <summary>
+        /// Updates a user's favorite status for an item and returns the updated UserItemData object.
+        /// </summary>
+        public async Task<DTOUserItemData> UpdateFavoriteStatusAsync(Guid itemId, Guid userId, bool isFavorite)
+        {
+            string url = ApiUrl + "/favoritestatus?id=" + itemId;
+
+            url += "&userid=" + userId;
+            url += "&isfavorite=" + (isFavorite ? "1" : "0");
+
+            using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false))
+            {
+                return DeserializeFromStream<DTOUserItemData>(stream);
+            }
+        }
+
         /// <summary>
         /// Authenticates a user and returns the result
         /// </summary>

+ 3 - 3
MediaBrowser.Controller/Resolvers/VideoResolver.cs

@@ -1,7 +1,7 @@
-using System.ComponentModel.Composition;
-using System.IO;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
+using System.ComponentModel.Composition;
+using System.IO;
 
 namespace MediaBrowser.Controller.Resolvers
 {

+ 1 - 1
MediaBrowser.Model/DTO/DTOBaseItem.cs

@@ -145,7 +145,7 @@ namespace MediaBrowser.Model.DTO
         /// User data for this item based on the user it's being requested for
         /// </summary>
         [ProtoMember(40)]
-        public UserItemData UserData { get; set; }
+        public DTOUserItemData UserData { get; set; }
 
         [ProtoMember(41)]
         public ItemSpecialCounts SpecialCounts { get; set; }

+ 23 - 0
MediaBrowser.Model/DTO/DTOUserItemData.cs

@@ -0,0 +1,23 @@
+using ProtoBuf;
+
+namespace MediaBrowser.Model.DTO
+{
+    [ProtoContract]
+    public class DTOUserItemData
+    {
+        [ProtoMember(1)]
+        public float? Rating { get; set; }
+
+        [ProtoMember(2)]
+        public long PlaybackPositionTicks { get; set; }
+
+        [ProtoMember(3)]
+        public int PlayCount { get; set; }
+
+        [ProtoMember(4)]
+        public bool IsFavorite { get; set; }
+
+        [ProtoMember(5)]
+        public bool? Likes { get; set; }
+    }
+}

+ 1 - 1
MediaBrowser.Model/DTO/VideoOutputFormats.cs

@@ -2,7 +2,7 @@
 namespace MediaBrowser.Model.DTO
 {
     /// <summary>
-    /// These are the audio output formats that the api is cabaple of streaming
+    /// These are the video output formats that the api is cabaple of streaming
     /// This does not limit the inputs, only the outputs.
     /// </summary>
     public enum VideoOutputFormats

+ 18 - 0
MediaBrowser.Model/Entities/Folder.cs

@@ -96,6 +96,24 @@ namespace MediaBrowser.Model.Entities
             return GetParentalAllowedRecursiveChildren(user).Where(f => f.Studios != null && f.Studios.Any(s => s.Equals(studio, StringComparison.OrdinalIgnoreCase)));
         }
 
+        /// <summary>
+        /// Finds all recursive items within a top-level parent that the user has marked as a favorite
+        /// </summary>
+        public IEnumerable<BaseItem> GetFavoriteItems(User user)
+        {
+            return GetParentalAllowedRecursiveChildren(user).Where(c =>
+            {
+                UserItemData data = c.GetUserData(user);
+
+                if (data != null)
+                {
+                    return data.IsFavorite;
+                }
+
+                return false;
+            });
+        }
+
         /// <summary>
         /// Finds all recursive items within a top-level parent that contain the given person and are allowed for the current user
         /// </summary>

+ 54 - 12
MediaBrowser.Model/Entities/UserItemData.cs

@@ -1,25 +1,67 @@
 using System;
-using ProtoBuf;
+using System.Runtime.Serialization;
 
 namespace MediaBrowser.Model.Entities
 {
-    [ProtoContract]
     public class UserItemData
     {
-        [ProtoMember(1)]
-        public UserItemRating Rating { get; set; }
+        private float? _Rating = null;
+        /// <summary>
+        /// Gets or sets the users 0-10 rating
+        /// </summary>
+        public float? Rating
+        {
+            get
+            {
+                return _Rating;
+            }
+            set
+            {
+                if (value.HasValue)
+                {
+                    if (value.Value < 0 || value.Value > 10)
+                    {
+                        throw new InvalidOperationException("A 0-10 rating is required for UserItemData.");
+                    }
+                }
+
+                _Rating = value;
+            }
+        }
 
-        [ProtoMember(2)]
         public long PlaybackPositionTicks { get; set; }
 
-        [ProtoMember(3)]
         public int PlayCount { get; set; }
-    }
 
-    public enum UserItemRating
-    {
-        Likes,
-        Dislikes,
-        Favorite
+        public bool IsFavorite { get; set; }
+
+        /// <summary>
+        /// This is an interpreted property to indicate likes or dislikes
+        /// This should never be serialized.
+        /// </summary>
+        [IgnoreDataMember]
+        public bool? Likes
+        {
+            get
+            {
+                if (Rating != null)
+                {
+                    return Rating >= 6.5;
+                }
+
+                return null;
+            }
+            set
+            {
+                if (value.HasValue)
+                {
+                    Rating = value.Value ? 10 : 1;
+                }
+                else
+                {
+                    Rating = null;
+                }
+            }
+        }
     }
 }

+ 1 - 0
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -36,6 +36,7 @@
     <Compile Include="Configuration\ServerConfiguration.cs" />
     <Compile Include="DTO\AudioInfo.cs" />
     <Compile Include="DTO\AudioOutputFormats.cs" />
+    <Compile Include="DTO\DTOUserItemData.cs" />
     <Compile Include="DTO\SeriesInfo.cs" />
     <Compile Include="Authentication\AuthenticationResult.cs" />
     <Compile Include="DTO\DTOBaseItem.cs" />