瀏覽代碼

All calls to get items now require passing in a userId. Made the model project portable. Also filled in more api calls.

LukePulverenti Luke Pulverenti luke pulverenti 13 年之前
父節點
當前提交
6fbd5cf464
共有 46 個文件被更改,包括 983 次插入407 次删除
  1. 70 31
      MediaBrowser.Api/ApiService.cs
  2. 2 2
      MediaBrowser.Api/HttpHandlers/GenreHandler.cs
  3. 4 2
      MediaBrowser.Api/HttpHandlers/GenresHandler.cs
  4. 3 2
      MediaBrowser.Api/HttpHandlers/ImageHandler.cs
  5. 2 1
      MediaBrowser.Api/HttpHandlers/InProgressItemsHandler.cs
  6. 21 14
      MediaBrowser.Api/HttpHandlers/ItemHandler.cs
  7. 11 2
      MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
  8. 2 1
      MediaBrowser.Api/HttpHandlers/PersonHandler.cs
  9. 3 2
      MediaBrowser.Api/HttpHandlers/RecentlyAddedItemsHandler.cs
  10. 28 0
      MediaBrowser.Api/HttpHandlers/StudioHandler.cs
  11. 26 0
      MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
  12. 22 0
      MediaBrowser.Api/HttpHandlers/UsersHandler.cs
  13. 6 1
      MediaBrowser.Api/MediaBrowser.Api.csproj
  14. 15 0
      MediaBrowser.Api/Model/BaseItemInfo.cs
  15. 6 1
      MediaBrowser.Api/Plugin.cs
  16. 113 0
      MediaBrowser.Common/ApiInteraction/ApiController.cs
  17. 412 0
      MediaBrowser.Common/ApiInteraction/DictionaryBaseItem.cs
  18. 3 2
      MediaBrowser.Common/MediaBrowser.Common.csproj
  19. 0 227
      MediaBrowser.Common/Model/DictionaryBaseItem.cs
  20. 0 4
      MediaBrowser.Configuration/MediaBrowser.Configuration.csproj
  21. 126 1
      MediaBrowser.Controller/Kernel.cs
  22. 18 0
      MediaBrowser.Controller/Library/ItemController.cs
  23. 1 1
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  24. 1 1
      MediaBrowser.HtmlBrowser/MediaBrowser.HtmlBrowser.csproj
  25. 0 4
      MediaBrowser.InternetProviders/MediaBrowser.InternetProviders.csproj
  26. 2 0
      MediaBrowser.Model/Configuration/Configuration.cs
  27. 1 6
      MediaBrowser.Model/Entities/Audio.cs
  28. 1 11
      MediaBrowser.Model/Entities/BaseItem.cs
  29. 21 0
      MediaBrowser.Model/Entities/CategoryInfo.cs
  30. 0 13
      MediaBrowser.Model/Entities/Folder.cs
  31. 7 0
      MediaBrowser.Model/Entities/Genre.cs
  32. 5 9
      MediaBrowser.Model/Entities/Person.cs
  33. 0 12
      MediaBrowser.Model/Entities/PlaybackStatus.cs
  34. 7 0
      MediaBrowser.Model/Entities/Studio.cs
  35. 4 8
      MediaBrowser.Model/Entities/Video.cs
  36. 7 0
      MediaBrowser.Model/Entities/Year.cs
  37. 0 4
      MediaBrowser.Model/Logging/LogSeverity.cs
  38. 12 14
      MediaBrowser.Model/MediaBrowser.Model.csproj
  39. 3 9
      MediaBrowser.Model/Properties/AssemblyInfo.cs
  40. 0 4
      MediaBrowser.Model/Users/User.cs
  41. 5 7
      MediaBrowser.Model/Users/UserItemData.cs
  42. 3 2
      MediaBrowser.Movies/Entities/Movie.cs
  43. 2 1
      MediaBrowser.Movies/MediaBrowser.Movies.csproj
  44. 1 1
      MediaBrowser.Program/MediaBrowser.Program.csproj
  45. 1 1
      MediaBrowser.TV/MediaBrowser.TV.csproj
  46. 6 6
      MediaBrowser.sln

+ 70 - 31
MediaBrowser.Api/ApiService.cs

@@ -9,52 +9,91 @@ namespace MediaBrowser.Api
     {
         public static BaseItem GetItemById(string id)
         {
-            if (string.IsNullOrEmpty(id))
-            {
-                return Kernel.Instance.RootFolder;
-            }
+            Guid guid = string.IsNullOrEmpty(id) ? Guid.Empty : new Guid(id);
 
-            return GetItemById(new Guid(id));
+            return Kernel.Instance.GetItemById(guid);
         }
 
-        public static BaseItem GetItemById(Guid id)
+        public static IEnumerable<CategoryInfo> GetAllStudios(Folder parent, Guid userId)
         {
-            if (id == Guid.Empty)
+            Dictionary<string, int> data = new Dictionary<string, int>();
+            
+            IEnumerable<BaseItem> allItems = Kernel.Instance.GetParentalAllowedRecursiveChildren(parent, userId);
+
+            foreach (var item in allItems)
             {
-                return Kernel.Instance.RootFolder;
+                if (item.Studios == null)
+                {
+                    continue;
+                }
+
+                foreach (string val in item.Studios)
+                {
+                    if (!data.ContainsKey(val))
+                    {
+                        data.Add(val, 1);
+                    }
+                    else
+                    {
+                        data[val]++;
+                    }
+                }
             }
 
-            return Kernel.Instance.RootFolder.FindById(id);
-        }
+            List<CategoryInfo> list = new List<CategoryInfo>();
 
-        public static Person GetPersonByName(string name)
-        {
-            return null;
-        }
+            foreach (string key in data.Keys)
+            {
+                list.Add(new CategoryInfo()
+                {
+                    Name = key,
+                    ItemCount = data[key]
 
-        public static IEnumerable<BaseItem> GetItemsWithGenre(Folder parent, string genre)
-        {
-            return new BaseItem[] { };
+                });
+            }
+            
+            return list;
         }
 
-        public static IEnumerable<string> GetAllGenres(Folder parent)
+        public static IEnumerable<CategoryInfo> GetAllGenres(Folder parent, Guid userId)
         {
-            return new string[] { };
-        }
+            Dictionary<string, int> data = new Dictionary<string, int>();
 
-        public static IEnumerable<BaseItem> GetRecentlyAddedItems(Folder parent)
-        {
-            return new BaseItem[] { };
-        }
+            IEnumerable<BaseItem> allItems = Kernel.Instance.GetParentalAllowedRecursiveChildren(parent, userId);
 
-        public static IEnumerable<BaseItem> GetRecentlyAddedUnplayedItems(Folder parent)
-        {
-            return new BaseItem[] { };
-        }
+            foreach (var item in allItems)
+            {
+                if (item.Genres == null)
+                {
+                    continue;
+                }
 
-        public static IEnumerable<BaseItem> GetInProgressItems(Folder parent)
-        {
-            return new BaseItem[] { };
+                foreach (string val in item.Genres)
+                {
+                    if (!data.ContainsKey(val))
+                    {
+                        data.Add(val, 1);
+                    }
+                    else
+                    {
+                        data[val]++;
+                    }
+                }
+            }
+
+            List<CategoryInfo> list = new List<CategoryInfo>();
+
+            foreach (string key in data.Keys)
+            {
+                list.Add(new CategoryInfo()
+                {
+                    Name = key,
+                    ItemCount = data[key]
+
+                });
+            }
+
+            return list;
         }
     }
 }

+ 2 - 2
MediaBrowser.Api/HttpHandlers/GenreHandler.cs

@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Api;
 
 namespace MediaBrowser.Api.HttpHandlers
 {
@@ -21,7 +21,7 @@ namespace MediaBrowser.Api.HttpHandlers
             {
                 Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
 
-                return ApiService.GetItemsWithGenre(parent, QueryString["name"]);
+                return Kernel.Instance.GetItemsWithGenre(parent, QueryString["name"], UserId);
             }
         }
     }

+ 4 - 2
MediaBrowser.Api/HttpHandlers/GenresHandler.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using System;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net.Handlers;
 using MediaBrowser.Model.Entities;
 
@@ -16,8 +17,9 @@ namespace MediaBrowser.Api.HttpHandlers
             get
             {
                 Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
+                Guid userId = Guid.Parse(QueryString["userid"]);
 
-                return ApiService.GetAllGenres(parent);
+                return ApiService.GetAllGenres(parent, userId);
             }
         }
     }

+ 3 - 2
MediaBrowser.Api/HttpHandlers/ImageHandler.cs

@@ -1,9 +1,10 @@
 using System;
 using System.IO;
+using System.IO.Compression;
 using System.Linq;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
-using System.IO.Compression;
 
 namespace MediaBrowser.Api.HttpHandlers
 {
@@ -174,7 +175,7 @@ namespace MediaBrowser.Api.HttpHandlers
 
             if (!string.IsNullOrEmpty(personName))
             {
-                item = ApiService.GetPersonByName(personName);
+                item = Kernel.Instance.ItemController.GetPerson(personName);
             }
             else
             {

+ 2 - 1
MediaBrowser.Api/HttpHandlers/InProgressItemsHandler.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Api.HttpHandlers
@@ -17,7 +18,7 @@ namespace MediaBrowser.Api.HttpHandlers
             {
                 Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
 
-                return ApiService.GetInProgressItems(parent);
+                return Kernel.Instance.GetInProgressItems(parent, UserId);
             }
         }
     }

+ 21 - 14
MediaBrowser.Api/HttpHandlers/ItemHandler.cs

@@ -1,7 +1,9 @@
-using MediaBrowser.Common.Net;
+using System;
+using MediaBrowser.Api.Model;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Common.Json;
 
 namespace MediaBrowser.Api.HttpHandlers
 {
@@ -16,26 +18,31 @@ namespace MediaBrowser.Api.HttpHandlers
         {
             get
             {
-                return GetSerializationObject(ItemToSerialize, true);
+                Guid userId = Guid.Parse(QueryString["userid"]);
+
+                return GetSerializationObject(ItemToSerialize, true, userId);
             }
         }
 
-        public static object GetSerializationObject(BaseItem item, bool includeChildren)
+        public static object GetSerializationObject(BaseItem item, bool includeChildren, Guid userId)
         {
-            if (includeChildren && item.IsFolder)
+            BaseItemInfo wrapper = new BaseItemInfo()
             {
-                Folder folder = item as Folder;
+                Item = item,
+                UserItemData = Kernel.Instance.GetUserItemData(userId, item.Id)
+            };
 
-                return new
-                {
-                    BaseItem = item,
-                    Children = folder.Children
-                };
-            }
-            else
+            if (includeChildren)
             {
-                return item;
+                var folder = item as Folder;
+
+                if (folder != null)
+                {
+                    wrapper.Children = Kernel.Instance.GetParentalAllowedChildren(folder, userId);
+                }
             }
+
+            return wrapper;
         }
 
         protected virtual BaseItem ItemToSerialize

+ 11 - 2
MediaBrowser.Api/HttpHandlers/ItemListHandler.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using System.Linq;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net.Handlers;
@@ -19,7 +20,7 @@ namespace MediaBrowser.Api.HttpHandlers
             {
                 return ItemsToSerialize.Select(i =>
                 {
-                    return ItemHandler.GetSerializationObject(i, false);
+                    return ItemHandler.GetSerializationObject(i, false, UserId);
 
                 });
             }
@@ -29,5 +30,13 @@ namespace MediaBrowser.Api.HttpHandlers
         {
             get;
         }
+
+        protected Guid UserId
+        {
+            get
+            {
+                return Guid.Parse(QueryString["userid"]);
+            }
+        }
     }
 }

+ 2 - 1
MediaBrowser.Api/HttpHandlers/PersonHandler.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Api.HttpHandlers
@@ -14,7 +15,7 @@ namespace MediaBrowser.Api.HttpHandlers
         {
             get
             {
-                return ApiService.GetPersonByName(QueryString["name"]);
+                return Kernel.Instance.ItemController.GetPerson(QueryString["name"]);
             }
         }
     }

+ 3 - 2
MediaBrowser.Api/HttpHandlers/RecentlyAddedItemsHandler.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Api.HttpHandlers
@@ -19,10 +20,10 @@ namespace MediaBrowser.Api.HttpHandlers
 
                 if (QueryString["unplayed"] == "1")
                 {
-                    return ApiService.GetRecentlyAddedUnplayedItems(parent);
+                    return Kernel.Instance.GetRecentlyAddedUnplayedItems(parent, UserId);
                 }
 
-                return ApiService.GetRecentlyAddedItems(parent);
+                return Kernel.Instance.GetRecentlyAddedItems(parent, UserId);
             }
         }
     }

+ 28 - 0
MediaBrowser.Api/HttpHandlers/StudioHandler.cs

@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+    /// <summary>
+    /// Gets all items within containing a studio
+    /// </summary>
+    public class StudioHandler : ItemListHandler
+    {
+        public StudioHandler(RequestContext ctx)
+            : base(ctx)
+        {
+        }
+
+        protected override IEnumerable<BaseItem> ItemsToSerialize
+        {
+            get
+            {
+                Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
+
+                return Kernel.Instance.GetItemsWithStudio(parent, QueryString["name"], UserId);
+            }
+        }
+    }
+}

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

@@ -0,0 +1,26 @@
+using System;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+    public class StudiosHandler : JsonHandler
+    {
+        public StudiosHandler(RequestContext ctx)
+            : base(ctx)
+        {
+        }
+
+        protected sealed override object ObjectToSerialize
+        {
+            get
+            {
+                Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
+                Guid userId = Guid.Parse(QueryString["userid"]);
+
+                return ApiService.GetAllStudios(parent, userId);
+            }
+        }
+    }
+}

+ 22 - 0
MediaBrowser.Api/HttpHandlers/UsersHandler.cs

@@ -0,0 +1,22 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net.Handlers;
+using MediaBrowser.Controller;
+
+namespace MediaBrowser.Api.HttpHandlers
+{
+    class UsersHandler : JsonHandler
+    {
+        public UsersHandler(RequestContext ctx)
+            : base(ctx)
+        {
+        }
+
+        protected override object ObjectToSerialize
+        {
+            get
+            {
+                return Kernel.Instance.Users;
+            }
+        }
+    }
+}

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

@@ -53,8 +53,12 @@
     <Compile Include="HttpHandlers\ItemListHandler.cs" />
     <Compile Include="HttpHandlers\PersonHandler.cs" />
     <Compile Include="HttpHandlers\RecentlyAddedItemsHandler.cs" />
+    <Compile Include="HttpHandlers\StudioHandler.cs" />
+    <Compile Include="HttpHandlers\StudiosHandler.cs" />
+    <Compile Include="HttpHandlers\UsersHandler.cs" />
     <Compile Include="ImageProcessor.cs" />
     <Compile Include="HttpHandlers\MediaHandler.cs" />
+    <Compile Include="Model\BaseItemInfo.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
@@ -68,13 +72,14 @@
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>

+ 15 - 0
MediaBrowser.Api/Model/BaseItemInfo.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Users;
+
+namespace MediaBrowser.Api.Model
+{
+    public class BaseItemInfo
+    {
+        public BaseItem Item { get; set; }
+
+        public UserItemData UserItemData { get; set; }
+
+        public IEnumerable<BaseItem> Children { get; set; }
+    }
+}

+ 6 - 1
MediaBrowser.Api/Plugin.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Collections.Generic;
 using System.Reactive.Linq;
 using MediaBrowser.Api.HttpHandlers;
 using MediaBrowser.Common.Plugins;
@@ -13,6 +12,8 @@ namespace MediaBrowser.Api
         {
             var httpServer = Kernel.Instance.HttpServer;
 
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/users", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new UsersHandler(ctx)));
+
             httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/media", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new MediaHandler(ctx)));
 
             httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/item", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new ItemHandler(ctx)));
@@ -23,6 +24,10 @@ namespace MediaBrowser.Api
 
             httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/genres", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new GenresHandler(ctx)));
 
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/studio", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new StudioHandler(ctx)));
+
+            httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/studios", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new StudiosHandler(ctx)));
+
             httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/recentlyaddeditems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new RecentlyAddedItemsHandler(ctx)));
 
             httpServer.Where(ctx => ctx.LocalPath.EndsWith("/api/inprogressitems", StringComparison.OrdinalIgnoreCase)).Subscribe(ctx => ctx.Respond(new InProgressItemsHandler(ctx)));

+ 113 - 0
MediaBrowser.Common/ApiInteraction/ApiController.cs

@@ -0,0 +1,113 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Net;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Json;
+using MediaBrowser.Model.Users;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Common.ApiInteraction
+{
+    public class ApiController
+    {
+        public string ApiUrl { get; set; }
+
+        private WebClient WebClient { get; set; }
+
+        public ApiController()
+        {
+            WebClient = new WebClient();
+        }
+
+        public async Task<DictionaryBaseItem> GetRootItem(Guid userId)
+        {
+            string url = ApiUrl + "/item?userId=" + userId.ToString();
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return DictionaryBaseItem.FromApiOutput(gzipStream);
+            }
+        }
+
+        public async Task<DictionaryBaseItem> GetItem(Guid id, Guid userId)
+        {
+            string url = ApiUrl + "/item?userId=" + userId.ToString();
+
+            if (id != Guid.Empty)
+            {
+                url += "&id=" + id.ToString();
+            }
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return DictionaryBaseItem.FromApiOutput(gzipStream);
+            }
+        }
+
+        public async Task<IEnumerable<User>> GetAllUsers()
+        {
+            string url = ApiUrl + "/users";
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return JsonSerializer.DeserializeFromStream<IEnumerable<User>>(gzipStream);
+            }
+        }
+
+        public async Task<IEnumerable<CategoryInfo>> GetAllGenres(Guid userId)
+        {
+            string url = ApiUrl + "/genres?userId=" + userId.ToString();
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return JsonSerializer.DeserializeFromStream<IEnumerable<CategoryInfo>>(gzipStream);
+            }
+        }
+
+        public async Task<CategoryInfo> GetGenre(string name, Guid userId)
+        {
+            string url = ApiUrl + "/genre?userId=" + userId.ToString() + "&name=" + name;
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return JsonSerializer.DeserializeFromStream<CategoryInfo>(gzipStream);
+            }
+        }
+
+        public async Task<IEnumerable<CategoryInfo>> GetAllStudios(Guid userId)
+        {
+            string url = ApiUrl + "/studios?userId=" + userId.ToString();
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return JsonSerializer.DeserializeFromStream<IEnumerable<CategoryInfo>>(gzipStream);
+            }
+        }
+
+        public async Task<CategoryInfo> GetStudio(string name, Guid userId)
+        {
+            string url = ApiUrl + "/studio?userId=" + userId.ToString() + "&name=" + name;
+
+            Stream stream = await WebClient.OpenReadTaskAsync(url);
+
+            using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Decompress, false))
+            {
+                return JsonSerializer.DeserializeFromStream<CategoryInfo>(gzipStream);
+            }
+        }
+    }
+}

+ 412 - 0
MediaBrowser.Common/ApiInteraction/DictionaryBaseItem.cs

@@ -0,0 +1,412 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using MediaBrowser.Common.Json;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Users;
+using System.Linq;
+
+namespace MediaBrowser.Common.ApiInteraction
+{
+    public class DictionaryBaseItem : BaseItem
+    {
+        private Dictionary<string, object> Dictionary { get; set; }
+
+        public UserItemData UserItemData { get; set; }
+        public IEnumerable<DictionaryBaseItem> Children { get; set; }
+
+        public DictionaryBaseItem(Dictionary<string, object> dictionary)
+        {
+            Dictionary = dictionary;
+        }
+
+        public override string Name
+        {
+            get
+            {
+                return GetString("Name");
+            }
+            set
+            {
+                SetValue("Name", value);
+            }
+        }
+
+        public override string ArtImagePath
+        {
+            get
+            {
+                return GetString("ArtImagePath");
+            }
+            set
+            {
+                SetValue("ArtImagePath", value);
+            }
+        }
+
+        public override string AspectRatio
+        {
+            get
+            {
+                return GetString("AspectRatio");
+            }
+            set
+            {
+                SetValue("AspectRatio", value);
+            }
+        }
+
+        public override string BannerImagePath
+        {
+            get
+            {
+                return GetString("BannerImagePath");
+            }
+            set
+            {
+                SetValue("BannerImagePath", value);
+            }
+        }
+
+        public override string CustomPin
+        {
+            get
+            {
+                return GetString("CustomPin");
+            }
+            set
+            {
+                SetValue("CustomPin", value);
+            }
+        }
+
+        public override string CustomRating
+        {
+            get
+            {
+                return GetString("CustomRating");
+            }
+            set
+            {
+                SetValue("CustomRating", value);
+            }
+        }
+
+        public override string DisplayMediaType
+        {
+            get
+            {
+                return GetString("DisplayMediaType");
+            }
+            set
+            {
+                SetValue("DisplayMediaType", value);
+            }
+        }
+
+        public override string LogoImagePath
+        {
+            get
+            {
+                return GetString("LogoImagePath");
+            }
+            set
+            {
+                SetValue("LogoImagePath", value);
+            }
+        }
+
+        public override string OfficialRating
+        {
+            get
+            {
+                return GetString("OfficialRating");
+            }
+            set
+            {
+                SetValue("OfficialRating", value);
+            }
+        }
+
+        public override string Overview
+        {
+            get
+            {
+                return GetString("Overview");
+            }
+            set
+            {
+                SetValue("Overview", value);
+            }
+        }
+
+        public override string Path
+        {
+            get
+            {
+                return GetString("Path");
+            }
+            set
+            {
+                SetValue("Path", value);
+            }
+        }
+
+        public override string PrimaryImagePath
+        {
+            get
+            {
+                return GetString("PrimaryImagePath");
+            }
+            set
+            {
+                SetValue("PrimaryImagePath", value);
+            }
+        }
+
+        public override string SortName
+        {
+            get
+            {
+                return GetString("SortName");
+            }
+            set
+            {
+                SetValue("SortName", value);
+            }
+        }
+
+        public override string Tagline
+        {
+            get
+            {
+                return GetString("Tagline");
+            }
+            set
+            {
+                SetValue("Tagline", value);
+            }
+        }
+
+        public override string TrailerUrl
+        {
+            get
+            {
+                return GetString("TrailerUrl");
+            }
+            set
+            {
+                SetValue("TrailerUrl", value);
+            }
+        }
+
+        public override DateTime DateCreated
+        {
+            get
+            {
+                return GetDateTime("DateCreated");
+            }
+            set
+            {
+                SetValue("DateCreated", value);
+            }
+        }
+
+        public override DateTime DateModified
+        {
+            get
+            {
+                return GetDateTime("DateModified");
+            }
+            set
+            {
+                SetValue("DateModified", value);
+            }
+        }
+
+        public override float? UserRating
+        {
+            get
+            {
+                return GetNullableFloat("UserRating");
+            }
+            set
+            {
+                SetValue("UserRating", value);
+            }
+        }
+
+        public override string ThumbnailImagePath
+        {
+            get
+            {
+                return GetString("ThumbnailImagePath");
+            }
+            set
+            {
+                SetValue("ThumbnailImagePath", value);
+            }
+        }
+
+        public override int? ProductionYear
+        {
+            get
+            {
+                return GetNullableInt("ProductionYear");
+            }
+            set
+            {
+                SetValue("ProductionYear", value);
+            }
+        }
+
+        public override TimeSpan? RunTime
+        {
+            get
+            {
+                return GetNullableTimeSpan("RunTime");
+            }
+            set
+            {
+                SetValue("RunTime", value);
+            }
+        }
+
+        public bool IsFolder
+        {
+            get
+            {
+                return GetBool("IsFolder");
+            }
+        }
+
+        public override Guid Id
+        {
+            get
+            {
+                return GetGuid("Id");
+            }
+            set
+            {
+                SetValue("Id", value);
+            }
+        }
+
+        public TimeSpan? GetNullableTimeSpan(string name)
+        {
+            string val = Dictionary[name] as string;
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return null;
+            }
+
+            return TimeSpan.Parse(val);
+        }
+
+        public int? GetNullableInt(string name)
+        {
+            string val = Dictionary[name] as string;
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return null;
+            }
+
+            return int.Parse(val);
+        }
+
+        public float? GetNullableFloat(string name)
+        {
+            string val = Dictionary[name] as string;
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return null;
+            }
+
+            return float.Parse(val);
+        }
+
+        public DateTime? GetNullableDateTime(string name)
+        {
+            string val = Dictionary[name] as string;
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return null;
+            }
+
+            return DateTime.Parse(val);
+        }
+
+        public DateTime GetDateTime(string name)
+        {
+            DateTime? val = GetNullableDateTime(name);
+
+            return val ?? DateTime.MinValue;
+        }
+
+        public bool? GetNullableBool(string name)
+        {
+            string val = Dictionary[name] as string;
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return null;
+            }
+
+            return val != "false";
+        }
+
+        public Guid GetGuid(string name)
+        {
+            string val = GetString(name);
+
+            if (string.IsNullOrEmpty(val))
+            {
+                return Guid.Empty;
+            }
+
+            return Guid.Parse(val);
+        }
+
+        public bool GetBool(string name)
+        {
+            bool? val = GetNullableBool(name);
+
+            return val ?? false;
+        }
+
+        public string GetString(string name)
+        {
+            return Dictionary[name] as string;
+        }
+
+        private void SetValue<T>(string name, T value)
+        {
+            Dictionary[name] = value;
+        }
+
+        public static DictionaryBaseItem FromApiOutput(Stream stream)
+        {
+            Dictionary<string, object> data = JsonSerializer.DeserializeFromStream<Dictionary<string, object>>(stream);
+
+            string baseItem = data["Item"] as string;
+
+            DictionaryBaseItem item = new DictionaryBaseItem(JsonSerializer.DeserializeFromString<Dictionary<string, object>>(baseItem));
+
+            if (data.ContainsKey("UserItemData"))
+            {
+                item.UserItemData = JsonSerializer.DeserializeFromString<UserItemData>(data["UserItemData"].ToString());
+            }
+
+            if (data.ContainsKey("Children"))
+            {
+                item.Children = JsonSerializer.DeserializeFromString<IEnumerable<Dictionary<string, object>>>(data["Children"].ToString()).Select(c => new DictionaryBaseItem(c));
+            }
+
+            return item;
+        }
+    }
+}

+ 3 - 2
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -45,9 +45,10 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ApiInteraction\ApiController.cs" />
     <Compile Include="Events\GenericItemEventArgs.cs" />
     <Compile Include="Json\JsonSerializer.cs" />
-    <Compile Include="Model\DictionaryBaseItem.cs" />
+    <Compile Include="ApiInteraction\DictionaryBaseItem.cs" />
     <Compile Include="Net\CollectionExtensions.cs" />
     <Compile Include="Net\Handlers\BaseEmbeddedResourceHandler.cs" />
     <Compile Include="Net\Handlers\JsonHandler.cs" />
@@ -70,7 +71,7 @@
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 0 - 227
MediaBrowser.Common/Model/DictionaryBaseItem.cs

@@ -1,227 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Entities;
-using System.IO;
-using MediaBrowser.Common.Json;
-
-namespace MediaBrowser.Common.Model
-{
-    public class DictionaryBaseItem : BaseItem
-    {
-        private Dictionary<string, object> Dictionary { get; set; }
-
-        public DictionaryBaseItem(Dictionary<string, object> dictionary)
-        {
-            Dictionary = dictionary;
-        }
-
-        public override string Name
-        {
-            get
-            {
-                return GetString("Name");
-            }
-            set
-            {
-                SetValue("Name", value);
-            }
-        }
-
-        public override string ArtImagePath
-        {
-            get
-            {
-                return GetString("ArtImagePath");
-            }
-            set
-            {
-                SetValue("ArtImagePath", value);
-            }
-        }
-
-        public override string AspectRatio
-        {
-            get
-            {
-                return GetString("AspectRatio");
-            }
-            set
-            {
-                SetValue("AspectRatio", value);
-            }
-        }
-
-        public override string BannerImagePath
-        {
-            get
-            {
-                return GetString("BannerImagePath");
-            }
-            set
-            {
-                SetValue("BannerImagePath", value);
-            }
-        }
-
-        public override string CustomPin
-        {
-            get
-            {
-                return GetString("CustomPin");
-            }
-            set
-            {
-                SetValue("CustomPin", value);
-            }
-        }
-
-        public override string CustomRating
-        {
-            get
-            {
-                return GetString("CustomRating");
-            }
-            set
-            {
-                SetValue("CustomRating", value);
-            }
-        }
-
-        public override string DisplayMediaType
-        {
-            get
-            {
-                return GetString("DisplayMediaType");
-            }
-            set
-            {
-                SetValue("DisplayMediaType", value);
-            }
-        }
-
-        public override string LogoImagePath
-        {
-            get
-            {
-                return GetString("LogoImagePath");
-            }
-            set
-            {
-                SetValue("LogoImagePath", value);
-            }
-        }
-
-        public override string OfficialRating
-        {
-            get
-            {
-                return GetString("OfficialRating");
-            }
-            set
-            {
-                SetValue("OfficialRating", value);
-            }
-        }
-
-        public override string Overview
-        {
-            get
-            {
-                return GetString("Overview");
-            }
-            set
-            {
-                SetValue("Overview", value);
-            }
-        }
-
-        public override string Path
-        {
-            get
-            {
-                return GetString("Path");
-            }
-            set
-            {
-                SetValue("Path", value);
-            }
-        }
-
-        public override string PrimaryImagePath
-        {
-            get
-            {
-                return GetString("PrimaryImagePath");
-            }
-            set
-            {
-                SetValue("PrimaryImagePath", value);
-            }
-        }
-
-        public override string SortName
-        {
-            get
-            {
-                return GetString("SortName");
-            }
-            set
-            {
-                SetValue("SortName", value);
-            }
-        }
-
-        public override string Tagline
-        {
-            get
-            {
-                return GetString("Tagline");
-            }
-            set
-            {
-                SetValue("Tagline", value);
-            }
-        }
-
-        public override string TrailerUrl
-        {
-            get
-            {
-                return GetString("TrailerUrl");
-            }
-            set
-            {
-                SetValue("TrailerUrl", value);
-            }
-        }
-
-        private string GetString(string name)
-        {
-            return Dictionary[name] as string;
-        }
-
-        private void SetValue<T>(string name, T value)
-        {
-            Dictionary[name] = value;
-        }
-
-        public static DictionaryBaseItem FromApiOutput(Stream stream)
-        {
-            Dictionary<string,object> data = JsonSerializer.DeserializeFromStream<Dictionary<string, object>>(stream);
-
-            if (data.ContainsKey("BaseItem"))
-            {
-                string baseItem = data["BaseItem"] as string;
-
-                data = JsonSerializer.DeserializeFromString<Dictionary<string, object>>(baseItem);
-
-                return new DictionaryBaseItem(data);
-            }
-
-            return new DictionaryBaseItem(data);
-        }
-    }
-}

+ 0 - 4
MediaBrowser.Configuration/MediaBrowser.Configuration.csproj

@@ -55,10 +55,6 @@
       <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
-      <Name>MediaBrowser.Model</Name>
-    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />

+ 126 - 1
MediaBrowser.Controller/Kernel.cs

@@ -84,7 +84,6 @@ namespace MediaBrowser.Controller
             // Get users from users folder
             // Load root media folder
             Parallel.Invoke(ReloadUsers, ReloadRoot);
-            var b = true;
         }
 
         private void ReloadConfiguration()
@@ -234,5 +233,131 @@ namespace MediaBrowser.Controller
                 item.Parent.Children = children.ToArray();
             }
         }
+
+        /// <summary>
+        /// Finds a library item by Id
+        /// </summary>
+        public BaseItem GetItemById(Guid id)
+        {
+            if (id == Guid.Empty)
+            {
+                return RootFolder;
+            }
+
+            return RootFolder.FindById(id);
+        }
+
+        /// <summary>
+        /// Determines if an item is allowed for a given user
+        /// </summary>
+        public bool IsParentalAllowed(BaseItem item, Guid userId)
+        {
+            // not yet implemented
+            return true;
+        }
+
+        /// <summary>
+        /// Gets allowed children of an item
+        /// </summary>
+        public IEnumerable<BaseItem> GetParentalAllowedChildren(Folder folder, Guid userId)
+        {
+            return folder.Children.ToList().Where(i => IsParentalAllowed(i, userId));
+        }
+
+        /// <summary>
+        /// Gets allowed recursive children of an item
+        /// </summary>
+        public IEnumerable<BaseItem> GetParentalAllowedRecursiveChildren(Folder folder, Guid userId)
+        {
+            foreach (var item in GetParentalAllowedChildren(folder, userId))
+            {
+                yield return item;
+
+                var subFolder = item as Folder;
+
+                if (subFolder != null)
+                {
+                    foreach (var subitem in GetParentalAllowedRecursiveChildren(subFolder, userId))
+                    {
+                        yield return subitem;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets user data for an item, if there is any
+        /// </summary>
+        public UserItemData GetUserItemData(Guid userId, Guid itemId)
+        {
+            User user = Users.First(u => u.Id == userId);
+
+            if (user.ItemData.ContainsKey(itemId))
+            {
+                return user.ItemData[itemId];
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Gets all recently added items (recursive) within a folder, based on configuration and parental settings
+        /// </summary>
+        public IEnumerable<BaseItem> GetRecentlyAddedItems(Folder parent, Guid userId)
+        {
+            DateTime now = DateTime.Now;
+
+            return GetParentalAllowedRecursiveChildren(parent, userId).Where(i => (now - i.DateCreated).TotalDays < Configuration.RecentItemDays);
+        }
+
+        /// <summary>
+        /// Gets all recently added unplayed items (recursive) within a folder, based on configuration and parental settings
+        /// </summary>
+        public IEnumerable<BaseItem> GetRecentlyAddedUnplayedItems(Folder parent, Guid userId)
+        {
+            return GetRecentlyAddedItems(parent, userId).Where(i =>
+            {
+                var userdata = GetUserItemData(userId, i.Id);
+
+                return userdata == null || userdata.PlayCount == 0;
+            });
+        }
+
+        /// <summary>
+        /// Gets all in-progress items (recursive) within a folder
+        /// </summary>
+        public IEnumerable<BaseItem> GetInProgressItems(Folder parent, Guid userId)
+        {
+            return GetParentalAllowedRecursiveChildren(parent, userId).Where(i =>
+            {
+                var userdata = GetUserItemData(userId, i.Id);
+
+                return userdata != null && userdata.PlaybackPosition.Ticks > 0;
+            });
+        }
+
+        /// <summary>
+        /// Finds all recursive items within a top-level parent that contain the given studio and are allowed for the current user
+        /// </summary>
+        public IEnumerable<BaseItem> GetItemsWithStudio(Folder parent, string studio, Guid userId)
+        {
+            return GetParentalAllowedRecursiveChildren(parent, userId).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 genre and are allowed for the current user
+        /// </summary>
+        public IEnumerable<BaseItem> GetItemsWithGenre(Folder parent, string genre, Guid userId)
+        {
+            return GetParentalAllowedRecursiveChildren(parent, userId).Where(f => f.Genres != null && f.Genres.Any(s => s.Equals(genre, 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(Folder parent, string personName, Guid userId)
+        {
+            return GetParentalAllowedRecursiveChildren(parent, userId).Where(f => f.People != null && f.People.Any(s => s.Name.Equals(personName, StringComparison.OrdinalIgnoreCase)));
+        }
     }
 }

+ 18 - 0
MediaBrowser.Controller/Library/ItemController.cs

@@ -310,5 +310,23 @@ namespace MediaBrowser.Controller.Library
 
             return returnFiles;
         }
+
+        public Person GetPerson(string name)
+        {
+            // not yet implemented
+            return null;
+        }
+
+        public Studio GetStudio(string name)
+        {
+            // not yet implemented
+            return null;
+        }
+
+        public Year GetYear(int value)
+        {
+            // not yet implemented
+            return null;
+        }
     }
 }

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -63,7 +63,7 @@
       <Name>MediaBrowser.Common</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 1 - 1
MediaBrowser.HtmlBrowser/MediaBrowser.HtmlBrowser.csproj

@@ -56,7 +56,7 @@
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 0 - 4
MediaBrowser.InternetProviders/MediaBrowser.InternetProviders.csproj

@@ -52,10 +52,6 @@
       <Project>{17e1f4e6-8abd-4fe5-9ecf-43d4b6087ba2}</Project>
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
-    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
-      <Name>MediaBrowser.Model</Name>
-    </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Movies\MediaBrowser.Movies.csproj">
       <Project>{92b9f802-4415-438f-90e1-44602135ea41}</Project>
       <Name>MediaBrowser.Movies</Name>

+ 2 - 0
MediaBrowser.Model/Configuration/Configuration.cs

@@ -6,11 +6,13 @@ namespace MediaBrowser.Model.Configuration
     {
         public string ImagesByNamePath { get; set; }
         public int HttpServerPortNumber { get; set; }
+        public int RecentItemDays { get; set; }
         public LogSeverity LogSeverity { get; set; }
 
         public Configuration()
         {
             HttpServerPortNumber = 8096;
+            RecentItemDays = 14;
             LogSeverity = LogSeverity.Info;
         }
     }

+ 1 - 6
MediaBrowser.Model/Entities/Audio.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
+
 namespace MediaBrowser.Model.Entities
 {
     public class Audio : BaseItem

+ 1 - 11
MediaBrowser.Model/Entities/BaseItem.cs

@@ -51,6 +51,7 @@ namespace MediaBrowser.Model.Entities
         public virtual string AspectRatio { get; set; }
         public virtual int? ProductionYear { get; set; }
 
+        [IgnoreDataMember]
         public virtual IEnumerable<Video> LocalTrailers { get; set; }
 
         public virtual string TrailerUrl { get; set; }
@@ -60,17 +61,6 @@ namespace MediaBrowser.Model.Entities
             return Name;
         }
 
-        /// <summary>
-        /// This is strictly to enhance json output, until I can find a way to customize service stack to add this without having to use a property
-        /// </summary>
-        public virtual bool IsFolder
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         /// <summary>
         /// This is strictly to enhance json output, until I can find a way to customize service stack to add this without having to use a property
         /// </summary>

+ 21 - 0
MediaBrowser.Model/Entities/CategoryInfo.cs

@@ -0,0 +1,21 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    /// <summary>
+    /// This is a stub class used by the api to get IBN types in a compact format
+    /// </summary>
+    public class CategoryInfo
+    {
+        /// <summary>
+        /// The name of the genre, year, studio, etc
+        /// </summary>
+        public string Name { get; set; }
+
+        public string PrimaryImagePath { get; set; }
+
+        /// <summary>
+        /// The number of items that have the genre, year, studio, etc
+        /// </summary>
+        public int ItemCount { get; set; }
+    }
+}

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

@@ -18,25 +18,12 @@ namespace MediaBrowser.Model.Entities
             }
         }
 
-        public override bool IsFolder
-        {
-            get
-            {
-                return true;
-            }
-        }
-
         [IgnoreDataMember]
         public BaseItem[] Children { get; set; }
 
         [IgnoreDataMember]
         public IEnumerable<Folder> FolderChildren { get { return Children.OfType<Folder>(); } }
 
-        public Folder GetFolderByName(string name)
-        {
-            return FolderChildren.FirstOrDefault(f => System.IO.Path.GetFileName(f.Path).Equals(name, StringComparison.OrdinalIgnoreCase));
-        }
-
         /// <summary>
         /// Finds an item by ID, recursively
         /// </summary>

+ 7 - 0
MediaBrowser.Model/Entities/Genre.cs

@@ -0,0 +1,7 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    public class Genre : BaseItem
+    {
+    }
+}

+ 5 - 9
MediaBrowser.Model/Entities/Person.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
+
 namespace MediaBrowser.Model.Entities
 {
     /// <summary>
@@ -26,8 +21,9 @@ namespace MediaBrowser.Model.Entities
 
     public enum PersonType
     {
-        Actor = 1,
-        Director = 2,
-        Writer = 3
+        Actor,
+        Director,
+        Writer,
+        Producer
     }
 }

+ 0 - 12
MediaBrowser.Model/Entities/PlaybackStatus.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Model.Entities
-{
-    public class PlaybackStatus
-    {
-    }
-}

+ 7 - 0
MediaBrowser.Model/Entities/Studio.cs

@@ -0,0 +1,7 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    public class Studio : BaseItem
+    {
+    }
+}

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

@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Collections.Generic;
 
 namespace MediaBrowser.Model.Entities
 {
@@ -35,8 +31,8 @@ namespace MediaBrowser.Model.Entities
 
     public enum VideoType
     {
-        VideoFile = 1,
-        DVD = 2,
-        BluRay = 3
+        VideoFile,
+        DVD,
+        BluRay
     }
 }

+ 7 - 0
MediaBrowser.Model/Entities/Year.cs

@@ -0,0 +1,7 @@
+
+namespace MediaBrowser.Model.Entities
+{
+    public class Year : BaseItem
+    {
+    }
+}

+ 0 - 4
MediaBrowser.Model/Logging/LogSeverity.cs

@@ -1,8 +1,4 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Model.Logging
 {

+ 12 - 14
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -4,13 +4,15 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}</ProjectGuid>
+    <ProjectGuid>{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>MediaBrowser.Model</RootNamespace>
     <AssemblyName>MediaBrowser.Model</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Profile4</TargetFrameworkProfile>
     <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -30,29 +32,25 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
+    <!-- A reference to the entire .NET Framework is automatically included -->
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Configuration\Configuration.cs" />
-    <Compile Include="Entities\Person.cs" />
     <Compile Include="Entities\Audio.cs" />
     <Compile Include="Entities\BaseItem.cs" />
+    <Compile Include="Entities\CategoryInfo.cs" />
     <Compile Include="Entities\Folder.cs" />
-    <Compile Include="Entities\PlaybackStatus.cs" />
+    <Compile Include="Entities\Genre.cs" />
+    <Compile Include="Entities\Person.cs" />
+    <Compile Include="Entities\Studio.cs" />
+    <Compile Include="Entities\Video.cs" />
+    <Compile Include="Entities\Year.cs" />
     <Compile Include="Logging\LogSeverity.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Users\User.cs" />
     <Compile Include="Users\UserItemData.cs" />
-    <Compile Include="Entities\Video.cs" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.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. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 3 - 9
MediaBrowser.Model/Properties/AssemblyInfo.cs

@@ -1,4 +1,5 @@
-using System.Reflection;
+using System.Resources;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
@@ -13,14 +14,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyCopyright("Copyright ©  2012")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4478b410-9582-4c22-b890-2a309708b9f1")]
+[assembly: NeutralResourcesLanguage("en")]
 
 // Version information for an assembly consists of the following four values:
 //

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

@@ -1,8 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Model.Users
@@ -11,7 +8,6 @@ namespace MediaBrowser.Model.Users
     {
         public string Password { get; set; }
         public string MaxParentalRating { get; set; }
-        public bool HideBlockedContent { get; set; }
 
         private Dictionary<Guid, UserItemData> _ItemData = new Dictionary<Guid, UserItemData>();
         public Dictionary<Guid, UserItemData> ItemData { get { return _ItemData; } set { _ItemData = value; } }

+ 5 - 7
MediaBrowser.Model/Users/UserItemData.cs

@@ -1,9 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
+using System;
 
 namespace MediaBrowser.Model.Users
 {
@@ -11,7 +7,9 @@ namespace MediaBrowser.Model.Users
     {
         public UserItemRating Rating { get; set; }
 
-        public PlaybackStatus PlaybackStatus { get; set; }
+        public TimeSpan PlaybackPosition { get; set; }
+
+        public int PlayCount { get; set; }
     }
 
     public enum UserItemRating

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

@@ -1,6 +1,6 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using MediaBrowser.Model.Entities;
+using System.Runtime.Serialization;
 
 namespace MediaBrowser.Movies.Entities
 {
@@ -9,6 +9,7 @@ namespace MediaBrowser.Movies.Entities
         public string TmdbId { get; set; }
         public string ImdbId { get; set; }
 
+        [IgnoreDataMember]
         public IEnumerable<Video> SpecialFeatures { get; set; }
     }
 }

+ 2 - 1
MediaBrowser.Movies/MediaBrowser.Movies.csproj

@@ -32,6 +32,7 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
@@ -57,7 +58,7 @@
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 1 - 1
MediaBrowser.Program/MediaBrowser.Program.csproj

@@ -58,7 +58,7 @@
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 1 - 1
MediaBrowser.TV/MediaBrowser.TV.csproj

@@ -62,7 +62,7 @@
       <Name>MediaBrowser.Controller</Name>
     </ProjectReference>
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj">
-      <Project>{9b1ddd79-5134-4df3-ace3-d1957a7350d8}</Project>
+      <Project>{7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b}</Project>
       <Name>MediaBrowser.Model</Name>
     </ProjectReference>
   </ItemGroup>

+ 6 - 6
MediaBrowser.sln

@@ -1,8 +1,6 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2012
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Controller", "MediaBrowser.Controller\MediaBrowser.Controller.csproj", "{17E1F4E6-8ABD-4FE5-9ECF-43D4B6087BA2}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Movies", "MediaBrowser.Movies\MediaBrowser.Movies.csproj", "{92B9F802-4415-438F-90E1-44602135EA41}"
@@ -21,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.HtmlBrowser",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Common", "MediaBrowser.Common\MediaBrowser.Common.csproj", "{9142EEFA-7570-41E1-BFCC-468BB571AF2F}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MediaBrowser.Model", "MediaBrowser.Model\MediaBrowser.Model.csproj", "{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -47,6 +47,10 @@ Global
 		{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{78AEA637-AF42-4F43-8E2B-0F2F0E2931F3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7EEEB4BB-F3E8-48FC-B4C5-70F0FFF8329B}.Release|Any CPU.Build.0 = Release|Any CPU
 		{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9142EEFA-7570-41E1-BFCC-468BB571AF2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -63,10 +67,6 @@ Global
 		{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{99B4CFE8-1441-4F0D-8C40-A70D0DD372ED}.Release|Any CPU.Build.0 = Release|Any CPU
-		{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{9B1DDD79-5134-4DF3-ACE3-D1957A7350D8}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE