소스 검색

Added IDtoService

Luke Pulverenti 11 년 전
부모
커밋
dfe91e43b6
57개의 변경된 파일1117개의 추가작업 그리고 1125개의 파일을 삭제
  1. 6 2
      MediaBrowser.Api/AlbumsService.cs
  2. 6 2
      MediaBrowser.Api/GamesService.cs
  3. 9 10
      MediaBrowser.Api/Images/ImageService.cs
  4. 6 11
      MediaBrowser.Api/InstantMixService.cs
  5. 6 6
      MediaBrowser.Api/ItemRefreshService.cs
  6. 4 4
      MediaBrowser.Api/ItemUpdateService.cs
  7. 14 23
      MediaBrowser.Api/LibraryService.cs
  8. 7 3
      MediaBrowser.Api/MoviesService.cs
  9. 9 7
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  10. 3 2
      MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
  11. 3 2
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  12. 3 2
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  13. 3 2
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  14. 6 5
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  15. 1 4
      MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
  16. 3 2
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  17. 4 2
      MediaBrowser.Api/SearchService.cs
  18. 5 2
      MediaBrowser.Api/SessionsService.cs
  19. 4 5
      MediaBrowser.Api/SimilarItemsHelper.cs
  20. 7 3
      MediaBrowser.Api/TrailersService.cs
  21. 6 5
      MediaBrowser.Api/TvShowsService.cs
  22. 4 6
      MediaBrowser.Api/UserLibrary/ArtistsService.cs
  23. 7 5
      MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
  24. 4 6
      MediaBrowser.Api/UserLibrary/GameGenresService.cs
  25. 4 6
      MediaBrowser.Api/UserLibrary/GenresService.cs
  26. 5 3
      MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
  27. 8 10
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  28. 4 6
      MediaBrowser.Api/UserLibrary/MusicGenresService.cs
  29. 5 8
      MediaBrowser.Api/UserLibrary/PersonsService.cs
  30. 5 7
      MediaBrowser.Api/UserLibrary/StudiosService.cs
  31. 21 27
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  32. 5 7
      MediaBrowser.Api/UserLibrary/YearsService.cs
  33. 7 14
      MediaBrowser.Api/UserService.cs
  34. 5 7
      MediaBrowser.Api/VideosService.cs
  35. 5 2
      MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs
  36. 1 1
      MediaBrowser.Controller/Drawing/ImageManager.cs
  37. 71 0
      MediaBrowser.Controller/Dto/IDtoService.cs
  38. 0 50
      MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs
  39. 0 72
      MediaBrowser.Controller/Dto/UserDtoBuilder.cs
  40. 1 3
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  41. 3 8
      MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
  42. 0 1
      MediaBrowser.Controller/Persistence/IRepository.cs
  43. 1 8
      MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
  44. 2 11
      MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs
  45. 45 5
      MediaBrowser.Providers/Music/LastfmAlbumProvider.cs
  46. 1 2
      MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
  47. 1 2
      MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
  48. 747 682
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  49. 5 9
      MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs
  50. 0 10
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  51. 1 0
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  52. 2 14
      MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs
  53. 1 6
      MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
  54. 12 14
      MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
  55. 8 2
      MediaBrowser.ServerApplication/ApplicationHost.cs
  56. 5 3
      MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs
  57. 6 4
      MediaBrowser.WebDashboard/Api/DashboardService.cs

+ 6 - 2
MediaBrowser.Api/AlbumsService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -30,13 +31,15 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly ILibraryManager _libraryManager;
         private readonly IItemRepository _itemRepo;
+        private readonly IDtoService _dtoService;
 
-        public AlbumsService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public AlbumsService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -50,6 +53,7 @@ namespace MediaBrowser.Api
                 _itemRepo,
                 _libraryManager,
                 _userDataRepository,
+                _dtoService,
                 Logger,
                 request, item => item is MusicAlbum,
                 GetAlbumSimilarityScore);

+ 6 - 2
MediaBrowser.Api/GamesService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using ServiceStack.ServiceHost;
@@ -34,6 +35,7 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
 
         private readonly IItemRepository _itemRepo;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="GamesService" /> class.
@@ -42,12 +44,13 @@ namespace MediaBrowser.Api
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="itemRepo">The item repo.</param>
-        public GamesService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public GamesService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -61,6 +64,7 @@ namespace MediaBrowser.Api
                 _itemRepo,
                 _libraryManager,
                 _userDataRepository,
+                _dtoService,
                 Logger,
                 request, item => item is Game,
                 SimilarItemsHelper.GetSimiliarityScore);

+ 9 - 10
MediaBrowser.Api/Images/ImageService.cs

@@ -337,21 +337,19 @@ namespace MediaBrowser.Api.Images
         private readonly IProviderManager _providerManager;
 
         private readonly IItemRepository _itemRepo;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageService" /> class.
         /// </summary>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="providerManager">The provider manager.</param>
-        public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo)
+        public ImageService(IUserManager userManager, ILibraryManager libraryManager, IApplicationPaths appPaths, IProviderManager providerManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _appPaths = appPaths;
             _providerManager = providerManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -361,7 +359,7 @@ namespace MediaBrowser.Api.Images
         /// <returns>System.Object.</returns>
         public object Get(GetItemImageInfos request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             var result = GetItemImageInfos(item).Result;
 
@@ -512,7 +510,7 @@ namespace MediaBrowser.Api.Images
         /// <returns>System.Object.</returns>
         public object Get(GetItemImage request)
         {
-            var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = string.IsNullOrEmpty(request.Id) ? _libraryManager.RootFolder : _dtoService.GetItemByDtoId(request.Id);
 
             return GetImage(request, item);
         }
@@ -824,9 +822,10 @@ namespace MediaBrowser.Api.Images
                     }
                 }
 
-                var memoryStream = new MemoryStream(bytes);
-
-                memoryStream.Position = 0;
+                var memoryStream = new MemoryStream(bytes)
+                {
+                    Position = 0
+                };
 
                 var imageIndex = 0;
 

+ 6 - 11
MediaBrowser.Api/InstantMixService.cs

@@ -1,7 +1,6 @@
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Querying;
 using ServiceStack.ServiceHost;
 using System;
@@ -42,22 +41,20 @@ namespace MediaBrowser.Api
     public class InstantMixService : BaseApiService
     {
         private readonly IUserManager _userManager;
-        private readonly IUserDataRepository _userDataRepository;
         private readonly ILibraryManager _libraryManager;
 
-        private readonly IItemRepository _itemRepo;
+        private readonly IDtoService _dtoService;
 
-        public InstantMixService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public InstantMixService(IUserManager userManager, ILibraryManager libraryManager, IDtoService dtoService)
         {
             _userManager = userManager;
-            _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
-            _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         public object Get(GetInstantMixFromSong request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             var result = GetInstantMixResult(request, item.Genres).Result;
 
@@ -66,7 +63,7 @@ namespace MediaBrowser.Api
 
         public object Get(GetInstantMixFromAlbum request)
         {
-            var album = (MusicAlbum)DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var album = (MusicAlbum)_dtoService.GetItemByDtoId(request.Id);
 
             var genres = album
                .RecursiveChildren
@@ -112,8 +109,6 @@ namespace MediaBrowser.Api
 
             var fields = request.GetItemFields().ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var inputItems = user == null
                                  ? _libraryManager.RootFolder.RecursiveChildren
                                  : user.RootFolder.GetRecursiveChildren(user);
@@ -138,7 +133,7 @@ namespace MediaBrowser.Api
             };
 
             var tasks = items.Take(request.Limit ?? items.Length)
-                .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user));
+                .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
 
             result.Items = await Task.WhenAll(tasks).ConfigureAwait(false);
 

+ 6 - 6
MediaBrowser.Api/ItemRefreshService.cs

@@ -1,9 +1,9 @@
-using System.Linq;
-using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using ServiceStack.ServiceHost;
 using System;
+using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -92,12 +92,12 @@ namespace MediaBrowser.Api
     public class ItemRefreshService : BaseApiService
     {
         private readonly ILibraryManager _libraryManager;
-        private readonly IUserManager _userManager;
+        private readonly IDtoService _dtoService;
 
-        public ItemRefreshService(ILibraryManager libraryManager, IUserManager userManager)
+        public ItemRefreshService(ILibraryManager libraryManager, IDtoService dtoService)
         {
             _libraryManager = libraryManager;
-            _userManager = userManager;
+            _dtoService = dtoService;
         }
 
         public void Post(RefreshArtist request)
@@ -244,7 +244,7 @@ namespace MediaBrowser.Api
         /// <returns>Task.</returns>
         private async Task RefreshItem(RefreshItem request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             var folder = item as Folder;
 

+ 4 - 4
MediaBrowser.Api/ItemUpdateService.cs

@@ -72,12 +72,12 @@ namespace MediaBrowser.Api
     public class ItemUpdateService : BaseApiService
     {
         private readonly ILibraryManager _libraryManager;
-        private readonly IUserManager _userManager;
+        private readonly IDtoService _dtoService;
 
-        public ItemUpdateService(ILibraryManager libraryManager, IUserManager userManager)
+        public ItemUpdateService(ILibraryManager libraryManager, IDtoService dtoService)
         {
             _libraryManager = libraryManager;
-            _userManager = userManager;
+            _dtoService = dtoService;
         }
 
         public void Post(UpdateItem request)
@@ -89,7 +89,7 @@ namespace MediaBrowser.Api
 
         private Task UpdateItem(UpdateItem request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.ItemId, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.ItemId);
 
             UpdateItem(request, item);
 

+ 14 - 23
MediaBrowser.Api/LibraryService.cs

@@ -187,27 +187,24 @@ namespace MediaBrowser.Api
 
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
-        private readonly IUserDataRepository _userDataRepository;
+
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// </summary>
-        /// <param name="itemRepo">The item repo.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="userDataRepository">The user data repository.</param>
         public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
-                              IUserDataRepository userDataRepository)
+                              IDtoService dtoService)
         {
             _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _userManager = userManager;
-            _userDataRepository = userDataRepository;
+            _dtoService = dtoService;
         }
 
         public object Get(GetFile request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             if (item.LocationType == LocationType.Remote || item.LocationType == LocationType.Virtual)
             {
@@ -240,7 +237,7 @@ namespace MediaBrowser.Api
         /// <returns>Task{BaseItemDto[]}.</returns>
         public async Task<BaseItemDto[]> GetAncestors(GetAncestors request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             var tasks = new List<Task<BaseItemDto>>();
 
@@ -251,8 +248,6 @@ namespace MediaBrowser.Api
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-            
             BaseItem parent = item.Parent;
 
             while (parent != null)
@@ -262,7 +257,7 @@ namespace MediaBrowser.Api
                     parent = TranslateParentItem(parent, user);
                 }
 
-                tasks.Add(dtoBuilder.GetBaseItemDto(parent, fields, user));
+                tasks.Add(_dtoService.GetBaseItemDto(parent, fields, user));
 
                 if (parent is UserRootFolder)
                 {
@@ -379,7 +374,7 @@ namespace MediaBrowser.Api
 
         private async Task DeleteItem(DeleteItem request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager);
+            var item = _dtoService.GetItemByDtoId(request.Id);
 
             var parent = item.Parent;
 
@@ -505,7 +500,7 @@ namespace MediaBrowser.Api
                            ? (request.UserId.HasValue
                                   ? user.RootFolder
                                   : (Folder)_libraryManager.RootFolder)
-                           : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, request.UserId);
+                           : _dtoService.GetItemByDtoId(request.Id, request.UserId);
 
             while (item.ThemeSongIds.Count == 0 && request.InheritFromParent && item.Parent != null)
             {
@@ -517,11 +512,9 @@ namespace MediaBrowser.Api
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var tasks = item.ThemeSongIds.Select(_itemRepo.RetrieveItem)
                             .OrderBy(i => i.SortName)
-                            .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, item));
+                            .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
 
             var items = await Task.WhenAll(tasks).ConfigureAwait(false);
 
@@ -529,7 +522,7 @@ namespace MediaBrowser.Api
             {
                 Items = items,
                 TotalRecordCount = items.Length,
-                OwnerId = DtoBuilder.GetClientItemId(item)
+                OwnerId = _dtoService.GetDtoId(item)
             };
         }
 
@@ -553,7 +546,7 @@ namespace MediaBrowser.Api
                            ? (request.UserId.HasValue
                                   ? user.RootFolder
                                   : (Folder)_libraryManager.RootFolder)
-                           : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, request.UserId);
+                           : _dtoService.GetItemByDtoId(request.Id, request.UserId);
 
             while (item.ThemeVideoIds.Count == 0 && request.InheritFromParent && item.Parent != null)
             {
@@ -566,11 +559,9 @@ namespace MediaBrowser.Api
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var tasks = item.ThemeVideoIds.Select(_itemRepo.RetrieveItem)
                             .OrderBy(i => i.SortName)
-                            .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, item));
+                            .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
 
             var items = await Task.WhenAll(tasks).ConfigureAwait(false);
 
@@ -578,7 +569,7 @@ namespace MediaBrowser.Api
             {
                 Items = items,
                 TotalRecordCount = items.Length,
-                OwnerId = DtoBuilder.GetClientItemId(item)
+                OwnerId = _dtoService.GetDtoId(item)
             };
         }
     }

+ 7 - 3
MediaBrowser.Api/MoviesService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -42,19 +43,21 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
 
         private readonly IItemRepository _itemRepo;
-        
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="MoviesService"/> class.
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public MoviesService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public MoviesService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -68,6 +71,7 @@ namespace MediaBrowser.Api
                 _itemRepo,
                 _libraryManager,
                 _userDataRepository,
+                _dtoService,
                 Logger,
                 request, item => item is Movie || (item is Trailer && request.IncludeTrailers),
                 SimilarItemsHelper.GetSimiliarityScore);

+ 9 - 7
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -31,31 +31,32 @@ namespace MediaBrowser.Api.Playback
         /// Gets or sets the application paths.
         /// </summary>
         /// <value>The application paths.</value>
-        protected IServerApplicationPaths ApplicationPaths { get; set; }
+        protected IServerApplicationPaths ApplicationPaths { get; private set; }
 
         /// <summary>
         /// Gets or sets the user manager.
         /// </summary>
         /// <value>The user manager.</value>
-        protected IUserManager UserManager { get; set; }
+        protected IUserManager UserManager { get; private set; }
 
         /// <summary>
         /// Gets or sets the library manager.
         /// </summary>
         /// <value>The library manager.</value>
-        protected ILibraryManager LibraryManager { get; set; }
+        protected ILibraryManager LibraryManager { get; private set; }
 
         /// <summary>
         /// Gets or sets the iso manager.
         /// </summary>
         /// <value>The iso manager.</value>
-        protected IIsoManager IsoManager { get; set; }
+        protected IIsoManager IsoManager { get; private set; }
 
         /// <summary>
         /// Gets or sets the media encoder.
         /// </summary>
         /// <value>The media encoder.</value>
-        protected IMediaEncoder MediaEncoder { get; set; }
+        protected IMediaEncoder MediaEncoder { get; private set; }
+        protected IDtoService DtoService { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
@@ -65,8 +66,9 @@ namespace MediaBrowser.Api.Playback
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder)
+        protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
         {
+            DtoService = dtoService;
             ApplicationPaths = appPaths;
             UserManager = userManager;
             LibraryManager = libraryManager;
@@ -751,7 +753,7 @@ namespace MediaBrowser.Api.Playback
         /// <returns>StreamState.</returns>
         protected StreamState GetState(StreamRequest request)
         {
-            var item = DtoBuilder.GetItemByClientId(request.Id, UserManager, LibraryManager);
+            var item = DtoService.GetItemByDtoId(request.Id);
 
             var media = (IHasMediaStreams)item;
 

+ 3 - 2
MediaBrowser.Api/Playback/Hls/AudioHlsService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.IO;
@@ -53,8 +54,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder)
+        public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
         {
         }
 

+ 3 - 2
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.IO;
@@ -37,8 +38,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder)
+        protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
         {
         }
 

+ 3 - 2
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.IO;
 using ServiceStack.ServiceHost;
@@ -69,8 +70,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder)
+        public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
         {
         }
 

+ 3 - 2
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.IO;
@@ -48,8 +49,8 @@ namespace MediaBrowser.Api.Playback.Progressive
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo)
+        public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService)
         {
         }
 

+ 6 - 5
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
@@ -23,9 +24,9 @@ namespace MediaBrowser.Api.Playback.Progressive
     public abstract class BaseProgressiveStreamingService : BaseStreamingService
     {
         protected readonly IItemRepository ItemRepository;
-        
-        protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository) :
-            base(appPaths, userManager, libraryManager, isoManager, mediaEncoder)
+
+        protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService) :
+            base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
         {
             ItemRepository = itemRepository;
         }
@@ -302,7 +303,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 }
             }
 
-            return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository)
+            return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService)
             {
                 Logger = Logger,
                 RequestContext = RequestContext,
@@ -342,7 +343,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
             }
 
-            var result = new ProgressiveStreamWriter(outputPath, state, Logger);
+            var result = new ProgressiveStreamWriter(outputPath, Logger);
 
             result.Options["Accept-Ranges"] = "none";
             result.Options["Content-Type"] = contentType;

+ 1 - 4
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs

@@ -12,7 +12,6 @@ namespace MediaBrowser.Api.Playback.Progressive
     public class ProgressiveStreamWriter : IStreamWriter, IHasOptions
     {
         private string Path { get; set; }
-        private StreamState State { get; set; }
         private ILogger Logger { get; set; }
 
         /// <summary>
@@ -32,12 +31,10 @@ namespace MediaBrowser.Api.Playback.Progressive
         /// Initializes a new instance of the <see cref="ProgressiveStreamWriter" /> class.
         /// </summary>
         /// <param name="path">The path.</param>
-        /// <param name="state">The state.</param>
         /// <param name="logger">The logger.</param>
-        public ProgressiveStreamWriter(string path, StreamState state, ILogger logger)
+        public ProgressiveStreamWriter(string path, ILogger logger)
         {
             Path = path;
-            State = state;
             Logger = logger;
         }
 

+ 3 - 2
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -60,8 +61,8 @@ namespace MediaBrowser.Api.Playback.Progressive
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo)
+        public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService)
         {
         }
 

+ 4 - 2
MediaBrowser.Api/SearchService.cs

@@ -65,6 +65,7 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly ILibrarySearchEngine _searchEngine;
         private readonly ILibraryManager _libraryManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SearchService" /> class.
@@ -72,11 +73,12 @@ namespace MediaBrowser.Api
         /// <param name="userManager">The user manager.</param>
         /// <param name="searchEngine">The search engine.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public SearchService(IUserManager userManager, ILibrarySearchEngine searchEngine, ILibraryManager libraryManager)
+        public SearchService(IUserManager userManager, ILibrarySearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService)
         {
             _userManager = userManager;
             _searchEngine = searchEngine;
             _libraryManager = libraryManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -149,7 +151,7 @@ namespace MediaBrowser.Api
                 Name = item.Name,
                 IndexNumber = item.IndexNumber,
                 ParentIndexNumber = item.ParentIndexNumber,
-                ItemId = DtoBuilder.GetClientItemId(item),
+                ItemId = _dtoService.GetDtoId(item),
                 Type = item.GetType().Name,
                 MediaType = item.MediaType,
                 MatchedTerm = hintInfo.MatchedTerm,

+ 5 - 2
MediaBrowser.Api/SessionsService.cs

@@ -180,13 +180,16 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly ISessionManager _sessionManager;
 
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SessionsService" /> class.
         /// </summary>
         /// <param name="sessionManager">The session manager.</param>
-        public SessionsService(ISessionManager sessionManager)
+        public SessionsService(ISessionManager sessionManager, IDtoService dtoService)
         {
             _sessionManager = sessionManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -203,7 +206,7 @@ namespace MediaBrowser.Api
                 result = result.Where(i => i.SupportsRemoteControl == request.SupportsRemoteControl.Value);
             }
 
-            return ToOptimizedResult(result.Select(SessionInfoDtoBuilder.GetSessionInfoDto).ToList());
+            return ToOptimizedResult(result.Select(_dtoService.GetSessionInfoDto).ToList());
         }
 
         public void Post(SendPlaystateCommand request)

+ 4 - 5
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -87,23 +87,22 @@ namespace MediaBrowser.Api
         /// <param name="itemRepository">The item repository.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
+        /// <param name="dtoService">The dto service.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="request">The request.</param>
         /// <param name="includeInSearch">The include in search.</param>
         /// <param name="getSimilarityScore">The get similarity score.</param>
         /// <returns>ItemsResult.</returns>
-        internal static ItemsResult GetSimilarItemsResult(IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataRepository userDataRepository, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
+        internal static ItemsResult GetSimilarItemsResult(IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
         {
             var user = request.UserId.HasValue ? userManager.GetUserById(request.UserId.Value) : null;
 
             var item = string.IsNullOrEmpty(request.Id) ?
                 (request.UserId.HasValue ? user.RootFolder :
-                (Folder)libraryManager.RootFolder) : DtoBuilder.GetItemByClientId(request.Id, userManager, libraryManager, request.UserId);
+                (Folder)libraryManager.RootFolder) : dtoService.GetItemByDtoId(request.Id, request.UserId);
 
             var fields = request.GetItemFields().ToList();
 
-            var dtoBuilder = new DtoBuilder(logger, libraryManager, userDataRepository, itemRepository);
-
             var inputItems = user == null
                                  ? libraryManager.RootFolder.RecursiveChildren
                                  : user.RootFolder.GetRecursiveChildren(user);
@@ -113,7 +112,7 @@ namespace MediaBrowser.Api
 
             var result = new ItemsResult
             {
-                Items = items.Take(request.Limit ?? items.Length).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToArray(),
+                Items = items.Take(request.Limit ?? items.Length).Select(i => dtoService.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToArray(),
 
                 TotalRecordCount = items.Length
             };

+ 7 - 3
MediaBrowser.Api/TrailersService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -35,19 +36,21 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
 
         private readonly IItemRepository _itemRepo;
-        
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="TrailersService"/> class.
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public TrailersService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public TrailersService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -61,6 +64,7 @@ namespace MediaBrowser.Api
                 _itemRepo,
                 _libraryManager,
                 _userDataRepository,
+                _dtoService,
                 Logger,
                 request, item => item is Movie || item is Trailer,
                 SimilarItemsHelper.GetSimiliarityScore);

+ 6 - 5
MediaBrowser.Api/TvShowsService.cs

@@ -101,19 +101,21 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
 
         private readonly IItemRepository _itemRepo;
-        
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="TvShowsService" /> class.
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public TvShowsService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo)
+        public TvShowsService(IUserManager userManager, IUserDataRepository userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService)
         {
             _userManager = userManager;
             _userDataRepository = userDataRepository;
             _libraryManager = libraryManager;
             _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -127,6 +129,7 @@ namespace MediaBrowser.Api
                 _itemRepo,
                 _libraryManager,
                 _userDataRepository,
+                _dtoService,
                 Logger,
                 request, item => item is Series,
                 SimilarItemsHelper.GetSimiliarityScore);
@@ -253,9 +256,7 @@ namespace MediaBrowser.Api
         /// <returns>Task.</returns>
         private Task<BaseItemDto[]> GetItemDtos(IEnumerable<BaseItem> pagedItems, User user, List<ItemFields> fields)
         {
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
-            return Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)));
+            return Task.WhenAll(pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)));
         }
 
         /// <summary>

+ 4 - 6
MediaBrowser.Api/UserLibrary/ArtistsService.cs

@@ -75,8 +75,8 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="itemRepo">The item repo.</param>
-        public ArtistsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public ArtistsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -104,16 +104,14 @@ namespace MediaBrowser.Api.UserLibrary
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
 
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 7 - 5
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -30,6 +30,7 @@ namespace MediaBrowser.Api.UserLibrary
         protected readonly ILibraryManager LibraryManager;
         protected readonly IUserDataRepository UserDataRepository;
         protected readonly IItemRepository ItemRepository;
+        protected IDtoService DtoService { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
@@ -37,12 +38,13 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="userManager">The user manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
-        protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepository)
+        protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepository, IDtoService dtoService)
         {
             UserManager = userManager;
             LibraryManager = libraryManager;
             UserDataRepository = userDataRepository;
             ItemRepository = itemRepository;
+            DtoService = dtoService;
         }
 
         /// <summary>
@@ -58,11 +60,11 @@ namespace MediaBrowser.Api.UserLibrary
             if (request.UserId.HasValue)
             {
                 user = UserManager.GetUserById(request.UserId.Value);
-                item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
+                item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoService.GetItemByDtoId(request.ParentId, user.Id);
             }
             else
             {
-                item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager);
+                item = string.IsNullOrEmpty(request.ParentId) ? LibraryManager.RootFolder : DtoService.GetItemByDtoId(request.ParentId);
             }
 
             IEnumerable<BaseItem> items;
@@ -285,8 +287,8 @@ namespace MediaBrowser.Api.UserLibrary
                 return null;
             }
 
-            var dto = user == null ? await new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository).GetBaseItemDto(item, fields).ConfigureAwait(false) :
-                await new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository).GetBaseItemDto(item, fields, user).ConfigureAwait(false);
+            var dto = user == null ? await DtoService.GetBaseItemDto(item, fields).ConfigureAwait(false) :
+                await DtoService.GetBaseItemDto(item, fields, user).ConfigureAwait(false);
 
             if (fields.Contains(ItemFields.ItemCounts))
             {

+ 4 - 6
MediaBrowser.Api/UserLibrary/GameGenresService.cs

@@ -63,8 +63,8 @@ namespace MediaBrowser.Api.UserLibrary
 
     public class GameGenresService : BaseItemsByNameService<GameGenre>
     {
-        public GameGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public GameGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -92,16 +92,14 @@ namespace MediaBrowser.Api.UserLibrary
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
 
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 4 - 6
MediaBrowser.Api/UserLibrary/GenresService.cs

@@ -69,8 +69,8 @@ namespace MediaBrowser.Api.UserLibrary
     /// </summary>
     public class GenresService : BaseItemsByNameService<Genre>
     {
-        public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public GenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -98,16 +98,14 @@ namespace MediaBrowser.Api.UserLibrary
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
 
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
        
         /// <summary>

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

@@ -138,16 +138,18 @@ namespace MediaBrowser.Api.UserLibrary
         /// The library manager
         /// </summary>
         protected readonly ILibraryManager LibraryManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ItemByNameUserDataService" /> class.
         /// </summary>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="libraryManager">The library manager.</param>
-        public ItemByNameUserDataService(IUserDataRepository userDataRepository, ILibraryManager libraryManager)
+        public ItemByNameUserDataService(IUserDataRepository userDataRepository, ILibraryManager libraryManager, IDtoService dtoService)
         {
             UserDataRepository = userDataRepository;
             LibraryManager = libraryManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -230,7 +232,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             data = UserDataRepository.GetUserData(userId, key);
 
-            return DtoBuilder.GetUserItemDataDto(data);
+            return _dtoService.GetUserItemDataDto(data);
         }
 
         /// <summary>
@@ -256,7 +258,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             data = UserDataRepository.GetUserData(userId, key);
 
-            return DtoBuilder.GetUserItemDataDto(data);
+            return _dtoService.GetUserItemDataDto(data);
         }
     }
 }

+ 8 - 10
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -210,8 +210,8 @@ namespace MediaBrowser.Api.UserLibrary
         private readonly ILibrarySearchEngine _searchEngine;
         private readonly ILocalizationManager _localization;
 
-        private readonly IItemRepository _itemRepo;
-        
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ItemsService" /> class.
         /// </summary>
@@ -219,14 +219,14 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="searchEngine">The search engine.</param>
         /// <param name="userDataRepository">The user data repository.</param>
-        public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine, IUserDataRepository userDataRepository, ILocalizationManager localization, IItemRepository itemRepo)
+        public ItemsService(IUserManager userManager, ILibraryManager libraryManager, ILibrarySearchEngine searchEngine, IUserDataRepository userDataRepository, ILocalizationManager localization, IDtoService dtoService)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _searchEngine = searchEngine;
             _userDataRepository = userDataRepository;
             _localization = localization;
-            _itemRepo = itemRepo;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -275,9 +275,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var fields = request.GetItemFields().ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
-            var returnItems = await Task.WhenAll(pagedItems.Select(i => dtoBuilder.GetBaseItemDto(i, fields, user))).ConfigureAwait(false);
+            var returnItems = await Task.WhenAll(pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user))).ConfigureAwait(false);
 
             return new ItemsResult
             {
@@ -295,7 +293,7 @@ namespace MediaBrowser.Api.UserLibrary
         /// <exception cref="System.InvalidOperationException"></exception>
         private IEnumerable<BaseItem> GetItemsToSerialize(GetItems request, User user)
         {
-            var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : _dtoService.GetItemByDtoId(request.ParentId, user.Id);
 
             // Default list type = children
 
@@ -303,7 +301,7 @@ namespace MediaBrowser.Api.UserLibrary
             {
                 var idList = request.Ids.Split(',').ToList();
 
-                return idList.Select(i => DtoBuilder.GetItemByClientId(i, _userManager, _libraryManager, user.Id));
+                return idList.Select(i => _dtoService.GetItemByDtoId(i, user.Id));
             }
 
             if (request.Recursive)
@@ -492,7 +490,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             if (!string.IsNullOrEmpty(request.AdjacentTo))
             {
-                var item = DtoBuilder.GetItemByClientId(request.AdjacentTo, _userManager, _libraryManager);
+                var item = _dtoService.GetItemByDtoId(request.AdjacentTo);
 
                 var allSiblings = item.Parent.GetChildren(user, true).OrderBy(i => i.SortName).ToList();
 

+ 4 - 6
MediaBrowser.Api/UserLibrary/MusicGenresService.cs

@@ -63,8 +63,8 @@ namespace MediaBrowser.Api.UserLibrary
 
     public class MusicGenresService : BaseItemsByNameService<MusicGenre>
     {
-        public MusicGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public MusicGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -92,16 +92,14 @@ namespace MediaBrowser.Api.UserLibrary
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
 
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 5 - 8
MediaBrowser.Api/UserLibrary/PersonsService.cs

@@ -6,7 +6,6 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using ServiceStack.ServiceHost;
 using System;
@@ -86,8 +85,8 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="itemRepo">The item repo.</param>
-        public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public PersonsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -114,17 +113,15 @@ namespace MediaBrowser.Api.UserLibrary
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
+            
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 5 - 7
MediaBrowser.Api/UserLibrary/StudiosService.cs

@@ -70,8 +70,8 @@ namespace MediaBrowser.Api.UserLibrary
     /// </summary>
     public class StudiosService : BaseItemsByNameService<Studio>
     {
-        public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public StudiosService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -98,17 +98,15 @@ namespace MediaBrowser.Api.UserLibrary
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
+            
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 21 - 27
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -366,6 +366,7 @@ namespace MediaBrowser.Api.UserLibrary
         private readonly IItemRepository _itemRepo;
 
         private readonly ISessionManager _sessionManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="UserLibraryService" /> class.
@@ -375,13 +376,14 @@ namespace MediaBrowser.Api.UserLibrary
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="itemRepo">The item repo.</param>
         /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
-        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, ISessionManager sessionManager)
+        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, ISessionManager sessionManager, IDtoService dtoService)
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _userDataRepository = userDataRepository;
             _itemRepo = itemRepo;
             _sessionManager = sessionManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -400,13 +402,11 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var movie = item as Movie;
 
             // Get them from the db
@@ -418,7 +418,7 @@ namespace MediaBrowser.Api.UserLibrary
                 var tasks = movie.SpecialFeatureIds
                     .Select(_itemRepo.RetrieveItem)
                     .OrderBy(i => i.SortName)
-                    .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, movie1));
+                    .Select(i => _dtoService.GetBaseItemDto(i, fields, user, movie1));
 
                 return Task.WhenAll(tasks);
             }
@@ -446,7 +446,7 @@ namespace MediaBrowser.Api.UserLibrary
                         return DateTime.MinValue;
                     })
                     .ThenBy(i => i.SortName)
-                    .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user));
+                    .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
 
                 return Task.WhenAll(tasks);
             }
@@ -470,17 +470,15 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var tasks = item.LocalTrailerIds
                 .Select(_itemRepo.RetrieveItem)
                 .OrderBy(i => i.SortName)
-                .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, item));
+                .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item));
 
             return Task.WhenAll(tasks);
         }
@@ -494,14 +492,12 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
-            var result = dtoBuilder.GetBaseItemDto(item, fields, user).Result;
+            var result = _dtoService.GetBaseItemDto(item, fields, user).Result;
 
             return ToOptimizedResult(result);
         }
@@ -520,9 +516,7 @@ namespace MediaBrowser.Api.UserLibrary
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
-            var result = dtoBuilder.GetBaseItemDto(item, fields, user).Result;
+            var result = _dtoService.GetBaseItemDto(item, fields, user).Result;
 
             return ToOptimizedResult(result);
         }
@@ -536,7 +530,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             var result = _libraryManager.GetIntros(item, user);
 
@@ -569,7 +563,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(userId);
 
-            var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : _dtoService.GetItemByDtoId(itemId, user.Id);
 
             var key = item.GetUserDataKey();
 
@@ -583,7 +577,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             data = _userDataRepository.GetUserData(user.Id, key);
 
-            return DtoBuilder.GetUserItemDataDto(data);
+            return _dtoService.GetUserItemDataDto(data);
         }
 
         /// <summary>
@@ -612,7 +606,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(userId);
 
-            var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
+            var item = string.IsNullOrEmpty(itemId) ? user.RootFolder : _dtoService.GetItemByDtoId(itemId, user.Id);
 
             var key = item.GetUserDataKey();
 
@@ -625,7 +619,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             data = _userDataRepository.GetUserData(user.Id, key);
 
-            return DtoBuilder.GetUserItemDataDto(data);
+            return _dtoService.GetUserItemDataDto(data);
         }
 
         /// <summary>
@@ -666,7 +660,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             _sessionManager.OnPlaybackStart(item, GetSession().Id);
         }
@@ -679,7 +673,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             var task = _sessionManager.OnPlaybackProgress(item, request.PositionTicks, request.IsPaused, request.IsMuted, GetSession().Id);
 
@@ -694,7 +688,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var item = DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, user.Id);
+            var item = _dtoService.GetItemByDtoId(request.Id, user.Id);
 
             var task = _sessionManager.OnPlaybackStopped(item, request.PositionTicks, GetSession().Id);
 
@@ -723,11 +717,11 @@ namespace MediaBrowser.Api.UserLibrary
         /// <returns>Task.</returns>
         private async Task<UserItemDataDto> UpdatePlayedStatus(User user, string itemId, bool wasPlayed)
         {
-            var item = DtoBuilder.GetItemByClientId(itemId, _userManager, _libraryManager, user.Id);
+            var item = _dtoService.GetItemByDtoId(itemId, user.Id);
 
             await item.SetPlayedStatus(user, wasPlayed, _userDataRepository).ConfigureAwait(false);
 
-            return DtoBuilder.GetUserItemDataDto(_userDataRepository.GetUserData(user.Id, item.GetUserDataKey()));
+            return _dtoService.GetUserItemDataDto(_userDataRepository.GetUserData(user.Id, item.GetUserDataKey()));
         }
     }
 }

+ 5 - 7
MediaBrowser.Api/UserLibrary/YearsService.cs

@@ -54,8 +54,8 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
-        public YearsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
-            : base(userManager, libraryManager, userDataRepository, itemRepo)
+        public YearsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo, IDtoService dtoService)
+            : base(userManager, libraryManager, userDataRepository, itemRepo, dtoService)
         {
         }
 
@@ -82,17 +82,15 @@ namespace MediaBrowser.Api.UserLibrary
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true));
-
-            var builder = new DtoBuilder(Logger, LibraryManager, UserDataRepository, ItemRepository);
-
+            
             if (request.UserId.HasValue)
             {
                 var user = UserManager.GetUserById(request.UserId.Value);
 
-                return await builder.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
+                return await DtoService.GetBaseItemDto(item, fields.ToList(), user).ConfigureAwait(false);
             }
 
-            return await builder.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
+            return await DtoService.GetBaseItemDto(item, fields.ToList()).ConfigureAwait(false);
         }
 
         /// <summary>

+ 7 - 14
MediaBrowser.Api/UserService.cs

@@ -171,16 +171,15 @@ namespace MediaBrowser.Api
         /// The _user manager
         /// </summary>
         private readonly IUserManager _userManager;
-        private readonly ILibraryManager _libraryManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="UserService" /> class.
         /// </summary>
         /// <param name="xmlSerializer">The XML serializer.</param>
         /// <param name="userManager">The user manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
         /// <exception cref="System.ArgumentNullException">xmlSerializer</exception>
-        public UserService(IXmlSerializer xmlSerializer, IUserManager userManager, ILibraryManager libraryManager)
+        public UserService(IXmlSerializer xmlSerializer, IUserManager userManager, IDtoService dtoService)
             : base()
         {
             if (xmlSerializer == null)
@@ -190,7 +189,7 @@ namespace MediaBrowser.Api
 
             _xmlSerializer = xmlSerializer;
             _userManager = userManager;
-            _libraryManager = libraryManager;
+            _dtoService = dtoService;
         }
 
         public object Get(GetPublicUsers request)
@@ -209,8 +208,6 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetUsers request)
         {
-            var dtoBuilder = new UserDtoBuilder(Logger);
-
             var users = _userManager.Users;
 
             if (request.IsDisabled.HasValue)
@@ -223,7 +220,7 @@ namespace MediaBrowser.Api
                 users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
             }
 
-            var tasks = users.OrderBy(u => u.Name).Select(dtoBuilder.GetUserDto).Select(i => i.Result);
+            var tasks = users.OrderBy(u => u.Name).Select(_dtoService.GetUserDto).Select(i => i.Result);
 
             return ToOptimizedResult(tasks.ToList());
         }
@@ -242,9 +239,7 @@ namespace MediaBrowser.Api
                 throw new ResourceNotFoundException("User not found");
             }
 
-            var dtoBuilder = new UserDtoBuilder(Logger);
-
-            var result = dtoBuilder.GetUserDto(user).Result;
+            var result = _dtoService.GetUserDto(user).Result;
 
             return ToOptimizedResult(result);
         }
@@ -310,7 +305,7 @@ namespace MediaBrowser.Api
 
             var result = new AuthenticationResult
             {
-                User = await new UserDtoBuilder(Logger).GetUserDto(user).ConfigureAwait(false)
+                User = await _dtoService.GetUserDto(user).ConfigureAwait(false)
             };
 
             return result;
@@ -409,9 +404,7 @@ namespace MediaBrowser.Api
 
             newUser.UpdateConfiguration(dtoUser.Configuration, _xmlSerializer);
 
-            var dtoBuilder = new UserDtoBuilder(Logger);
-
-            var result = dtoBuilder.GetUserDto(newUser).Result;
+            var result = _dtoService.GetUserDto(newUser).Result;
 
             return ToOptimizedResult(result);
         }

+ 5 - 7
MediaBrowser.Api/VideosService.cs

@@ -30,14 +30,14 @@ namespace MediaBrowser.Api
 
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
-        private readonly IUserDataRepository _userDataRepository;
+        private readonly IDtoService _dtoService;
 
-        public VideosService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IUserDataRepository userDataRepository)
+        public VideosService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IDtoService dtoService)
         {
             _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _userManager = userManager;
-            _userDataRepository = userDataRepository;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -53,20 +53,18 @@ namespace MediaBrowser.Api
                            ? (request.UserId.HasValue
                                   ? user.RootFolder
                                   : (Folder)_libraryManager.RootFolder)
-                           : DtoBuilder.GetItemByClientId(request.Id, _userManager, _libraryManager, request.UserId);
+                           : _dtoService.GetItemByDtoId(request.Id, request.UserId);
 
             // Get everything
             var fields = Enum.GetNames(typeof(ItemFields))
                     .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
                     .ToList();
 
-            var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository, _itemRepo);
-
             var video = (Video)item;
 
             var items = video.AdditionalPartIds.Select(_itemRepo.RetrieveItem)
                          .OrderBy(i => i.SortName)
-                         .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user, video))
+                         .Select(i => _dtoService.GetBaseItemDto(i, fields, user, video))
                          .Select(t => t.Result)
                          .ToArray();
 

+ 5 - 2
MediaBrowser.Api/WebSocket/SessionInfoWebSocketListener.cs

@@ -14,6 +14,8 @@ namespace MediaBrowser.Api.WebSocket
     /// </summary>
     class SessionInfoWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<SessionInfoDto>, object>
     {
+        private readonly IDtoService _dtoService;
+
         /// <summary>
         /// Gets the name.
         /// </summary>
@@ -33,10 +35,11 @@ namespace MediaBrowser.Api.WebSocket
         /// </summary>
         /// <param name="logger">The logger.</param>
         /// <param name="sessionManager">The session manager.</param>
-        public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager)
+        public SessionInfoWebSocketListener(ILogger logger, ISessionManager sessionManager, IDtoService dtoService)
             : base(logger)
         {
             _sessionManager = sessionManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -46,7 +49,7 @@ namespace MediaBrowser.Api.WebSocket
         /// <returns>Task{SystemInfo}.</returns>
         protected override Task<IEnumerable<SessionInfoDto>> GetDataToSend(object state)
         {
-            return Task.FromResult(_sessionManager.Sessions.Select(SessionInfoDtoBuilder.GetSessionInfoDto));
+            return Task.FromResult(_sessionManager.Sessions.Select(_dtoService.GetSessionInfoDto));
         }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Drawing/ImageManager.cs

@@ -612,7 +612,7 @@ namespace MediaBrowser.Controller.Drawing
         /// <param name="supportedEnhancers">The supported enhancers.</param>
         /// <returns>System.String.</returns>
         /// <exception cref="System.ArgumentNullException">originalImagePath</exception>
-        public async Task<string> GetEnhancedImage(string originalImagePath, DateTime dateModified, BaseItem item, ImageType imageType, int imageIndex, IEnumerable<IImageEnhancer> supportedEnhancers)
+        public async Task<string> GetEnhancedImage(string originalImagePath, DateTime dateModified, BaseItem item, ImageType imageType, int imageIndex, List<IImageEnhancer> supportedEnhancers)
         {
             if (string.IsNullOrEmpty(originalImagePath))
             {

+ 71 - 0
MediaBrowser.Controller/Dto/IDtoService.cs

@@ -0,0 +1,71 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Session;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Dto
+{
+    /// <summary>
+    /// Interface IDtoService
+    /// </summary>
+    public interface IDtoService
+    {
+        /// <summary>
+        /// Gets the user dto.
+        /// </summary>
+        /// <param name="user">The user.</param>
+        /// <returns>Task{UserDto}.</returns>
+        Task<UserDto> GetUserDto(User user);
+
+        /// <summary>
+        /// Gets the session info dto.
+        /// </summary>
+        /// <param name="session">The session.</param>
+        /// <returns>SessionInfoDto.</returns>
+        SessionInfoDto GetSessionInfoDto(SessionInfo session);
+
+        /// <summary>
+        /// Gets the base item info.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>BaseItemInfo.</returns>
+        BaseItemInfo GetBaseItemInfo(BaseItem item);
+
+        /// <summary>
+        /// Gets the dto id.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>System.String.</returns>
+        string GetDtoId(BaseItem item);
+
+        /// <summary>
+        /// Gets the user item data dto.
+        /// </summary>
+        /// <param name="data">The data.</param>
+        /// <returns>UserItemDataDto.</returns>
+        UserItemDataDto GetUserItemDataDto(UserItemData data);
+
+        /// <summary>
+        /// Gets the item by dto id.
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <param name="userId">The user id.</param>
+        /// <returns>BaseItem.</returns>
+        BaseItem GetItemByDtoId(string id, Guid? userId = null);
+
+        /// <summary>
+        /// Gets the base item dto.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="fields">The fields.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="owner">The owner.</param>
+        /// <returns>Task{BaseItemDto}.</returns>
+        Task<BaseItemDto> GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null);
+    }
+}

+ 0 - 50
MediaBrowser.Controller/Dto/SessionInfoDtoBuilder.cs

@@ -1,50 +0,0 @@
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Session;
-
-namespace MediaBrowser.Controller.Dto
-{
-    /// <summary>
-    /// Class SessionInfoDtoBuilder
-    /// </summary>
-    public static class SessionInfoDtoBuilder
-    {
-        /// <summary>
-        /// Gets the session info dto.
-        /// </summary>
-        /// <param name="session">The session.</param>
-        /// <returns>SessionInfoDto.</returns>
-        public static SessionInfoDto GetSessionInfoDto(SessionInfo session)
-        {
-            var dto = new SessionInfoDto
-            {
-                Client = session.Client,
-                DeviceId = session.DeviceId,
-                DeviceName = session.DeviceName,
-                Id = session.Id.ToString("N"),
-                LastActivityDate = session.LastActivityDate,
-                NowPlayingPositionTicks = session.NowPlayingPositionTicks,
-                SupportsRemoteControl = session.SupportsRemoteControl,
-                IsPaused = session.IsPaused,
-                IsMuted = session.IsMuted,
-                NowViewingContext = session.NowViewingContext,
-                NowViewingItemId = session.NowViewingItemId,
-                NowViewingItemName = session.NowViewingItemName,
-                NowViewingItemType = session.NowViewingItemType,
-                ApplicationVersion = session.ApplicationVersion
-            };
-
-            if (session.NowPlayingItem != null)
-            {
-                dto.NowPlayingItem = DtoBuilder.GetBaseItemInfo(session.NowPlayingItem);
-            }
-
-            if (session.User != null)
-            {
-                dto.UserId = session.User.Id.ToString("N");
-                dto.UserName = session.User.Name;
-            }
-
-            return dto;
-        }
-    }
-}

+ 0 - 72
MediaBrowser.Controller/Dto/UserDtoBuilder.cs

@@ -1,72 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using System;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Dto
-{
-    /// <summary>
-    /// Class UserDtoBuilder
-    /// </summary>
-    public class UserDtoBuilder
-    {
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="UserDtoBuilder"/> class.
-        /// </summary>
-        /// <param name="logger">The logger.</param>
-        public UserDtoBuilder(ILogger logger)
-        {
-            _logger = logger;
-        }
-
-        /// <summary>
-        /// Converts a User to a DTOUser
-        /// </summary>
-        /// <param name="user">The user.</param>
-        /// <returns>DtoUser.</returns>
-        /// <exception cref="System.ArgumentNullException">user</exception>
-        public async Task<UserDto> GetUserDto(User user)
-        {
-            if (user == null)
-            {
-                throw new ArgumentNullException("user");
-            }
-
-            var dto = new UserDto
-            {
-                Id = user.Id.ToString("N"),
-                Name = user.Name,
-                HasPassword = !String.IsNullOrEmpty(user.Password),
-                LastActivityDate = user.LastActivityDate,
-                LastLoginDate = user.LastLoginDate,
-                Configuration = user.Configuration
-            };
-
-            var image = user.PrimaryImagePath;
-
-            if (!string.IsNullOrEmpty(image))
-            {
-                dto.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(user, ImageType.Primary, image);
-
-                try
-                {
-                    await DtoBuilder.AttachPrimaryImageAspectRatio(dto, user, _logger).ConfigureAwait(false);
-                }
-                catch (Exception ex)
-                {
-                    // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
-                    _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, user.Name);
-                }
-            }
-
-            return dto;
-        }
-    }
-}

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

@@ -71,10 +71,10 @@
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
+    <Compile Include="Dto\IDtoService.cs" />
     <Compile Include="Entities\AdultVideo.cs" />
     <Compile Include="Entities\Book.cs" />
     <Compile Include="Notifications\Configuration\IServerConfigurationManager.cs" />
-    <Compile Include="Dto\SessionInfoDtoBuilder.cs" />
     <Compile Include="Entities\Audio\MusicGenre.cs" />
     <Compile Include="Entities\Game.cs" />
     <Compile Include="Entities\GameGenre.cs" />
@@ -93,7 +93,6 @@
     <Compile Include="Drawing\ImageExtensions.cs" />
     <Compile Include="Drawing\ImageHeader.cs" />
     <Compile Include="Drawing\ImageManager.cs" />
-    <Compile Include="Dto\UserDtoBuilder.cs" />
     <Compile Include="Entities\AggregateFolder.cs" />
     <Compile Include="Entities\Audio\Artist.cs" />
     <Compile Include="Entities\Audio\Audio.cs" />
@@ -128,7 +127,6 @@
     <Compile Include="IO\NativeMethods.cs" />
     <Compile Include="IServerApplicationHost.cs" />
     <Compile Include="IServerApplicationPaths.cs" />
-    <Compile Include="Dto\DtoBuilder.cs" />
     <Compile Include="Library\SearchHintInfo.cs" />
     <Compile Include="Providers\IProviderManager.cs" />
     <Compile Include="MediaInfo\MediaEncoderHelpers.cs" />

+ 3 - 8
MediaBrowser.Controller/MediaInfo/FFMpegManager.cs

@@ -1,12 +1,11 @@
-using System.Collections.Generic;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using System;
+using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
@@ -31,8 +30,6 @@ namespace MediaBrowser.Controller.MediaInfo
         /// <value>The subtitle cache.</value>
         internal FileSystemRepository SubtitleCache { get; set; }
 
-        private readonly ILibraryManager _libraryManager;
-
         private readonly IServerApplicationPaths _appPaths;
         private readonly IMediaEncoder _encoder;
         private readonly ILogger _logger;
@@ -43,15 +40,13 @@ namespace MediaBrowser.Controller.MediaInfo
         /// </summary>
         /// <param name="appPaths">The app paths.</param>
         /// <param name="encoder">The encoder.</param>
-        /// <param name="libraryManager">The library manager.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="itemRepo">The item repo.</param>
         /// <exception cref="System.ArgumentNullException">zipClient</exception>
-        public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
+        public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo)
         {
             _appPaths = appPaths;
             _encoder = encoder;
-            _libraryManager = libraryManager;
             _logger = logger;
             _itemRepo = itemRepo;
 

+ 0 - 1
MediaBrowser.Controller/Persistence/IRepository.cs

@@ -1,5 +1,4 @@
 using System;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Persistence
 {

+ 1 - 8
MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs

@@ -38,22 +38,15 @@ namespace MediaBrowser.Providers.MediaInfo
         /// </summary>
         private readonly IMediaEncoder _mediaEncoder;
 
-        /// <summary>
-        /// The _library manager
-        /// </summary>
-        private readonly ILibraryManager _libraryManager;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class.
         /// </summary>
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public AudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder)
+        public AudioImageProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IMediaEncoder mediaEncoder)
             : base(logManager, configurationManager)
         {
-            _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
 
             ImageCache = new FileSystemRepository(Kernel.Instance.FFMpegManager.AudioImagesDataPath);

+ 2 - 11
MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
@@ -11,7 +10,6 @@ using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
-using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
@@ -38,11 +36,6 @@ namespace MediaBrowser.Providers.Movies
         /// </summary>
         private readonly IJsonSerializer _jsonSerializer;
 
-        /// <summary>
-        /// The _HTTP client
-        /// </summary>
-        private readonly IHttpClient _httpClient;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="MovieDbImagesProvider"/> class.
         /// </summary>
@@ -50,13 +43,11 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="httpClient">The HTTP client.</param>
-        public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer, IHttpClient httpClient)
+        public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
             _jsonSerializer = jsonSerializer;
-            _httpClient = httpClient;
         }
 
         /// <summary>

+ 45 - 5
MediaBrowser.Providers/Music/LastfmAlbumProvider.cs

@@ -69,7 +69,9 @@ namespace MediaBrowser.Providers.Music
 
         protected override async Task FetchLastfmData(BaseItem item, string id, CancellationToken cancellationToken)
         {
-            var result = await GetAlbumResult(item, cancellationToken).ConfigureAwait(false);
+            var album = (MusicAlbum)item;
+
+            var result = await GetAlbumResult(album, cancellationToken).ConfigureAwait(false);
 
             if (result != null && result.album != null)
             {
@@ -83,15 +85,35 @@ namespace MediaBrowser.Providers.Music
                 item.ProviderData[Id] = data;
             }
 
-            data.FileStamp = GetComparisonData(item as MusicAlbum);
+            data.FileStamp = GetComparisonData(album);
         }
 
-        private async Task<LastfmGetAlbumResult> GetAlbumResult(BaseItem item, CancellationToken cancellationToken)
+        private async Task<LastfmGetAlbumResult> GetAlbumResult(MusicAlbum item, CancellationToken cancellationToken)
         {
-            var folder = (Folder)item;
+            // Try album release Id
+            if (!string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Musicbrainz)))
+            {
+                var result = await GetAlbumResult(item.GetProviderId(MetadataProviders.Musicbrainz), cancellationToken).ConfigureAwait(false);
+
+                if (result != null && result.album != null)
+                {
+                    return result;
+                }
+            }
 
+            // Try album release group Id
+            if (!string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup)))
+            {
+                var result = await GetAlbumResult(item.GetProviderId(MetadataProviders.MusicBrainzReleaseGroup), cancellationToken).ConfigureAwait(false);
+
+                if (result != null && result.album != null)
+                {
+                    return result;
+                }
+            }
+            
             // Get each song, distinct by the combination of AlbumArtist and Album
-            var songs = folder.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
+            var songs = item.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
 
             foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
             {
@@ -124,6 +146,24 @@ namespace MediaBrowser.Providers.Music
                 return JsonSerializer.DeserializeFromStream<LastfmGetAlbumResult>(json);
             }
         }
+
+        private async Task<LastfmGetAlbumResult> GetAlbumResult(string musicbraizId, CancellationToken cancellationToken)
+        {
+            // Get albu info using artist and album name
+            var url = RootUrl + string.Format("method=album.getInfo&mbid={0}&api_key={1}&format=json", musicbraizId, ApiKey);
+
+            using (var json = await HttpClient.Get(new HttpRequestOptions
+            {
+                Url = url,
+                ResourcePool = LastfmResourcePool,
+                CancellationToken = cancellationToken,
+                EnableHttpCompression = false
+
+            }).ConfigureAwait(false))
+            {
+                return JsonSerializer.DeserializeFromStream<LastfmGetAlbumResult>(json);
+            }
+        }
         
         protected override Task FetchData(BaseItem item, CancellationToken cancellationToken)
         {

+ 1 - 2
MediaBrowser.Providers/TV/FanArtSeasonProvider.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;

+ 1 - 2
MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;

+ 747 - 682
MediaBrowser.Controller/Dto/DtoBuilder.cs → MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1,47 +1,45 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Session;
+using MoreLinq;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
-using MoreLinq;
 
-namespace MediaBrowser.Controller.Dto
+namespace MediaBrowser.Server.Implementations.Dto
 {
-    /// <summary>
-    /// Generates DTO's from domain entities
-    /// </summary>
-    public class DtoBuilder
+    public class DtoService : IDtoService
     {
-        /// <summary>
-        /// The index folder delimeter
-        /// </summary>
-        const string IndexFolderDelimeter = "-index-";
-
         private readonly ILogger _logger;
         private readonly ILibraryManager _libraryManager;
+        private readonly IUserManager _userManager;
         private readonly IUserDataRepository _userDataRepository;
         private readonly IItemRepository _itemRepo;
 
-        public DtoBuilder(ILogger logger, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
+        public DtoService(ILogger logger, ILibraryManager libraryManager, IUserManager userManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
         {
             _logger = logger;
             _libraryManager = libraryManager;
+            _userManager = userManager;
             _userDataRepository = userDataRepository;
             _itemRepo = itemRepo;
-        }
-
+        }        
+        
         /// <summary>
         /// Converts a BaseItem to a DTOBaseItem
         /// </summary>
@@ -81,7 +79,7 @@ namespace MediaBrowser.Controller.Dto
             {
                 try
                 {
-                    await AttachPrimaryImageAspectRatio(dto, item, _logger).ConfigureAwait(false);
+                    await AttachPrimaryImageAspectRatio(dto, item).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
@@ -140,7 +138,7 @@ namespace MediaBrowser.Controller.Dto
                         dto.ChildCount = folder.GetChildren(user, true).Count();
                     }
 
-                    SetSpecialCounts(folder, user, dto, _userDataRepository);
+                    SetSpecialCounts(folder, user, dto);
                 }
             }
 
@@ -154,957 +152,1024 @@ namespace MediaBrowser.Controller.Dto
             }
         }
 
-        /// <summary>
-        /// Attaches the primary image aspect ratio.
-        /// </summary>
-        /// <param name="dto">The dto.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="logger">The _logger.</param>
-        /// <returns>Task.</returns>
-        internal static async Task AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item, ILogger logger)
+        public async Task<UserDto> GetUserDto(User user)
         {
-            var path = item.PrimaryImagePath;
-
-            if (string.IsNullOrEmpty(path))
+            if (user == null)
             {
-                return;
+                throw new ArgumentNullException("user");
             }
 
-            var metaFileEntry = item.ResolveArgs.GetMetaFileByPath(path);
-
-            // See if we can avoid a file system lookup by looking for the file in ResolveArgs
-            var dateModified = metaFileEntry == null ? File.GetLastWriteTimeUtc(path) : metaFileEntry.LastWriteTimeUtc;
-
-            ImageSize size;
-
-            try
-            {
-                size = await Kernel.Instance.ImageManager.GetImageSize(path, dateModified).ConfigureAwait(false);
-            }
-            catch (FileNotFoundException)
-            {
-                logger.Error("Image file does not exist: {0}", path);
-                return;
-            }
-            catch (Exception ex)
+            var dto = new UserDto
             {
-                logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
-                return;
-            }
+                Id = user.Id.ToString("N"),
+                Name = user.Name,
+                HasPassword = !String.IsNullOrEmpty(user.Password),
+                LastActivityDate = user.LastActivityDate,
+                LastLoginDate = user.LastLoginDate,
+                Configuration = user.Configuration
+            };
 
-            dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height;
+            var image = user.PrimaryImagePath;
 
-            var supportedEnhancers = Kernel.Instance.ImageManager.ImageEnhancers.Where(i =>
+            if (!string.IsNullOrEmpty(image))
             {
+                dto.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(user, ImageType.Primary, image);
+
                 try
                 {
-                    return i.Supports(item, ImageType.Primary);
+                    await AttachPrimaryImageAspectRatio(dto, user).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
-                    logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
-
-                    return false;
+                    // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
+                    _logger.ErrorException("Error generating PrimaryImageAspectRatio for {0}", ex, user.Name);
                 }
+            }
 
-            }).ToList();
+            return dto;
+        }
 
+        public SessionInfoDto GetSessionInfoDto(SessionInfo session)
+        {
+            var dto = new SessionInfoDto
+            {
+                Client = session.Client,
+                DeviceId = session.DeviceId,
+                DeviceName = session.DeviceName,
+                Id = session.Id.ToString("N"),
+                LastActivityDate = session.LastActivityDate,
+                NowPlayingPositionTicks = session.NowPlayingPositionTicks,
+                SupportsRemoteControl = session.SupportsRemoteControl,
+                IsPaused = session.IsPaused,
+                IsMuted = session.IsMuted,
+                NowViewingContext = session.NowViewingContext,
+                NowViewingItemId = session.NowViewingItemId,
+                NowViewingItemName = session.NowViewingItemName,
+                NowViewingItemType = session.NowViewingItemType,
+                ApplicationVersion = session.ApplicationVersion
+            };
 
-            foreach (var enhancer in supportedEnhancers)
+            if (session.NowPlayingItem != null)
             {
-                try
-                {
-                    size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size);
-                }
-                catch (Exception ex)
-                {
-                    logger.ErrorException("Error in image enhancer: {0}", ex, enhancer.GetType().Name);
-                }
+                dto.NowPlayingItem = GetBaseItemInfo(session.NowPlayingItem);
             }
 
-            dto.PrimaryImageAspectRatio = size.Width / size.Height;
+            if (session.User != null)
+            {
+                dto.UserId = session.User.Id.ToString("N");
+                dto.UserName = session.User.Name;
+            }
+
+            return dto;
         }
 
         /// <summary>
-        /// Sets simple property values on a DTOBaseItem
+        /// Converts a BaseItem to a BaseItemInfo
         /// </summary>
-        /// <param name="dto">The dto.</param>
         /// <param name="item">The item.</param>
-        /// <param name="owner">The owner.</param>
-        /// <param name="fields">The fields.</param>
-        private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, List<ItemFields> fields)
+        /// <returns>BaseItemInfo.</returns>
+        /// <exception cref="System.ArgumentNullException">item</exception>
+        public BaseItemInfo GetBaseItemInfo(BaseItem item)
         {
-            if (fields.Contains(ItemFields.DateCreated))
+            if (item == null)
             {
-                dto.DateCreated = item.DateCreated;
+                throw new ArgumentNullException("item");
             }
 
-            if (fields.Contains(ItemFields.OriginalRunTimeTicks))
+            var info = new BaseItemInfo
             {
-                dto.OriginalRunTimeTicks = item.OriginalRunTimeTicks;
-            }
-
-            dto.DisplayMediaType = item.DisplayMediaType;
+                Id = GetDtoId(item),
+                Name = item.Name,
+                MediaType = item.MediaType,
+                Type = item.GetType().Name,
+                IsFolder = item.IsFolder,
+                RunTimeTicks = item.RunTimeTicks
+            };
 
-            if (fields.Contains(ItemFields.MetadataSettings))
-            {
-                dto.LockedFields = item.LockedFields;
-                dto.EnableInternetProviders = !item.DontFetchMeta;
-            }
+            var imagePath = item.PrimaryImagePath;
 
-            if (fields.Contains(ItemFields.Budget))
+            if (!string.IsNullOrEmpty(imagePath))
             {
-                dto.Budget = item.Budget;
+                try
+                {
+                    info.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Primary, imagePath);
+                }
+                catch (IOException)
+                {
+                }
             }
 
-            if (fields.Contains(ItemFields.Revenue))
-            {
-                dto.Revenue = item.Revenue;
-            }
+            return info;
+        }
 
-            dto.EndDate = item.EndDate;
+        const string IndexFolderDelimeter = "-index-";
 
-            if (fields.Contains(ItemFields.HomePageUrl))
+        /// <summary>
+        /// Gets client-side Id of a server-side BaseItem
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>System.String.</returns>
+        /// <exception cref="System.ArgumentNullException">item</exception>
+        public string GetDtoId(BaseItem item)
+        {
+            if (item == null)
             {
-                dto.HomePageUrl = item.HomePageUrl;
+                throw new ArgumentNullException("item");
             }
 
-            if (fields.Contains(ItemFields.Tags))
-            {
-                dto.Tags = item.Tags;
-            }
+            var indexFolder = item as IndexFolder;
 
-            if (fields.Contains(ItemFields.ProductionLocations))
+            if (indexFolder != null)
             {
-                dto.ProductionLocations = item.ProductionLocations;
+                return GetDtoId(indexFolder.Parent) + IndexFolderDelimeter + (indexFolder.IndexName ?? string.Empty) + IndexFolderDelimeter + indexFolder.Id;
             }
 
-            dto.AspectRatio = item.AspectRatio;
-
-            dto.BackdropImageTags = GetBackdropImageTags(item);
-            dto.ScreenshotImageTags = GetScreenshotImageTags(item);
+            return item.Id.ToString("N");
+        }
 
-            if (fields.Contains(ItemFields.Genres))
+        /// <summary>
+        /// Converts a UserItemData to a DTOUserItemData
+        /// </summary>
+        /// <param name="data">The data.</param>
+        /// <returns>DtoUserItemData.</returns>
+        /// <exception cref="System.ArgumentNullException"></exception>
+        public UserItemDataDto GetUserItemDataDto(UserItemData data)
+        {
+            if (data == null)
             {
-                dto.Genres = item.Genres;
+                throw new ArgumentNullException("data");
             }
 
-            dto.ImageTags = new Dictionary<ImageType, Guid>();
-
-            foreach (var image in item.Images)
+            return new UserItemDataDto
             {
-                var type = image.Key;
+                IsFavorite = data.IsFavorite,
+                Likes = data.Likes,
+                PlaybackPositionTicks = data.PlaybackPositionTicks,
+                PlayCount = data.PlayCount,
+                Rating = data.Rating,
+                Played = data.Played,
+                LastPlayedDate = data.LastPlayedDate
+            };
+        }
+        private void SetBookProperties(BaseItemDto dto, Book item)
+        {
+            dto.SeriesName = item.SeriesName;
+        }
 
-                var tag = GetImageCacheTag(item, type, image.Value);
+        private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
+        {
+            if (!string.IsNullOrEmpty(item.Album))
+            {
+                var parentAlbum = _libraryManager.RootFolder
+                    .RecursiveChildren
+                    .OfType<MusicAlbum>()
+                    .FirstOrDefault(i => string.Equals(i.Name, item.Album, StringComparison.OrdinalIgnoreCase));
 
-                if (tag.HasValue)
+                if (parentAlbum != null)
                 {
-                    dto.ImageTags[type] = tag.Value;
+                    dto.AlbumId = GetDtoId(parentAlbum);
                 }
             }
 
-            dto.Id = GetClientItemId(item);
-            dto.IndexNumber = item.IndexNumber;
-            dto.IsFolder = item.IsFolder;
-            dto.Language = item.Language;
-            dto.MediaType = item.MediaType;
-            dto.LocationType = item.LocationType;
-            dto.CriticRating = item.CriticRating;
-
-            if (fields.Contains(ItemFields.CriticRatingSummary))
-            {
-                dto.CriticRatingSummary = item.CriticRatingSummary;
-            }
-
-            var localTrailerCount = item.LocalTrailerIds.Count;
+            dto.Album = item.Album;
+            dto.Artists = string.IsNullOrEmpty(item.Artist) ? new string[] { } : new[] { item.Artist };
+        }
 
-            if (localTrailerCount > 0)
-            {
-                dto.LocalTrailerCount = localTrailerCount;
-            }
+        private void SetGameProperties(BaseItemDto dto, Game item)
+        {
+            dto.Players = item.PlayersSupported;
+            dto.GameSystem = item.GameSystem;
+        }
 
-            dto.Name = item.Name;
-            dto.OfficialRating = item.OfficialRating;
+        /// <summary>
+        /// Gets the backdrop image tags.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>List{System.String}.</returns>
+        private List<Guid> GetBackdropImageTags(BaseItem item)
+        {
+            return item.BackdropImagePaths
+                .Select(p => GetImageCacheTag(item, ImageType.Backdrop, p))
+                .Where(i => i.HasValue)
+                .Select(i => i.Value)
+                .ToList();
+        }
 
-            var hasOverview = fields.Contains(ItemFields.Overview);
-            var hasHtmlOverview = fields.Contains(ItemFields.OverviewHtml);
+        /// <summary>
+        /// Gets the screenshot image tags.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>List{Guid}.</returns>
+        private List<Guid> GetScreenshotImageTags(BaseItem item)
+        {
+            return item.ScreenshotImagePaths
+                .Select(p => GetImageCacheTag(item, ImageType.Screenshot, p))
+                .Where(i => i.HasValue)
+                .Select(i => i.Value)
+                .ToList();
+        }
 
-            if (hasOverview || hasHtmlOverview)
+        private Guid? GetImageCacheTag(BaseItem item, ImageType type, string path)
+        {
+            try
             {
-                var strippedOverview = string.IsNullOrEmpty(item.Overview) ? item.Overview : item.Overview.StripHtml();
-
-                if (hasOverview)
-                {
-                    dto.Overview = strippedOverview;
-                }
-
-                // Only supply the html version if there was actually html content
-                if (hasHtmlOverview)
-                {
-                    dto.OverviewHtml = item.Overview;
-                }
+                return Kernel.Instance.ImageManager.GetImageCacheTag(item, type, path);
             }
-
-            // If there are no backdrops, indicate what parent has them in case the Ui wants to allow inheritance
-            if (dto.BackdropImageTags.Count == 0)
+            catch (IOException ex)
             {
-                var parentWithBackdrop = GetParentBackdropItem(item, owner);
-
-                if (parentWithBackdrop != null)
-                {
-                    dto.ParentBackdropItemId = GetClientItemId(parentWithBackdrop);
-                    dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop);
-                }
+                _logger.ErrorException("Error getting {0} image info for {1}", ex, type, path);
+                return null;
             }
+        }        /// <summary>
+        /// Attaches People DTO's to a DTOBaseItem
+        /// </summary>
+        /// <param name="dto">The dto.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>Task.</returns>
+        private async Task AttachPeople(BaseItemDto dto, BaseItem item)
+        {
+            // Ordering by person type to ensure actors and artists are at the front.
+            // This is taking advantage of the fact that they both begin with A
+            // This should be improved in the future
+            var people = item.People.OrderBy(i => i.Type).ToList();
 
-            if (item.Parent != null && fields.Contains(ItemFields.ParentId))
-            {
-                dto.ParentId = GetClientItemId(item.Parent);
-            }
+            // Attach People by transforming them into BaseItemPerson (DTO)
+            dto.People = new BaseItemPerson[people.Count];
 
-            dto.ParentIndexNumber = item.ParentIndexNumber;
+            var entities = await Task.WhenAll(people.Select(p => p.Name)
+                .Distinct(StringComparer.OrdinalIgnoreCase).Select(c =>
+                    Task.Run(async () =>
+                    {
+                        try
+                        {
+                            return await _libraryManager.GetPerson(c).ConfigureAwait(false);
+                        }
+                        catch (IOException ex)
+                        {
+                            _logger.ErrorException("Error getting person {0}", ex, c);
+                            return null;
+                        }
+                    })
 
-            // If there is no logo, indicate what parent has one in case the Ui wants to allow inheritance
-            if (!dto.HasLogo)
+            )).ConfigureAwait(false);
+
+            var dictionary = entities.Where(i => i != null)
+                .DistinctBy(i => i.Name)
+                .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+
+            for (var i = 0; i < people.Count; i++)
             {
-                var parentWithLogo = GetParentImageItem(item, ImageType.Logo, owner);
+                var person = people[i];
 
-                if (parentWithLogo != null)
+                var baseItemPerson = new BaseItemPerson
                 {
-                    dto.ParentLogoItemId = GetClientItemId(parentWithLogo);
+                    Name = person.Name,
+                    Role = person.Role,
+                    Type = person.Type
+                };
 
-                    dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo, parentWithLogo.GetImage(ImageType.Logo));
+                Person entity;
+
+                if (dictionary.TryGetValue(person.Name, out entity))
+                {
+                    var primaryImagePath = entity.PrimaryImagePath;
+
+                    if (!string.IsNullOrEmpty(primaryImagePath))
+                    {
+                        baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
+                    }
                 }
+
+                dto.People[i] = baseItemPerson;
             }
+        }
 
-            // If there is no art, indicate what parent has one in case the Ui wants to allow inheritance
-            if (!dto.HasArtImage)
+        /// <summary>
+        /// Attaches the studios.
+        /// </summary>
+        /// <param name="dto">The dto.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>Task.</returns>
+        private async Task AttachStudios(BaseItemDto dto, BaseItem item)
+        {
+            var studios = item.Studios.ToList();
+
+            dto.Studios = new StudioDto[studios.Count];
+
+            var entities = await Task.WhenAll(studios.Distinct(StringComparer.OrdinalIgnoreCase).Select(c =>
+
+                    Task.Run(async () =>
+                    {
+                        try
+                        {
+                            return await _libraryManager.GetStudio(c).ConfigureAwait(false);
+                        }
+                        catch (IOException ex)
+                        {
+                            _logger.ErrorException("Error getting studio {0}", ex, c);
+                            return null;
+                        }
+                    })
+
+            )).ConfigureAwait(false);
+
+            var dictionary = entities
+                .Where(i => i != null)
+                .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+
+            for (var i = 0; i < studios.Count; i++)
             {
-                var parentWithImage = GetParentImageItem(item, ImageType.Art, owner);
+                var studio = studios[i];
 
-                if (parentWithImage != null)
+                var studioDto = new StudioDto
                 {
-                    dto.ParentArtItemId = GetClientItemId(parentWithImage);
+                    Name = studio
+                };
 
-                    dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImage(ImageType.Art));
+                Studio entity;
+
+                if (dictionary.TryGetValue(studio, out entity))
+                {
+                    var primaryImagePath = entity.PrimaryImagePath;
+
+                    if (!string.IsNullOrEmpty(primaryImagePath))
+                    {
+                        studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
+                    }
                 }
-            }
 
-            if (fields.Contains(ItemFields.Path))
-            {
-                dto.Path = item.Path;
+                dto.Studios[i] = studioDto;
             }
+        }
 
-            dto.PremiereDate = item.PremiereDate;
-            dto.ProductionYear = item.ProductionYear;
+        /// <summary>
+        /// If an item does not any backdrops, this can be used to find the first parent that does have one
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="owner">The owner.</param>
+        /// <returns>BaseItem.</returns>
+        private BaseItem GetParentBackdropItem(BaseItem item, BaseItem owner)
+        {
+            var parent = item.Parent ?? owner;
 
-            if (fields.Contains(ItemFields.ProviderIds))
+            while (parent != null)
             {
-                dto.ProviderIds = item.ProviderIds;
+                if (parent.BackdropImagePaths != null && parent.BackdropImagePaths.Count > 0)
+                {
+                    return parent;
+                }
+
+                parent = parent.Parent;
             }
 
-            dto.RunTimeTicks = item.RunTimeTicks;
+            return null;
+        }
 
-            if (fields.Contains(ItemFields.SortName))
+        /// <summary>
+        /// If an item does not have a logo, this can be used to find the first parent that does have one
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="owner">The owner.</param>
+        /// <returns>BaseItem.</returns>
+        private BaseItem GetParentImageItem(BaseItem item, ImageType type, BaseItem owner)
+        {
+            var parent = item.Parent ?? owner;
+
+            while (parent != null)
             {
-                dto.SortName = item.SortName;
+                if (parent.HasImage(type))
+                {
+                    return parent;
+                }
+
+                parent = parent.Parent;
             }
 
-            if (fields.Contains(ItemFields.CustomRating))
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the chapter info dto.
+        /// </summary>
+        /// <param name="chapterInfo">The chapter info.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>ChapterInfoDto.</returns>
+        private ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item)
+        {
+            var dto = new ChapterInfoDto
             {
-                dto.CustomRating = item.CustomRating;
-            }
+                Name = chapterInfo.Name,
+                StartPositionTicks = chapterInfo.StartPositionTicks
+            };
 
-            if (fields.Contains(ItemFields.Taglines))
+            if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
             {
-                dto.Taglines = item.Taglines;
+                dto.ImageTag = GetImageCacheTag(item, ImageType.Chapter, chapterInfo.ImagePath);
             }
 
-            if (fields.Contains(ItemFields.RemoteTrailers))
+            return dto;
+        }
+
+
+        /// <summary>
+        /// Gets a BaseItem based upon it's client-side item id
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <param name="userId">The user id.</param>
+        /// <returns>BaseItem.</returns>
+        public BaseItem GetItemByDtoId(string id, Guid? userId = null)
+        {
+            if (string.IsNullOrEmpty(id))
             {
-                dto.RemoteTrailers = item.RemoteTrailers;
+                throw new ArgumentNullException("id");
             }
 
-            dto.Type = item.GetType().Name;
-            dto.CommunityRating = item.CommunityRating;
+            // If the item is an indexed folder we have to do a special routine to get it
+            var isIndexFolder = id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1;
 
-            if (item.IsFolder)
+            if (isIndexFolder)
             {
-                var folder = (Folder)item;
-
-                if (fields.Contains(ItemFields.IndexOptions))
+                if (userId.HasValue)
                 {
-                    dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
+                    return GetIndexFolder(id, userId.Value);
                 }
             }
 
-            // Add audio info
-            var audio = item as Audio;
-            if (audio != null)
-            {
-                dto.Album = audio.Album;
-                dto.AlbumArtist = audio.AlbumArtist;
-                dto.Artists = new[] { audio.Artist };
+            BaseItem item = null;
 
-                var albumParent = audio.FindParent<MusicAlbum>();
+            if (userId.HasValue || !isIndexFolder)
+            {
+                item = _libraryManager.GetItemById(new Guid(id));
+            }
 
-                if (albumParent != null)
+            // If we still don't find it, look within individual user views
+            if (item == null && !userId.HasValue && isIndexFolder)
+            {
+                foreach (var user in _userManager.Users)
                 {
-                    dto.AlbumId = GetClientItemId(albumParent);
-
-                    var imagePath = albumParent.PrimaryImagePath;
+                    item = GetItemByDtoId(id, user.Id);
 
-                    if (!string.IsNullOrEmpty(imagePath))
+                    if (item != null)
                     {
-                        dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary, imagePath);
+                        break;
                     }
                 }
             }
 
-            var album = item as MusicAlbum;
+            return item;
+        }
 
-            if (album != null)
-            {
-                var songs = album.RecursiveChildren.OfType<Audio>().ToList();
+        /// <summary>
+        /// Finds an index folder based on an Id and userId
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <param name="userId">The user id.</param>
+        /// <returns>BaseItem.</returns>
+        private BaseItem GetIndexFolder(string id, Guid userId)
+        {
+            var user = _userManager.GetUserById(userId);
 
-                dto.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));
+            var stringSeparators = new[] { IndexFolderDelimeter };
 
-                dto.Artists =
-                    songs.Select(i => i.Artist ?? string.Empty)
-                         .Where(i => !string.IsNullOrEmpty(i))
-                         .Distinct(StringComparer.OrdinalIgnoreCase)
-                         .ToArray();
-            }
+            // Split using the delimeter
+            var values = id.Split(stringSeparators, StringSplitOptions.None).ToList();
 
-            // Add video info
-            var video = item as Video;
-            if (video != null)
-            {
-                dto.VideoType = video.VideoType;
-                dto.Video3DFormat = video.Video3DFormat;
-                dto.IsoType = video.IsoType;
-                dto.MainFeaturePlaylistName = video.MainFeaturePlaylistName;
+            // Get the top folder normally using the first id
+            var folder = GetItemByDtoId(values[0], userId) as Folder;
 
-                dto.PartCount = video.AdditionalPartIds.Count + 1;
+            values.RemoveAt(0);
 
-                if (fields.Contains(ItemFields.Chapters))
-                {
-                    dto.Chapters = _itemRepo.GetChapters(video.Id).Select(c => GetChapterInfoDto(c, item)).ToList();
-                }
-            }
+            // Get indexed folders using the remaining values in the id string
+            return GetIndexFolder(values, folder, user);
+        }
 
-            if (fields.Contains(ItemFields.MediaStreams))
-            {
-                // Add VideoInfo
-                var iHasMediaStreams = item as IHasMediaStreams;
+        /// <summary>
+        /// Gets indexed folders based on a list of index names and folder id's
+        /// </summary>
+        /// <param name="values">The values.</param>
+        /// <param name="parentFolder">The parent folder.</param>
+        /// <param name="user">The user.</param>
+        /// <returns>BaseItem.</returns>
+        private BaseItem GetIndexFolder(List<string> values, Folder parentFolder, User user)
+        {
+            // The index name is first
+            var indexBy = values[0];
 
-                if (iHasMediaStreams != null)
-                {
-                    dto.MediaStreams = iHasMediaStreams.MediaStreams;
-                }
-            }
+            // The index folder id is next
+            var indexFolderId = new Guid(values[1]);
 
-            // Add MovieInfo
-            var movie = item as Movie;
+            // Remove them from the lst
+            values.RemoveRange(0, 2);
 
-            if (movie != null)
-            {
-                var specialFeatureCount = movie.SpecialFeatureIds.Count;
+            // Get the IndexFolder
+            var indexFolder = parentFolder.GetChildren(user, false, indexBy).FirstOrDefault(i => i.Id == indexFolderId) as Folder;
 
-                if (specialFeatureCount > 0)
-                {
-                    dto.SpecialFeatureCount = specialFeatureCount;
-                }
+            // Nested index folder
+            if (values.Count > 0)
+            {
+                return GetIndexFolder(values, indexFolder, user);
             }
 
-            // Add EpisodeInfo
-            var episode = item as Episode;
+            return indexFolder;
+        }
 
-            if (episode != null)
+        /// <summary>
+        /// Sets simple property values on a DTOBaseItem
+        /// </summary>
+        /// <param name="dto">The dto.</param>
+        /// <param name="item">The item.</param>
+        /// <param name="owner">The owner.</param>
+        /// <param name="fields">The fields.</param>
+        private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, List<ItemFields> fields)
+        {
+            if (fields.Contains(ItemFields.DateCreated))
             {
-                dto.IndexNumberEnd = episode.IndexNumberEnd;
+                dto.DateCreated = item.DateCreated;
             }
 
-            // Add SeriesInfo
-            var series = item as Series;
-
-            if (series != null)
+            if (fields.Contains(ItemFields.OriginalRunTimeTicks))
             {
-                dto.AirDays = series.AirDays;
-                dto.AirTime = series.AirTime;
-                dto.Status = series.Status;
+                dto.OriginalRunTimeTicks = item.OriginalRunTimeTicks;
+            }
 
-                dto.SpecialFeatureCount = series.SpecialFeatureIds.Count;
+            dto.DisplayMediaType = item.DisplayMediaType;
 
-                dto.SeasonCount = series.SeasonCount;
+            if (fields.Contains(ItemFields.MetadataSettings))
+            {
+                dto.LockedFields = item.LockedFields;
+                dto.EnableInternetProviders = !item.DontFetchMeta;
             }
 
-            if (episode != null)
+            if (fields.Contains(ItemFields.Budget))
             {
-                series = item.FindParent<Series>();
-
-                dto.SeriesId = GetClientItemId(series);
-                dto.SeriesName = series.Name;
+                dto.Budget = item.Budget;
             }
 
-            // Add SeasonInfo
-            var season = item as Season;
-
-            if (season != null)
+            if (fields.Contains(ItemFields.Revenue))
             {
-                series = item.FindParent<Series>();
-
-                dto.SeriesId = GetClientItemId(series);
-                dto.SeriesName = series.Name;
+                dto.Revenue = item.Revenue;
             }
 
-            var game = item as Game;
+            dto.EndDate = item.EndDate;
 
-            if (game != null)
+            if (fields.Contains(ItemFields.HomePageUrl))
             {
-                SetGameProperties(dto, game);
+                dto.HomePageUrl = item.HomePageUrl;
             }
 
-            var musicVideo = item as MusicVideo;
+            if (fields.Contains(ItemFields.Tags))
+            {
+                dto.Tags = item.Tags;
+            }
 
-            if (musicVideo != null)
+            if (fields.Contains(ItemFields.ProductionLocations))
             {
-                SetMusicVideoProperties(dto, musicVideo);
+                dto.ProductionLocations = item.ProductionLocations;
             }
 
-            var book = item as Book;
+            dto.AspectRatio = item.AspectRatio;
 
-            if (book != null)
+            dto.BackdropImageTags = GetBackdropImageTags(item);
+            dto.ScreenshotImageTags = GetScreenshotImageTags(item);
+
+            if (fields.Contains(ItemFields.Genres))
             {
-                SetBookProperties(dto, book);
+                dto.Genres = item.Genres;
             }
-        }
 
-        private void SetBookProperties(BaseItemDto dto, Book item)
-        {
-            dto.SeriesName = item.SeriesName;
-        }
+            dto.ImageTags = new Dictionary<ImageType, Guid>();
 
-        private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
-        {
-            if (!string.IsNullOrEmpty(item.Album))
+            foreach (var image in item.Images)
             {
-                var parentAlbum = _libraryManager.RootFolder
-                    .RecursiveChildren
-                    .OfType<MusicAlbum>()
-                    .FirstOrDefault(i => string.Equals(i.Name, item.Album, StringComparison.OrdinalIgnoreCase));
+                var type = image.Key;
 
-                if (parentAlbum != null)
+                var tag = GetImageCacheTag(item, type, image.Value);
+
+                if (tag.HasValue)
                 {
-                    dto.AlbumId = GetClientItemId(parentAlbum);
+                    dto.ImageTags[type] = tag.Value;
                 }
             }
 
-            dto.Album = item.Album;
-            dto.Artists = string.IsNullOrEmpty(item.Artist) ? new string[] { } : new[] { item.Artist };
-        }
-
-        private void SetGameProperties(BaseItemDto dto, Game item)
-        {
-            dto.Players = item.PlayersSupported;
-            dto.GameSystem = item.GameSystem;
-        }
+            dto.Id = GetDtoId(item);
+            dto.IndexNumber = item.IndexNumber;
+            dto.IsFolder = item.IsFolder;
+            dto.Language = item.Language;
+            dto.MediaType = item.MediaType;
+            dto.LocationType = item.LocationType;
+            dto.CriticRating = item.CriticRating;
 
-        /// <summary>
-        /// Since it can be slow to make all of these calculations independently, this method will provide a way to do them all at once
-        /// </summary>
-        /// <param name="folder">The folder.</param>
-        /// <param name="user">The user.</param>
-        /// <param name="dto">The dto.</param>
-        /// <param name="userDataRepository">The user data repository.</param>
-        /// <returns>Task.</returns>
-        private static void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserDataRepository userDataRepository)
-        {
-            var rcentlyAddedItemCount = 0;
-            var recursiveItemCount = 0;
-            var unplayed = 0;
-            long runtime = 0;
+            if (fields.Contains(ItemFields.CriticRatingSummary))
+            {
+                dto.CriticRatingSummary = item.CriticRatingSummary;
+            }
 
-            double totalPercentPlayed = 0;
+            var localTrailerCount = item.LocalTrailerIds.Count;
 
-            // Loop through each recursive child
-            foreach (var child in folder.GetRecursiveChildren(user, true).Where(i => !i.IsFolder).ToList())
+            if (localTrailerCount > 0)
             {
-                var userdata = userDataRepository.GetUserData(user.Id, child.GetUserDataKey());
+                dto.LocalTrailerCount = localTrailerCount;
+            }
 
-                recursiveItemCount++;
+            dto.Name = item.Name;
+            dto.OfficialRating = item.OfficialRating;
 
-                // Check is recently added
-                if (child.IsRecentlyAdded())
-                {
-                    rcentlyAddedItemCount++;
-                }
+            var hasOverview = fields.Contains(ItemFields.Overview);
+            var hasHtmlOverview = fields.Contains(ItemFields.OverviewHtml);
 
-                var isUnplayed = true;
+            if (hasOverview || hasHtmlOverview)
+            {
+                var strippedOverview = string.IsNullOrEmpty(item.Overview) ? item.Overview : item.Overview.StripHtml();
 
-                // Incrememt totalPercentPlayed
-                if (userdata != null)
+                if (hasOverview)
                 {
-                    if (userdata.Played)
-                    {
-                        totalPercentPlayed += 100;
-
-                        isUnplayed = false;
-                    }
-                    else if (userdata.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
-                    {
-                        double itemPercent = userdata.PlaybackPositionTicks;
-                        itemPercent /= child.RunTimeTicks.Value;
-                        totalPercentPlayed += itemPercent;
-                    }
+                    dto.Overview = strippedOverview;
                 }
 
-                if (isUnplayed)
+                // Only supply the html version if there was actually html content
+                if (hasHtmlOverview)
                 {
-                    unplayed++;
+                    dto.OverviewHtml = item.Overview;
                 }
-
-                runtime += child.RunTimeTicks ?? 0;
             }
 
-            dto.RecursiveItemCount = recursiveItemCount;
-            dto.RecentlyAddedItemCount = rcentlyAddedItemCount;
-            dto.RecursiveUnplayedItemCount = unplayed;
-
-            if (recursiveItemCount > 0)
+            // If there are no backdrops, indicate what parent has them in case the Ui wants to allow inheritance
+            if (dto.BackdropImageTags.Count == 0)
             {
-                dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
+                var parentWithBackdrop = GetParentBackdropItem(item, owner);
+
+                if (parentWithBackdrop != null)
+                {
+                    dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop);
+                    dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop);
+                }
             }
 
-            if (runtime > 0)
+            if (item.Parent != null && fields.Contains(ItemFields.ParentId))
             {
-                dto.CumulativeRunTimeTicks = runtime;
+                dto.ParentId = GetDtoId(item.Parent);
             }
-        }
 
-        /// <summary>
-        /// Attaches People DTO's to a DTOBaseItem
-        /// </summary>
-        /// <param name="dto">The dto.</param>
-        /// <param name="item">The item.</param>
-        /// <returns>Task.</returns>
-        private async Task AttachPeople(BaseItemDto dto, BaseItem item)
-        {
-            // Ordering by person type to ensure actors and artists are at the front.
-            // This is taking advantage of the fact that they both begin with A
-            // This should be improved in the future
-            var people = item.People.OrderBy(i => i.Type).ToList();
-
-            // Attach People by transforming them into BaseItemPerson (DTO)
-            dto.People = new BaseItemPerson[people.Count];
-
-            var entities = await Task.WhenAll(people.Select(p => p.Name)
-                .Distinct(StringComparer.OrdinalIgnoreCase).Select(c =>
-                    Task.Run(async () =>
-                    {
-                        try
-                        {
-                            return await _libraryManager.GetPerson(c).ConfigureAwait(false);
-                        }
-                        catch (IOException ex)
-                        {
-                            _logger.ErrorException("Error getting person {0}", ex, c);
-                            return null;
-                        }
-                    })
-
-            )).ConfigureAwait(false);
-
-            var dictionary = entities.Where(i => i != null)
-                .DistinctBy(i => i.Name)
-                .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+            dto.ParentIndexNumber = item.ParentIndexNumber;
 
-            for (var i = 0; i < people.Count; i++)
+            // If there is no logo, indicate what parent has one in case the Ui wants to allow inheritance
+            if (!dto.HasLogo)
             {
-                var person = people[i];
+                var parentWithLogo = GetParentImageItem(item, ImageType.Logo, owner);
 
-                var baseItemPerson = new BaseItemPerson
+                if (parentWithLogo != null)
                 {
-                    Name = person.Name,
-                    Role = person.Role,
-                    Type = person.Type
-                };
+                    dto.ParentLogoItemId = GetDtoId(parentWithLogo);
 
-                Person entity;
+                    dto.ParentLogoImageTag = GetImageCacheTag(parentWithLogo, ImageType.Logo, parentWithLogo.GetImage(ImageType.Logo));
+                }
+            }
 
-                if (dictionary.TryGetValue(person.Name, out entity))
+            // If there is no art, indicate what parent has one in case the Ui wants to allow inheritance
+            if (!dto.HasArtImage)
+            {
+                var parentWithImage = GetParentImageItem(item, ImageType.Art, owner);
+
+                if (parentWithImage != null)
                 {
-                    var primaryImagePath = entity.PrimaryImagePath;
+                    dto.ParentArtItemId = GetDtoId(parentWithImage);
 
-                    if (!string.IsNullOrEmpty(primaryImagePath))
-                    {
-                        baseItemPerson.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
-                    }
+                    dto.ParentArtImageTag = GetImageCacheTag(parentWithImage, ImageType.Art, parentWithImage.GetImage(ImageType.Art));
                 }
+            }
 
-                dto.People[i] = baseItemPerson;
+            if (fields.Contains(ItemFields.Path))
+            {
+                dto.Path = item.Path;
             }
-        }
 
-        /// <summary>
-        /// Attaches the studios.
-        /// </summary>
-        /// <param name="dto">The dto.</param>
-        /// <param name="item">The item.</param>
-        /// <returns>Task.</returns>
-        private async Task AttachStudios(BaseItemDto dto, BaseItem item)
-        {
-            var studios = item.Studios.ToList();
+            dto.PremiereDate = item.PremiereDate;
+            dto.ProductionYear = item.ProductionYear;
 
-            dto.Studios = new StudioDto[studios.Count];
+            if (fields.Contains(ItemFields.ProviderIds))
+            {
+                dto.ProviderIds = item.ProviderIds;
+            }
 
-            var entities = await Task.WhenAll(studios.Distinct(StringComparer.OrdinalIgnoreCase).Select(c =>
+            dto.RunTimeTicks = item.RunTimeTicks;
 
-                    Task.Run(async () =>
-                    {
-                        try
-                        {
-                            return await _libraryManager.GetStudio(c).ConfigureAwait(false);
-                        }
-                        catch (IOException ex)
-                        {
-                            _logger.ErrorException("Error getting studio {0}", ex, c);
-                            return null;
-                        }
-                    })
+            if (fields.Contains(ItemFields.SortName))
+            {
+                dto.SortName = item.SortName;
+            }
 
-            )).ConfigureAwait(false);
+            if (fields.Contains(ItemFields.CustomRating))
+            {
+                dto.CustomRating = item.CustomRating;
+            }
 
-            var dictionary = entities
-                .Where(i => i != null)
-                .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
+            if (fields.Contains(ItemFields.Taglines))
+            {
+                dto.Taglines = item.Taglines;
+            }
 
-            for (var i = 0; i < studios.Count; i++)
+            if (fields.Contains(ItemFields.RemoteTrailers))
             {
-                var studio = studios[i];
+                dto.RemoteTrailers = item.RemoteTrailers;
+            }
 
-                var studioDto = new StudioDto
-                {
-                    Name = studio
-                };
+            dto.Type = item.GetType().Name;
+            dto.CommunityRating = item.CommunityRating;
 
-                Studio entity;
+            if (item.IsFolder)
+            {
+                var folder = (Folder)item;
 
-                if (dictionary.TryGetValue(studio, out entity))
+                if (fields.Contains(ItemFields.IndexOptions))
                 {
-                    var primaryImagePath = entity.PrimaryImagePath;
-
-                    if (!string.IsNullOrEmpty(primaryImagePath))
-                    {
-                        studioDto.PrimaryImageTag = GetImageCacheTag(entity, ImageType.Primary, primaryImagePath);
-                    }
+                    dto.IndexOptions = folder.IndexByOptionStrings.ToArray();
                 }
-
-                dto.Studios[i] = studioDto;
             }
-        }
-
-        /// <summary>
-        /// If an item does not any backdrops, this can be used to find the first parent that does have one
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="owner">The owner.</param>
-        /// <returns>BaseItem.</returns>
-        private BaseItem GetParentBackdropItem(BaseItem item, BaseItem owner)
-        {
-            var parent = item.Parent ?? owner;
 
-            while (parent != null)
+            // Add audio info
+            var audio = item as Audio;
+            if (audio != null)
             {
-                if (parent.BackdropImagePaths != null && parent.BackdropImagePaths.Count > 0)
-                {
-                    return parent;
-                }
+                dto.Album = audio.Album;
+                dto.AlbumArtist = audio.AlbumArtist;
+                dto.Artists = new[] { audio.Artist };
 
-                parent = parent.Parent;
-            }
+                var albumParent = audio.FindParent<MusicAlbum>();
 
-            return null;
-        }
+                if (albumParent != null)
+                {
+                    dto.AlbumId = GetDtoId(albumParent);
 
-        /// <summary>
-        /// If an item does not have a logo, this can be used to find the first parent that does have one
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="owner">The owner.</param>
-        /// <returns>BaseItem.</returns>
-        private BaseItem GetParentImageItem(BaseItem item, ImageType type, BaseItem owner)
-        {
-            var parent = item.Parent ?? owner;
+                    var imagePath = albumParent.PrimaryImagePath;
 
-            while (parent != null)
-            {
-                if (parent.HasImage(type))
-                {
-                    return parent;
+                    if (!string.IsNullOrEmpty(imagePath))
+                    {
+                        dto.AlbumPrimaryImageTag = GetImageCacheTag(albumParent, ImageType.Primary, imagePath);
+                    }
                 }
-
-                parent = parent.Parent;
             }
 
-            return null;
-        }
+            var album = item as MusicAlbum;
 
-        /// <summary>
-        /// Converts a UserItemData to a DTOUserItemData
-        /// </summary>
-        /// <param name="data">The data.</param>
-        /// <returns>DtoUserItemData.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public static UserItemDataDto GetUserItemDataDto(UserItemData data)
-        {
-            if (data == null)
+            if (album != null)
             {
-                throw new ArgumentNullException("data");
-            }
+                var songs = album.RecursiveChildren.OfType<Audio>().ToList();
 
-            return new UserItemDataDto
-            {
-                IsFavorite = data.IsFavorite,
-                Likes = data.Likes,
-                PlaybackPositionTicks = data.PlaybackPositionTicks,
-                PlayCount = data.PlayCount,
-                Rating = data.Rating,
-                Played = data.Played,
-                LastPlayedDate = data.LastPlayedDate
-            };
-        }
+                dto.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));
 
-        /// <summary>
-        /// Gets the chapter info dto.
-        /// </summary>
-        /// <param name="chapterInfo">The chapter info.</param>
-        /// <param name="item">The item.</param>
-        /// <returns>ChapterInfoDto.</returns>
-        private ChapterInfoDto GetChapterInfoDto(ChapterInfo chapterInfo, BaseItem item)
-        {
-            var dto = new ChapterInfoDto
-            {
-                Name = chapterInfo.Name,
-                StartPositionTicks = chapterInfo.StartPositionTicks
-            };
+                dto.Artists =
+                    songs.Select(i => i.Artist ?? string.Empty)
+                         .Where(i => !string.IsNullOrEmpty(i))
+                         .Distinct(StringComparer.OrdinalIgnoreCase)
+                         .ToArray();
+            }
 
-            if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
+            // Add video info
+            var video = item as Video;
+            if (video != null)
             {
-                dto.ImageTag = GetImageCacheTag(item, ImageType.Chapter, chapterInfo.ImagePath);
-            }
+                dto.VideoType = video.VideoType;
+                dto.Video3DFormat = video.Video3DFormat;
+                dto.IsoType = video.IsoType;
+                dto.MainFeaturePlaylistName = video.MainFeaturePlaylistName;
 
-            return dto;
-        }
+                dto.PartCount = video.AdditionalPartIds.Count + 1;
 
-        /// <summary>
-        /// Converts a BaseItem to a BaseItemInfo
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>BaseItemInfo.</returns>
-        /// <exception cref="System.ArgumentNullException">item</exception>
-        public static BaseItemInfo GetBaseItemInfo(BaseItem item)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
+                if (fields.Contains(ItemFields.Chapters))
+                {
+                    dto.Chapters = _itemRepo.GetChapters(video.Id).Select(c => GetChapterInfoDto(c, item)).ToList();
+                }
             }
 
-            var info = new BaseItemInfo
+            if (fields.Contains(ItemFields.MediaStreams))
             {
-                Id = GetClientItemId(item),
-                Name = item.Name,
-                MediaType = item.MediaType,
-                Type = item.GetType().Name,
-                IsFolder = item.IsFolder,
-                RunTimeTicks = item.RunTimeTicks
-            };
+                // Add VideoInfo
+                var iHasMediaStreams = item as IHasMediaStreams;
 
-            var imagePath = item.PrimaryImagePath;
+                if (iHasMediaStreams != null)
+                {
+                    dto.MediaStreams = iHasMediaStreams.MediaStreams;
+                }
+            }
+
+            // Add MovieInfo
+            var movie = item as Movie;
 
-            if (!string.IsNullOrEmpty(imagePath))
+            if (movie != null)
             {
-                try
-                {
-                    info.PrimaryImageTag = Kernel.Instance.ImageManager.GetImageCacheTag(item, ImageType.Primary, imagePath);
-                }
-                catch (IOException)
+                var specialFeatureCount = movie.SpecialFeatureIds.Count;
+
+                if (specialFeatureCount > 0)
                 {
+                    dto.SpecialFeatureCount = specialFeatureCount;
                 }
             }
 
-            return info;
-        }
+            // Add EpisodeInfo
+            var episode = item as Episode;
 
-        /// <summary>
-        /// Gets client-side Id of a server-side BaseItem
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="System.ArgumentNullException">item</exception>
-        public static string GetClientItemId(BaseItem item)
-        {
-            if (item == null)
+            if (episode != null)
             {
-                throw new ArgumentNullException("item");
+                dto.IndexNumberEnd = episode.IndexNumberEnd;
             }
 
-            var indexFolder = item as IndexFolder;
+            // Add SeriesInfo
+            var series = item as Series;
 
-            if (indexFolder != null)
+            if (series != null)
             {
-                return GetClientItemId(indexFolder.Parent) + IndexFolderDelimeter + (indexFolder.IndexName ?? string.Empty) + IndexFolderDelimeter + indexFolder.Id;
-            }
+                dto.AirDays = series.AirDays;
+                dto.AirTime = series.AirTime;
+                dto.Status = series.Status;
 
-            return item.Id.ToString("N");
-        }
+                dto.SpecialFeatureCount = series.SpecialFeatureIds.Count;
 
-        /// <summary>
-        /// Gets a BaseItem based upon it's client-side item id
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>BaseItem.</returns>
-        public static BaseItem GetItemByClientId(string id, IUserManager userManager, ILibraryManager libraryManager, Guid? userId = null)
-        {
-            if (string.IsNullOrEmpty(id))
+                dto.SeasonCount = series.SeasonCount;
+            }
+
+            if (episode != null)
             {
-                throw new ArgumentNullException("id");
+                series = item.FindParent<Series>();
+
+                dto.SeriesId = GetDtoId(series);
+                dto.SeriesName = series.Name;
             }
 
-            // If the item is an indexed folder we have to do a special routine to get it
-            var isIndexFolder = id.IndexOf(IndexFolderDelimeter, StringComparison.OrdinalIgnoreCase) != -1;
+            // Add SeasonInfo
+            var season = item as Season;
 
-            if (isIndexFolder)
+            if (season != null)
             {
-                if (userId.HasValue)
-                {
-                    return GetIndexFolder(id, userId.Value, userManager, libraryManager);
-                }
+                series = item.FindParent<Series>();
+
+                dto.SeriesId = GetDtoId(series);
+                dto.SeriesName = series.Name;
             }
 
-            BaseItem item = null;
+            var game = item as Game;
 
-            if (userId.HasValue || !isIndexFolder)
+            if (game != null)
             {
-                item = libraryManager.GetItemById(new Guid(id));
+                SetGameProperties(dto, game);
             }
 
-            // If we still don't find it, look within individual user views
-            if (item == null && !userId.HasValue && isIndexFolder)
-            {
-                foreach (var user in userManager.Users)
-                {
-                    item = GetItemByClientId(id, userManager, libraryManager, user.Id);
+            var musicVideo = item as MusicVideo;
 
-                    if (item != null)
-                    {
-                        break;
-                    }
-                }
+            if (musicVideo != null)
+            {
+                SetMusicVideoProperties(dto, musicVideo);
             }
 
-            return item;
+            var book = item as Book;
+
+            if (book != null)
+            {
+                SetBookProperties(dto, book);
+            }
         }
 
         /// <summary>
-        /// Finds an index folder based on an Id and userId
+        /// Since it can be slow to make all of these calculations independently, this method will provide a way to do them all at once
         /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="userId">The user id.</param>
-        /// <param name="userManager">The user manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <returns>BaseItem.</returns>
-        private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager, ILibraryManager libraryManager)
+        /// <param name="folder">The folder.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="dto">The dto.</param>
+        /// <returns>Task.</returns>
+        private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto)
         {
-            var user = userManager.GetUserById(userId);
+            var rcentlyAddedItemCount = 0;
+            var recursiveItemCount = 0;
+            var unplayed = 0;
+            long runtime = 0;
 
-            var stringSeparators = new[] { IndexFolderDelimeter };
+            double totalPercentPlayed = 0;
 
-            // Split using the delimeter
-            var values = id.Split(stringSeparators, StringSplitOptions.None).ToList();
+            // Loop through each recursive child
+            foreach (var child in folder.GetRecursiveChildren(user, true).Where(i => !i.IsFolder).ToList())
+            {
+                var userdata = _userDataRepository.GetUserData(user.Id, child.GetUserDataKey());
 
-            // Get the top folder normally using the first id
-            var folder = GetItemByClientId(values[0], userManager, libraryManager, userId) as Folder;
+                recursiveItemCount++;
 
-            values.RemoveAt(0);
+                // Check is recently added
+                if (child.IsRecentlyAdded())
+                {
+                    rcentlyAddedItemCount++;
+                }
 
-            // Get indexed folders using the remaining values in the id string
-            return GetIndexFolder(values, folder, user);
-        }
+                var isUnplayed = true;
 
-        /// <summary>
-        /// Gets indexed folders based on a list of index names and folder id's
-        /// </summary>
-        /// <param name="values">The values.</param>
-        /// <param name="parentFolder">The parent folder.</param>
-        /// <param name="user">The user.</param>
-        /// <returns>BaseItem.</returns>
-        private static BaseItem GetIndexFolder(List<string> values, Folder parentFolder, User user)
-        {
-            // The index name is first
-            var indexBy = values[0];
+                // Incrememt totalPercentPlayed
+                if (userdata != null)
+                {
+                    if (userdata.Played)
+                    {
+                        totalPercentPlayed += 100;
 
-            // The index folder id is next
-            var indexFolderId = new Guid(values[1]);
+                        isUnplayed = false;
+                    }
+                    else if (userdata.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0)
+                    {
+                        double itemPercent = userdata.PlaybackPositionTicks;
+                        itemPercent /= child.RunTimeTicks.Value;
+                        totalPercentPlayed += itemPercent;
+                    }
+                }
 
-            // Remove them from the lst
-            values.RemoveRange(0, 2);
+                if (isUnplayed)
+                {
+                    unplayed++;
+                }
 
-            // Get the IndexFolder
-            var indexFolder = parentFolder.GetChildren(user, false, indexBy).FirstOrDefault(i => i.Id == indexFolderId) as Folder;
+                runtime += child.RunTimeTicks ?? 0;
+            }
 
-            // Nested index folder
-            if (values.Count > 0)
+            dto.RecursiveItemCount = recursiveItemCount;
+            dto.RecentlyAddedItemCount = rcentlyAddedItemCount;
+            dto.RecursiveUnplayedItemCount = unplayed;
+
+            if (recursiveItemCount > 0)
             {
-                return GetIndexFolder(values, indexFolder, user);
+                dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount;
             }
 
-            return indexFolder;
+            if (runtime > 0)
+            {
+                dto.CumulativeRunTimeTicks = runtime;
+            }
         }
 
         /// <summary>
-        /// Gets the backdrop image tags.
+        /// Attaches the primary image aspect ratio.
         /// </summary>
+        /// <param name="dto">The dto.</param>
         /// <param name="item">The item.</param>
-        /// <returns>List{System.String}.</returns>
-        private List<Guid> GetBackdropImageTags(BaseItem item)
+        /// <param name="logger">The _logger.</param>
+        /// <returns>Task.</returns>
+        private async Task AttachPrimaryImageAspectRatio(IItemDto dto, BaseItem item)
         {
-            return item.BackdropImagePaths
-                .Select(p => GetImageCacheTag(item, ImageType.Backdrop, p))
-                .Where(i => i.HasValue)
-                .Select(i => i.Value)
-                .ToList();
-        }
+            var path = item.PrimaryImagePath;
 
-        /// <summary>
-        /// Gets the screenshot image tags.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>List{Guid}.</returns>
-        private List<Guid> GetScreenshotImageTags(BaseItem item)
-        {
-            return item.ScreenshotImagePaths
-                .Select(p => GetImageCacheTag(item, ImageType.Screenshot, p))
-                .Where(i => i.HasValue)
-                .Select(i => i.Value)
-                .ToList();
-        }
+            if (string.IsNullOrEmpty(path))
+            {
+                return;
+            }
+
+            var metaFileEntry = item.ResolveArgs.GetMetaFileByPath(path);
+
+            // See if we can avoid a file system lookup by looking for the file in ResolveArgs
+            var dateModified = metaFileEntry == null ? File.GetLastWriteTimeUtc(path) : metaFileEntry.LastWriteTimeUtc;
+
+            ImageSize size;
 
-        private Guid? GetImageCacheTag(BaseItem item, ImageType type, string path)
-        {
             try
             {
-                return Kernel.Instance.ImageManager.GetImageCacheTag(item, type, path);
+                size = await Kernel.Instance.ImageManager.GetImageSize(path, dateModified).ConfigureAwait(false);
             }
-            catch (IOException ex)
+            catch (FileNotFoundException)
             {
-                _logger.ErrorException("Error getting {0} image info for {1}", ex, type, path);
-                return null;
+                _logger.Error("Image file does not exist: {0}", path);
+                return;
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
+                return;
+            }
+
+            dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height;
+
+            var supportedEnhancers = Kernel.Instance.ImageManager.ImageEnhancers.Where(i =>
+            {
+                try
+                {
+                    return i.Supports(item, ImageType.Primary);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
+
+                    return false;
+                }
+
+            }).ToList();
+
+
+            foreach (var enhancer in supportedEnhancers)
+            {
+                try
+                {
+                    size = enhancer.GetEnhancedImageSize(item, ImageType.Primary, 0, size);
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error in image enhancer: {0}", ex, enhancer.GetType().Name);
+                }
             }
+
+            dto.PrimaryImageAspectRatio = size.Width / size.Height;
         }
+
     }
 }

+ 5 - 9
MediaBrowser.Server.Implementations/EntryPoints/WebSocketEvents.cs

@@ -8,9 +8,7 @@ using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Tasks;
-using MediaBrowser.Model.Updates;
 using System;
 
 namespace MediaBrowser.Server.Implementations.EntryPoints
@@ -24,10 +22,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         /// The _server manager
         /// </summary>
         private readonly IServerManager _serverManager;
-        /// <summary>
-        /// The _logger
-        /// </summary>
-        private readonly ILogger _logger;
 
         /// <summary>
         /// The _user manager
@@ -49,20 +43,22 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         /// </summary>
         private readonly ITaskManager _taskManager;
 
+        private readonly IDtoService _dtoService;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketEvents" /> class.
         /// </summary>
         /// <param name="serverManager">The server manager.</param>
         /// <param name="logger">The logger.</param>
         /// <param name="userManager">The user manager.</param>
-        public WebSocketEvents(IServerManager serverManager, IServerApplicationHost appHost, ILogger logger, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager)
+        public WebSocketEvents(IServerManager serverManager, IServerApplicationHost appHost, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager, IDtoService dtoService)
         {
             _serverManager = serverManager;
-            _logger = logger;
             _userManager = userManager;
             _installationManager = installationManager;
             _appHost = appHost;
             _taskManager = taskManager;
+            _dtoService = dtoService;
         }
 
         public void Run()
@@ -140,7 +136,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         /// <param name="e">The e.</param>
         async void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
         {
-            var dto = await new UserDtoBuilder(_logger).GetUserDto(e.Argument).ConfigureAwait(false);
+            var dto = await _dtoService.GetUserDto(e.Argument).ConfigureAwait(false);
 
             _serverManager.SendWebSocketMessage("UserUpdated", dto);
         }

+ 0 - 10
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -250,14 +250,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }
         }
 
-        /// <summary>
-        /// The _internet providers enabled
-        /// </summary>
-        private bool _internetProvidersEnabled;
-        /// <summary>
-        /// The _people image fetching enabled
-        /// </summary>
-        private bool _peopleImageFetchingEnabled;
         /// <summary>
         /// The _items by name path
         /// </summary>
@@ -275,8 +267,6 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             _seasonZeroDisplayName = ConfigurationManager.Configuration.SeasonZeroDisplayName;
             _itemsByNamePath = ConfigurationManager.ApplicationPaths.ItemsByNamePath;
-            _internetProvidersEnabled = configuration.EnableInternetProviders;
-            _peopleImageFetchingEnabled = configuration.InternetProviderExcludeTypes == null || !configuration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase);
         }
 
         /// <summary>

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -112,6 +112,7 @@
     </Compile>
     <Compile Include="BdInfo\BdInfoExaminer.cs" />
     <Compile Include="Configuration\ServerConfigurationManager.cs" />
+    <Compile Include="Dto\DtoService.cs" />
     <Compile Include="EntryPoints\LibraryChangedNotifier.cs" />
     <Compile Include="EntryPoints\LoadRegistrations.cs" />
     <Compile Include="EntryPoints\Notifications\Notifier.cs" />

+ 2 - 14
MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
@@ -40,32 +39,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
         /// <value>The json serializer.</value>
         private readonly IJsonSerializer _jsonSerializer;
 
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
-
         /// <summary>
         /// Initializes a new instance of the <see cref="SqliteUserRepository" /> class.
         /// </summary>
         /// <param name="connection">The connection.</param>
-        /// <param name="appPaths">The app paths.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="logManager">The log manager.</param>
         /// <exception cref="System.ArgumentNullException">appPaths</exception>
-        public SqliteUserRepository(IDbConnection connection, IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+        public SqliteUserRepository(IDbConnection connection, IJsonSerializer jsonSerializer, ILogManager logManager)
         {
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
             if (jsonSerializer == null)
             {
                 throw new ArgumentNullException("jsonSerializer");
             }
 
             _connection = connection;
-            _appPaths = appPaths;
             _jsonSerializer = jsonSerializer;
 
             _logger = logManager.GetLogger(GetType().Name);

+ 1 - 6
MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs

@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
 using MoreLinq;
 using System;
 using System.Collections.Generic;
@@ -21,8 +20,6 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
     /// </summary>
     class ChapterImagesTask : IScheduledTask
     {
-        private readonly IJsonSerializer _jsonSerializer;
-
         /// <summary>
         /// The _kernel
         /// </summary>
@@ -54,14 +51,12 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         /// <param name="kernel">The kernel.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="libraryManager">The library manager.</param>
-        /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="itemRepo">The item repo.</param>
-        public ChapterImagesTask(Kernel kernel, ILogManager logManager, ILibraryManager libraryManager, IJsonSerializer jsonSerializer, IItemRepository itemRepo)
+        public ChapterImagesTask(Kernel kernel, ILogManager logManager, ILibraryManager libraryManager, IItemRepository itemRepo)
         {
             _kernel = kernel;
             _logger = logManager.GetLogger(GetType().Name);
             _libraryManager = libraryManager;
-            _jsonSerializer = jsonSerializer;
             _itemRepo = itemRepo;
 
             libraryManager.ItemAdded += libraryManager_ItemAdded;

+ 12 - 14
MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs

@@ -1,13 +1,11 @@
-using System.Globalization;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
 using System;
 using System.Linq;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Net;
 
 namespace MediaBrowser.Server.Implementations.Session
 {
@@ -31,22 +29,22 @@ namespace MediaBrowser.Server.Implementations.Session
         /// </summary>
         private readonly ILogger _logger;
 
-        private readonly IUserManager _userManager;
-        private readonly ILibraryManager _libraryManager;
+        /// <summary>
+        /// The _dto service
+        /// </summary>
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
         /// </summary>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="logManager">The log manager.</param>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="userManager">The user manager.</param>
-        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, ILibraryManager libraryManager, IUserManager userManager)
+        /// <param name="dtoService">The dto service.</param>
+        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IDtoService dtoService)
         {
             _sessionManager = sessionManager;
             _logger = logManager.GetLogger(GetType().Name);
-            _libraryManager = libraryManager;
-            _userManager = userManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -109,7 +107,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
                 if (session != null && session.User != null)
                 {
-                    var item = DtoBuilder.GetItemByClientId(message.Data, _userManager, _libraryManager);
+                    var item = _dtoService.GetItemByDtoId(message.Data);
 
                     _sessionManager.OnPlaybackStart(item, session.Id);
                 }
@@ -122,7 +120,7 @@ namespace MediaBrowser.Server.Implementations.Session
                 {
                     var vals = message.Data.Split('|');
 
-                    var item = DtoBuilder.GetItemByClientId(vals[0], _userManager, _libraryManager);
+                    var item = _dtoService.GetItemByDtoId(vals[0]);
 
                     long? positionTicks = null;
 
@@ -152,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Session
                 {
                     var vals = message.Data.Split('|');
 
-                    var item = DtoBuilder.GetItemByClientId(vals[0], _userManager, _libraryManager);
+                    var item = _dtoService.GetItemByDtoId(vals[0]);
 
                     long? positionTicks = null;
 

+ 8 - 2
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -12,6 +12,7 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
@@ -32,6 +33,7 @@ using MediaBrowser.Providers;
 using MediaBrowser.Server.Implementations;
 using MediaBrowser.Server.Implementations.BdInfo;
 using MediaBrowser.Server.Implementations.Configuration;
+using MediaBrowser.Server.Implementations.Dto;
 using MediaBrowser.Server.Implementations.HttpServer;
 using MediaBrowser.Server.Implementations.IO;
 using MediaBrowser.Server.Implementations.Library;
@@ -155,6 +157,7 @@ namespace MediaBrowser.ServerApplication
         /// </summary>
         /// <value>The HTTP server.</value>
         private IHttpServer HttpServer { get; set; }
+        private IDtoService DtoService { get; set; }
 
         /// <summary>
         /// Gets or sets the media encoder.
@@ -290,6 +293,9 @@ namespace MediaBrowser.ServerApplication
             LocalizationManager = new LocalizationManager(ServerConfigurationManager);
             RegisterSingleInstance(LocalizationManager);
 
+            DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataRepository, ItemRepository);
+            RegisterSingleInstance(DtoService);
+
             var displayPreferencesTask = Task.Run(async () => await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false));
             var itemsTask = Task.Run(async () => await ConfigureItemRepositories().ConfigureAwait(false));
             var userdataTask = Task.Run(async () => await ConfigureUserDataRepositories().ConfigureAwait(false));
@@ -309,7 +315,7 @@ namespace MediaBrowser.ServerApplication
             ServerKernel.ImageManager = new ImageManager(LogManager.GetLogger("ImageManager"),
                                                          ApplicationPaths, ItemRepository);
             Parallel.Invoke(
-                 () => ServerKernel.FFMpegManager = new FFMpegManager(ApplicationPaths, MediaEncoder, LibraryManager, Logger, ItemRepository),
+                 () => ServerKernel.FFMpegManager = new FFMpegManager(ApplicationPaths, MediaEncoder, Logger, ItemRepository),
                  () => ServerKernel.ImageManager.ImageEnhancers = GetExports<IImageEnhancer>().OrderBy(e => e.Priority).ToArray(),
                  () => LocalizedStrings.StringFiles = GetExports<LocalizedStringData>(),
                  SetStaticProperties
@@ -322,7 +328,7 @@ namespace MediaBrowser.ServerApplication
 
             var connection = await ConnectToDb(dbFile).ConfigureAwait(false);
 
-            var repo = new SqliteUserRepository(connection, ApplicationPaths, JsonSerializer, LogManager);
+            var repo = new SqliteUserRepository(connection, JsonSerializer, LogManager);
 
             repo.Initialize();
 

+ 5 - 3
MediaBrowser.WebDashboard/Api/DashboardInfoWebSocketListener.cs

@@ -1,7 +1,7 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Logging;
 using System.Threading.Tasks;
@@ -31,6 +31,7 @@ namespace MediaBrowser.WebDashboard.Api
         private readonly ITaskManager _taskManager;
 
         private readonly ISessionManager _sessionManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardInfoWebSocketListener" /> class.
@@ -39,12 +40,13 @@ namespace MediaBrowser.WebDashboard.Api
         /// <param name="logger">The logger.</param>
         /// <param name="taskManager">The task manager.</param>
         /// <param name="sessionManager">The session manager.</param>
-        public DashboardInfoWebSocketListener(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, ISessionManager sessionManager)
+        public DashboardInfoWebSocketListener(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, ISessionManager sessionManager, IDtoService dtoService)
             : base(logger)
         {
             _appHost = appHost;
             _taskManager = taskManager;
             _sessionManager = sessionManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -54,7 +56,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>Task{IEnumerable{TaskInfo}}.</returns>
         protected override Task<DashboardInfo> GetDataToSend(object state)
         {
-            return Task.FromResult(DashboardService.GetDashboardInfo(_appHost, _taskManager, _sessionManager));
+            return Task.FromResult(DashboardService.GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService));
         }
     }
 }

+ 6 - 4
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -117,6 +117,7 @@ namespace MediaBrowser.WebDashboard.Api
         private readonly IServerConfigurationManager _serverConfigurationManager;
 
         private readonly ISessionManager _sessionManager;
+        private readonly IDtoService _dtoService;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardService" /> class.
@@ -125,12 +126,13 @@ namespace MediaBrowser.WebDashboard.Api
         /// <param name="appHost">The app host.</param>
         /// <param name="serverConfigurationManager">The server configuration manager.</param>
         /// <param name="sessionManager">The session manager.</param>
-        public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager)
+        public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IDtoService dtoService)
         {
             _taskManager = taskManager;
             _appHost = appHost;
             _serverConfigurationManager = serverConfigurationManager;
             _sessionManager = sessionManager;
+            _dtoService = dtoService;
         }
 
         /// <summary>
@@ -169,7 +171,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>System.Object.</returns>
         public object Get(GetDashboardInfo request)
         {
-            var result = GetDashboardInfo(_appHost, _taskManager, _sessionManager);
+            var result = GetDashboardInfo(_appHost, _taskManager, _sessionManager, _dtoService);
 
             return ResultFactory.GetOptimizedResult(RequestContext, result);
         }
@@ -183,7 +185,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>DashboardInfo.</returns>
         public static DashboardInfo GetDashboardInfo(IServerApplicationHost appHost,
             ITaskManager taskManager,
-            ISessionManager connectionManager)
+            ISessionManager connectionManager, IDtoService dtoService)
         {
             var connections = connectionManager.Sessions.Where(i => i.IsActive).ToArray();
 
@@ -197,7 +199,7 @@ namespace MediaBrowser.WebDashboard.Api
 
                 ApplicationUpdateTaskId = taskManager.ScheduledTasks.First(t => t.ScheduledTask.GetType().Name.Equals("SystemUpdateTask", StringComparison.OrdinalIgnoreCase)).Id,
 
-                ActiveConnections = connections.Select(SessionInfoDtoBuilder.GetSessionInfoDto).ToArray()
+                ActiveConnections = connections.Select(dtoService.GetSessionInfoDto).ToArray()
             };
         }