소스 검색

added HasSyncJob

Luke Pulverenti 10 년 전
부모
커밋
ee00f8bf72
51개의 변경된 파일419개의 추가작업 그리고 165개의 파일을 삭제
  1. 35 1
      MediaBrowser.Api/BaseApiService.cs
  2. 3 1
      MediaBrowser.Api/GamesService.cs
  3. 1 28
      MediaBrowser.Api/IHasDtoOptions.cs
  4. 2 1
      MediaBrowser.Api/ItemLookupService.cs
  5. 8 8
      MediaBrowser.Api/Library/LibraryService.cs
  6. 1 1
      MediaBrowser.Api/Movies/CollectionService.cs
  7. 7 7
      MediaBrowser.Api/Movies/MoviesService.cs
  8. 5 3
      MediaBrowser.Api/Movies/TrailersService.cs
  9. 3 1
      MediaBrowser.Api/Music/AlbumsService.cs
  10. 2 5
      MediaBrowser.Api/Music/InstantMixService.cs
  11. 4 3
      MediaBrowser.Api/PlaylistService.cs
  12. 3 2
      MediaBrowser.Api/SimilarItemsHelper.cs
  13. 4 3
      MediaBrowser.Api/Sync/SyncService.cs
  14. 12 10
      MediaBrowser.Api/TvShowsService.cs
  15. 1 1
      MediaBrowser.Api/UserLibrary/ArtistsService.cs
  16. 1 1
      MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
  17. 1 1
      MediaBrowser.Api/UserLibrary/GameGenresService.cs
  18. 1 1
      MediaBrowser.Api/UserLibrary/GenresService.cs
  19. 3 3
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  20. 1 1
      MediaBrowser.Api/UserLibrary/MusicGenresService.cs
  21. 1 1
      MediaBrowser.Api/UserLibrary/PersonsService.cs
  22. 1 1
      MediaBrowser.Api/UserLibrary/StudiosService.cs
  23. 8 8
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  24. 1 1
      MediaBrowser.Api/UserLibrary/YearsService.cs
  25. 1 1
      MediaBrowser.Api/VideosService.cs
  26. 53 0
      MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
  27. 6 0
      MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
  28. 0 1
      MediaBrowser.Common/Net/INetworkManager.cs
  29. 7 0
      MediaBrowser.Controller/Collections/ICollectionManager.cs
  30. 1 0
      MediaBrowser.Controller/Dto/DtoOptions.cs
  31. 11 0
      MediaBrowser.Controller/Dto/IDtoService.cs
  32. 9 3
      MediaBrowser.Controller/IServerApplicationHost.cs
  33. 7 0
      MediaBrowser.Controller/Sync/ISyncManager.cs
  34. 7 0
      MediaBrowser.Controller/Sync/ISyncRepository.cs
  35. 1 1
      MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
  36. 2 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  37. 2 1
      MediaBrowser.Model/Dto/BaseItemDto.cs
  38. 6 0
      MediaBrowser.Model/Tasks/TaskResult.cs
  39. 4 4
      MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
  40. 10 2
      MediaBrowser.Server.Implementations/Collections/CollectionManager.cs
  41. 2 2
      MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
  42. 91 8
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  43. 1 1
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  44. 1 2
      MediaBrowser.Server.Implementations/Library/UserManager.cs
  45. 25 13
      MediaBrowser.Server.Implementations/Library/UserViewManager.cs
  46. 2 2
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  47. 5 0
      MediaBrowser.Server.Implementations/Sync/SyncManager.cs
  48. 21 6
      MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
  49. 6 8
      MediaBrowser.Server.Implementations/Udp/UdpServer.cs
  50. 24 17
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  51. 5 0
      MediaBrowser.sln

+ 35 - 1
MediaBrowser.Api/BaseApiService.cs

@@ -1,8 +1,10 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using ServiceStack.Text.Controller;
 using ServiceStack.Text.Controller;
 using ServiceStack.Web;
 using ServiceStack.Web;
@@ -36,6 +38,7 @@ namespace MediaBrowser.Api
         public IRequest Request { get; set; }
         public IRequest Request { get; set; }
 
 
         public ISessionContext SessionContext { get; set; }
         public ISessionContext SessionContext { get; set; }
+        public IAuthorizationContext AuthorizationContext { get; set; }
 
 
         public string GetHeader(string name)
         public string GetHeader(string name)
         {
         {
@@ -110,6 +113,37 @@ namespace MediaBrowser.Api
         private readonly char[] _dashReplaceChars = { '?', '/', '&' };
         private readonly char[] _dashReplaceChars = { '?', '/', '&' };
         private const char SlugChar = '-';
         private const char SlugChar = '-';
 
 
+        protected DtoOptions GetDtoOptions(object request)
+        {
+            var options = new DtoOptions();
+
+            options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId;
+
+            var hasFields = request as IHasItemFields;
+            if (hasFields != null)
+            {
+                options.Fields = hasFields.GetItemFields().ToList();
+            }
+
+            var hasDtoOptions = request as IHasDtoOptions;
+            if (hasDtoOptions != null)
+            {
+                options.EnableImages = hasDtoOptions.EnableImages ?? true;
+
+                if (hasDtoOptions.ImageTypeLimit.HasValue)
+                {
+                    options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
+                }
+
+                if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
+                {
+                    options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
+                }
+            }
+
+            return options;
+        }
+
         protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
         protected MusicArtist GetArtist(string name, ILibraryManager libraryManager)
         {
         {
             return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));
             return libraryManager.GetArtist(DeSlugArtistName(name, libraryManager));

+ 3 - 1
MediaBrowser.Api/GamesService.cs

@@ -172,7 +172,9 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetSimilarGames request)
         public object Get(GetSimilarGames request)
         {
         {
-            var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
+            var dtoOptions = GetDtoOptions(request);
+
+            var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
                 _itemRepo,
                 _itemRepo,
                 _libraryManager,
                 _libraryManager,
                 _userDataRepository,
                 _userDataRepository,

+ 1 - 28
MediaBrowser.Api/IHasDtoOptions.cs

@@ -1,8 +1,4 @@
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Linq;
-
+
 namespace MediaBrowser.Api
 namespace MediaBrowser.Api
 {
 {
     public interface IHasDtoOptions : IHasItemFields
     public interface IHasDtoOptions : IHasItemFields
@@ -13,27 +9,4 @@ namespace MediaBrowser.Api
 
 
         string EnableImageTypes { get; set; }
         string EnableImageTypes { get; set; }
     }
     }
-
-    public static class HasDtoOptionsExtensions
-    {
-        public static DtoOptions GetDtoOptions(this IHasDtoOptions request)
-        {
-            var options = new DtoOptions();
-
-            options.Fields = request.GetItemFields().ToList();
-            options.EnableImages = request.EnableImages ?? true;
-
-            if (request.ImageTypeLimit.HasValue)
-            {
-                options.ImageTypeLimit = request.ImageTypeLimit.Value;
-            }
-
-            if (!string.IsNullOrWhiteSpace(request.EnableImageTypes))
-            {
-                options.ImageTypes = (request.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList();
-            }
-
-            return options;
-        }
-    }
 }
 }

+ 2 - 1
MediaBrowser.Api/ItemLookupService.cs

@@ -205,7 +205,8 @@ namespace MediaBrowser.Api
                 Logger = Logger,
                 Logger = Logger,
                 Request = Request,
                 Request = Request,
                 ResultFactory = ResultFactory,
                 ResultFactory = ResultFactory,
-                SessionContext = SessionContext
+                SessionContext = SessionContext,
+                AuthorizationContext = AuthorizationContext
             };
             };
 
 
             service.Post(new RefreshItem
             service.Post(new RefreshItem

+ 8 - 8
MediaBrowser.Api/Library/LibraryService.cs

@@ -272,7 +272,7 @@ namespace MediaBrowser.Api.Library
                 items = items.Where(i => i.IsHidden == val).ToList();
                 items = items.Where(i => i.IsHidden == val).ToList();
             }
             }
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
             
             
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
@@ -344,7 +344,7 @@ namespace MediaBrowser.Api.Library
 
 
             var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
             var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             BaseItem parent = item.Parent;
             BaseItem parent = item.Parent;
             
             
@@ -544,7 +544,7 @@ namespace MediaBrowser.Api.Library
                 ThemeSongsResult = themeSongs,
                 ThemeSongsResult = themeSongs,
                 ThemeVideosResult = themeVideos,
                 ThemeVideosResult = themeVideos,
 
 
-                SoundtrackSongsResult = GetSoundtrackSongs(request.Id, request.UserId, request.InheritFromParent)
+                SoundtrackSongsResult = GetSoundtrackSongs(request, request.Id, request.UserId, request.InheritFromParent)
             });
             });
         }
         }
 
 
@@ -597,7 +597,7 @@ namespace MediaBrowser.Api.Library
                 }
                 }
             }
             }
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = themeSongIds.Select(_libraryManager.GetItemById)
             var dtos = themeSongIds.Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .OrderBy(i => i.SortName)
@@ -667,7 +667,7 @@ namespace MediaBrowser.Api.Library
                 }
                 }
             }
             }
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
             var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .OrderBy(i => i.SortName)
@@ -732,17 +732,17 @@ namespace MediaBrowser.Api.Library
             return ToOptimizedSerializedResultUsingCache(lookup);
             return ToOptimizedSerializedResultUsingCache(lookup);
         }
         }
 
 
-        public ThemeMediaResult GetSoundtrackSongs(string id, Guid? userId, bool inheritFromParent)
+        public ThemeMediaResult GetSoundtrackSongs(GetThemeMedia request, string id, Guid? userId, bool inheritFromParent)
         {
         {
             var user = userId.HasValue ? _userManager.GetUserById(userId.Value) : null;
             var user = userId.HasValue ? _userManager.GetUserById(userId.Value) : null;
 
 
             var item = string.IsNullOrEmpty(id)
             var item = string.IsNullOrEmpty(id)
                            ? (userId.HasValue
                            ? (userId.HasValue
                                   ? user.RootFolder
                                   ? user.RootFolder
-                                  : (Folder)_libraryManager.RootFolder)
+                                  : _libraryManager.RootFolder)
                            : _libraryManager.GetItemById(id);
                            : _libraryManager.GetItemById(id);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = GetSoundtrackSongIds(item, inheritFromParent)
             var dtos = GetSoundtrackSongIds(item, inheritFromParent)
                 .Select(_libraryManager.GetItemById)
                 .Select(_libraryManager.GetItemById)

+ 1 - 1
MediaBrowser.Api/Movies/CollectionService.cs

@@ -71,7 +71,7 @@ namespace MediaBrowser.Api.Movies
 
 
             }).ConfigureAwait(false);
             }).ConfigureAwait(false);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
             var dto = _dtoService.GetBaseItemDto(item, dtoOptions);
 
 

+ 7 - 7
MediaBrowser.Api/Movies/MoviesService.cs

@@ -157,7 +157,7 @@ namespace MediaBrowser.Api.Movies
                 .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
                 .DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString(), StringComparer.OrdinalIgnoreCase)
                 .ToList();
                 .ToList();
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             dtoOptions.Fields = request.GetItemFields().ToList();
             dtoOptions.Fields = request.GetItemFields().ToList();
             
             
@@ -174,8 +174,6 @@ namespace MediaBrowser.Api.Movies
                 (request.UserId.HasValue ? user.RootFolder :
                 (request.UserId.HasValue ? user.RootFolder :
                 _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
                 _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id);
 
 
-            var fields = request.GetItemFields().ToList();
-
             var inputItems = user == null
             var inputItems = user == null
                                  ? _libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
                                  ? _libraryManager.RootFolder.GetRecursiveChildren().Where(i => i.Id != item.Id)
                                  : user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
                                  : user.RootFolder.GetRecursiveChildren(user).Where(i => i.Id != item.Id);
@@ -225,10 +223,12 @@ namespace MediaBrowser.Api.Movies
             {
             {
                 returnItems = returnItems.Take(request.Limit.Value);
                 returnItems = returnItems.Take(request.Limit.Value);
             }
             }
+
+            var dtoOptions = GetDtoOptions(request);
           
           
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
-                Items = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
+                Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
 
 
                 TotalRecordCount = items.Count
                 TotalRecordCount = items.Count
             };
             };
@@ -351,7 +351,7 @@ namespace MediaBrowser.Api.Movies
                         BaselineItemName = director,
                         BaselineItemName = director,
                         CategoryId = director.GetMD5().ToString("N"),
                         CategoryId = director.GetMD5().ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
+                        Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
                     };
                     };
                 }
                 }
             }
             }
@@ -375,7 +375,7 @@ namespace MediaBrowser.Api.Movies
                         BaselineItemName = name,
                         BaselineItemName = name,
                         CategoryId = name.GetMD5().ToString("N"),
                         CategoryId = name.GetMD5().ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
+                        Items = _dtoService.GetBaseItemDtos(items, dtoOptions, user).ToArray()
                     };
                     };
                 }
                 }
             }
             }
@@ -399,7 +399,7 @@ namespace MediaBrowser.Api.Movies
                         BaselineItemName = item.Name,
                         BaselineItemName = item.Name,
                         CategoryId = item.Id.ToString("N"),
                         CategoryId = item.Id.ToString("N"),
                         RecommendationType = type,
                         RecommendationType = type,
-                        Items = similar.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
+                        Items = _dtoService.GetBaseItemDtos(similar, dtoOptions, user).ToArray()
                     };
                     };
                 }
                 }
             }
             }

+ 5 - 3
MediaBrowser.Api/Movies/TrailersService.cs

@@ -84,7 +84,9 @@ namespace MediaBrowser.Api.Movies
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetSimilarTrailers request)
         public object Get(GetSimilarTrailers request)
         {
         {
-            var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
+            var dtoOptions = GetDtoOptions(request);
+
+            var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
                 _itemRepo,
                 _itemRepo,
                 _libraryManager,
                 _libraryManager,
                 _userDataRepository,
                 _userDataRepository,
@@ -119,9 +121,9 @@ namespace MediaBrowser.Api.Movies
 
 
             var pagedItems = ApplyPaging(request, itemsArray);
             var pagedItems = ApplyPaging(request, itemsArray);
 
 
-            var fields = request.GetItemFields().ToList();
+            var dtoOptions = GetDtoOptions(request);
 
 
-            var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
 
 
             return new ItemsResult
             return new ItemsResult
             {
             {

+ 3 - 1
MediaBrowser.Api/Music/AlbumsService.cs

@@ -50,7 +50,9 @@ namespace MediaBrowser.Api.Music
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetSimilarAlbums request)
         public object Get(GetSimilarAlbums request)
         {
         {
-            var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
+            var dtoOptions = GetDtoOptions(request);
+
+            var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
                 _itemRepo,
                 _itemRepo,
                 _libraryManager,
                 _libraryManager,
                 _userDataRepository,
                 _userDataRepository,

+ 2 - 5
MediaBrowser.Api/Music/InstantMixService.cs

@@ -146,8 +146,6 @@ namespace MediaBrowser.Api.Music
 
 
         private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
         private object GetResult(IEnumerable<Audio> items, User user, BaseGetSimilarItems request)
         {
         {
-            var fields = request.GetItemFields().ToList();
-
             var list = items.ToList();
             var list = items.ToList();
 
 
             var result = new ItemsResult
             var result = new ItemsResult
@@ -155,10 +153,9 @@ namespace MediaBrowser.Api.Music
                 TotalRecordCount = list.Count
                 TotalRecordCount = list.Count
             };
             };
 
 
-            var dtos = list.Take(request.Limit ?? list.Count)
-                .Select(i => _dtoService.GetBaseItemDto(i, fields, user));
+            var dtoOptions = GetDtoOptions(request);
 
 
-            result.Items = dtos.ToArray();
+            result.Items = _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user).ToArray();
 
 
             return ToOptimizedResult(result);
             return ToOptimizedResult(result);
         }
         }

+ 4 - 3
MediaBrowser.Api/PlaylistService.cs

@@ -151,9 +151,10 @@ namespace MediaBrowser.Api
             {
             {
                 items = items.Take(request.Limit.Value).ToArray();
                 items = items.Take(request.Limit.Value).ToArray();
             }
             }
-            
-            var dtos = items
-                   .Select(i => _dtoService.GetBaseItemDto(i.Item2, request.GetItemFields().ToList(), user))
+
+            var dtoOptions = GetDtoOptions(request);
+
+            var dtos = _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user)
                    .ToArray();
                    .ToArray();
 
 
             var index = 0;
             var index = 0;

+ 3 - 2
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -57,6 +57,7 @@ namespace MediaBrowser.Api
         /// <summary>
         /// <summary>
         /// Gets the similar items.
         /// Gets the similar items.
         /// </summary>
         /// </summary>
+        /// <param name="dtoOptions">The dto options.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="itemRepository">The item repository.</param>
         /// <param name="itemRepository">The item repository.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="libraryManager">The library manager.</param>
@@ -67,7 +68,7 @@ namespace MediaBrowser.Api
         /// <param name="includeInSearch">The include in search.</param>
         /// <param name="includeInSearch">The include in search.</param>
         /// <param name="getSimilarityScore">The get similarity score.</param>
         /// <param name="getSimilarityScore">The get similarity score.</param>
         /// <returns>ItemsResult.</returns>
         /// <returns>ItemsResult.</returns>
-        internal static ItemsResult GetSimilarItemsResult(IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager userDataRepository, IDtoService dtoService, ILogger logger, BaseGetSimilarItemsFromItem request, Func<BaseItem, bool> includeInSearch, Func<BaseItem, BaseItem, int> getSimilarityScore)
+        internal static ItemsResult GetSimilarItemsResult(DtoOptions dtoOptions, IUserManager userManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserDataManager 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 user = request.UserId.HasValue ? userManager.GetUserById(request.UserId.Value) : null;
 
 
@@ -93,7 +94,7 @@ namespace MediaBrowser.Api
 
 
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
-                Items = returnItems.Select(i => dtoService.GetBaseItemDto(i, fields, user)).ToArray(),
+                Items = dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(),
 
 
                 TotalRecordCount = items.Count
                 TotalRecordCount = items.Count
             };
             };

+ 4 - 3
MediaBrowser.Api/Sync/SyncService.cs

@@ -235,10 +235,11 @@ namespace MediaBrowser.Api.Sync
                     }
                     }
                 };
                 };
 
 
-                var dtos = request.ItemIds.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
+                var items = request.ItemIds.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
                     .Select(_libraryManager.GetItemById)
                     .Select(_libraryManager.GetItemById)
-                    .Where(i => i != null)
-                    .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions))
+                    .Where(i => i != null);
+
+                var dtos = _dtoService.GetBaseItemDtos(items, dtoOptions)
                     .ToList();
                     .ToList();
 
 
                 result.Options = SyncHelper.GetSyncOptions(dtos);
                 result.Options = SyncHelper.GetSyncOptions(dtos);

+ 12 - 10
MediaBrowser.Api/TvShowsService.cs

@@ -238,7 +238,9 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object Get(GetSimilarShows request)
         public object Get(GetSimilarShows request)
         {
         {
-            var result = SimilarItemsHelper.GetSimilarItemsResult(_userManager,
+            var dtoOptions = GetDtoOptions(request);
+
+            var result = SimilarItemsHelper.GetSimilarItemsResult(dtoOptions, _userManager,
                 _itemRepo,
                 _itemRepo,
                 _libraryManager,
                 _libraryManager,
                 _userDataManager,
                 _userDataManager,
@@ -270,9 +272,9 @@ namespace MediaBrowser.Api
 
 
             var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
             var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit);
 
 
-            var options = request.GetDtoOptions();
+            var options = GetDtoOptions(request);
 
 
-            var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, options, user)).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(pagedItems, options, user).ToArray();
 
 
             var result = new ItemsResult
             var result = new ItemsResult
             {
             {
@@ -301,9 +303,9 @@ namespace MediaBrowser.Api
 
 
             var user = _userManager.GetUserById(request.UserId);
             var user = _userManager.GetUserById(request.UserId);
 
 
-            var options = request.GetDtoOptions();
+            var options = GetDtoOptions(request);
 
 
-            var returnItems = result.Items.Select(i => _dtoService.GetBaseItemDto(i, options, user)).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(result.Items, options, user).ToArray();
 
 
             return ToOptimizedSerializedResultUsingCache(new ItemsResult
             return ToOptimizedSerializedResultUsingCache(new ItemsResult
             {
             {
@@ -365,9 +367,9 @@ namespace MediaBrowser.Api
                     .Cast<Season>();
                     .Cast<Season>();
             }
             }
 
 
-            var fields = request.GetItemFields().ToList();
+            var dtoOptions = GetDtoOptions(request);
 
 
-            var returnItems = seasons.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+            var returnItems = _dtoService.GetBaseItemDtos(seasons, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             return new ItemsResult
             return new ItemsResult
@@ -455,11 +457,11 @@ namespace MediaBrowser.Api
                     .Cast<Episode>();
                     .Cast<Episode>();
             }
             }
 
 
-            var fields = request.GetItemFields().ToList();
-
             episodes = _libraryManager.ReplaceVideosWithPrimaryVersions(episodes).Cast<Episode>();
             episodes = _libraryManager.ReplaceVideosWithPrimaryVersions(episodes).Cast<Episode>();
 
 
-            var returnItems = episodes.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
+            var dtoOptions = GetDtoOptions(request);
+
+            var returnItems = _dtoService.GetBaseItemDtos(episodes, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             return new ItemsResult
             return new ItemsResult

+ 1 - 1
MediaBrowser.Api/UserLibrary/ArtistsService.cs

@@ -83,7 +83,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetArtist(request.Name, LibraryManager);
             var item = GetArtist(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 1 - 1
MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs

@@ -129,7 +129,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
             var tuples = ibnItems.Select(i => new Tuple<TItemType, List<BaseItem>>(i, i.GetTaggedItems(libraryItems).ToList()));
 
 
-            var dtoOptions = request.GetDtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2));
             var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2));
 
 

+ 1 - 1
MediaBrowser.Api/UserLibrary/GameGenresService.cs

@@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetGameGenre(request.Name, LibraryManager);
             var item = GetGameGenre(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 1 - 1
MediaBrowser.Api/UserLibrary/GenresService.cs

@@ -74,7 +74,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetGenre(request.Name, LibraryManager);
             var item = GetGenre(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 3 - 3
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -321,14 +321,14 @@ namespace MediaBrowser.Api.UserLibrary
             var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
             var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false);
 
 
             var isFiltered = result.Item2;
             var isFiltered = result.Item2;
-            var dtoOptions = request.GetDtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (isFiltered)
             if (isFiltered)
             {
             {
                 return new ItemsResult
                 return new ItemsResult
                 {
                 {
                     TotalRecordCount = result.Item1.TotalRecordCount,
                     TotalRecordCount = result.Item1.TotalRecordCount,
-                    Items = result.Item1.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray()
+                    Items = _dtoService.GetBaseItemDtos(result.Item1.Items, dtoOptions, user).ToArray()
                 };
                 };
             }
             }
 
 
@@ -362,7 +362,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var pagedItems = ApplyPaging(request, itemsArray);
             var pagedItems = ApplyPaging(request, itemsArray);
 
 
-            var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray();
+            var returnItems = _dtoService.GetBaseItemDtos(pagedItems, dtoOptions, user).ToArray();
 
 
             return new ItemsResult
             return new ItemsResult
             {
             {

+ 1 - 1
MediaBrowser.Api/UserLibrary/MusicGenresService.cs

@@ -69,7 +69,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetMusicGenre(request.Name, LibraryManager);
             var item = GetMusicGenre(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 1 - 1
MediaBrowser.Api/UserLibrary/PersonsService.cs

@@ -86,7 +86,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetPerson(request.Name, LibraryManager);
             var item = GetPerson(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 1 - 1
MediaBrowser.Api/UserLibrary/StudiosService.cs

@@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = GetStudio(request.Name, LibraryManager);
             var item = GetStudio(request.Name, LibraryManager);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 8 - 8
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -371,7 +371,7 @@ namespace MediaBrowser.Api.UserLibrary
                 }
                 }
             }
             }
 
 
-            var options = request.GetDtoOptions();
+            var options = GetDtoOptions(request);
 
 
             var dtos = list.Select(i =>
             var dtos = list.Select(i =>
             {
             {
@@ -420,7 +420,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
             var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
             var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
                 .ToArray();
                 .ToArray();
@@ -447,7 +447,7 @@ namespace MediaBrowser.Api.UserLibrary
             // Get them from the child tree
             // Get them from the child tree
             if (series != null)
             if (series != null)
             {
             {
-                var dtoOptions = new DtoOptions();
+                var dtoOptions = GetDtoOptions(request);
 
 
                 // Avoid implicitly captured closure
                 // Avoid implicitly captured closure
                 var currentUser = user;
                 var currentUser = user;
@@ -479,7 +479,7 @@ namespace MediaBrowser.Api.UserLibrary
             // Get them from the db
             // Get them from the db
             if (movie != null)
             if (movie != null)
             {
             {
-                var dtoOptions = new DtoOptions();
+                var dtoOptions = GetDtoOptions(request);
 
 
                 var dtos = movie.SpecialFeatureIds
                 var dtos = movie.SpecialFeatureIds
                     .Select(_libraryManager.GetItemById)
                     .Select(_libraryManager.GetItemById)
@@ -518,7 +518,7 @@ namespace MediaBrowser.Api.UserLibrary
                 trailerIds = hasTrailers.GetTrailerIds();
                 trailerIds = hasTrailers.GetTrailerIds();
             }
             }
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = trailerIds
             var dtos = trailerIds
                 .Select(_libraryManager.GetItemById)
                 .Select(_libraryManager.GetItemById)
@@ -539,7 +539,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
             var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
             var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
 
 
@@ -557,7 +557,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var item = user.RootFolder;
             var item = user.RootFolder;
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
             var result = _dtoService.GetBaseItemDto(item, dtoOptions, user);
 
 
@@ -577,7 +577,7 @@ namespace MediaBrowser.Api.UserLibrary
 
 
             var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
             var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
             var dtos = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
                 .ToArray();
                 .ToArray();

+ 1 - 1
MediaBrowser.Api/UserLibrary/YearsService.cs

@@ -73,7 +73,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
         {
             var item = LibraryManager.GetYear(request.Year);
             var item = LibraryManager.GetYear(request.Year);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             if (request.UserId.HasValue)
             if (request.UserId.HasValue)
             {
             {

+ 1 - 1
MediaBrowser.Api/VideosService.cs

@@ -80,7 +80,7 @@ namespace MediaBrowser.Api
                                   : _libraryManager.RootFolder)
                                   : _libraryManager.RootFolder)
                            : _libraryManager.GetItemById(request.Id);
                            : _libraryManager.GetItemById(request.Id);
 
 
-            var dtoOptions = new DtoOptions();
+            var dtoOptions = GetDtoOptions(request);
 
 
             var video = (Video)item;
             var video = (Video)item;
 
 

+ 53 - 0
MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs

@@ -18,11 +18,64 @@ namespace MediaBrowser.Common.Implementations.Networking
             Logger = logger;
             Logger = logger;
         }
         }
 
 
+        private volatile List<string> _localIpAddresses;
+        private readonly object _localIpAddressSyncLock = new object();
+
         /// <summary>
         /// <summary>
         /// Gets the machine's local ip address
         /// Gets the machine's local ip address
         /// </summary>
         /// </summary>
         /// <returns>IPAddress.</returns>
         /// <returns>IPAddress.</returns>
         public IEnumerable<string> GetLocalIpAddresses()
         public IEnumerable<string> GetLocalIpAddresses()
+        {
+            if (_localIpAddresses == null)
+            {
+                lock (_localIpAddressSyncLock)
+                {
+                    if (_localIpAddresses == null)
+                    {
+                        var addresses = GetLocalIpAddressesInternal().ToList();
+
+                        _localIpAddresses = addresses;
+                        BindEvents();
+
+                        return addresses;
+                    }
+                }
+            }
+
+            return _localIpAddresses;
+        }
+
+        private void BindEvents()
+        {
+            NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
+            NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
+            
+            NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
+            NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
+        }
+
+        void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
+        {
+            Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
+
+            lock (_localIpAddressSyncLock)
+            {
+                _localIpAddresses = null;
+            }
+        }
+
+        void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
+        {
+            Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
+
+            lock (_localIpAddressSyncLock)
+            {
+                _localIpAddresses = null;
+            }
+        }
+
+        private IEnumerable<string> GetLocalIpAddressesInternal()
         {
         {
             var list = GetIPsDefault()
             var list = GetIPsDefault()
                 .Where(i => !IPAddress.IsLoopback(i))
                 .Where(i => !IPAddress.IsLoopback(i))

+ 6 - 0
MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs

@@ -544,6 +544,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
                 Id = Id
                 Id = Id
             };
             };
 
 
+            var hasKey = ScheduledTask as IHasKey;
+            if (hasKey != null)
+            {
+                result.Key = hasKey.Key;
+            }
+
             if (ex != null)
             if (ex != null)
             {
             {
                 result.ErrorMessage = ex.Message;
                 result.ErrorMessage = ex.Message;

+ 0 - 1
MediaBrowser.Common/Net/INetworkManager.cs

@@ -2,7 +2,6 @@ using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Net;
 using System.Net;
-using MediaBrowser.Model.Logging;
 
 
 namespace MediaBrowser.Common.Net
 namespace MediaBrowser.Common.Net
 {
 {

+ 7 - 0
MediaBrowser.Controller/Collections/ICollectionManager.cs

@@ -60,5 +60,12 @@ namespace MediaBrowser.Controller.Collections
         /// <param name="userId">The user identifier.</param>
         /// <param name="userId">The user identifier.</param>
         /// <returns>Folder.</returns>
         /// <returns>Folder.</returns>
         Folder GetCollectionsFolder(string userId);
         Folder GetCollectionsFolder(string userId);
+
+        /// <summary>
+        /// Gets the collections.
+        /// </summary>
+        /// <param name="user">The user.</param>
+        /// <returns>IEnumerable&lt;BoxSet&gt;.</returns>
+        IEnumerable<BoxSet> GetCollections(User user);
     }
     }
 }
 }

+ 1 - 0
MediaBrowser.Controller/Dto/DtoOptions.cs

@@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Dto
         public List<ImageType> ImageTypes { get; set; }
         public List<ImageType> ImageTypes { get; set; }
         public int ImageTypeLimit { get; set; }
         public int ImageTypeLimit { get; set; }
         public bool EnableImages { get; set; }
         public bool EnableImages { get; set; }
+        public string DeviceId { get; set; }
 
 
         public DtoOptions()
         public DtoOptions()
         {
         {

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

@@ -44,6 +44,17 @@ namespace MediaBrowser.Controller.Dto
         /// <param name="owner">The owner.</param>
         /// <param name="owner">The owner.</param>
         /// <returns>BaseItemDto.</returns>
         /// <returns>BaseItemDto.</returns>
         BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
         BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
+
+        /// <summary>
+        /// Gets the base item dtos.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="user">The user.</param>
+        /// <param name="owner">The owner.</param>
+        /// <returns>IEnumerable&lt;BaseItemDto&gt;.</returns>
+        IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null,
+            BaseItem owner = null);
         
         
         /// <summary>
         /// <summary>
         /// Gets the chapter information dto.
         /// Gets the chapter information dto.

+ 9 - 3
MediaBrowser.Controller/IServerApplicationHost.cs

@@ -55,9 +55,15 @@ namespace MediaBrowser.Controller
         string FriendlyName { get; }
         string FriendlyName { get; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets the HTTP server ip addresses.
+        /// Gets the local ip address.
         /// </summary>
         /// </summary>
-        /// <value>The HTTP server ip addresses.</value>
-        IEnumerable<string> HttpServerIpAddresses { get; }
+        /// <value>The local ip address.</value>
+        string LocalIpAddress { get; }
+
+        /// <summary>
+        /// Gets the local API URL.
+        /// </summary>
+        /// <value>The local API URL.</value>
+        string LocalApiUrl { get; }
     }
     }
 }
 }

+ 7 - 0
MediaBrowser.Controller/Sync/ISyncManager.cs

@@ -142,5 +142,12 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="id">The identifier.</param>
         /// <param name="id">The identifier.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task UnmarkJobItemForRemoval(string id);
         Task UnmarkJobItemForRemoval(string id);
+
+        /// <summary>
+        /// Gets the library item ids.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>QueryResult&lt;System.String&gt;.</returns>
+        QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query);
     }
     }
 }
 }

+ 7 - 0
MediaBrowser.Controller/Sync/ISyncRepository.cs

@@ -68,5 +68,12 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="query">The query.</param>
         /// <param name="query">The query.</param>
         /// <returns>IEnumerable&lt;SyncJobItem&gt;.</returns>
         /// <returns>IEnumerable&lt;SyncJobItem&gt;.</returns>
         QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query);
         QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query);
+
+        /// <summary>
+        /// Gets the library item ids.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>QueryResult&lt;System.String&gt;.</returns>
+        QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query);
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs

@@ -86,7 +86,7 @@ namespace MediaBrowser.Dlna.Ssdp
 
 
             try
             try
             {
             {
-                var ip = _appHost.HttpServerIpAddresses.FirstOrDefault();
+                var ip = _appHost.LocalIpAddress;
 
 
                 if (!string.IsNullOrWhiteSpace(ip))
                 if (!string.IsNullOrWhiteSpace(ip))
                 {
                 {

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

@@ -203,6 +203,8 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableAudioArchiveFiles { get; set; }
         public bool EnableAudioArchiveFiles { get; set; }
         public bool EnableVideoArchiveFiles { get; set; }
         public bool EnableVideoArchiveFiles { get; set; }
 
 
+        public bool EnableLegacyCollections { get; set; }
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
         /// </summary>

+ 2 - 1
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -69,7 +69,8 @@ namespace MediaBrowser.Model.Dto
         public int? AnimeSeriesIndex { get; set; }
         public int? AnimeSeriesIndex { get; set; }
 
 
         public bool? SupportsSync { get; set; }
         public bool? SupportsSync { get; set; }
-        
+        public bool? HasSyncJob { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the DVD season number.
         /// Gets or sets the DVD season number.
         /// </summary>
         /// </summary>

+ 6 - 0
MediaBrowser.Model/Tasks/TaskResult.cs

@@ -31,6 +31,12 @@ namespace MediaBrowser.Model.Tasks
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
 
 
+        /// <summary>
+        /// Gets or sets the key.
+        /// </summary>
+        /// <value>The key.</value>
+        public string Key { get; set; }
+        
         /// <summary>
         /// <summary>
         /// Gets or sets the id.
         /// Gets or sets the id.
         /// </summary>
         /// </summary>

+ 4 - 4
MediaBrowser.Server.Implementations/Channels/ChannelManager.cs

@@ -180,7 +180,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
 
 
-            var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
+            var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
@@ -556,7 +556,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
 
 
-            var returnItems = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
+            var returnItems = _dtoService.GetBaseItemDtos(items, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
@@ -823,7 +823,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
 
 
-            var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
+            var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
@@ -972,7 +972,7 @@ namespace MediaBrowser.Server.Implementations.Channels
 
 
             var dtoOptions = new DtoOptions();
             var dtoOptions = new DtoOptions();
 
 
-            var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
+            var returnItems = _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
                 .ToArray();
                 .ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>

+ 10 - 2
MediaBrowser.Server.Implementations/Collections/CollectionManager.cs

@@ -6,7 +6,6 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
-using MoreLinq;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
@@ -41,6 +40,14 @@ namespace MediaBrowser.Server.Implementations.Collections
                 .FirstOrDefault();
                 .FirstOrDefault();
         }
         }
 
 
+        public IEnumerable<BoxSet> GetCollections(User user)
+        {
+            var folder = GetCollectionsFolder(user.Id.ToString("N"));
+            return folder == null ?
+                new List<BoxSet>() :
+                folder.GetChildren(user, true).OfType<BoxSet>();
+        }
+
         public async Task<BoxSet> CreateCollection(CollectionCreationOptions options)
         public async Task<BoxSet> CreateCollection(CollectionCreationOptions options)
         {
         {
             var name = options.Name;
             var name = options.Name;
@@ -269,7 +276,8 @@ namespace MediaBrowser.Server.Implementations.Collections
         public IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
         public IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
         {
         {
             var results = new Dictionary<Guid, BaseItem>();
             var results = new Dictionary<Guid, BaseItem>();
-            var allBoxsets = new List<BoxSet>();
+
+            var allBoxsets = GetCollections(user).ToList();
 
 
             foreach (var item in items)
             foreach (var item in items)
             {
             {

+ 2 - 2
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -153,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Connect
 
 
             try
             try
             {
             {
-                var localAddress = _appHost.GetSystemInfo().LocalAddress;
+                var localAddress = _appHost.LocalApiUrl;
 
 
                 var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
                 var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
                                   !string.IsNullOrWhiteSpace(ConnectAccessKey);
                                   !string.IsNullOrWhiteSpace(ConnectAccessKey);
@@ -195,7 +195,7 @@ namespace MediaBrowser.Server.Implementations.Connect
         private string _lastReportedIdentifier;
         private string _lastReportedIdentifier;
         private string GetConnectReportingIdentifier()
         private string GetConnectReportingIdentifier()
         {
         {
-            return GetConnectReportingIdentifier(_appHost.GetSystemInfo().LocalAddress, WanApiAddress);
+            return GetConnectReportingIdentifier(_appHost.LocalApiUrl, WanApiAddress);
         }
         }
         private string GetConnectReportingIdentifier(string localAddress, string remoteAddress)
         private string GetConnectReportingIdentifier(string localAddress, string remoteAddress)
         {
         {

+ 91 - 8
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
@@ -19,6 +20,7 @@ using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Sync;
 using MoreLinq;
 using MoreLinq;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -42,8 +44,9 @@ namespace MediaBrowser.Server.Implementations.Dto
         private readonly Func<IChannelManager> _channelManagerFactory;
         private readonly Func<IChannelManager> _channelManagerFactory;
         private readonly ISyncManager _syncManager;
         private readonly ISyncManager _syncManager;
         private readonly IApplicationHost _appHost;
         private readonly IApplicationHost _appHost;
+        private readonly Func<IDeviceManager> _deviceManager;
 
 
-        public DtoService(ILogger logger, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager, Func<IChannelManager> channelManagerFactory, ISyncManager syncManager, IApplicationHost appHost)
+        public DtoService(ILogger logger, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager, Func<IChannelManager> channelManagerFactory, ISyncManager syncManager, IApplicationHost appHost, Func<IDeviceManager> deviceManager)
         {
         {
             _logger = logger;
             _logger = logger;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
@@ -56,6 +59,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             _channelManagerFactory = channelManagerFactory;
             _channelManagerFactory = channelManagerFactory;
             _syncManager = syncManager;
             _syncManager = syncManager;
             _appHost = appHost;
             _appHost = appHost;
+            _deviceManager = deviceManager;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -73,10 +77,39 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
             {
                 Fields = fields
                 Fields = fields
             };
             };
-            
+
             return GetBaseItemDto(item, options, user, owner);
             return GetBaseItemDto(item, options, user, owner);
         }
         }
 
 
+        public IEnumerable<BaseItemDto> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
+        {
+            var itemIdsWithSyncJobs = GetItemIdsWithSyncJobs(options).ToList();
+
+            var list = new List<BaseItemDto>();
+
+            foreach (var item in items)
+            {
+                var dto = GetBaseItemDtoInternal(item, options, user, owner);
+
+                var byName = item as IItemByName;
+
+                if (byName != null && !(item is LiveTvChannel))
+                {
+                    var libraryItems = user != null ?
+                       user.RootFolder.GetRecursiveChildren(user) :
+                       _libraryManager.RootFolder.RecursiveChildren;
+
+                    SetItemByNameInfo(item, dto, byName.GetTaggedItems(libraryItems).ToList(), user);
+                }
+
+                FillSyncInfo(dto, item, itemIdsWithSyncJobs, options);
+
+                list.Add(dto);
+            }
+
+            return list;
+        }
+
         public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
         public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
         {
         {
             var dto = GetBaseItemDtoInternal(item, options, user, owner);
             var dto = GetBaseItemDtoInternal(item, options, user, owner);
@@ -94,9 +127,64 @@ namespace MediaBrowser.Server.Implementations.Dto
                 return dto;
                 return dto;
             }
             }
 
 
+            FillSyncInfo(dto, item, options);
+
             return dto;
             return dto;
         }
         }
 
 
+        private IEnumerable<string> GetItemIdsWithSyncJobs(DtoOptions options)
+        {
+            if (!options.Fields.Contains(ItemFields.SyncInfo))
+            {
+                return new List<string>();
+            }
+
+            var deviceId = options.DeviceId;
+            if (string.IsNullOrWhiteSpace(deviceId))
+            {
+                return new List<string>();
+            }
+
+            var caps = _deviceManager().GetCapabilities(deviceId);
+            if (caps == null || !caps.SupportsSync)
+            {
+                return new List<string>();
+            }
+
+            var result = _syncManager.GetLibraryItemIds(new SyncJobItemQuery
+            {
+                TargetId = deviceId
+            });
+
+            return result.Items;
+        }
+
+        private void FillSyncInfo(BaseItemDto dto, BaseItem item, DtoOptions options)
+        {
+            if (options.Fields.Contains(ItemFields.SyncInfo))
+            {
+                dto.SupportsSync = _syncManager.SupportsSync(item);
+            }
+
+            if (dto.SupportsSync ?? false)
+            {
+                dto.HasSyncJob = GetItemIdsWithSyncJobs(options).Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+            }
+        }
+
+        private void FillSyncInfo(BaseItemDto dto, BaseItem item, IEnumerable<string> itemIdsWithSyncJobs, DtoOptions options)
+        {
+            if (options.Fields.Contains(ItemFields.SyncInfo))
+            {
+                dto.SupportsSync = _syncManager.SupportsSync(item);
+            }
+
+            if (dto.SupportsSync ?? false)
+            {
+                dto.HasSyncJob = itemIdsWithSyncJobs.Contains(dto.Id, StringComparer.OrdinalIgnoreCase);
+            }
+        }
+
         private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
         private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
         {
         {
             var fields = options.Fields;
             var fields = options.Fields;
@@ -167,11 +255,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
             AttachBasicFields(dto, item, owner, options);
             AttachBasicFields(dto, item, owner, options);
 
 
-            if (fields.Contains(ItemFields.SyncInfo))
-            {
-                dto.SupportsSync = _syncManager.SupportsSync(item);
-            }
-
             if (fields.Contains(ItemFields.SoundtrackIds))
             if (fields.Contains(ItemFields.SoundtrackIds))
             {
             {
                 var hasSoundtracks = item as IHasSoundtracks;
                 var hasSoundtracks = item as IHasSoundtracks;
@@ -1029,7 +1112,7 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
                 //if (fields.Contains(ItemFields.MediaSourceCount))
                 //if (fields.Contains(ItemFields.MediaSourceCount))
                 //{
                 //{
-                    // Songs always have one
+                // Songs always have one
                 //}
                 //}
             }
             }
 
 

+ 1 - 1
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1575,7 +1575,7 @@ namespace MediaBrowser.Server.Implementations.Library
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
         {
         {
             var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath,
             var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath,
-                "views");
+                            "views");
 
 
             path = Path.Combine(path, _fileSystem.GetValidFilename(type));
             path = Path.Combine(path, _fileSystem.GetValidFilename(type));
 
 

+ 1 - 2
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -696,8 +696,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
             var text = new StringBuilder();
             var text = new StringBuilder();
 
 
-            var info = _appHost.GetSystemInfo();
-            var localAddress = info.LocalAddress ?? string.Empty;
+            var localAddress = _appHost.LocalApiUrl ?? string.Empty;
 
 
             text.AppendLine("Use your web browser to visit:");
             text.AppendLine("Use your web browser to visit:");
             text.AppendLine(string.Empty);
             text.AppendLine(string.Empty);

+ 25 - 13
MediaBrowser.Server.Implementations/Library/UserViewManager.cs

@@ -1,6 +1,6 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Collections;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
@@ -23,24 +23,24 @@ namespace MediaBrowser.Server.Implementations.Library
     {
     {
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ILocalizationManager _localizationManager;
         private readonly ILocalizationManager _localizationManager;
-        private readonly IFileSystem _fileSystem;
         private readonly IUserManager _userManager;
         private readonly IUserManager _userManager;
 
 
         private readonly IChannelManager _channelManager;
         private readonly IChannelManager _channelManager;
         private readonly ILiveTvManager _liveTvManager;
         private readonly ILiveTvManager _liveTvManager;
-        private readonly IServerApplicationPaths _appPaths;
         private readonly IPlaylistManager _playlists;
         private readonly IPlaylistManager _playlists;
+        private readonly ICollectionManager _collectionManager;
+        private readonly IServerConfigurationManager _config;
 
 
-        public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IFileSystem fileSystem, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IServerApplicationPaths appPaths, IPlaylistManager playlists)
+        public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IUserManager userManager, IChannelManager channelManager, ILiveTvManager liveTvManager, IPlaylistManager playlists, ICollectionManager collectionManager, IServerConfigurationManager config)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _localizationManager = localizationManager;
             _localizationManager = localizationManager;
-            _fileSystem = fileSystem;
             _userManager = userManager;
             _userManager = userManager;
             _channelManager = channelManager;
             _channelManager = channelManager;
             _liveTvManager = liveTvManager;
             _liveTvManager = liveTvManager;
-            _appPaths = appPaths;
             _playlists = playlists;
             _playlists = playlists;
+            _collectionManager = collectionManager;
+            _config = config;
         }
         }
 
 
         public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
         public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
@@ -88,12 +88,24 @@ namespace MediaBrowser.Server.Implementations.Library
                 list.Add(await GetUserView(CollectionType.Games, string.Empty, cancellationToken).ConfigureAwait(false));
                 list.Add(await GetUserView(CollectionType.Games, string.Empty, cancellationToken).ConfigureAwait(false));
             }
             }
 
 
-            if (user.Configuration.DisplayCollectionsView &&
-                folders
-                .Except(standaloneFolders)
-                .SelectMany(i => i.GetRecursiveChildren(user, false)).OfType<BoxSet>().Any())
+            if (user.Configuration.DisplayCollectionsView)
             {
             {
-                list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, cancellationToken).ConfigureAwait(false));
+                bool showCollectionView;
+                if (_config.Configuration.EnableLegacyCollections)
+                {
+                    showCollectionView = folders
+                        .Except(standaloneFolders)
+                        .SelectMany(i => i.GetRecursiveChildren(user, false)).OfType<BoxSet>().Any();
+                }
+                else
+                {
+                    showCollectionView = _collectionManager.GetCollections(user).Any();
+                }
+
+                if (showCollectionView)
+                {
+                    list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, cancellationToken).ConfigureAwait(false));
+                }
             }
             }
 
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)))
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)))

+ 2 - 2
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -56,7 +56,7 @@
     "HeaderVideo": "Video",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "HeaderPaths": "Paths",
     "LabelSyncTempPath": "Temporary file path:",
     "LabelSyncTempPath": "Temporary file path:",
-    "LabelSyncTempPathHelp": "",
+    "LabelSyncTempPathHelp": "Specify a custom sync working folder. Converted media created during the sync process will be stored here.",
     "LabelCustomCertificatePath": "Custom certificate path:",
     "LabelCustomCertificatePath": "Custom certificate path:",
     "LabelCustomCertificatePathHelp": "Supply your own ssl certificate. If omitted, the server will create a self-signed certificate.",
     "LabelCustomCertificatePathHelp": "Supply your own ssl certificate. If omitted, the server will create a self-signed certificate.",
     "TitleNotifications": "Notifications",
     "TitleNotifications": "Notifications",
@@ -891,7 +891,7 @@
     "OptionCommunityMostWatchedSort": "Most Watched",
     "OptionCommunityMostWatchedSort": "Most Watched",
     "TabNextUp": "Next Up",
     "TabNextUp": "Next Up",
     "HeaderBecomeMediaBrowserSupporter": "Become a Media Browser Supporter",
     "HeaderBecomeMediaBrowserSupporter": "Become a Media Browser Supporter",
-    "TextAccessPremiumFeatures":  "Enjoy Premium Features",
+    "TextAccessPremiumFeatures": "Enjoy Premium Features",
     "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
     "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
     "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
     "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the + button to start creating Collections.",
     "MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
     "MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",

+ 5 - 0
MediaBrowser.Server.Implementations/Sync/SyncManager.cs

@@ -720,5 +720,10 @@ namespace MediaBrowser.Server.Implementations.Sync
 
 
             await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false);
             await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false);
         }
         }
+
+        public QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query)
+        {
+            return _repo.GetLibraryItemIds(query);
+        }
     }
     }
 }
 }

+ 21 - 6
MediaBrowser.Server.Implementations/Sync/SyncRepository.cs

@@ -459,7 +459,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             return null;
             return null;
         }
         }
 
 
-        public QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query)
+        private QueryResult<T> GetJobItemReader<T>(SyncJobItemQuery query, string baseSelectText, Func<IDataReader, T> itemFactory)
         {
         {
             if (query == null)
             if (query == null)
             {
             {
@@ -468,7 +468,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
 
             using (var cmd = _connection.CreateCommand())
             using (var cmd = _connection.CreateCommand())
             {
             {
-                cmd.CommandText = BaseJobItemSelectText;
+                cmd.CommandText = baseSelectText;
 
 
                 var whereClauses = new List<string>();
                 var whereClauses = new List<string>();
 
 
@@ -515,14 +515,14 @@ namespace MediaBrowser.Server.Implementations.Sync
 
 
                 cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
                 cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging;
 
 
-                var list = new List<SyncJobItem>();
+                var list = new List<T>();
                 var count = 0;
                 var count = 0;
 
 
                 using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
                 using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
                 {
                 {
                     while (reader.Read())
                     while (reader.Read())
                     {
                     {
-                        list.Add(GetJobItem(reader));
+                        list.Add(itemFactory(reader));
                     }
                     }
 
 
                     if (reader.NextResult() && reader.Read())
                     if (reader.NextResult() && reader.Read())
@@ -531,7 +531,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                     }
                     }
                 }
                 }
 
 
-                return new QueryResult<SyncJobItem>()
+                return new QueryResult<T>()
                 {
                 {
                     Items = list.ToArray(),
                     Items = list.ToArray(),
                     TotalRecordCount = count
                     TotalRecordCount = count
@@ -539,6 +539,16 @@ namespace MediaBrowser.Server.Implementations.Sync
             }
             }
         }
         }
 
 
+        public QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query)
+        {
+            return GetJobItemReader(query, "select ItemId from SyncJobItems", GetItemId);
+        }
+
+        public QueryResult<SyncJobItem> GetJobItems(SyncJobItemQuery query)
+        {
+            return GetJobItemReader(query, BaseJobItemSelectText, GetJobItem);
+        }
+
         public Task Create(SyncJobItem jobItem)
         public Task Create(SyncJobItem jobItem)
         {
         {
             return Update(jobItem);
             return Update(jobItem);
@@ -679,10 +689,15 @@ namespace MediaBrowser.Server.Implementations.Sync
 
 
             info.IsMarkedForRemoval = reader.GetBoolean(13);
             info.IsMarkedForRemoval = reader.GetBoolean(13);
             info.JobItemIndex = reader.GetInt32(14);
             info.JobItemIndex = reader.GetInt32(14);
-          
+
             return info;
             return info;
         }
         }
 
 
+        private string GetItemId(IDataReader reader)
+        {
+            return reader.GetString(0);
+        }
+
         /// <summary>
         /// <summary>
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
         /// </summary>
         /// </summary>

+ 6 - 8
MediaBrowser.Server.Implementations/Udp/UdpServer.cs

@@ -83,9 +83,7 @@ namespace MediaBrowser.Server.Implementations.Udp
 
 
         private async void RespondToV1Message(string endpoint)
         private async void RespondToV1Message(string endpoint)
         {
         {
-            var info = _appHost.GetSystemInfo();
-
-            var localAddress = info.LocalAddress;
+            var localAddress = _appHost.LocalApiUrl;
 
 
             if (!string.IsNullOrEmpty(localAddress))
             if (!string.IsNullOrEmpty(localAddress))
             {
             {
@@ -110,15 +108,15 @@ namespace MediaBrowser.Server.Implementations.Udp
 
 
         private async void RespondToV2Message(string endpoint)
         private async void RespondToV2Message(string endpoint)
         {
         {
-            var info = _appHost.GetSystemInfo();
+            var localUrl = _appHost.LocalApiUrl;
 
 
-            if (!string.IsNullOrEmpty(info.LocalAddress))
+            if (!string.IsNullOrEmpty(localUrl))
             {
             {
                 var response = new ServerDiscoveryInfo
                 var response = new ServerDiscoveryInfo
                 {
                 {
-                    Address = info.LocalAddress,
-                    Id = info.Id,
-                    Name = info.ServerName
+                    Address = localUrl,
+                    Id = _appHost.SystemId,
+                    Name = _appHost.FriendlyName
                 };
                 };
 
 
                 await SendAsync(Encoding.UTF8.GetBytes(_json.SerializeToString(response)), endpoint);
                 await SendAsync(Encoding.UTF8.GetBytes(_json.SerializeToString(response)), endpoint);

+ 24 - 17
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -446,7 +446,7 @@ namespace MediaBrowser.Server.Startup.Common
             SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager);
             SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager);
             RegisterSingleInstance(SyncManager);
             RegisterSingleInstance(SyncManager);
 
 
-            DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this);
+            DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager);
             RegisterSingleInstance(DtoService);
             RegisterSingleInstance(DtoService);
 
 
             var encryptionManager = new EncryptionManager();
             var encryptionManager = new EncryptionManager();
@@ -490,7 +490,7 @@ namespace MediaBrowser.Server.Startup.Common
             LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer);
             LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer);
             RegisterSingleInstance(LiveTvManager);
             RegisterSingleInstance(LiveTvManager);
 
 
-            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager, ApplicationPaths, playlistManager);
+            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, playlistManager, CollectionManager, ServerConfigurationManager);
             RegisterSingleInstance(UserViewManager);
             RegisterSingleInstance(UserViewManager);
 
 
             var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager);
             var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager);
@@ -1019,7 +1019,7 @@ namespace MediaBrowser.Server.Startup.Common
                 IsRunningAsService = IsRunningAsService,
                 IsRunningAsService = IsRunningAsService,
                 SupportsRunningAsService = SupportsRunningAsService,
                 SupportsRunningAsService = SupportsRunningAsService,
                 ServerName = FriendlyName,
                 ServerName = FriendlyName,
-                LocalAddress = GetLocalIpAddress()
+                LocalAddress = LocalApiUrl
             };
             };
         }
         }
 
 
@@ -1036,26 +1036,33 @@ namespace MediaBrowser.Server.Startup.Common
             get { return !string.IsNullOrWhiteSpace(HttpServer.CertificatePath); }
             get { return !string.IsNullOrWhiteSpace(HttpServer.CertificatePath); }
         }
         }
 
 
-        /// <summary>
-        /// Gets the local ip address.
-        /// </summary>
-        /// <returns>System.String.</returns>
-        private string GetLocalIpAddress()
+        public string LocalApiUrl
         {
         {
-            // Return the first matched address, if found, or the first known local address
-            var address = HttpServerIpAddresses.FirstOrDefault();
-
-            if (!string.IsNullOrWhiteSpace(address))
+            get
             {
             {
-                address = string.Format("http://{0}:{1}",
-                    address,
-                    HttpPort.ToString(CultureInfo.InvariantCulture));
+                // Return the first matched address, if found, or the first known local address
+                var address = LocalIpAddress;
+
+                if (!string.IsNullOrWhiteSpace(address))
+                {
+                    address = string.Format("http://{0}:{1}",
+                        address,
+                        HttpPort.ToString(CultureInfo.InvariantCulture));
+                }
+
+                return address;
             }
             }
+        }
 
 
-            return address;
+        public string LocalIpAddress
+        {
+            get
+            {
+                return HttpServerIpAddresses.FirstOrDefault();
+            }
         }
         }
 
 
-        public IEnumerable<string> HttpServerIpAddresses
+        private IEnumerable<string> HttpServerIpAddresses
         {
         {
             get
             get
             {
             {

+ 5 - 0
MediaBrowser.sln

@@ -10,6 +10,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		Performance1.psess = Performance1.psess
 		Performance1.psess = Performance1.psess
 		Performance19.psess = Performance19.psess
 		Performance19.psess = Performance19.psess
 		Performance2.psess = Performance2.psess
 		Performance2.psess = Performance2.psess
+		Performance3.psess = Performance3.psess
+		Performance4.psess = Performance4.psess
 	EndProjectSection
 	EndProjectSection
 EndProject
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}"
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}"
@@ -518,4 +520,7 @@ Global
 	GlobalSection(SolutionProperties) = preSolution
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	EndGlobalSection
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
 EndGlobal
 EndGlobal