Forráskód Böngészése

Added a completely separate DTOBaseItem to remove the ApiBaseItemWrapper mess and shrink json output size.

LukePulverenti Luke Pulverenti luke pulverenti 13 éve
szülő
commit
7835d690a1
31 módosított fájl, 581 hozzáadás és 364 törlés
  1. 99 48
      MediaBrowser.Api/ApiService.cs
  2. 0 1
      MediaBrowser.Api/HttpHandlers/GenresHandler.cs
  3. 6 3
      MediaBrowser.Api/HttpHandlers/ItemHandler.cs
  4. 7 7
      MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
  5. 0 1
      MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
  6. 1 1
      MediaBrowser.Api/HttpHandlers/UsersHandler.cs
  7. 8 8
      MediaBrowser.Api/HttpHandlers/VideoHandler.cs
  8. 0 1
      MediaBrowser.Api/HttpHandlers/YearsHandler.cs
  9. 42 25
      MediaBrowser.ApiInteraction/ApiClient.cs
  10. 0 11
      MediaBrowser.ApiInteraction/IHttpClient.cs
  11. 0 1
      MediaBrowser.ApiInteraction/MediaBrowser.ApiInteraction.csproj
  12. 0 1
      MediaBrowser.Controller/Configuration/ServerConfiguration.cs
  13. 1 2
      MediaBrowser.Controller/Kernel.cs
  14. 4 1
      MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
  15. 85 47
      MediaBrowser.Controller/Xml/BaseItemXmlParser.cs
  16. 0 67
      MediaBrowser.Model/DTO/ApiBaseItem.cs
  17. 86 0
      MediaBrowser.Model/DTO/DTOBaseItem.cs
  18. 2 2
      MediaBrowser.Model/DTO/IBNItem.cs
  19. 31 34
      MediaBrowser.Model/Entities/BaseItem.cs
  20. 105 39
      MediaBrowser.Model/Entities/Folder.cs
  21. 57 0
      MediaBrowser.Model/Entities/IHasProviderIds.cs
  22. 14 0
      MediaBrowser.Model/Entities/ItemSpecialCounts.cs
  23. 1 10
      MediaBrowser.Model/Entities/Person.cs
  24. 15 0
      MediaBrowser.Model/Entities/User.cs
  25. 3 4
      MediaBrowser.Model/Entities/UserItemData.cs
  26. 8 9
      MediaBrowser.Model/Entities/Video.cs
  27. 5 3
      MediaBrowser.Model/MediaBrowser.Model.csproj
  28. 0 34
      MediaBrowser.Model/Users/User.cs
  29. 0 2
      MediaBrowser.Movies/Entities/Movie.cs
  30. 0 1
      MediaBrowser.TV/Entities/Season.cs
  31. 1 1
      MediaBrowser.TV/Metadata/SeriesXmlParser.cs

+ 99 - 48
MediaBrowser.Api/ApiService.cs

@@ -6,7 +6,6 @@ using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
@@ -22,72 +21,91 @@ namespace MediaBrowser.Api
             return Kernel.Instance.GetItemById(guid);
             return Kernel.Instance.GetItemById(guid);
         }
         }
 
 
-        /// <summary>
-        /// Takes a BaseItem and returns the actual object that will be serialized by the api
-        /// </summary>
-        public static BaseItemContainer<BaseItem> GetSerializationObject(BaseItem item, bool includeChildren, Guid userId)
+        public static DTOBaseItem GetDTOBaseItem(BaseItem item, User user, 
+            bool includeChildren = true, 
+            bool includePeople = true)
         {
         {
-            User user = Kernel.Instance.Users.First(u => u.Id == userId);
-
-            BaseItemContainer<BaseItem> wrapper = new BaseItemContainer<BaseItem>()
-            {
-                Item = item,
-                UserItemData = user.GetItemData(item.Id),
-                Type = item.GetType().Name,
-                IsFolder = (item is Folder)
-            };
-
-            if (string.IsNullOrEmpty(item.LogoImagePath))
-            {
-                wrapper.ParentLogoItemId = GetParentLogoItemId(item);
-            }
-
-            if (item.BackdropImagePaths == null || !item.BackdropImagePaths.Any())
+            DTOBaseItem dto = new DTOBaseItem();
+
+            dto.AspectRatio = item.AspectRatio;
+            dto.BackdropCount = item.BackdropImagePaths == null ? 0 : item.BackdropImagePaths.Count();
+            dto.DateCreated = item.DateCreated;
+            dto.DisplayMediaType = item.DisplayMediaType;
+            dto.Genres = item.Genres;
+            dto.HasArt = !string.IsNullOrEmpty(item.ArtImagePath);
+            dto.HasBanner = !string.IsNullOrEmpty(item.BannerImagePath);
+            dto.HasLogo = !string.IsNullOrEmpty(item.LogoImagePath);
+            dto.HasPrimaryImage = !string.IsNullOrEmpty(item.LogoImagePath);
+            dto.HasThumb = !string.IsNullOrEmpty(item.ThumbnailImagePath);
+            dto.Id = item.Id;
+            dto.IndexNumber = item.IndexNumber;
+            dto.IsFolder = item is Folder;
+            dto.LocalTrailerCount = item.LocalTrailers == null ? 0 : item.LocalTrailers.Count();
+            dto.Name = item.Name;
+            dto.OfficialRating = item.OfficialRating;
+            dto.Overview = item.Overview;
+
+            // If there are no backdrops, indicate what parent has them in case the UI wants to allow inheritance
+            if (dto.BackdropCount == 0)
             {
             {
                 int backdropCount;
                 int backdropCount;
-                wrapper.ParentBackdropItemId = GetParentBackdropItemId(item, out backdropCount);
-                wrapper.ParentBackdropCount = backdropCount;
+                dto.ParentBackdropItemId = GetParentBackdropItemId(item, out backdropCount);
+                dto.ParentBackdropCount = backdropCount;
             }
             }
 
 
             if (item.Parent != null)
             if (item.Parent != null)
             {
             {
-                wrapper.ParentId = item.Parent.Id;
+                dto.ParentId = item.Parent.Id;
             }
             }
 
 
-            if (includeChildren)
+            // If there is no logo, indicate what parent has one in case the UI wants to allow inheritance
+            if (!dto.HasLogo)
             {
             {
-                var folder = item as Folder;
+                dto.ParentLogoItemId = GetParentLogoItemId(item);
+            }
 
 
-                if (folder != null)
-                {
-                    wrapper.Children = folder.GetParentalAllowedChildren(user).Select(c => GetSerializationObject(c, false, userId));
-                }
+            dto.Path = item.Path;
 
 
-                // Attach People by transforming them into BaseItemPerson (DTO)
-                if (item.People != null)
-                {
-                    wrapper.People = item.People.Select(p =>
-                    {
-                        BaseItemPerson baseItemPerson = new BaseItemPerson();
+            dto.PremiereDate = item.PremiereDate;
+            dto.ProductionYear = item.ProductionYear;
+            dto.ProviderIds = item.ProviderIds;
+            dto.RunTimeTicks = item.RunTimeTicks;
+            dto.SortName = item.SortName;
+            dto.Taglines = item.Taglines;
+            dto.TrailerUrl = item.TrailerUrl;
+            dto.Type = item.GetType().Name;
+            dto.UserRating = item.UserRating;
 
 
-                        baseItemPerson.PersonInfo = p;
+            dto.UserData = item.GetUserData(user);
 
 
-                        Person ibnObject = Kernel.Instance.ItemController.GetPerson(p.Name);
+            AttachStudios(dto, item);
 
 
-                        if (ibnObject != null)
-                        {
-                            baseItemPerson.PrimaryImagePath = ibnObject.PrimaryImagePath;
-                        }
+            if (includeChildren)
+            {
+                AttachChildren(dto, item, user);
+            }
 
 
-                        return baseItemPerson;
-                    });
-                }
+            if (includePeople)
+            {
+                AttachPeople(dto, item);
             }
             }
 
 
+            Folder folder = item as Folder;
+
+            if (folder != null)
+            {
+                dto.SpecialCounts = folder.GetSpecialCounts(user);
+            }
+            
+            return dto;
+        }
+
+        private static void AttachStudios(DTOBaseItem dto, BaseItem item)
+        {
             // Attach Studios by transforming them into BaseItemStudio (DTO)
             // Attach Studios by transforming them into BaseItemStudio (DTO)
             if (item.Studios != null)
             if (item.Studios != null)
             {
             {
-                wrapper.Studios = item.Studios.Select(s =>
+                dto.Studios = item.Studios.Select(s =>
                 {
                 {
                     BaseItemStudio baseItemStudio = new BaseItemStudio();
                     BaseItemStudio baseItemStudio = new BaseItemStudio();
 
 
@@ -97,14 +115,47 @@ namespace MediaBrowser.Api
 
 
                     if (ibnObject != null)
                     if (ibnObject != null)
                     {
                     {
-                        baseItemStudio.PrimaryImagePath = ibnObject.PrimaryImagePath;
+                        baseItemStudio.HasImage = !string.IsNullOrEmpty(ibnObject.PrimaryImagePath);
                     }
                     }
 
 
                     return baseItemStudio;
                     return baseItemStudio;
                 });
                 });
             }
             }
+        }
+
+        private static void AttachChildren(DTOBaseItem dto, BaseItem item, User user)
+        {
+            var folder = item as Folder;
+
+            if (folder != null)
+            {
+                dto.Children = folder.GetParentalAllowedChildren(user).Select(c => GetDTOBaseItem(c, user, false, false));
+            }
 
 
-            return wrapper;
+            dto.LocalTrailers = item.LocalTrailers;
+        }
+
+        private static void AttachPeople(DTOBaseItem dto, BaseItem item)
+        {
+            // Attach People by transforming them into BaseItemPerson (DTO)
+            if (item.People != null)
+            {
+                dto.People = item.People.Select(p =>
+                {
+                    BaseItemPerson baseItemPerson = new BaseItemPerson();
+
+                    baseItemPerson.PersonInfo = p;
+
+                    Person ibnObject = Kernel.Instance.ItemController.GetPerson(p.Name);
+
+                    if (ibnObject != null)
+                    {
+                        baseItemPerson.HasImage = !string.IsNullOrEmpty(ibnObject.PrimaryImagePath);
+                    }
+
+                    return baseItemPerson;
+                });
+            }
         }
         }
 
 
         private static Guid? GetParentBackdropItemId(BaseItem item, out int backdropCount)
         private static Guid? GetParentBackdropItemId(BaseItem item, out int backdropCount)

+ 0 - 1
MediaBrowser.Api/HttpHandlers/GenresHandler.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {

+ 6 - 3
MediaBrowser.Api/HttpHandlers/ItemHandler.cs

@@ -1,15 +1,18 @@
 using System;
 using System;
+using System.Linq;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {
-    public class ItemHandler : BaseJsonHandler<BaseItemContainer<BaseItem>>
+    public class ItemHandler : BaseJsonHandler<DTOBaseItem>
     {
     {
-        protected sealed override BaseItemContainer<BaseItem> GetObjectToSerialize()
+        protected sealed override DTOBaseItem GetObjectToSerialize()
         {
         {
             Guid userId = Guid.Parse(QueryString["userid"]);
             Guid userId = Guid.Parse(QueryString["userid"]);
+            User user = Kernel.Instance.Users.First(u => u.Id == userId);
 
 
             BaseItem item = ItemToSerialize;
             BaseItem item = ItemToSerialize;
 
 
@@ -18,7 +21,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 return null;
                 return null;
             }
             }
 
 
-            return ApiService.GetSerializationObject(item, true, userId);
+            return ApiService.GetDTOBaseItem(item, user);
         }
         }
 
 
         protected virtual BaseItem ItemToSerialize
         protected virtual BaseItem ItemToSerialize

+ 7 - 7
MediaBrowser.Api/HttpHandlers/ItemListHandler.cs

@@ -5,18 +5,18 @@ using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {
-    public class ItemListHandler : BaseJsonHandler<IEnumerable<BaseItemContainer<BaseItem>>>
+    public class ItemListHandler : BaseJsonHandler<IEnumerable<DTOBaseItem>>
     {
     {
-        protected override IEnumerable<BaseItemContainer<BaseItem>> GetObjectToSerialize()
+        protected override IEnumerable<DTOBaseItem> GetObjectToSerialize()
         {
         {
+            User user = Kernel.Instance.Users.First(u => u.Id == UserId);
+
             return ItemsToSerialize.Select(i =>
             return ItemsToSerialize.Select(i =>
             {
             {
-                return ApiService.GetSerializationObject(i, false, UserId);
-
+                return ApiService.GetDTOBaseItem(i, user, includeChildren: false, includePeople: false);
             });
             });
         }
         }
 
 
@@ -27,7 +27,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 Folder parent = ApiService.GetItemById(ItemId) as Folder;
                 Folder parent = ApiService.GetItemById(ItemId) as Folder;
 
 
                 User user = Kernel.Instance.Users.First(u => u.Id == UserId);
                 User user = Kernel.Instance.Users.First(u => u.Id == UserId);
-                
+
                 if (ListType.Equals("inprogressitems", StringComparison.OrdinalIgnoreCase))
                 if (ListType.Equals("inprogressitems", StringComparison.OrdinalIgnoreCase))
                 {
                 {
                     return parent.GetInProgressItems(user);
                     return parent.GetInProgressItems(user);
@@ -76,7 +76,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 return Guid.Parse(QueryString["userid"]);
                 return Guid.Parse(QueryString["userid"]);
             }
             }
         }
         }
-        
+
         private string ListType
         private string ListType
         {
         {
             get
             get

+ 0 - 1
MediaBrowser.Api/HttpHandlers/StudiosHandler.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {

+ 1 - 1
MediaBrowser.Api/HttpHandlers/UsersHandler.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
-using MediaBrowser.Model.Users;
+using MediaBrowser.Model.Entities;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {

+ 8 - 8
MediaBrowser.Api/HttpHandlers/VideoHandler.cs

@@ -48,11 +48,11 @@ namespace MediaBrowser.Api.HttpHandlers
                 return true;
                 return true;
             }
             }
 
 
-            AudioStream audio = LibraryItem.AudioStreams.FirstOrDefault();
+            AudioStream audioStream = (LibraryItem.AudioStreams ?? new AudioStream[] { }).FirstOrDefault();
 
 
-            if (audio != null)
+            if (audioStream != null)
             {
             {
-                if (RequiresAudioConversion(audio))
+                if (RequiresAudioConversion(audioStream))
                 {
                 {
                     return true;
                     return true;
                 }
                 }
@@ -121,7 +121,7 @@ namespace MediaBrowser.Api.HttpHandlers
 
 
         private string GetAudioArguments(string outputFormat)
         private string GetAudioArguments(string outputFormat)
         {
         {
-            AudioStream audioStream = LibraryItem.AudioStreams.FirstOrDefault();
+            AudioStream audioStream = (LibraryItem.AudioStreams ?? new AudioStream[] { }).FirstOrDefault();
 
 
             if (audioStream == null)
             if (audioStream == null)
             {
             {
@@ -261,7 +261,7 @@ namespace MediaBrowser.Api.HttpHandlers
                 }
                 }
             }
             }
 
 
-            if (LibraryItem.VideoCodec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || LibraryItem.VideoCodec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1)
+            if (LibraryItem.Codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || LibraryItem.Codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1)
             {
             {
                 return false;
                 return false;
             }
             }
@@ -279,15 +279,15 @@ namespace MediaBrowser.Api.HttpHandlers
                 }
                 }
             }
             }
 
 
-            if (audio.AudioFormat.IndexOf("aac", StringComparison.OrdinalIgnoreCase) != -1)
+            if (audio.Format.IndexOf("aac", StringComparison.OrdinalIgnoreCase) != -1)
             {
             {
                 return false;
                 return false;
             }
             }
-            if (audio.AudioFormat.IndexOf("ac-3", StringComparison.OrdinalIgnoreCase) != -1 || audio.AudioFormat.IndexOf("ac3", StringComparison.OrdinalIgnoreCase) != -1)
+            if (audio.Format.IndexOf("ac-3", StringComparison.OrdinalIgnoreCase) != -1 || audio.Format.IndexOf("ac3", StringComparison.OrdinalIgnoreCase) != -1)
             {
             {
                 return false;
                 return false;
             }
             }
-            if (audio.AudioFormat.IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1 || audio.AudioFormat.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1)
+            if (audio.Format.IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1 || audio.Format.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1)
             {
             {
                 return false;
                 return false;
             }
             }

+ 0 - 1
MediaBrowser.Api/HttpHandlers/YearsHandler.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Api.HttpHandlers
 namespace MediaBrowser.Api.HttpHandlers
 {
 {

+ 42 - 25
MediaBrowser.ApiInteraction/ApiClient.cs

@@ -1,16 +1,23 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
-using System.Linq;
+using System.Net;
+using System.Net.Http;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.DTO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.ApiInteraction
 namespace MediaBrowser.ApiInteraction
 {
 {
     public class ApiClient : IDisposable
     public class ApiClient : IDisposable
     {
     {
+        public ApiClient(HttpClientHandler handler)
+        {
+            handler.AutomaticDecompression = DecompressionMethods.Deflate;
+
+            HttpClient = new HttpClient(handler);
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the server host name (myserver or 192.168.x.x)
         /// Gets or sets the server host name (myserver or 192.168.x.x)
         /// </summary>
         /// </summary>
@@ -32,7 +39,7 @@ namespace MediaBrowser.ApiInteraction
             }
             }
         }
         }
 
 
-        public IHttpClient HttpClient { get; set; }
+        public HttpClient HttpClient { get; private set; }
         public IJsonSerializer JsonSerializer { get; set; }
         public IJsonSerializer JsonSerializer { get; set; }
 
 
         /// <summary>
         /// <summary>
@@ -84,26 +91,26 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// <summary>
         /// This is a helper to get a list of backdrop url's from a given ApiBaseItemWrapper. If the actual item does not have any backdrops it will return backdrops from the first parent that does.
         /// This is a helper to get a list of backdrop url's from a given ApiBaseItemWrapper. If the actual item does not have any backdrops it will return backdrops from the first parent that does.
         /// </summary>
         /// </summary>
-        /// <param name="itemWrapper">A given item.</param>
+        /// <param name="item">A given item.</param>
         /// <param name="width">Use if a fixed width is required. Aspect ratio will be preserved.</param>
         /// <param name="width">Use if a fixed width is required. Aspect ratio will be preserved.</param>
         /// <param name="height">Use if a fixed height is required. Aspect ratio will be preserved.</param>
         /// <param name="height">Use if a fixed height is required. Aspect ratio will be preserved.</param>
         /// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
         /// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
         /// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
         /// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
         /// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
         /// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
-        public IEnumerable<string> GetBackdropImageUrls(ApiBaseItemContainer itemWrapper, int? width = null, int? height = null, int? maxWidth = null, int? maxHeight = null, int? quality = null)
+        public IEnumerable<string> GetBackdropImageUrls(DTOBaseItem item, int? width = null, int? height = null, int? maxWidth = null, int? maxHeight = null, int? quality = null)
         {
         {
             Guid? backdropItemId = null;
             Guid? backdropItemId = null;
             int backdropCount = 0;
             int backdropCount = 0;
 
 
-            if (itemWrapper.Item.BackdropImagePaths == null || !itemWrapper.Item.BackdropImagePaths.Any())
+            if (item.BackdropCount == 0)
             {
             {
-                backdropItemId = itemWrapper.ParentBackdropItemId;
-                backdropCount = itemWrapper.ParentBackdropCount ?? 0;
+                backdropItemId = item.ParentBackdropItemId;
+                backdropCount = item.ParentBackdropCount ?? 0;
             }
             }
             else
             else
             {
             {
-                backdropItemId = itemWrapper.Item.Id;
-                backdropCount = itemWrapper.Item.BackdropImagePaths.Count();
+                backdropItemId = item.Id;
+                backdropCount = item.BackdropCount;
             }
             }
 
 
             if (backdropItemId == null)
             if (backdropItemId == null)
@@ -124,15 +131,15 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// <summary>
         /// This is a helper to get the logo image url from a given ApiBaseItemWrapper. If the actual item does not have a logo, it will return the logo from the first parent that does, or null.
         /// This is a helper to get the logo image url from a given ApiBaseItemWrapper. If the actual item does not have a logo, it will return the logo from the first parent that does, or null.
         /// </summary>
         /// </summary>
-        /// <param name="itemWrapper">A given item.</param>
+        /// <param name="item">A given item.</param>
         /// <param name="width">Use if a fixed width is required. Aspect ratio will be preserved.</param>
         /// <param name="width">Use if a fixed width is required. Aspect ratio will be preserved.</param>
         /// <param name="height">Use if a fixed height is required. Aspect ratio will be preserved.</param>
         /// <param name="height">Use if a fixed height is required. Aspect ratio will be preserved.</param>
         /// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
         /// <param name="maxWidth">Use if a max width is required. Aspect ratio will be preserved.</param>
         /// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
         /// <param name="maxHeight">Use if a max height is required. Aspect ratio will be preserved.</param>
         /// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
         /// <param name="quality">Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.</param>
-        public string GetLogoImageUrl(ApiBaseItemContainer itemWrapper, int? width = null, int? height = null, int? maxWidth = null, int? maxHeight = null, int? quality = null)
+        public string GetLogoImageUrl(DTOBaseItem item, int? width = null, int? height = null, int? maxWidth = null, int? maxHeight = null, int? quality = null)
         {
         {
-            Guid? logoItemId = !string.IsNullOrEmpty(itemWrapper.Item.LogoImagePath) ? itemWrapper.Item.Id : itemWrapper.ParentLogoItemId;
+            Guid? logoItemId = item.HasLogo ? item.Id : item.ParentLogoItemId;
 
 
             if (logoItemId.HasValue)
             if (logoItemId.HasValue)
             {
             {
@@ -153,7 +160,7 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// <summary>
         /// Gets a BaseItem
         /// Gets a BaseItem
         /// </summary>
         /// </summary>
-        public async Task<ApiBaseItemContainer> GetItemAsync(Guid id, Guid userId)
+        public async Task<DTOBaseItem> GetItemAsync(Guid id, Guid userId)
         {
         {
             string url = ApiUrl + "/item?userId=" + userId.ToString();
             string url = ApiUrl + "/item?userId=" + userId.ToString();
 
 
@@ -164,7 +171,7 @@ namespace MediaBrowser.ApiInteraction
 
 
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                return JsonSerializer.DeserializeFromStream<ApiBaseItemContainer>(stream);
+                return JsonSerializer.DeserializeFromStream<DTOBaseItem>(stream);
             }
             }
         }
         }
 
 
@@ -210,44 +217,54 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// <summary>
         /// Gets all items that contain a given Year
         /// Gets all items that contain a given Year
         /// </summary>
         /// </summary>
-        public async Task<IEnumerable<ApiBaseItemContainer>> GetItemsWithYearAsync(string name, Guid userId)
+        public async Task<IEnumerable<DTOBaseItem>> GetItemsWithYearAsync(string name, Guid userId)
         {
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name;
             string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name;
 
 
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                return JsonSerializer.DeserializeFromStream<IEnumerable<ApiBaseItemContainer>>(stream);
+                return JsonSerializer.DeserializeFromStream<IEnumerable<DTOBaseItem>>(stream);
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Gets all items that contain a given Genre
         /// Gets all items that contain a given Genre
         /// </summary>
         /// </summary>
-        public async Task<IEnumerable<ApiBaseItemContainer>> GetItemsWithGenreAsync(string name, Guid userId)
+        public async Task<IEnumerable<DTOBaseItem>> GetItemsWithGenreAsync(string name, Guid userId)
         {
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name;
             string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name;
 
 
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                return JsonSerializer.DeserializeFromStream<IEnumerable<ApiBaseItemContainer>>(stream);
+                return JsonSerializer.DeserializeFromStream<IEnumerable<DTOBaseItem>>(stream);
             }
             }
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Gets all items that contain a given Person
         /// Gets all items that contain a given Person
         /// </summary>
         /// </summary>
-        public async Task<IEnumerable<ApiBaseItemContainer>> GetItemsWithPersonAsync(string name, PersonType? personType, Guid userId)
+        public async Task<IEnumerable<DTOBaseItem>> GetItemsWithPersonAsync(string name, Guid userId)
         {
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
             string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
 
 
-            if (personType.HasValue)
+            using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                url += "&persontype=" + personType.Value.ToString();
+                return JsonSerializer.DeserializeFromStream<IEnumerable<DTOBaseItem>>(stream);
             }
             }
+        }
+        
+        /// <summary>
+        /// Gets all items that contain a given Person
+        /// </summary>
+        public async Task<IEnumerable<DTOBaseItem>> GetItemsWithPersonAsync(string name, string personType, Guid userId)
+        {
+            string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name;
+
+            url += "&persontype=" + personType;
 
 
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                return JsonSerializer.DeserializeFromStream<IEnumerable<ApiBaseItemContainer>>(stream);
+                return JsonSerializer.DeserializeFromStream<IEnumerable<DTOBaseItem>>(stream);
             }
             }
         }
         }
 
 
@@ -267,13 +284,13 @@ namespace MediaBrowser.ApiInteraction
         /// <summary>
         /// <summary>
         /// Gets all items that contain a given Studio
         /// Gets all items that contain a given Studio
         /// </summary>
         /// </summary>
-        public async Task<IEnumerable<ApiBaseItemContainer>> GetItemsWithStudioAsync(string name, Guid userId)
+        public async Task<IEnumerable<DTOBaseItem>> GetItemsWithStudioAsync(string name, Guid userId)
         {
         {
             string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name;
             string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name;
 
 
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             using (Stream stream = await HttpClient.GetStreamAsync(url))
             {
             {
-                return JsonSerializer.DeserializeFromStream<IEnumerable<ApiBaseItemContainer>>(stream);
+                return JsonSerializer.DeserializeFromStream<IEnumerable<DTOBaseItem>>(stream);
             }
             }
         }
         }
 
 

+ 0 - 11
MediaBrowser.ApiInteraction/IHttpClient.cs

@@ -1,11 +0,0 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.ApiInteraction
-{
-    public interface IHttpClient : IDisposable  
-    {
-        Task<Stream> GetStreamAsync(string url);
-    }
-}

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

@@ -40,7 +40,6 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="ApiClient.cs" />
     <Compile Include="ApiClient.cs" />
-    <Compile Include="IHttpClient.cs" />
     <Compile Include="IJsonSerializer.cs" />
     <Compile Include="IJsonSerializer.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   </ItemGroup>

+ 0 - 1
MediaBrowser.Controller/Configuration/ServerConfiguration.cs

@@ -5,6 +5,5 @@ namespace MediaBrowser.Controller.Configuration
 {
 {
     public class ServerConfiguration : BaseApplicationConfiguration
     public class ServerConfiguration : BaseApplicationConfiguration
     {
     {
-        public string ImagesByNamePath { get; set; }
     }
     }
 }
 }

+ 1 - 2
MediaBrowser.Controller/Kernel.cs

@@ -14,7 +14,6 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Progress;
 using MediaBrowser.Model.Progress;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Controller
 namespace MediaBrowser.Controller
 {
 {
@@ -193,7 +192,7 @@ namespace MediaBrowser.Controller
                 return RootFolder;
                 return RootFolder;
             }
             }
 
 
-            return RootFolder.FindById(id);
+            return RootFolder.FindItemById(id);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 4 - 1
MediaBrowser.Controller/Resolvers/BaseItemResolver.cs

@@ -137,7 +137,10 @@ namespace MediaBrowser.Controller.Resolvers
                 }
                 }
             }
             }
 
 
-            item.BackdropImagePaths = backdropFiles;
+            if (backdropFiles.Any())
+            {
+                item.BackdropImagePaths = backdropFiles;
+            }
         }
         }
 
 
         protected virtual void PopulateLocalTrailers(T item, ItemResolveEventArgs args)
         protected virtual void PopulateLocalTrailers(T item, ItemResolveEventArgs args)

+ 85 - 47
MediaBrowser.Controller/Xml/BaseItemXmlParser.cs

@@ -101,8 +101,24 @@ namespace MediaBrowser.Controller.Xml
                     break;
                     break;
 
 
                 case "TagLine":
                 case "TagLine":
-                    item.Tagline = reader.ReadString();
-                    break;
+                    {
+                        var list = (item.Taglines ?? new string[] { }).ToList();
+                        var tagline = reader.ReadString();
+
+                        if (!list.Contains(tagline))
+                        {
+                            list.Add(tagline);
+                        }
+
+                        item.Taglines = list;
+                        break;
+                    }
+
+                case "TagLines":
+                    {
+                        FetchFromTaglinesNode(reader.ReadSubtree(), item);
+                        break;
+                    }
 
 
                 case "ContentRating":
                 case "ContentRating":
                 case "MPAARating":
                 case "MPAARating":
@@ -138,7 +154,7 @@ namespace MediaBrowser.Controller.Xml
                 case "Director":
                 case "Director":
                     {
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
-                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Director }));
+                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, Type = "Director" }));
 
 
                         item.People = list;
                         item.People = list;
                         break;
                         break;
@@ -146,7 +162,7 @@ namespace MediaBrowser.Controller.Xml
                 case "Writer":
                 case "Writer":
                     {
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
-                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Writer }));
+                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, Type = "Writer" }));
 
 
                         item.People = list;
                         item.People = list;
                         break;
                         break;
@@ -156,7 +172,7 @@ namespace MediaBrowser.Controller.Xml
                 case "GuestStars":
                 case "GuestStars":
                     {
                     {
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
                         var list = (item.People ?? new PersonInfo[] { }).ToList();
-                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, PersonType = PersonType.Actor }));
+                        list.AddRange(GetSplitValues(reader.ReadString(), '|').Select(v => new PersonInfo() { Name = v, Type = "Actor" }));
 
 
                         item.People = list;
                         item.People = list;
                         break;
                         break;
@@ -287,7 +303,7 @@ namespace MediaBrowser.Controller.Xml
                             {
                             {
                                 AudioStream stream = FetchMediaInfoAudio(reader.ReadSubtree());
                                 AudioStream stream = FetchMediaInfoAudio(reader.ReadSubtree());
 
 
-                                List<AudioStream> streams = item.AudioStreams.ToList();
+                                List<AudioStream> streams = (item.AudioStreams ?? new AudioStream[] { }).ToList();
                                 streams.Add(stream);
                                 streams.Add(stream);
                                 item.AudioStreams = streams;
                                 item.AudioStreams = streams;
 
 
@@ -322,6 +338,14 @@ namespace MediaBrowser.Controller.Xml
                 {
                 {
                     switch (reader.Name)
                     switch (reader.Name)
                     {
                     {
+                        case "Default":
+                            stream.IsDefault = reader.ReadString() == "True";
+                            break;
+
+                        case "Forced":
+                            stream.IsForced = reader.ReadString() == "True";
+                            break;
+
                         case "BitRate":
                         case "BitRate":
                             stream.BitRate = reader.ReadIntSafe();
                             stream.BitRate = reader.ReadIntSafe();
                             break;
                             break;
@@ -343,40 +367,40 @@ namespace MediaBrowser.Controller.Xml
                                     case "dts-es":
                                     case "dts-es":
                                     case "dts-es matrix":
                                     case "dts-es matrix":
                                     case "dts-es discrete":
                                     case "dts-es discrete":
-                                        stream.AudioFormat = "DTS";
-                                        stream.AudioProfile = "ES";
+                                        stream.Format = "DTS";
+                                        stream.Profile = "ES";
                                         break;
                                         break;
                                     case "dts-hd hra":
                                     case "dts-hd hra":
                                     case "dts-hd high resolution":
                                     case "dts-hd high resolution":
-                                        stream.AudioFormat = "DTS";
-                                        stream.AudioProfile = "HRA";
+                                        stream.Format = "DTS";
+                                        stream.Profile = "HRA";
                                         break;
                                         break;
                                     case "dts ma":
                                     case "dts ma":
                                     case "dts-hd ma":
                                     case "dts-hd ma":
                                     case "dts-hd master":
                                     case "dts-hd master":
-                                        stream.AudioFormat = "DTS";
-                                        stream.AudioProfile = "MA";
+                                        stream.Format = "DTS";
+                                        stream.Profile = "MA";
                                         break;
                                         break;
                                     case "dolby digital":
                                     case "dolby digital":
                                     case "dolby digital surround ex":
                                     case "dolby digital surround ex":
                                     case "dolby surround":
                                     case "dolby surround":
-                                        stream.AudioFormat = "AC-3";
+                                        stream.Format = "AC-3";
                                         break;
                                         break;
                                     case "dolby digital plus":
                                     case "dolby digital plus":
-                                        stream.AudioFormat = "E-AC-3";
+                                        stream.Format = "E-AC-3";
                                         break;
                                         break;
                                     case "dolby truehd":
                                     case "dolby truehd":
-                                        stream.AudioFormat = "AC-3";
-                                        stream.AudioProfile = "TrueHD";
+                                        stream.Format = "AC-3";
+                                        stream.Profile = "TrueHD";
                                         break;
                                         break;
                                     case "mp2":
                                     case "mp2":
-                                        stream.AudioFormat = "MPEG Audio";
-                                        stream.AudioProfile = "Layer 2";
+                                        stream.Format = "MPEG Audio";
+                                        stream.Profile = "Layer 2";
                                         break;
                                         break;
                                     case "other":
                                     case "other":
                                         break;
                                         break;
                                     default:
                                     default:
-                                        stream.AudioFormat = codec;
+                                        stream.Format = codec;
                                         break;
                                         break;
                                 }
                                 }
 
 
@@ -412,7 +436,7 @@ namespace MediaBrowser.Controller.Xml
                             break;
                             break;
 
 
                         case "BitRate":
                         case "BitRate":
-                            item.VideoBitRate = reader.ReadIntSafe();
+                            item.BitRate = reader.ReadIntSafe();
                             break;
                             break;
 
 
                         case "FrameRate":
                         case "FrameRate":
@@ -424,14 +448,14 @@ namespace MediaBrowser.Controller.Xml
                             break;
                             break;
 
 
                         case "Duration":
                         case "Duration":
-                            item.RunTimeInMilliseconds = reader.ReadIntSafe() * 60000;
+                            item.RunTimeTicks = TimeSpan.FromMinutes(reader.ReadIntSafe()).Ticks;
                             break;
                             break;
 
 
                         case "DurationSeconds":
                         case "DurationSeconds":
                             int seconds = reader.ReadIntSafe();
                             int seconds = reader.ReadIntSafe();
                             if (seconds > 0)
                             if (seconds > 0)
                             {
                             {
-                                item.RunTimeInMilliseconds = seconds * 1000;
+                                item.RunTimeTicks = TimeSpan.FromSeconds(seconds).Ticks;
                             }
                             }
                             break;
                             break;
 
 
@@ -442,16 +466,16 @@ namespace MediaBrowser.Controller.Xml
                                 switch (videoCodec.ToLower())
                                 switch (videoCodec.ToLower())
                                 {
                                 {
                                     case "sorenson h.263":
                                     case "sorenson h.263":
-                                        item.VideoCodec = "Sorenson H263";
+                                        item.Codec = "Sorenson H263";
                                         break;
                                         break;
                                     case "h.262":
                                     case "h.262":
-                                        item.VideoCodec = "MPEG-2 Video";
+                                        item.Codec = "MPEG-2 Video";
                                         break;
                                         break;
                                     case "h.264":
                                     case "h.264":
-                                        item.VideoCodec = "AVC";
+                                        item.Codec = "AVC";
                                         break;
                                         break;
                                     default:
                                     default:
-                                        item.VideoCodec = videoCodec;
+                                        item.Codec = videoCodec;
                                         break;
                                         break;
                                 }
                                 }
 
 
@@ -499,6 +523,39 @@ namespace MediaBrowser.Controller.Xml
             item.Subtitles = list;
             item.Subtitles = list;
         }
         }
 
 
+        private void FetchFromTaglinesNode(XmlReader reader, T item)
+        {
+            List<string> list = (item.Taglines ?? new string[] { }).ToList();
+
+            reader.MoveToContent();
+
+            while (reader.Read())
+            {
+                if (reader.NodeType == XmlNodeType.Element)
+                {
+                    switch (reader.Name)
+                    {
+                        case "Tagline":
+                            {
+                                string val = reader.ReadString();
+
+                                if (!string.IsNullOrWhiteSpace(val))
+                                {
+                                    list.Add(val);
+                                }
+                                break;
+                            }
+
+                        default:
+                            reader.Skip();
+                            break;
+                    }
+                }
+            }
+
+            item.Taglines = list;
+        }
+
         private void FetchFromGenresNode(XmlReader reader, T item)
         private void FetchFromGenresNode(XmlReader reader, T item)
         {
         {
             List<string> list = (item.Genres ?? new string[] { }).ToList();
             List<string> list = (item.Genres ?? new string[] { }).ToList();
@@ -668,27 +725,8 @@ namespace MediaBrowser.Controller.Xml
                             break;
                             break;
 
 
                         case "Type":
                         case "Type":
-                            {
-                                string type = reader.ReadString();
-
-                                if (type.Equals("Director", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    person.PersonType = PersonType.Director;
-                                }
-                                else if (type.Equals("Actor", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    person.PersonType = PersonType.Actor;
-                                }
-                                else if (type.Equals("Writer", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    person.PersonType = PersonType.Writer;
-                                }
-                                else if (type.Equals("Producer", StringComparison.OrdinalIgnoreCase))
-                                {
-                                    person.PersonType = PersonType.Producer;
-                                }
-                                break;
-                            }
+                            person.Type = reader.ReadString();
+                            break;
 
 
                         case "Role":
                         case "Role":
                             person.Overview = reader.ReadString();
                             person.Overview = reader.ReadString();

+ 0 - 67
MediaBrowser.Model/DTO/ApiBaseItem.cs

@@ -1,67 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Users;
-
-namespace MediaBrowser.Model.DTO
-{
-    /// <summary>
-    /// This is a concrete class that the UI can use to deserialize
-    /// It is flat in the sense that it will be used regardless of the type of BaseItem involved
-    /// </summary>
-    public class ApiBaseItem : BaseItem
-    {
-        // Series properties
-        public string Status { get; set; }
-        public IEnumerable<DayOfWeek> AirDays { get; set; }
-        public string AirTime { get; set; }
-    }
-
-    /// <summary>
-    /// This is the full return object when requesting an Item
-    /// </summary>
-    public class BaseItemContainer<TItemType>
-        where TItemType : BaseItem
-    {
-        public TItemType Item { get; set; }
-
-        public UserItemData UserItemData { get; set; }
-
-        public IEnumerable<BaseItemContainer<TItemType>> Children { get; set; }
-
-        public bool IsFolder { get; set; }
-
-        public Guid? ParentId { get; set; }
-
-        public string Type { get; set; }
-
-        public bool IsType(Type type)
-        {
-            return IsType(type.Name);
-        }
-
-        public bool IsType(string type)
-        {
-            return Type.Equals(type, StringComparison.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<BaseItemPerson> People { get; set; }
-        public IEnumerable<BaseItemStudio> Studios { get; set; }
-
-        /// <summary>
-        /// If the item does not have a logo, this will hold the Id of the Parent that has one.
-        /// </summary>
-        public Guid? ParentLogoItemId { get; set; }
-
-        public Guid? ParentBackdropItemId { get; set; }
-
-        public int? ParentBackdropCount { get; set; }
-    }
-
-    /// <summary>
-    /// This is strictly for convenience so the UI's don't have to use the verbose generic syntax of BaseItemWrapper<ApiBaseItem>
-    /// </summary>
-    public class ApiBaseItemContainer : BaseItemContainer<ApiBaseItem>
-    {
-    }
-}

+ 86 - 0
MediaBrowser.Model/DTO/DTOBaseItem.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Model.DTO
+{
+    public class DTOBaseItem : IHasProviderIds
+    {
+        public string Name { get; set; }
+        public Guid Id { get; set; }
+        public DateTime DateCreated { get; set; }
+
+        public string SortName { get; set; }
+        public DateTime? PremiereDate { get; set; }
+        public string Path { get; set; }
+        public string OfficialRating { get; set; }
+        public string Overview { get; set; }
+        public IEnumerable<string> Taglines { get; set; }
+
+        public IEnumerable<string> Genres { get; set; }
+
+        public string DisplayMediaType { get; set; }
+
+        public float? UserRating { get; set; }
+        public long? RunTimeTicks { get; set; }
+
+        public string AspectRatio { get; set; }
+        public int? ProductionYear { get; set; }
+
+        public int? IndexNumber { get; set; }
+
+        public string TrailerUrl { get; set; }
+
+        public Dictionary<string, string> ProviderIds { get; set; }
+
+        public bool HasBanner { get; set; }
+        public bool HasArt { get; set; }
+        public bool HasLogo { get; set; }
+        public bool HasThumb { get; set; }
+        public bool HasPrimaryImage { get; set; }
+
+        public int BackdropCount { get; set; }
+
+        public IEnumerable<DTOBaseItem> Children { get; set; }
+
+        public bool IsFolder { get; set; }
+
+        public Guid? ParentId { get; set; }
+
+        public string Type { get; set; }
+
+        public IEnumerable<BaseItemPerson> People { get; set; }
+        public IEnumerable<BaseItemStudio> Studios { get; set; }
+
+        /// <summary>
+        /// If the item does not have a logo, this will hold the Id of the Parent that has one.
+        /// </summary>
+        public Guid? ParentLogoItemId { get; set; }
+
+        /// <summary>
+        /// If the item does not have any backdrops, this will hold the Id of the Parent that has one.
+        /// </summary>
+        public Guid? ParentBackdropItemId { get; set; }
+        public int? ParentBackdropCount { get; set; }
+
+        public IEnumerable<Video> LocalTrailers { get; set; }
+        public int LocalTrailerCount { get; set; }
+
+        /// <summary>
+        /// User data for this item based on the user it's being requested for
+        /// </summary>
+        public UserItemData UserData { get; set; }
+
+        public ItemSpecialCounts SpecialCounts { get; set; }
+
+        public bool IsType(Type type)
+        {
+            return IsType(type.Name);
+        }
+
+        public bool IsType(string type)
+        {
+            return Type.Equals(type, StringComparison.OrdinalIgnoreCase);
+        }
+    }
+}

+ 2 - 2
MediaBrowser.Model/DTO/IBNItem.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.Model.DTO
     public class BaseItemPerson
     public class BaseItemPerson
     {
     {
         public PersonInfo PersonInfo { get; set; }
         public PersonInfo PersonInfo { get; set; }
-        public string PrimaryImagePath { get; set; }
+        public bool HasImage { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -33,6 +33,6 @@ namespace MediaBrowser.Model.DTO
     public class BaseItemStudio
     public class BaseItemStudio
     {
     {
         public string Name { get; set; }
         public string Name { get; set; }
-        public string PrimaryImagePath { get; set; }
+        public bool HasImage { get; set; }
     }
     }
 }
 }

+ 31 - 34
MediaBrowser.Model/Entities/BaseItem.cs

@@ -1,11 +1,10 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Runtime.Serialization;
-using MediaBrowser.Model.Users;
+using System.Linq;
 
 
 namespace MediaBrowser.Model.Entities
 namespace MediaBrowser.Model.Entities
 {
 {
-    public abstract class BaseItem : BaseEntity
+    public abstract class BaseItem : BaseEntity, IHasProviderIds
     {
     {
         public string SortName { get; set; }
         public string SortName { get; set; }
 
 
@@ -16,25 +15,25 @@ namespace MediaBrowser.Model.Entities
 
 
         public string Path { get; set; }
         public string Path { get; set; }
 
 
-        [IgnoreDataMember]
         public Folder Parent { get; set; }
         public Folder Parent { get; set; }
 
 
         public string LogoImagePath { get; set; }
         public string LogoImagePath { get; set; }
+
         public string ArtImagePath { get; set; }
         public string ArtImagePath { get; set; }
+
         public string ThumbnailImagePath { get; set; }
         public string ThumbnailImagePath { get; set; }
+
         public string BannerImagePath { get; set; }
         public string BannerImagePath { get; set; }
 
 
         public IEnumerable<string> BackdropImagePaths { get; set; }
         public IEnumerable<string> BackdropImagePaths { get; set; }
 
 
         public string OfficialRating { get; set; }
         public string OfficialRating { get; set; }
         
         
-        [IgnoreDataMember]
         public string CustomRating { get; set; }
         public string CustomRating { get; set; }
 
 
         public string Overview { get; set; }
         public string Overview { get; set; }
-        public string Tagline { get; set; }
+        public IEnumerable<string> Taglines { get; set; }
 
 
-        [IgnoreDataMember]
         public IEnumerable<PersonInfo> People { get; set; }
         public IEnumerable<PersonInfo> People { get; set; }
 
 
         public IEnumerable<string> Studios { get; set; }
         public IEnumerable<string> Studios { get; set; }
@@ -44,7 +43,7 @@ namespace MediaBrowser.Model.Entities
         public string DisplayMediaType { get; set; }
         public string DisplayMediaType { get; set; }
 
 
         public float? UserRating { get; set; }
         public float? UserRating { get; set; }
-        public int? RunTimeInMilliseconds { get; set; }
+        public long? RunTimeTicks { get; set; }
 
 
         public string AspectRatio { get; set; }
         public string AspectRatio { get; set; }
         public int? ProductionYear { get; set; }
         public int? ProductionYear { get; set; }
@@ -61,54 +60,52 @@ namespace MediaBrowser.Model.Entities
 
 
         public Dictionary<string, string> ProviderIds { get; set; }
         public Dictionary<string, string> ProviderIds { get; set; }
 
 
-        /// <summary>
-        /// Gets a provider id
-        /// </summary>
-        public string GetProviderId(MetadataProviders provider)
-        {
-            return GetProviderId(provider.ToString());
-        }
+        public Dictionary<Guid, UserItemData> UserData { get; set; }
 
 
-        /// <summary>
-        /// Gets a provider id
-        /// </summary>
-        public string GetProviderId(string name)
+        public UserItemData GetUserData(User user)
         {
         {
-            if (ProviderIds == null)
+            if (UserData == null || !UserData.ContainsKey(user.Id))
             {
             {
                 return null;
                 return null;
             }
             }
 
 
-            return ProviderIds[name];
+            return UserData[user.Id];
         }
         }
 
 
-        /// <summary>
-        /// Sets a provider id
-        /// </summary>
-        public void SetProviderId(string name, string value)
+        public void AddUserData(User user, UserItemData data)
         {
         {
-            if (ProviderIds == null)
+            if (UserData == null)
             {
             {
-                ProviderIds = new Dictionary<string, string>();
+                UserData = new Dictionary<Guid, UserItemData>();
             }
             }
 
 
-            ProviderIds[name] = value;
+            UserData[user.Id] = data;
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Sets a provider id
+        /// Determines if a given user has access to this item
         /// </summary>
         /// </summary>
-        public void SetProviderId(MetadataProviders provider, string value)
+        internal bool IsParentalAllowed(User user)
         {
         {
-            SetProviderId(provider.ToString(), value);
+            return true;
         }
         }
 
 
         /// <summary>
         /// <summary>
-        /// Determines if a given user has access to this item
+        /// Finds an item by ID, recursively
         /// </summary>
         /// </summary>
-        internal bool IsParentalAllowed(User user)
+        public virtual BaseItem FindItemById(Guid id)
         {
         {
-            return true;
+            if (Id == id)
+            {
+                return this;
+            }
+
+            if (LocalTrailers != null)
+            {
+                return LocalTrailers.FirstOrDefault(i => i.Id == id);
+            }
+
+            return null;
         }
         }
     }
     }
 }
 }

+ 105 - 39
MediaBrowser.Model/Entities/Folder.cs

@@ -1,8 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
-using System.Runtime.Serialization;
-using MediaBrowser.Model.Users;
 
 
 namespace MediaBrowser.Model.Entities
 namespace MediaBrowser.Model.Entities
 {
 {
@@ -18,7 +16,6 @@ namespace MediaBrowser.Model.Entities
             }
             }
         }
         }
 
 
-        [IgnoreDataMember]
         public BaseItem[] Children { get; set; }
         public BaseItem[] Children { get; set; }
 
 
         /// <summary>
         /// <summary>
@@ -50,6 +47,23 @@ namespace MediaBrowser.Model.Entities
             }
             }
         }
         }
 
 
+        /// <summary>
+        /// Since it can be slow to make all of these calculations at once, this method will provide a way to get them all back together
+        /// </summary>
+        public ItemSpecialCounts GetSpecialCounts(User user)
+        {
+            ItemSpecialCounts counts = new ItemSpecialCounts();
+
+            IEnumerable<BaseItem> recursiveChildren = GetParentalAllowedRecursiveChildren(user);
+
+            counts.RecentlyAddedItemCount = GetRecentlyAddedItems(recursiveChildren, user).Count();
+            counts.RecentlyAddedUnPlayedItemCount = GetRecentlyAddedUnplayedItems(recursiveChildren, user).Count();
+            counts.InProgressItemCount = GetInProgressItems(recursiveChildren, user).Count();
+            counts.WatchedPercentage = GetWatchedPercentage(recursiveChildren, user);
+
+            return counts;
+        }
+
         /// <summary>
         /// <summary>
         /// Finds all recursive items within a top-level parent that contain the given genre and are allowed for the current user
         /// Finds all recursive items within a top-level parent that contain the given genre and are allowed for the current user
         /// </summary>
         /// </summary>
@@ -74,24 +88,33 @@ namespace MediaBrowser.Model.Entities
             return GetParentalAllowedRecursiveChildren(user).Where(f => f.Studios != null && f.Studios.Any(s => s.Equals(studio, StringComparison.OrdinalIgnoreCase)));
             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 contain the given person and are allowed for the current user
+        /// </summary>
+        public IEnumerable<BaseItem> GetItemsWithPerson(string person, User user)
+        {
+            return GetParentalAllowedRecursiveChildren(user).Where(c =>
+            {
+                if (c.People != null)
+                {
+                    return c.People.Any(p => p.Name.Equals(person, StringComparison.OrdinalIgnoreCase));
+                }
+
+                return false;
+            });
+        }
+
         /// <summary>
         /// <summary>
         /// Finds all recursive items within a top-level parent that contain the given person and are allowed for the current user
         /// Finds all recursive items within a top-level parent that contain the given person and are allowed for the current user
         /// </summary>
         /// </summary>
         /// <param name="personType">Specify this to limit results to a specific PersonType</param>
         /// <param name="personType">Specify this to limit results to a specific PersonType</param>
-        public IEnumerable<BaseItem> GetItemsWithPerson(string person, PersonType? personType, User user)
+        public IEnumerable<BaseItem> GetItemsWithPerson(string person, string personType, User user)
         {
         {
             return GetParentalAllowedRecursiveChildren(user).Where(c =>
             return GetParentalAllowedRecursiveChildren(user).Where(c =>
             {
             {
                 if (c.People != null)
                 if (c.People != null)
                 {
                 {
-                    if (personType.HasValue)
-                    {
-                        return c.People.Any(p => p.Name.Equals(person, StringComparison.OrdinalIgnoreCase) && p.PersonType == personType.Value);
-                    }
-                    else
-                    {
-                        return c.People.Any(p => p.Name.Equals(person, StringComparison.OrdinalIgnoreCase));
-                    }
+                    return c.People.Any(p => p.Name.Equals(person, StringComparison.OrdinalIgnoreCase) && p.Type == personType);
                 }
                 }
 
 
                 return false;
                 return false;
@@ -103,9 +126,7 @@ namespace MediaBrowser.Model.Entities
         /// </summary>
         /// </summary>
         public IEnumerable<BaseItem> GetRecentlyAddedItems(User user)
         public IEnumerable<BaseItem> GetRecentlyAddedItems(User user)
         {
         {
-            DateTime now = DateTime.Now;
-
-            return GetParentalAllowedRecursiveChildren(user).Where(i => !(i is Folder) && (now - i.DateCreated).TotalDays < user.RecentItemDays);
+            return GetRecentlyAddedItems(GetParentalAllowedRecursiveChildren(user), user);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -113,12 +134,7 @@ namespace MediaBrowser.Model.Entities
         /// </summary>
         /// </summary>
         public IEnumerable<BaseItem> GetRecentlyAddedUnplayedItems(User user)
         public IEnumerable<BaseItem> GetRecentlyAddedUnplayedItems(User user)
         {
         {
-            return GetRecentlyAddedItems(user).Where(i =>
-            {
-                var userdata = user.GetItemData(i.Id);
-
-                return userdata == null || userdata.PlayCount == 0;
-            });
+            return GetRecentlyAddedUnplayedItems(GetParentalAllowedRecursiveChildren(user), user);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -126,45 +142,95 @@ namespace MediaBrowser.Model.Entities
         /// </summary>
         /// </summary>
         public IEnumerable<BaseItem> GetInProgressItems(User user)
         public IEnumerable<BaseItem> GetInProgressItems(User user)
         {
         {
-            return GetParentalAllowedRecursiveChildren(user).Where(i =>
+            return GetInProgressItems(GetParentalAllowedRecursiveChildren(user), user);
+        }
+
+        private static IEnumerable<BaseItem> GetRecentlyAddedItems(IEnumerable<BaseItem> itemSet, User user)
+        {
+            DateTime now = DateTime.Now;
+
+            return itemSet.Where(i => !(i is Folder) && (now - i.DateCreated).TotalDays < user.RecentItemDays);
+        }
+
+        private static IEnumerable<BaseItem> GetRecentlyAddedUnplayedItems(IEnumerable<BaseItem> itemSet, User user)
+        {
+            return GetRecentlyAddedItems(itemSet, user).Where(i =>
+            {
+                var userdata = i.GetUserData(user);
+
+                return userdata == null || userdata.PlayCount == 0;
+            });
+        }
+
+        private static IEnumerable<BaseItem> GetInProgressItems(IEnumerable<BaseItem> itemSet, User user)
+        {
+            return itemSet.Where(i =>
             {
             {
                 if (i is Folder)
                 if (i is Folder)
                 {
                 {
                     return false;
                     return false;
                 }
                 }
 
 
-                var userdata = user.GetItemData(i.Id);
+                var userdata = i.GetUserData(user);
 
 
-                return userdata != null && userdata.PlaybackPosition.Ticks > 0;
+                return userdata != null && userdata.PlaybackPositionTicks > 0;
             });
             });
         }
         }
 
 
+        private static decimal GetWatchedPercentage(IEnumerable<BaseItem> itemSet, User user)
+        {
+            itemSet = itemSet.Where(i => !(i is Folder));
+
+            if (!itemSet.Any())
+            {
+                return 0;
+            }
+
+            decimal totalPercent = 0;
+
+            foreach (BaseItem item in itemSet)
+            {
+                UserItemData data = item.GetUserData(user);
+
+                if (data == null)
+                {
+                    continue;
+                }
+
+                if (data.PlayCount > 0)
+                {
+                    totalPercent += 100;
+                }
+                else if (data.PlaybackPositionTicks > 0 && item.RunTimeTicks.HasValue)
+                {
+                    decimal itemPercent = data.PlaybackPositionTicks;
+                    itemPercent /= item.RunTimeTicks.Value;
+                    totalPercent += itemPercent;
+                }
+            }
+
+            return totalPercent / itemSet.Count();
+        }
+        
         /// <summary>
         /// <summary>
         /// Finds an item by ID, recursively
         /// Finds an item by ID, recursively
         /// </summary>
         /// </summary>
-        public BaseItem FindById(Guid id)
+        public override BaseItem FindItemById(Guid id)
         {
         {
-            if (Id == id)
+            var result = base.FindItemById(id);
+
+            if (result != null)
             {
             {
-                return this;
+                return result;
             }
             }
 
 
             foreach (BaseItem item in Children)
             foreach (BaseItem item in Children)
             {
             {
-                var folder = item as Folder;
+                result = item.FindItemById(id);
 
 
-                if (folder != null)
+                if (result != null)
                 {
                 {
-                    var foundItem = folder.FindById(id);
-
-                    if (foundItem != null)
-                    {
-                        return foundItem;
-                    }
-                }
-                else if (item.Id == id)
-                {
-                    return item;
+                    return result;
                 }
                 }
             }
             }
 
 

+ 57 - 0
MediaBrowser.Model/Entities/IHasProviderIds.cs

@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Model.Entities
+{
+    /// <summary>
+    /// Since BaseItem and DTOBaseItem both have ProviderIds, this interface helps avoid code repition using extension methods
+    /// </summary>
+    public interface IHasProviderIds
+    {
+        Dictionary<string, string> ProviderIds { get; set; }
+    }
+
+    public static class IProviderIdsExtensions
+    {
+        /// <summary>
+        /// Gets a provider id
+        /// </summary>
+        public static string GetProviderId(this IHasProviderIds instance, MetadataProviders provider)
+        {
+            return instance.GetProviderId(provider.ToString());
+        }
+
+        /// <summary>
+        /// Gets a provider id
+        /// </summary>
+        public static string GetProviderId(this IHasProviderIds instance, string name)
+        {
+            if (instance.ProviderIds == null)
+            {
+                return null;
+            }
+
+            return instance.ProviderIds[name];
+        }
+
+        /// <summary>
+        /// Sets a provider id
+        /// </summary>
+        public static void SetProviderId(this IHasProviderIds instance, string name, string value)
+        {
+            if (instance.ProviderIds == null)
+            {
+                instance.ProviderIds = new Dictionary<string, string>();
+            }
+
+            instance.ProviderIds[name] = value;
+        }
+
+        /// <summary>
+        /// Sets a provider id
+        /// </summary>
+        public static void SetProviderId(this IHasProviderIds instance, MetadataProviders provider, string value)
+        {
+            instance.SetProviderId(provider.ToString(), value);
+        }
+    }
+}

+ 14 - 0
MediaBrowser.Model/Entities/ItemSpecialCounts.cs

@@ -0,0 +1,14 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    /// <summary>
+    /// Since it can be slow to collect this data. This class helps provide a way to calculate them all at once.
+    /// </summary>
+    public class ItemSpecialCounts
+    {
+        public int RecentlyAddedItemCount { get; set; }
+        public int RecentlyAddedUnPlayedItemCount { get; set; }
+        public int InProgressItemCount { get; set; }
+        public decimal WatchedPercentage { get; set; }
+    }
+}

+ 1 - 10
MediaBrowser.Model/Entities/Person.cs

@@ -15,20 +15,11 @@ namespace MediaBrowser.Model.Entities
     {
     {
         public string Name { get; set; }
         public string Name { get; set; }
         public string Overview { get; set; }
         public string Overview { get; set; }
-        public PersonType PersonType { get; set; }
+        public string Type { get; set; }
 
 
         public override string ToString()
         public override string ToString()
         {
         {
             return Name;
             return Name;
         }
         }
     }
     }
-
-    public enum PersonType
-    {
-        Other,
-        Actor,
-        Director,
-        Writer,
-        Producer
-    }
 }
 }

+ 15 - 0
MediaBrowser.Model/Entities/User.cs

@@ -0,0 +1,15 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    public class User : BaseEntity
+    {
+        public string MaxParentalRating { get; set; }
+
+        public int RecentItemDays { get; set; }
+
+        public User()
+        {
+            RecentItemDays = 14;
+        }
+    }
+}

+ 3 - 4
MediaBrowser.Model/Users/UserItemData.cs → MediaBrowser.Model/Entities/UserItemData.cs

@@ -1,13 +1,12 @@
-using MediaBrowser.Model.Entities;
-using System;
+using System;
 
 
-namespace MediaBrowser.Model.Users
+namespace MediaBrowser.Model.Entities
 {
 {
     public class UserItemData
     public class UserItemData
     {
     {
         public UserItemRating Rating { get; set; }
         public UserItemRating Rating { get; set; }
 
 
-        public TimeSpan PlaybackPosition { get; set; }
+        public long PlaybackPositionTicks { get; set; }
 
 
         public int PlayCount { get; set; }
         public int PlayCount { get; set; }
     }
     }

+ 8 - 9
MediaBrowser.Model/Entities/Video.cs

@@ -6,28 +6,27 @@ namespace MediaBrowser.Model.Entities
     {
     {
         public VideoType VideoType { get; set; }
         public VideoType VideoType { get; set; }
 
 
-        private IEnumerable<string> _Subtitles = new string[] { };
-        public IEnumerable<string> Subtitles { get { return _Subtitles; } set { _Subtitles = value; } }
-
-        private IEnumerable<AudioStream> _AudioStreams = new AudioStream[] { };
-        public IEnumerable<AudioStream> AudioStreams { get { return _AudioStreams; } set { _AudioStreams = value; } }
+        public IEnumerable<string> Subtitles { get; set; }
+        public IEnumerable<AudioStream> AudioStreams { get; set; }
 
 
         public int Height { get; set; }
         public int Height { get; set; }
         public int Width { get; set; }
         public int Width { get; set; }
         public string ScanType { get; set; }
         public string ScanType { get; set; }
         public string FrameRate { get; set; }
         public string FrameRate { get; set; }
-        public int VideoBitRate { get; set; }
-        public string VideoCodec { get; set; }
+        public int BitRate { get; set; }
+        public string Codec { get; set; }
     }
     }
 
 
     public class AudioStream
     public class AudioStream
     {
     {
-        public string AudioFormat { get; set; }
-        public string AudioProfile { get; set; }
+        public string Format { get; set; }
+        public string Profile { get; set; }
         public string Language { get; set; }
         public string Language { get; set; }
         public int BitRate { get; set; }
         public int BitRate { get; set; }
         public int Channels { get; set; }
         public int Channels { get; set; }
         public int SampleRate { get; set; }
         public int SampleRate { get; set; }
+        public bool IsDefault { get; set; }
+        public bool IsForced { get; set; }
     }
     }
 
 
     public enum VideoType
     public enum VideoType

+ 5 - 3
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -32,7 +32,7 @@
     <WarningLevel>4</WarningLevel>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
-    <Compile Include="DTO\ApiBaseItem.cs" />
+    <Compile Include="DTO\DTOBaseItem.cs" />
     <Compile Include="Entities\Audio.cs" />
     <Compile Include="Entities\Audio.cs" />
     <Compile Include="Entities\BaseEntity.cs" />
     <Compile Include="Entities\BaseEntity.cs" />
     <Compile Include="Entities\BaseItem.cs" />
     <Compile Include="Entities\BaseItem.cs" />
@@ -40,6 +40,8 @@
     <Compile Include="Entities\Folder.cs" />
     <Compile Include="Entities\Folder.cs" />
     <Compile Include="Entities\Genre.cs" />
     <Compile Include="Entities\Genre.cs" />
     <Compile Include="Entities\ImageType.cs" />
     <Compile Include="Entities\ImageType.cs" />
+    <Compile Include="Entities\IHasProviderIds.cs" />
+    <Compile Include="Entities\ItemSpecialCounts.cs" />
     <Compile Include="Entities\MetadataProviders.cs" />
     <Compile Include="Entities\MetadataProviders.cs" />
     <Compile Include="Entities\Person.cs" />
     <Compile Include="Entities\Person.cs" />
     <Compile Include="Entities\Studio.cs" />
     <Compile Include="Entities\Studio.cs" />
@@ -49,8 +51,8 @@
     <Compile Include="DTO\PluginInfo.cs" />
     <Compile Include="DTO\PluginInfo.cs" />
     <Compile Include="Progress\TaskProgress.cs" />
     <Compile Include="Progress\TaskProgress.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Users\User.cs" />
-    <Compile Include="Users\UserItemData.cs" />
+    <Compile Include="Entities\User.cs" />
+    <Compile Include="Entities\UserItemData.cs" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 

+ 0 - 34
MediaBrowser.Model/Users/User.cs

@@ -1,34 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MediaBrowser.Model.Entities;
-
-namespace MediaBrowser.Model.Users
-{
-    public class User : BaseEntity
-    {
-        public string MaxParentalRating { get; set; }
-
-        private Dictionary<Guid, UserItemData> _ItemData = new Dictionary<Guid, UserItemData>();
-        public Dictionary<Guid, UserItemData> ItemData { get { return _ItemData; } set { _ItemData = value; } }
-
-        public int RecentItemDays { get; set; }
-
-        public User()
-        {
-            RecentItemDays = 14;
-        }
-
-        /// <summary>
-        /// Gets user data for an item, if there is any
-        /// </summary>
-        public UserItemData GetItemData(Guid itemId)
-        {
-            if (ItemData.ContainsKey(itemId))
-            {
-                return ItemData[itemId];
-            }
-
-            return null;
-        }
-    }
-}

+ 0 - 2
MediaBrowser.Movies/Entities/Movie.cs

@@ -1,12 +1,10 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Runtime.Serialization;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 
 
 namespace MediaBrowser.Movies.Entities
 namespace MediaBrowser.Movies.Entities
 {
 {
     public class Movie : Video
     public class Movie : Video
     {
     {
-        [IgnoreDataMember]
         public IEnumerable<Video> SpecialFeatures { get; set; }
         public IEnumerable<Video> SpecialFeatures { get; set; }
     }
     }
 }
 }

+ 0 - 1
MediaBrowser.TV/Entities/Season.cs

@@ -9,7 +9,6 @@ namespace MediaBrowser.TV.Entities
         /// <summary>
         /// <summary>
         /// Store these to reduce disk access in Episode Resolver
         /// Store these to reduce disk access in Episode Resolver
         /// </summary>
         /// </summary>
-        [IgnoreDataMember]
         internal IEnumerable<string> MetadataFiles { get; set; }
         internal IEnumerable<string> MetadataFiles { get; set; }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.TV/Metadata/SeriesXmlParser.cs

@@ -71,7 +71,7 @@ namespace MediaBrowser.TV.Metadata
                             int runtime;
                             int runtime;
                             if (int.TryParse(text.Split(' ')[0], out runtime))
                             if (int.TryParse(text.Split(' ')[0], out runtime))
                             {
                             {
-                                item.RunTimeInMilliseconds = runtime * 60000;
+                                item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
                             }
                             }
                         }
                         }
                         break;
                         break;