Luke Pulverenti пре 8 година
родитељ
комит
fd6aa72dac

+ 4 - 0
MediaBrowser.Api/BaseApiService.cs

@@ -139,6 +139,10 @@ namespace MediaBrowser.Api
                 {
                 {
                     options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
                     options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value;
                 }
                 }
+                if (hasDtoOptions.EnableUserData.HasValue)
+                {
+                    options.EnableUserData = hasDtoOptions.EnableUserData.Value;
+                }
 
 
                 if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
                 if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
                 {
                 {

+ 1 - 0
MediaBrowser.Api/IHasDtoOptions.cs

@@ -4,6 +4,7 @@ namespace MediaBrowser.Api
     public interface IHasDtoOptions : IHasItemFields
     public interface IHasDtoOptions : IHasItemFields
     {
     {
         bool? EnableImages { get; set; }
         bool? EnableImages { get; set; }
+        bool? EnableUserData { get; set; }
 
 
         int? ImageTypeLimit { get; set; }
         int? ImageTypeLimit { get; set; }
 
 

+ 26 - 1
MediaBrowser.Api/LiveTv/LiveTvService.cs

@@ -82,6 +82,9 @@ namespace MediaBrowser.Api.LiveTv
         [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "AddCurrentProgram", Description = "Optional. Adds current program info to each channel", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public bool AddCurrentProgram { get; set; }
         public bool AddCurrentProgram { get; set; }
 
 
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
         public GetChannels()
         public GetChannels()
         {
         {
             AddCurrentProgram = true;
             AddCurrentProgram = true;
@@ -149,6 +152,9 @@ namespace MediaBrowser.Api.LiveTv
 
 
         public bool EnableTotalRecordCount { get; set; }
         public bool EnableTotalRecordCount { get; set; }
 
 
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
         public GetRecordings()
         public GetRecordings()
         {
         {
             EnableTotalRecordCount = true;
             EnableTotalRecordCount = true;
@@ -271,6 +277,9 @@ namespace MediaBrowser.Api.LiveTv
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
 
 
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
         /// <summary>
         /// <summary>
         /// Fields to return within the items, in addition to basic information
         /// Fields to return within the items, in addition to basic information
         /// </summary>
         /// </summary>
@@ -331,6 +340,9 @@ namespace MediaBrowser.Api.LiveTv
         /// <value>The fields.</value>
         /// <value>The fields.</value>
         [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Fields { get; set; }
         public string Fields { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
     }
     }
 
 
     [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
     [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
@@ -726,7 +738,12 @@ namespace MediaBrowser.Api.LiveTv
 
 
             var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
             var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId);
 
 
-            var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, GetDtoOptions(Request), user).ConfigureAwait(false)).ToArray();
+            var options = GetDtoOptions(request);
+            RemoveFields(options);
+
+            options.AddCurrentProgram = request.AddCurrentProgram;
+
+            var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user).ConfigureAwait(false)).ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
             {
             {
@@ -737,6 +754,14 @@ namespace MediaBrowser.Api.LiveTv
             return ToOptimizedSerializedResultUsingCache(result);
             return ToOptimizedSerializedResultUsingCache(result);
         }
         }
 
 
+        private void RemoveFields(DtoOptions options)
+        {
+            options.Fields.Remove(ItemFields.CanDelete);
+            options.Fields.Remove(ItemFields.CanDownload);
+            options.Fields.Remove(ItemFields.DisplayPreferencesId);
+            options.Fields.Remove(ItemFields.Etag);
+        }
+
         public object Get(GetChannel request)
         public object Get(GetChannel request)
         {
         {
             var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);
             var user = string.IsNullOrWhiteSpace(request.UserId) ? null : _userManager.GetUserById(request.UserId);

+ 13 - 1
MediaBrowser.Api/PlaylistService.cs

@@ -72,7 +72,7 @@ namespace MediaBrowser.Api
     }
     }
 
 
     [Route("/Playlists/{Id}/Items", "GET", Summary = "Gets the original items of a playlist")]
     [Route("/Playlists/{Id}/Items", "GET", Summary = "Gets the original items of a playlist")]
-    public class GetPlaylistItems : IReturn<QueryResult<BaseItemDto>>, IHasItemFields
+    public class GetPlaylistItems : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
     {
     {
         [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
         [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
         public string Id { get; set; }
         public string Id { get; set; }
@@ -104,6 +104,18 @@ namespace MediaBrowser.Api
         /// <value>The fields.</value>
         /// <value>The fields.</value>
         [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Fields { get; set; }
         public string Fields { get; set; }
+
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
     }
     }
 
 
     [Authenticated]
     [Authenticated]

+ 13 - 1
MediaBrowser.Api/SimilarItemsHelper.cs

@@ -29,8 +29,20 @@ namespace MediaBrowser.Api
         public string ExcludeArtistIds { get; set; }
         public string ExcludeArtistIds { get; set; }
     }
     }
 
 
-    public class BaseGetSimilarItems : IReturn<ItemsResult>, IHasItemFields
+    public class BaseGetSimilarItems : IReturn<ItemsResult>, IHasDtoOptions
     {
     {
+        [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableImages { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
+        [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? ImageTypeLimit { get; set; }
+
+        [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string EnableImageTypes { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the user id.
         /// Gets or sets the user id.
         /// </summary>
         /// </summary>

+ 2 - 2
MediaBrowser.Api/Sync/SyncHelper.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.Api.Sync
                         }
                         }
                         break;
                         break;
                     }
                     }
-                    if (item.IsFolder && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre)
+                    if (item.IsFolderItem && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre)
                     {
                     {
                         options.Add(SyncJobOption.Quality);
                         options.Add(SyncJobOption.Quality);
                         options.Add(SyncJobOption.Profile);
                         options.Add(SyncJobOption.Profile);
@@ -44,7 +44,7 @@ namespace MediaBrowser.Api.Sync
             {
             {
                 if (item.SupportsSync ?? false)
                 if (item.SupportsSync ?? false)
                 {
                 {
-                    if (item.IsFolder || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson)
+                    if (item.IsFolderItem || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson)
                     {
                     {
                         options.Add(SyncJobOption.SyncNewContent);
                         options.Add(SyncJobOption.SyncNewContent);
                         options.Add(SyncJobOption.ItemLimit);
                         options.Add(SyncJobOption.ItemLimit);

+ 14 - 0
MediaBrowser.Api/TvShowsService.cs

@@ -69,6 +69,9 @@ namespace MediaBrowser.Api
 
 
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
     }
     }
 
 
     [Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
     [Route("/Shows/Upcoming", "GET", Summary = "Gets a list of upcoming episodes")]
@@ -117,6 +120,9 @@ namespace MediaBrowser.Api
 
 
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
     }
     }
 
 
     [Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")]
     [Route("/Shows/{Id}/Similar", "GET", Summary = "Finds tv shows similar to a given one.")]
@@ -184,6 +190,10 @@ namespace MediaBrowser.Api
 
 
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
     }
     }
 
 
     [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
     [Route("/Shows/{Id}/Seasons", "GET", Summary = "Gets seasons for a tv series")]
@@ -226,6 +236,10 @@ namespace MediaBrowser.Api
 
 
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
+
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
     }
     }
 
 
     /// <summary>
     /// <summary>

+ 3 - 0
MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs

@@ -226,6 +226,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
         public bool? EnableImages { get; set; }
         public bool? EnableImages { get; set; }
 
 
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
         [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "ImageTypeLimit", Description = "Optional, the max number of images to return, per image type", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
         public int? ImageTypeLimit { get; set; }
         public int? ImageTypeLimit { get; set; }
 
 

+ 3 - 0
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -246,6 +246,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string EnableImageTypes { get; set; }
         public string EnableImageTypes { get; set; }
 
 
+        [ApiMember(Name = "EnableUserData", Description = "Optional, include user data", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
+        public bool? EnableUserData { get; set; }
+
         public GetLatestMedia()
         public GetLatestMedia()
         {
         {
             Limit = 20;
             Limit = 20;

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

@@ -19,12 +19,16 @@ namespace MediaBrowser.Controller.Dto
         public bool EnableImages { get; set; }
         public bool EnableImages { get; set; }
         public bool AddProgramRecordingInfo { get; set; }
         public bool AddProgramRecordingInfo { get; set; }
         public string DeviceId { get; set; }
         public string DeviceId { get; set; }
+        public bool EnableUserData { get; set; }
+        public bool AddCurrentProgram { get; set; }
 
 
         public DtoOptions()
         public DtoOptions()
         {
         {
             Fields = new List<ItemFields>();
             Fields = new List<ItemFields>();
             ImageTypeLimit = int.MaxValue;
             ImageTypeLimit = int.MaxValue;
             EnableImages = true;
             EnableImages = true;
+            EnableUserData = true;
+            AddCurrentProgram = true;
 
 
             Fields = Enum.GetNames(typeof (ItemFields))
             Fields = Enum.GetNames(typeof (ItemFields))
                     .Select(i => (ItemFields) Enum.Parse(typeof (ItemFields), i, true))
                     .Select(i => (ItemFields) Enum.Parse(typeof (ItemFields), i, true))

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

@@ -346,7 +346,16 @@ namespace MediaBrowser.Model.Dto
         /// Gets or sets a value indicating whether this instance is folder.
         /// Gets or sets a value indicating whether this instance is folder.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
-        public bool IsFolder { get; set; }
+        public bool? IsFolder { get; set; }
+
+        [IgnoreDataMember]
+        public bool IsFolderItem
+        {
+            get
+            {
+                return IsFolder ?? false;
+            }
+        }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets the parent id.
         /// Gets or sets the parent id.
@@ -656,7 +665,7 @@ namespace MediaBrowser.Model.Dto
         {
         {
             get
             get
             {
             {
-                return RunTimeTicks.HasValue || IsFolder || IsGenre || IsMusicGenre || IsArtist;
+                return RunTimeTicks.HasValue || IsFolderItem || IsGenre || IsMusicGenre || IsArtist;
             }
             }
         }
         }
 
 

+ 6 - 0
MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs

@@ -59,5 +59,11 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [add current program]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [add current program]; otherwise, <c>false</c>.</value>
         public bool AddCurrentProgram { get; set; }
         public bool AddCurrentProgram { get; set; }
+        public bool EnableUserData { get; set; }
+
+        public LiveTvChannelQuery()
+        {
+            EnableUserData = true;
+        }
     }
     }
 }
 }

+ 2 - 0
MediaBrowser.Model/LiveTv/ProgramQuery.cs

@@ -15,9 +15,11 @@ namespace MediaBrowser.Model.LiveTv
             SortBy = new string[] { };
             SortBy = new string[] { };
             Genres = new string[] { };
             Genres = new string[] { };
             EnableTotalRecordCount = true;
             EnableTotalRecordCount = true;
+            EnableUserData = true;
         }
         }
 
 
         public bool EnableTotalRecordCount { get; set; }
         public bool EnableTotalRecordCount { get; set; }
+        public bool EnableUserData { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Fields to return within the items, in addition to basic information
         /// Fields to return within the items, in addition to basic information

+ 1 - 0
MediaBrowser.Model/Sync/SyncJobQuery.cs

@@ -23,6 +23,7 @@ namespace MediaBrowser.Model.Sync
         /// </summary>
         /// </summary>
         /// <value>The user identifier.</value>
         /// <value>The user identifier.</value>
         public string UserId { get; set; }
         public string UserId { get; set; }
+        public string ExcludeTargetIds { get; set; }
         /// <summary>
         /// <summary>
         /// Gets or sets the status.
         /// Gets or sets the status.
         /// </summary>
         /// </summary>

+ 26 - 10
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -329,7 +329,7 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
             if (user != null)
             if (user != null)
             {
             {
-                await AttachUserSpecificInfo(dto, item, user, fields).ConfigureAwait(false);
+                await AttachUserSpecificInfo(dto, item, user, options).ConfigureAwait(false);
             }
             }
 
 
             var hasMediaSources = item as IHasMediaSources;
             var hasMediaSources = item as IHasMediaSources;
@@ -446,17 +446,18 @@ namespace MediaBrowser.Server.Implementations.Dto
         /// <summary>
         /// <summary>
         /// Attaches the user specific info.
         /// Attaches the user specific info.
         /// </summary>
         /// </summary>
-        /// <param name="dto">The dto.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="user">The user.</param>
-        /// <param name="fields">The fields.</param>
-        private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
+        private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, DtoOptions dtoOptions)
         {
         {
+            var fields = dtoOptions.Fields;
+
             if (item.IsFolder)
             if (item.IsFolder)
             {
             {
                 var folder = (Folder)item;
                 var folder = (Folder)item;
 
 
-                dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false);
+                if (dtoOptions.EnableUserData)
+                {
+                    dto.UserData = await _userDataRepository.GetUserDataDto(item, dto, user).ConfigureAwait(false);
+                }
 
 
                 if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library)
                 if (!dto.ChildCount.HasValue && item.SourceType == SourceType.Library)
                 {
                 {
@@ -476,7 +477,10 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
             else
             else
             {
             {
-                dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result;
+                if (dtoOptions.EnableUserData)
+                {
+                    dto.UserData = _userDataRepository.GetUserDataDto(item, user).Result;
+                }
             }
             }
 
 
             dto.PlayAccess = item.GetPlayAccess(user);
             dto.PlayAccess = item.GetPlayAccess(user);
@@ -484,7 +488,10 @@ namespace MediaBrowser.Server.Implementations.Dto
             if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo))
             if (fields.Contains(ItemFields.BasicSyncInfo) || fields.Contains(ItemFields.SyncInfo))
             {
             {
                 var userCanSync = user != null && user.Policy.EnableSync;
                 var userCanSync = user != null && user.Policy.EnableSync;
-                dto.SupportsSync = userCanSync && _syncManager.SupportsSync(item);
+                if (userCanSync && _syncManager.SupportsSync(item))
+                {
+                    dto.SupportsSync = true;
+                }
             }
             }
 
 
             if (fields.Contains(ItemFields.SeasonUserData))
             if (fields.Contains(ItemFields.SeasonUserData))
@@ -969,7 +976,16 @@ namespace MediaBrowser.Server.Implementations.Dto
             dto.Id = GetDtoId(item);
             dto.Id = GetDtoId(item);
             dto.IndexNumber = item.IndexNumber;
             dto.IndexNumber = item.IndexNumber;
             dto.ParentIndexNumber = item.ParentIndexNumber;
             dto.ParentIndexNumber = item.ParentIndexNumber;
-            dto.IsFolder = item.IsFolder;
+
+            if (item.IsFolder)
+            {
+                dto.IsFolder = true;
+            }
+            else if (item is IHasMediaSources)
+            {
+                dto.IsFolder = false;
+            }
+
             dto.MediaType = item.MediaType;
             dto.MediaType = item.MediaType;
             dto.LocationType = item.LocationType;
             dto.LocationType = item.LocationType;
             if (item.IsHD.HasValue && item.IsHD.Value)
             if (item.IsHD.HasValue && item.IsHD.Value)

+ 29 - 7
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -951,6 +951,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var queryResult = _libraryManager.QueryItems(internalQuery);
             var queryResult = _libraryManager.QueryItems(internalQuery);
 
 
+            RemoveFields(options);
+
             var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
             var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user).ConfigureAwait(false)).ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
@@ -1031,6 +1033,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var user = _userManager.GetUserById(query.UserId);
             var user = _userManager.GetUserById(query.UserId);
 
 
+            RemoveFields(options);
+
             var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
             var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
 
 
             var result = new QueryResult<BaseItemDto>
             var result = new QueryResult<BaseItemDto>
@@ -1662,6 +1666,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false);
             var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false);
 
 
+            RemoveFields(options);
+
             var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
             var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user).ConfigureAwait(false)).ToArray();
 
 
             return new QueryResult<BaseItemDto>
             return new QueryResult<BaseItemDto>
@@ -1922,7 +1928,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var channelIds = tuples.Select(i => i.Item2.Id.ToString("N")).Distinct().ToArray();
             var channelIds = tuples.Select(i => i.Item2.Id.ToString("N")).Distinct().ToArray();
 
 
-            var programs = _libraryManager.GetItemList(new InternalItemsQuery(user)
+            var programs = options.AddCurrentProgram ? _libraryManager.GetItemList(new InternalItemsQuery(user)
             {
             {
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 IncludeItemTypes = new[] { typeof(LiveTvProgram).Name },
                 ChannelIds = channelIds,
                 ChannelIds = channelIds,
@@ -1932,7 +1938,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 SortBy = new[] { "StartDate" },
                 SortBy = new[] { "StartDate" },
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }
                 TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }
 
 
-            }).ToList();
+            }).ToList() : new List<BaseItem>();
+
+            RemoveFields(options);
 
 
             foreach (var tuple in tuples)
             foreach (var tuple in tuples)
             {
             {
@@ -1944,14 +1952,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 dto.ChannelType = channel.ChannelType;
                 dto.ChannelType = channel.ChannelType;
                 dto.ServiceName = GetService(channel).Name;
                 dto.ServiceName = GetService(channel).Name;
 
 
-                dto.MediaSources = channel.GetMediaSources(true).ToList();
+                if (options.Fields.Contains(ItemFields.MediaSources))
+                {
+                    dto.MediaSources = channel.GetMediaSources(true).ToList();
+                }
 
 
                 var channelIdString = channel.Id.ToString("N");
                 var channelIdString = channel.Id.ToString("N");
-                var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
-
-                if (currentProgram != null)
+                if (options.AddCurrentProgram)
                 {
                 {
-                    dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
+                    var currentProgram = programs.FirstOrDefault(i => string.Equals(i.ChannelId, channelIdString));
+
+                    if (currentProgram != null)
+                    {
+                        dto.CurrentProgram = _dtoService.GetBaseItemDto(currentProgram, options, user);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -2447,6 +2461,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user);
             return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user);
         }
         }
 
 
+        private void RemoveFields(DtoOptions options)
+        {
+            options.Fields.Remove(ItemFields.CanDelete);
+            options.Fields.Remove(ItemFields.CanDownload);
+            options.Fields.Remove(ItemFields.DisplayPreferencesId);
+            options.Fields.Remove(ItemFields.Etag);
+        }
+
         public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken)
         public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken)
         {
         {
             var name = _localization.GetLocalizedString("ViewTypeLiveTV");
             var name = _localization.GetLocalizedString("ViewTypeLiveTV");

+ 14 - 0
MediaBrowser.Server.Implementations/Sync/SyncRepository.cs

@@ -414,6 +414,20 @@ namespace MediaBrowser.Server.Implementations.Sync
                         whereClauses.Add("TargetId=@TargetId");
                         whereClauses.Add("TargetId=@TargetId");
                         cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
                         cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
                     }
                     }
+                    if (!string.IsNullOrWhiteSpace(query.ExcludeTargetIds))
+                    {
+                        var excludeIds = (query.ExcludeTargetIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+                        if (excludeIds.Length == 1)
+                        {
+                            whereClauses.Add("TargetId<>@ExcludeTargetId");
+                            cmd.Parameters.Add(cmd, "@ExcludeTargetId", DbType.String).Value = excludeIds[0];
+                        }
+                        else if (excludeIds.Length > 1)
+                        {
+                            whereClauses.Add("TargetId<>@ExcludeTargetId");
+                            cmd.Parameters.Add(cmd, "@ExcludeTargetId", DbType.String).Value = excludeIds[0];
+                        }
+                    }
                     if (!string.IsNullOrWhiteSpace(query.UserId))
                     if (!string.IsNullOrWhiteSpace(query.UserId))
                     {
                     {
                         whereClauses.Add("UserId=@UserId");
                         whereClauses.Add("UserId=@UserId");