diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 8cb814b971..b8b74369ce 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dto; @@ -460,6 +461,9 @@ namespace MediaBrowser.Api.LiveTv public async Task Get(GetRecordings request) { + var options = new DtoOptions(); + options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; + var result = await _liveTvManager.GetRecordings(new RecordingQuery { ChannelId = request.ChannelId, @@ -471,7 +475,7 @@ namespace MediaBrowser.Api.LiveTv SeriesTimerId = request.SeriesTimerId, IsInProgress = request.IsInProgress - }, CancellationToken.None).ConfigureAwait(false); + }, options, CancellationToken.None).ConfigureAwait(false); return ToOptimizedResult(result); } @@ -480,7 +484,10 @@ namespace MediaBrowser.Api.LiveTv { var user = string.IsNullOrEmpty(request.UserId) ? null : _userManager.GetUserById(request.UserId); - var result = await _liveTvManager.GetRecording(request.Id, CancellationToken.None, user).ConfigureAwait(false); + var options = new DtoOptions(); + options.DeviceId = AuthorizationContext.GetAuthorizationInfo(Request).DeviceId; + + var result = await _liveTvManager.GetRecording(request.Id, options, CancellationToken.None, user).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index ea311d9937..5ec8f274be 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -35,6 +35,14 @@ namespace MediaBrowser.Controller.Dto /// Task{BaseItemDto}. BaseItemDto GetBaseItemDto(BaseItem item, List fields, User user = null, BaseItem owner = null); + /// + /// Fills the synchronize information. + /// + /// The dtos. + /// The options. + /// The user. + void FillSyncInfo(IEnumerable dtos, DtoOptions options, User user); + /// /// Gets the base item dto. /// diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 5e5735d34c..562ae9f621 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -50,6 +50,16 @@ namespace MediaBrowser.Controller.Entities { var user = query.User; + if (query.IncludeItemTypes != null && + query.IncludeItemTypes.Length == 1 && + string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase)) + { + if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) + { + return await FindPlaylists(queryParent, user, query).ConfigureAwait(false); + } + } + switch (viewType) { case CollectionType.Channels: @@ -240,6 +250,16 @@ namespace MediaBrowser.Controller.Entities } } + private async Task> FindPlaylists(Folder parent, User user, InternalItemsQuery query) + { + var collectionFolders = user.RootFolder.GetChildren(user, true).Select(i => i.Id).ToList(); + + var list = _playlistManager.GetPlaylists(user.Id.ToString("N")) + .Where(i => i.GetChildren(user, true).Any(media => _libraryManager.GetCollectionFolders(media).Select(c => c.Id).Any(collectionFolders.Contains))); + + return GetResult(list, parent, query); + } + private int GetSpecialItemsLimit() { return 50; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index d5b5d92a6e..4ee0565f9b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Dto; using MediaBrowser.Model.LiveTv; @@ -74,10 +75,11 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the recording. /// /// The identifier. - /// The user. + /// The options. /// The cancellation token. + /// The user. /// Task{RecordingInfoDto}. - Task GetRecording(string id, CancellationToken cancellationToken, User user = null); + Task GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null); /// /// Gets the channel. @@ -103,14 +105,15 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task{TimerInfoDto}. Task GetSeriesTimer(string id, CancellationToken cancellationToken); - + /// /// Gets the recordings. /// /// The query. + /// The options. /// The cancellation token. /// QueryResult{RecordingInfoDto}. - Task> GetRecordings(RecordingQuery query, CancellationToken cancellationToken); + Task> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken); /// /// Gets the timers. diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index c3ec911de8..1aa8d7f1f1 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -464,6 +464,9 @@ Dto\IHasServerId.cs + + Dto\IHasSyncInfo.cs + Dto\IItemDto.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 437fcc8fff..5d4633f507 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -429,6 +429,9 @@ Dto\IHasServerId.cs + + Dto\IHasSyncInfo.cs + Dto\IItemDto.cs diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index d984fe89e5..6b223ea069 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Library; using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Sync; using System; using System.Collections.Generic; using System.ComponentModel; @@ -16,7 +17,7 @@ namespace MediaBrowser.Model.Dto /// This holds information about a BaseItem in a format that is convenient for the client. /// [DebuggerDisplay("Name = {Name}, ID = {Id}, Type = {Type}")] - public class BaseItemDto : IHasProviderIds, IHasPropertyChangedEvent, IItemDto, IHasServerId + public class BaseItemDto : IHasProviderIds, IHasPropertyChangedEvent, IItemDto, IHasServerId, IHasSyncInfo { /// /// Gets or sets the name. @@ -87,6 +88,11 @@ namespace MediaBrowser.Model.Dto /// /// null if [is synced] contains no value, true if [is synced]; otherwise, false. public bool? IsSynced { get; set; } + /// + /// Gets or sets the synchronize status. + /// + /// The synchronize status. + public SyncJobItemStatus? SyncStatus { get; set; } /// /// Gets or sets the DVD season number. diff --git a/MediaBrowser.Model/Dto/IHasSyncInfo.cs b/MediaBrowser.Model/Dto/IHasSyncInfo.cs new file mode 100644 index 0000000000..d2cf1f8cfe --- /dev/null +++ b/MediaBrowser.Model/Dto/IHasSyncInfo.cs @@ -0,0 +1,13 @@ +using MediaBrowser.Model.Sync; + +namespace MediaBrowser.Model.Dto +{ + public interface IHasSyncInfo + { + string Id { get; } + bool? SupportsSync { get; set; } + bool? HasSyncJob { get; set; } + bool? IsSynced { get; set; } + SyncJobItemStatus? SyncStatus { get; set; } + } +} diff --git a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs index d6d6980381..0988b11a6e 100644 --- a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs +++ b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Library; +using MediaBrowser.Model.Sync; using System; using System.Collections.Generic; using System.ComponentModel; @@ -11,7 +12,7 @@ using System.Runtime.Serialization; namespace MediaBrowser.Model.LiveTv { [DebuggerDisplay("Name = {Name}, ChannelName = {ChannelName}")] - public class RecordingInfoDto : IHasPropertyChangedEvent, IItemDto, IHasServerId + public class RecordingInfoDto : IHasPropertyChangedEvent, IItemDto, IHasServerId, IHasSyncInfo { /// /// Id of the recording. @@ -35,6 +36,27 @@ namespace MediaBrowser.Model.LiveTv /// /// The original primary image aspect ratio. public double? OriginalPrimaryImageAspectRatio { get; set; } + + /// + /// Gets or sets a value indicating whether [supports synchronize]. + /// + /// null if [supports synchronize] contains no value, true if [supports synchronize]; otherwise, false. + public bool? SupportsSync { get; set; } + /// + /// Gets or sets a value indicating whether this instance has synchronize job. + /// + /// null if [has synchronize job] contains no value, true if [has synchronize job]; otherwise, false. + public bool? HasSyncJob { get; set; } + /// + /// Gets or sets a value indicating whether this instance is synced. + /// + /// null if [is synced] contains no value, true if [is synced]; otherwise, false. + public bool? IsSynced { get; set; } + /// + /// Gets or sets the synchronize status. + /// + /// The synchronize status. + public SyncJobItemStatus? SyncStatus { get; set; } /// /// Gets or sets the series timer identifier. diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 2a210b7a2f..eb36712c2f 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -138,6 +138,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 612c33d872..6a7323fdee 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -188,7 +188,22 @@ namespace MediaBrowser.Server.Implementations.Dto return new Tuple, IEnumerable>(result1.Items, result2.Items); } - private void FillSyncInfo(BaseItemDto dto, BaseItem item, DtoOptions options, User user) + public void FillSyncInfo(IEnumerable dtos, DtoOptions options, User user) + { + if (options.Fields.Contains(ItemFields.SyncInfo)) + { + var tuple = GetItemIdsWithSyncJobs(options); + + foreach (var dto in dtos) + { + var item = _libraryManager.GetItemById(dto.Id); + + FillSyncInfo(dto, item, tuple.Item1, tuple.Item2, options, user); + } + } + } + + private void FillSyncInfo(IHasSyncInfo dto, BaseItem item, DtoOptions options, User user) { if (options.Fields.Contains(ItemFields.SyncInfo)) { @@ -202,10 +217,20 @@ namespace MediaBrowser.Server.Implementations.Dto dto.HasSyncJob = tuple.Item1.Contains(dto.Id, StringComparer.OrdinalIgnoreCase); dto.IsSynced = tuple.Item2.Contains(dto.Id, StringComparer.OrdinalIgnoreCase); + + if (dto.IsSynced.Value) + { + dto.SyncStatus = SyncJobItemStatus.Synced; + } + + else if (dto.HasSyncJob.Value) + { + dto.SyncStatus = SyncJobItemStatus.Queued; + } } } - private void FillSyncInfo(BaseItemDto dto, BaseItem item, IEnumerable itemIdsWithPendingSyncJobs, IEnumerable syncedItemIds, DtoOptions options, User user) + private void FillSyncInfo(IHasSyncInfo dto, BaseItem item, IEnumerable itemIdsWithPendingSyncJobs, IEnumerable syncedItemIds, DtoOptions options, User user) { if (options.Fields.Contains(ItemFields.SyncInfo)) { @@ -217,6 +242,16 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.HasSyncJob = itemIdsWithPendingSyncJobs.Contains(dto.Id, StringComparer.OrdinalIgnoreCase); dto.IsSynced = syncedItemIds.Contains(dto.Id, StringComparer.OrdinalIgnoreCase); + + if (dto.IsSynced.Value) + { + dto.SyncStatus = SyncJobItemStatus.Synced; + } + + else if (dto.HasSyncJob.Value) + { + dto.SyncStatus = SyncJobItemStatus.Queued; + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 401cf87657..61017ffb35 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -8,12 +8,12 @@ using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.LiveTv { diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 92e2aedd25..3f164ee6f5 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1148,7 +1148,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv RefreshIfNeeded(programs.Take(500)); // Load these now which will prefetch metadata - await GetRecordings(new RecordingQuery(), cancellationToken).ConfigureAwait(false); + var dtoOptions = new DtoOptions(); + dtoOptions.Fields.Remove(ItemFields.SyncInfo); + await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false); progress.Report(100); } @@ -1322,7 +1324,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv }; } - public async Task> GetRecordings(RecordingQuery query, CancellationToken cancellationToken) + public async Task> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); @@ -1338,6 +1340,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv }) .ToArray(); + if (user != null) + { + _dtoService.FillSyncInfo(returnArray, new DtoOptions(), user); + } + return new QueryResult { Items = returnArray, @@ -1410,7 +1417,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task DeleteRecording(string recordingId) { - var recording = await GetRecording(recordingId, CancellationToken.None).ConfigureAwait(false); + var dtoOptions = new DtoOptions(); + dtoOptions.Fields.Remove(ItemFields.SyncInfo); + + var recording = await GetRecording(recordingId, dtoOptions, CancellationToken.None).ConfigureAwait(false); if (recording == null) { @@ -1450,14 +1460,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false); } - public async Task GetRecording(string id, CancellationToken cancellationToken, User user = null) + public async Task GetRecording(string id, DtoOptions options, CancellationToken cancellationToken, User user = null) { var results = await GetRecordings(new RecordingQuery { UserId = user == null ? null : user.Id.ToString("N"), Id = id - }, cancellationToken).ConfigureAwait(false); + }, options, cancellationToken).ConfigureAwait(false); return results.Items.FirstOrDefault(); } @@ -1737,11 +1747,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv public async Task> GetRecordingGroups(RecordingGroupQuery query, CancellationToken cancellationToken) { + var dtoOptions = new DtoOptions(); + dtoOptions.Fields.Remove(ItemFields.SyncInfo); + var recordingResult = await GetRecordings(new RecordingQuery { UserId = query.UserId - }, cancellationToken).ConfigureAwait(false); + }, dtoOptions, cancellationToken).ConfigureAwait(false); var recordings = recordingResult.Items; diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs index 4c9a65cf62..4b7bfad3fa 100644 --- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Server.Implementations.Photos protected abstract Task> GetItemsWithImages(IHasImages item); - private const string Version = "27"; + private const string Version = "29"; protected string GetConfigurationCacheKey(List items, string itemName) { var parts = Version + "_" + (itemName ?? string.Empty) + "_" +