From 1a3cd2a1c4e06372fb65dabefea8344c7ec5c318 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 29 Nov 2014 15:22:35 -0500 Subject: add single art limit setting to dlna profile --- MediaBrowser.Server.Implementations/Localization/Server/server.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 117a5c407..e328ca2c6 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1291,5 +1291,7 @@ "HeaderYears": "Years", "HeaderAddTag": "Add Tag", "LabelBlockItemsWithTags": "Block items with tags:", - "LabelTag": "Tag:" + "LabelTag": "Tag:", + "LabelEnableSingleImageInDidlLimit": "Limit to single embedded image", + "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl." } -- cgit v1.2.3 From d7bdb744ca9d4b3955071dfe3c38ed631dbafbfd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 30 Nov 2014 14:01:33 -0500 Subject: add new image params --- MediaBrowser.Api/Library/LibraryService.cs | 6 +- MediaBrowser.Api/Movies/MoviesService.cs | 2 +- MediaBrowser.Api/PackageService.cs | 7 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 5 - MediaBrowser.Api/PlaylistService.cs | 2 +- MediaBrowser.Api/StartupWizardService.cs | 1 + MediaBrowser.Api/UserLibrary/ArtistsService.cs | 2 +- .../UserLibrary/BaseItemsByNameService.cs | 12 +- MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs | 47 ++++++- MediaBrowser.Api/UserLibrary/ItemsService.cs | 9 +- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 2 +- MediaBrowser.Common/Extensions/BaseExtensions.cs | 2 + MediaBrowser.Controller/Dlna/DlnaIconResponse.cs | 22 --- MediaBrowser.Controller/Dlna/IDlnaManager.cs | 5 +- MediaBrowser.Controller/Dto/IDtoService.cs | 18 ++- MediaBrowser.Controller/Entities/BaseItem.cs | 6 +- MediaBrowser.Controller/Entities/Folder.cs | 2 +- MediaBrowser.Controller/Entities/User.cs | 3 +- MediaBrowser.Controller/Library/ILibraryManager.cs | 8 ++ MediaBrowser.Controller/Library/IUserManager.cs | 14 ++ MediaBrowser.Controller/LiveTv/ILiveTvService.cs | 7 +- .../LiveTv/StreamResponseInfo.cs | 20 --- .../MediaBrowser.Controller.csproj | 2 - .../ContentDirectory/ControlHandler.cs | 111 +++++++++++---- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 13 +- MediaBrowser.Dlna/DlnaManager.cs | 5 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 3 + .../MediaBrowser.Model.Portable.csproj | 6 + .../MediaBrowser.Model.net35.csproj | 6 + .../Configuration/ServerConfiguration.cs | 6 + MediaBrowser.Model/Dlna/StreamBuilder.cs | 1 - MediaBrowser.Model/Dlna/TranscodingProfile.cs | 3 - MediaBrowser.Model/Dto/BaseItemDto.cs | 15 +- MediaBrowser.Model/Dto/DtoOptions.cs | 32 +++++ MediaBrowser.Model/MediaBrowser.Model.csproj | 2 + MediaBrowser.Model/Querying/ItemFields.cs | 25 ++++ MediaBrowser.Model/Users/UserPolicy.cs | 11 ++ .../Connect/ConnectManager.cs | 41 +++++- .../Dto/DtoService.cs | 154 +++++++++++++-------- .../Library/LibraryManager.cs | 46 ++++-- .../Library/ResolverHelper.cs | 7 +- .../Library/UserManager.cs | 15 +- .../LiveTv/LiveTvDtoService.cs | 16 ++- .../Localization/Server/server.json | 2 +- 44 files changed, 519 insertions(+), 205 deletions(-) delete mode 100644 MediaBrowser.Controller/Dlna/DlnaIconResponse.cs delete mode 100644 MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs create mode 100644 MediaBrowser.Model/Dto/DtoOptions.cs create mode 100644 MediaBrowser.Model/Users/UserPolicy.cs (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 06d8e0478..5cb007f8f 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -276,7 +276,7 @@ namespace MediaBrowser.Api.Library var fields = Enum.GetNames(typeof(ItemFields)) .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) .ToList(); - + var result = new ItemsResult { TotalRecordCount = items.Count, @@ -353,7 +353,7 @@ namespace MediaBrowser.Api.Library .ToList(); BaseItem parent = item.Parent; - + while (parent != null) { if (user != null) @@ -607,7 +607,7 @@ namespace MediaBrowser.Api.Library } } } - + var dtos = themeSongIds.Select(_libraryManager.GetItemById) .OrderBy(i => i.SortName) .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item)); diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index ef86a46e8..8d6568d79 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -208,7 +208,7 @@ namespace MediaBrowser.Api.Movies { returnItems = returnItems.Take(request.Limit.Value); } - + var result = new ItemsResult { Items = returnItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(), diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index eebdafc5c..e24fa4964 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Api /// Class GetPackage /// [Route("/Packages/{Name}", "GET", Summary = "Gets a package, by name or assembly guid")] + [Authenticated] public class GetPackage : IReturn { /// @@ -37,6 +38,7 @@ namespace MediaBrowser.Api /// Class GetPackages /// [Route("/Packages", "GET", Summary = "Gets available packages")] + [Authenticated] public class GetPackages : IReturn> { /// @@ -60,6 +62,7 @@ namespace MediaBrowser.Api /// Class GetPackageVersionUpdates /// [Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")] + [Authenticated(Roles = "Admin")] public class GetPackageVersionUpdates : IReturn> { /// @@ -74,6 +77,7 @@ namespace MediaBrowser.Api /// Class InstallPackage /// [Route("/Packages/Installed/{Name}", "POST", Summary = "Installs a package")] + [Authenticated(Roles = "Admin")] public class InstallPackage : IReturnVoid { /// @@ -109,6 +113,7 @@ namespace MediaBrowser.Api /// Class CancelPackageInstallation /// [Route("/Packages/Installing/{Id}", "DELETE", Summary = "Cancels a package installation")] + [Authenticated(Roles = "Admin")] public class CancelPackageInstallation : IReturnVoid { /// @@ -122,7 +127,6 @@ namespace MediaBrowser.Api /// /// Class PackageService /// - [Authenticated(Roles = "Admin")] public class PackageService : BaseApiService { private readonly IInstallationManager _installationManager; @@ -139,7 +143,6 @@ namespace MediaBrowser.Api /// /// The request. /// System.Object. - /// Unsupported PackageType public object Get(GetPackageVersionUpdates request) { var result = new List(); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 21c4a3dff..12ccfb6b1 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2011,11 +2011,6 @@ namespace MediaBrowser.Api.Playback state.EstimateContentLength = transcodingProfile.EstimateContentLength; state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; - - if (state.VideoRequest != null && string.IsNullOrWhiteSpace(state.VideoRequest.Profile)) - { - state.VideoRequest.Profile = transcodingProfile.VideoProfile; - } } } diff --git a/MediaBrowser.Api/PlaylistService.cs b/MediaBrowser.Api/PlaylistService.cs index 5325e9c44..7f7717f71 100644 --- a/MediaBrowser.Api/PlaylistService.cs +++ b/MediaBrowser.Api/PlaylistService.cs @@ -151,7 +151,7 @@ namespace MediaBrowser.Api { items = items.Take(request.Limit.Value).ToArray(); } - + var dtos = items .Select(i => _dtoService.GetBaseItemDto(i.Item2, request.GetItemFields().ToList(), user)) .ToArray(); diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index fd5019126..4443b2a2b 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -61,6 +61,7 @@ namespace MediaBrowser.Api public void Post(ReportStartupWizardComplete request) { _config.Configuration.IsStartupWizardCompleted = true; + _config.Configuration.EnableLocalizedGuids = true; _config.SaveConfiguration(); } diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs index 07015ecae..2299b2b1a 100644 --- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs +++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.Api.UserLibrary if (request.UserId.HasValue) { var user = UserManager.GetUserById(request.UserId.Value); - + return DtoService.GetBaseItemDto(item, fields.ToList(), user); } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 3ae53daf8..9d211a419 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -127,11 +127,11 @@ namespace MediaBrowser.Api.UserLibrary } - var fields = request.GetItemFields().ToList(); - var tuples = ibnItems.Select(i => new Tuple>(i, i.GetTaggedItems(libraryItems).ToList())); - var dtos = tuples.Select(i => GetDto(i.Item1, user, fields, i.Item2)); + var dtoOptions = request.GetDtoOptions(); + + var dtos = tuples.Select(i => GetDto(i.Item1, user, dtoOptions, i.Item2)); result.Items = dtos.Where(i => i != null).ToArray(); @@ -332,12 +332,12 @@ namespace MediaBrowser.Api.UserLibrary /// /// The item. /// The user. - /// The fields. + /// The options. /// The library items. /// Task{DtoBaseItem}. - private BaseItemDto GetDto(TItemType item, User user, List fields, List libraryItems) + private BaseItemDto GetDto(TItemType item, User user, DtoOptions options, List libraryItems) { - var dto = DtoService.GetItemByNameDto(item, fields, libraryItems, user); + var dto = DtoService.GetItemByNameDto(item, options, libraryItems, user); return dto; } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 6b0c64b79..808dbb1ff 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; using System; @@ -9,6 +10,11 @@ namespace MediaBrowser.Api.UserLibrary { public abstract class BaseItemsRequest : IHasItemFields { + protected BaseItemsRequest() + { + EnableImages = true; + } + /// /// Skips over a given number of items within the results. Use for paging. /// @@ -116,6 +122,15 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "Years", Description = "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string Years { 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 = "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; } + public string[] GetGenres() { return (Genres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); @@ -198,5 +213,35 @@ namespace MediaBrowser.Api.UserLibrary return val.Split(','); } + + public DtoOptions GetDtoOptions() + { + var options = new DtoOptions(); + + options.Fields = this.GetItemFields().ToList(); + options.EnableImages = EnableImages; + + if (ImageTypeLimit.HasValue) + { + options.ImageTypeLimit = ImageTypeLimit.Value; + } + + if (string.IsNullOrWhiteSpace(EnableImageTypes)) + { + if (options.EnableImages) + { + // Get everything + options.ImageTypes = Enum.GetNames(typeof(ImageType)) + .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true)) + .ToList(); + } + } + else + { + options.ImageTypes = (EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList(); + } + + return options; + } } } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index b87ee895a..d15556f55 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -321,15 +321,14 @@ namespace MediaBrowser.Api.UserLibrary var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false); var isFiltered = result.Item2; + var dtoOptions = request.GetDtoOptions(); if (isFiltered) { - var currentFields = request.GetItemFields().ToList(); - return new ItemsResult { TotalRecordCount = result.Item1.TotalRecordCount, - Items = result.Item1.Items.Select(i => _dtoService.GetBaseItemDto(i, currentFields, user)).ToArray() + Items = result.Item1.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray() }; } @@ -363,9 +362,7 @@ namespace MediaBrowser.Api.UserLibrary var pagedItems = ApplyPaging(request, itemsArray); - var fields = request.GetItemFields().ToList(); - - var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(); + var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray(); return new ItemsResult { diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index fd0e79a21..511312a63 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -374,7 +374,7 @@ namespace MediaBrowser.Api.UserLibrary item = i.Item1; childCount = i.Item2.Count; } - + var dto = _dtoService.GetBaseItemDto(item, fields, user); dto.ChildCount = childCount; diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index be2fbffc6..4daee4875 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -96,6 +96,8 @@ namespace MediaBrowser.Common.Extensions /// The STR. /// The type. /// Guid. + /// type + [Obsolete("Use LibraryManager.GetNewItemId")] public static Guid GetMBId(this string str, Type type) { if (type == null) diff --git a/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs b/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs deleted file mode 100644 index 5ae92082d..000000000 --- a/MediaBrowser.Controller/Dlna/DlnaIconResponse.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.IO; -using MediaBrowser.Model.Drawing; - -namespace MediaBrowser.Controller.Dlna -{ - public class DlnaIconResponse : IDisposable - { - public Stream Stream { get; set; } - - public ImageFormat Format { get; set; } - - public void Dispose() - { - if (Stream != null) - { - Stream.Dispose(); - Stream = null; - } - } - } -} diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index b7a06b368..34464f6a2 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Dlna; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Model.Dlna; using System.Collections.Generic; namespace MediaBrowser.Controller.Dlna @@ -69,6 +70,6 @@ namespace MediaBrowser.Controller.Dlna /// /// The filename. /// DlnaIconResponse. - DlnaIconResponse GetIcon(string filename); + ImageStream GetIcon(string filename); } } diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 61b2caec0..7c7ec56d5 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -22,7 +22,8 @@ namespace MediaBrowser.Controller.Dto /// /// The dto. /// The item. - void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item); + /// The fields. + void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List fields); /// /// Gets the base item dto. @@ -34,6 +35,16 @@ namespace MediaBrowser.Controller.Dto /// Task{BaseItemDto}. BaseItemDto GetBaseItemDto(BaseItem item, List fields, User user = null, BaseItem owner = null); + /// + /// Gets the base item dto. + /// + /// The item. + /// The options. + /// The user. + /// The owner. + /// BaseItemDto. + BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null); + /// /// Gets the chapter information dto. /// @@ -51,12 +62,13 @@ namespace MediaBrowser.Controller.Dto /// /// Gets the item by name dto. /// + /// /// The item. - /// The fields. + /// The options. /// The tagged items. /// The user. /// BaseItemDto. - BaseItemDto GetItemByNameDto(T item, List fields, List taggedItems, User user = null) + BaseItemDto GetItemByNameDto(T item, DtoOptions options, List taggedItems, User user = null) where T : BaseItem, IItemByName; } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 990ea49f6..ea615f023 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1820,7 +1820,11 @@ namespace MediaBrowser.Controller.Entities if (pct > 0) { pct = userData.PlaybackPositionTicks / pct; - dto.PlayedPercentage = 100 * pct; + + if (pct > 0) + { + dto.PlayedPercentage = 100 * pct; + } } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 34f52aac5..0e712dc45 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Controller.Entities if (item.Id == Guid.Empty) { - item.Id = item.Path.GetMBId(item.GetType()); + item.Id = LibraryManager.GetNewItemId(item.Path, item.GetType()); } if (ActualChildren.Any(i => i.Id == item.Id)) diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 0bbd2eeca..3fa0a0435 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Serialization; +using MediaBrowser.Model.Users; using System; using System.IO; using System.Linq; @@ -287,7 +288,7 @@ namespace MediaBrowser.Controller.Entities var localTime = date.ToLocalTime(); - return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && + return DayOfWeekHelper.GetDaysOfWeek(schedule.DayOfWeek).Contains(localTime.DayOfWeek) && IsWithinTime(schedule, localTime); } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 3367f98e4..10fee05a9 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -414,5 +414,13 @@ namespace MediaBrowser.Controller.Library IEnumerable GetAdditionalParts(string file, VideoType type, IEnumerable files); + + /// + /// Gets the new item identifier. + /// + /// The key. + /// The type. + /// Guid. + Guid GetNewItemId(string key, Type type); } } \ No newline at end of file diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index bd44f786f..debdafe4d 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -164,5 +164,19 @@ namespace MediaBrowser.Controller.Library /// The pin. /// true if XXXX, false otherwise. Task RedeemPasswordResetPin(string pin); + + /// + /// Gets the user policy. + /// + /// The user identifier. + /// UserPolicy. + UserPolicy GetUserPolicy(string userId); + + /// + /// Updates the user policy. + /// + /// The user identifier. + /// The user policy. + Task UpdateUserPolicy(string userId, UserPolicy userPolicy); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index eda69b164..993db0004 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Drawing; namespace MediaBrowser.Controller.LiveTv { @@ -109,7 +110,7 @@ namespace MediaBrowser.Controller.LiveTv /// The channel identifier. /// The cancellation token. /// Task{Stream}. - Task GetChannelImageAsync(string channelId, CancellationToken cancellationToken); + Task GetChannelImageAsync(string channelId, CancellationToken cancellationToken); /// /// Gets the recording image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to RecordingInfo @@ -117,7 +118,7 @@ namespace MediaBrowser.Controller.LiveTv /// The recording identifier. /// The cancellation token. /// Task{ImageResponseInfo}. - Task GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken); + Task GetRecordingImageAsync(string recordingId, CancellationToken cancellationToken); /// /// Gets the program image asynchronous. This only needs to be implemented if an image path or url cannot be supplied to ProgramInfo @@ -126,7 +127,7 @@ namespace MediaBrowser.Controller.LiveTv /// The channel identifier. /// The cancellation token. /// Task{ImageResponseInfo}. - Task GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken); + Task GetProgramImageAsync(string programId, string channelId, CancellationToken cancellationToken); /// /// Gets the recordings asynchronous. diff --git a/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs b/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs deleted file mode 100644 index cb6aa22d2..000000000 --- a/MediaBrowser.Controller/LiveTv/StreamResponseInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.IO; -using MediaBrowser.Model.Drawing; - -namespace MediaBrowser.Controller.LiveTv -{ - public class StreamResponseInfo - { - /// - /// Gets or sets the stream. - /// - /// The stream. - public Stream Stream { get; set; } - - /// - /// Gets or sets the type of the MIME. - /// - /// The type of the MIME. - public ImageFormat Format { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 931bc51d1..dbff88fd8 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -105,7 +105,6 @@ - @@ -191,7 +190,6 @@ - diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index 438b5a4ce..d979e3d89 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -236,7 +236,7 @@ namespace MediaBrowser.Dlna.ContentDirectory foreach (var i in childrenResult.Items) { var childItem = i.Item; - var displayStubType = GetDisplayStubType(childItem, serverItem.Item); + var displayStubType = i.StubType; if (childItem.IsFolder || displayStubType.HasValue) { @@ -263,29 +263,6 @@ namespace MediaBrowser.Dlna.ContentDirectory }; } - private StubType? GetDisplayStubType(BaseItem item, BaseItem context) - { - if (context == null || context.IsFolder) - { - var movie = item as Movie; - if (movie != null) - { - if (movie.LocalTrailerIds.Count > 0 || - movie.SpecialFeatureIds.Count > 0) - { - return StubType.Folder; - } - - if (movie.People.Count > 0) - { - return StubType.Folder; - } - } - } - - return null; - } - private async Task>> HandleSearch(Headers sparams, User user, string deviceId) { var searchCriteria = new SearchCriteria(sparams.GetValueOrDefault("SearchCriteria", "")); @@ -418,11 +395,36 @@ namespace MediaBrowser.Dlna.ContentDirectory { if (stubType.HasValue) { - var movie = item as Movie; + if (stubType.Value == StubType.People) + { + var items = item.People.Select(i => + { + try + { + return _libraryManager.GetPerson(i.Name); + } + catch + { + return null; + } + + }).Where(i => i != null).ToArray(); + + var result = new QueryResult + { + Items = items.Select(i => new ServerItem { Item = i }).ToArray(), + TotalRecordCount = items.Length + }; - if (movie != null) + return ApplyPaging(result, startIndex, limit); + } + if (stubType.Value == StubType.Folder) { - return await GetMovieItems(movie).ConfigureAwait(false); + var movie = item as Movie; + if (movie != null) + { + return ApplyPaging(await GetMovieItems(movie).ConfigureAwait(false), startIndex, limit); + } } } @@ -445,13 +447,52 @@ namespace MediaBrowser.Dlna.ContentDirectory }).ConfigureAwait(false); + var serverItems = queryResult + .Items + .Select(i => new ServerItem + { + Item = i, + StubType = GetDisplayStubType(i, item) + }) + .ToArray(); + return new QueryResult { TotalRecordCount = queryResult.TotalRecordCount, - Items = queryResult.Items.Select(i => new ServerItem { Item = i, StubType = null }).ToArray() + Items = serverItems }; } + private QueryResult ApplyPaging(QueryResult result, int? startIndex, int? limit) + { + result.Items = result.Items.Skip(startIndex ?? 0).Take(limit ?? int.MaxValue).ToArray(); + + return result; + } + + private StubType? GetDisplayStubType(BaseItem item, BaseItem context) + { + if (context == null || context.IsFolder) + { + var movie = item as Movie; + if (movie != null) + { + if (movie.LocalTrailerIds.Count > 0 || + movie.SpecialFeatureIds.Count > 0) + { + return StubType.Folder; + } + + if (movie.People.Count > 0) + { + return StubType.Folder; + } + } + } + + return null; + } + private Task> GetMovieItems(Movie item) { var list = new List(); @@ -464,6 +505,12 @@ namespace MediaBrowser.Dlna.ContentDirectory var serverItems = list.Select(i => new ServerItem { Item = i, StubType = null }) .ToList(); + serverItems.Add(new ServerItem + { + Item = item, + StubType = StubType.People + }); + return Task.FromResult(new QueryResult { Items = serverItems.ToArray(), @@ -512,6 +559,11 @@ namespace MediaBrowser.Dlna.ContentDirectory stubType = StubType.Folder; id = id.Split(new[] { '_' }, 2)[1]; } + else if (id.StartsWith("people_", StringComparison.OrdinalIgnoreCase)) + { + stubType = StubType.People; + id = id.Split(new[] { '_' }, 2)[1]; + } if (Guid.TryParse(id, out itemId)) { @@ -538,6 +590,7 @@ namespace MediaBrowser.Dlna.ContentDirectory public enum StubType { - Folder = 0 + Folder = 0, + People = 1 } } diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 565431758..5d5d24b1c 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -293,8 +293,17 @@ namespace MediaBrowser.Dlna.Didl container.AppendChild(res); } - private string GetDisplayName(BaseItem item, BaseItem context) + private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context) { + if (itemStubType.HasValue && itemStubType.Value == StubType.People) + { + if (item is Video) + { + return _localization.GetLocalizedString("HeaderCastCrew"); + } + return _localization.GetLocalizedString("HeaderPeople"); + } + var episode = item as Episode; var season = context as Season; @@ -491,7 +500,7 @@ namespace MediaBrowser.Dlna.Didl // MediaMonkey for example won't display content without a title //if (filter.Contains("dc:title")) { - AddValue(element, "dc", "title", GetDisplayName(item, context), NS_DC); + AddValue(element, "dc", "title", GetDisplayName(item, itemStubType, context), NS_DC); } element.AppendChild(CreateObjectClass(element.OwnerDocument, item, itemStubType)); diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 219196ecc..fad23ae42 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Plugins; using MediaBrowser.Dlna.Profiles; using MediaBrowser.Dlna.Server; @@ -469,13 +470,13 @@ namespace MediaBrowser.Dlna return new DescriptionXmlBuilder(profile, serverUuId, "").GetXml(); } - public DlnaIconResponse GetIcon(string filename) + public ImageStream GetIcon(string filename) { var format = filename.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? ImageFormat.Png : ImageFormat.Jpg; - return new DlnaIconResponse + return new ImageStream { Format = format, Stream = GetType().Assembly.GetManifestResourceStream("MediaBrowser.Dlna.Images." + filename.ToLower()) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 82d5e0344..7fb27e25f 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -299,6 +299,9 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + // TODO: Output in webp for smaller sizes + // -f image2 -f webp + // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) : string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 1e0c5c7ea..6f0943cfa 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -422,6 +422,9 @@ Dto\ChapterInfoDto.cs + + Dto\DtoOptions.cs + Dto\GameSystemSummary.cs @@ -1118,6 +1121,9 @@ Users\PinRedeemResult.cs + + Users\UserPolicy.cs + Properties\SharedVersion.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index e1ad7b36a..088fd023c 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -387,6 +387,9 @@ Dto\ChapterInfoDto.cs + + Dto\DtoOptions.cs + Dto\GameSystemSummary.cs @@ -1077,6 +1080,9 @@ Users\PinRedeemResult.cs + + Users\UserPolicy.cs + Properties\SharedVersion.cs diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c9df615e1..b9eaf7001 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -55,6 +55,12 @@ namespace MediaBrowser.Model.Configuration /// true if [save local meta]; otherwise, false. public bool SaveLocalMeta { get; set; } + /// + /// Gets or sets a value indicating whether [enable localized guids]. + /// + /// true if [enable localized guids]; otherwise, false. + public bool EnableLocalizedGuids { get; set; } + /// /// Gets or sets the preferred metadata language. /// diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 4907abfd7..fb26f1ff8 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -298,7 +298,6 @@ namespace MediaBrowser.Model.Dlna playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.Protocol = transcodingProfile.Protocol; playlistItem.AudioStreamIndex = audioStreamIndex; - playlistItem.VideoProfile = transcodingProfile.VideoProfile; List videoTranscodingConditions = new List(); foreach (CodecProfile i in options.Profile.CodecProfiles) diff --git a/MediaBrowser.Model/Dlna/TranscodingProfile.cs b/MediaBrowser.Model/Dlna/TranscodingProfile.cs index ad82d6fac..d9963eb75 100644 --- a/MediaBrowser.Model/Dlna/TranscodingProfile.cs +++ b/MediaBrowser.Model/Dlna/TranscodingProfile.cs @@ -29,9 +29,6 @@ namespace MediaBrowser.Model.Dlna [XmlAttribute("transcodeSeekInfo")] public TranscodeSeekInfo TranscodeSeekInfo { get; set; } - [XmlAttribute("videoProfile")] - public string VideoProfile { get; set; } - [XmlAttribute("context")] public EncodingContext Context { get; set; } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index a9f13374b..e0f250deb 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Model.Dto public float? Metascore { get; set; } - public bool IsUnidentified { get; set; } + public bool? IsUnidentified { get; set; } public int? AnimeSeriesIndex { get; set; } @@ -217,6 +217,12 @@ namespace MediaBrowser.Model.Dto /// The run time ticks. public long? RunTimeTicks { get; set; } + /// + /// Gets or sets the recursive unplayed item count. + /// + /// The recursive unplayed item count. + public int? RecursiveUnplayedItemCount { get; set; } + /// /// Gets or sets the play access. /// @@ -235,13 +241,6 @@ namespace MediaBrowser.Model.Dto /// The production year. public int? ProductionYear { get; set; } - /// - /// Gets or sets the recursive unplayed item count. - /// - /// The recursive unplayed item count. - [Obsolete] - public int? RecursiveUnplayedItemCount { get; set; } - /// /// Gets or sets the season count. /// diff --git a/MediaBrowser.Model/Dto/DtoOptions.cs b/MediaBrowser.Model/Dto/DtoOptions.cs new file mode 100644 index 000000000..069d71fce --- /dev/null +++ b/MediaBrowser.Model/Dto/DtoOptions.cs @@ -0,0 +1,32 @@ +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Querying; +using System.Collections.Generic; + +namespace MediaBrowser.Model.Dto +{ + public class DtoOptions + { + public List Fields { get; set; } + public List ImageTypes { get; set; } + public int ImageTypeLimit { get; set; } + public bool EnableImages { get; set; } + + public DtoOptions() + { + Fields = new List(); + ImageTypes = new List(); + ImageTypeLimit = int.MaxValue; + EnableImages = true; + } + + public int GetImageLimit(ImageType type) + { + if (EnableImages && ImageTypes.Contains(type)) + { + return ImageTypeLimit; + } + + return 0; + } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index df4e6949e..f7eb54292 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -125,6 +125,7 @@ + @@ -412,6 +413,7 @@ + diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index 9ceca311c..84f6bd651 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -81,11 +81,21 @@ namespace MediaBrowser.Model.Querying /// Keywords, + /// + /// The media source count + /// + MediaSourceCount, + /// /// The media versions /// MediaSources, + /// + /// The metascore + /// + Metascore, + /// /// The metadata settings /// @@ -101,6 +111,11 @@ namespace MediaBrowser.Model.Querying /// ParentId, + /// + /// The part count + /// + PartCount, + /// /// The physical path of the item /// @@ -126,6 +141,11 @@ namespace MediaBrowser.Model.Querying /// PrimaryImageAspectRatio, + /// + /// The original primary image aspect ratio + /// + OriginalPrimaryImageAspectRatio, + /// /// The revenue /// @@ -171,6 +191,11 @@ namespace MediaBrowser.Model.Querying /// Tags, + /// + /// The vote count + /// + VoteCount, + /// /// The TMDB collection name /// diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs new file mode 100644 index 000000000..02d177747 --- /dev/null +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MediaBrowser.Model.Users +{ + public class UserPolicy + { + } +} diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index cff49df10..cbd75cdeb 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -88,6 +88,11 @@ namespace MediaBrowser.Server.Implementations.Connect } } + private string XApplicationValue + { + get { return "Media Browser Server/" + _appHost.ApplicationVersion; } + } + public ConnectManager(ILogger logger, IApplicationPaths appPaths, IJsonSerializer json, @@ -204,9 +209,18 @@ namespace MediaBrowser.Server.Implementations.Connect postData["localAddress"] = localAddress; } - using (var stream = await _httpClient.Post(url, postData, CancellationToken.None).ConfigureAwait(false)) + var options = new HttpRequestOptions + { + Url = url, + CancellationToken = CancellationToken.None + }; + + options.SetPostData(postData); + SetApplicationHeader(options); + + using (var response = await _httpClient.Post(options).ConfigureAwait(false)) { - var data = _json.DeserializeFromStream(stream); + var data = _json.DeserializeFromStream(response.Content); _data.ServerId = data.Id; _data.AccessKey = data.AccessKey; @@ -252,6 +266,7 @@ namespace MediaBrowser.Server.Implementations.Connect options.SetPostData(postData); SetServerAccessToken(options); + SetApplicationHeader(options); // No need to examine the response using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) @@ -398,6 +413,7 @@ namespace MediaBrowser.Server.Implementations.Connect options.SetPostData(postData); SetServerAccessToken(options); + SetApplicationHeader(options); var result = new UserLinkResult(); @@ -517,6 +533,7 @@ namespace MediaBrowser.Server.Implementations.Connect options.SetPostData(postData); SetServerAccessToken(options); + SetApplicationHeader(options); // No need to examine the response using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) @@ -562,6 +579,7 @@ namespace MediaBrowser.Server.Implementations.Connect }; options.SetPostData(postData); + SetApplicationHeader(options); // No need to examine the response using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content) @@ -629,6 +647,7 @@ namespace MediaBrowser.Server.Implementations.Connect }; SetServerAccessToken(options); + SetApplicationHeader(options); using (var stream = await _httpClient.Get(options).ConfigureAwait(false)) { @@ -645,6 +664,11 @@ namespace MediaBrowser.Server.Implementations.Connect } } + private void SetApplicationHeader(HttpRequestOptions options) + { + options.RequestHeaders.Add("X-Application", XApplicationValue); + } + private void SetServerAccessToken(HttpRequestOptions options) { if (string.IsNullOrWhiteSpace(ConnectAccessKey)) @@ -687,6 +711,7 @@ namespace MediaBrowser.Server.Implementations.Connect }; SetServerAccessToken(options); + SetApplicationHeader(options); try { @@ -974,6 +999,7 @@ namespace MediaBrowser.Server.Implementations.Connect options.SetPostData(postData); SetServerAccessToken(options); + SetApplicationHeader(options); try { @@ -1006,20 +1032,22 @@ namespace MediaBrowser.Server.Implementations.Connect { throw new ArgumentNullException("passwordMd5"); } - - var request = new HttpRequestOptions + + var options = new HttpRequestOptions { Url = GetConnectUrl("user/authenticate") }; - request.SetPostData(new Dictionary + options.SetPostData(new Dictionary { {"userName",username}, {"password",passwordMd5} }); + SetApplicationHeader(options); + // No need to examine the response - using (var stream = (await _httpClient.SendAsync(request, "POST").ConfigureAwait(false)).Content) + using (var response = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content) { } } @@ -1062,6 +1090,7 @@ namespace MediaBrowser.Server.Implementations.Connect options.SetPostData(postData); SetServerAccessToken(options); + SetApplicationHeader(options); try { diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index bfed3887f..b4393572e 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -69,7 +69,22 @@ namespace MediaBrowser.Server.Implementations.Dto /// item public BaseItemDto GetBaseItemDto(BaseItem item, List fields, User user = null, BaseItem owner = null) { - var dto = GetBaseItemDtoInternal(item, fields, user, owner); + var options = new DtoOptions + { + Fields = fields + }; + + // Get everything + options.ImageTypes = Enum.GetNames(typeof(ImageType)) + .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true)) + .ToList(); + + return GetBaseItemDto(item, options, user, owner); + } + + public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) + { + var dto = GetBaseItemDtoInternal(item, options, user, owner); var byName = item as IItemByName; @@ -87,8 +102,10 @@ namespace MediaBrowser.Server.Implementations.Dto return dto; } - private BaseItemDto GetBaseItemDtoInternal(BaseItem item, List fields, User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) { + var fields = options.Fields; + if (item == null) { throw new ArgumentNullException("item"); @@ -115,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.Dto { try { - AttachPrimaryImageAspectRatio(dto, item); + AttachPrimaryImageAspectRatio(dto, item, fields); } catch (Exception ex) { @@ -155,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.Dto AttachStudios(dto, item); } - AttachBasicFields(dto, item, owner, fields); + AttachBasicFields(dto, item, owner, options); if (fields.Contains(ItemFields.SyncInfo)) { @@ -174,18 +191,19 @@ namespace MediaBrowser.Server.Implementations.Dto } } - if (item is Playlist) + var playlist = item as Playlist; + if (playlist != null) { - AttachLinkedChildImages(dto, (Folder)item, user); + AttachLinkedChildImages(dto, playlist, user, options); } return dto; } - public BaseItemDto GetItemByNameDto(T item, List fields, List taggedItems, User user = null) + public BaseItemDto GetItemByNameDto(T item, DtoOptions options, List taggedItems, User user = null) where T : BaseItem, IItemByName { - var dto = GetBaseItemDtoInternal(item, fields, user); + var dto = GetBaseItemDtoInternal(item, options, user); SetItemByNameInfo(item, dto, taggedItems, user); @@ -369,36 +387,27 @@ namespace MediaBrowser.Server.Implementations.Dto dto.GameSystem = item.GameSystemName; } - /// - /// Gets the backdrop image tags. - /// - /// The item. - /// List{System.String}. - private List GetBackdropImageTags(BaseItem item) + private List GetBackdropImageTags(BaseItem item, int limit) { - return GetCacheTags(item, ImageType.Backdrop).ToList(); + return GetCacheTags(item, ImageType.Backdrop, limit).ToList(); } - /// - /// Gets the screenshot image tags. - /// - /// The item. - /// List{Guid}. - private List GetScreenshotImageTags(BaseItem item) + private List GetScreenshotImageTags(BaseItem item, int limit) { var hasScreenshots = item as IHasScreenshots; if (hasScreenshots == null) { return new List(); } - return GetCacheTags(item, ImageType.Screenshot).ToList(); + return GetCacheTags(item, ImageType.Screenshot, limit).ToList(); } - private IEnumerable GetCacheTags(BaseItem item, ImageType type) + private IEnumerable GetCacheTags(BaseItem item, ImageType type, int limit) { return item.GetImages(type) .Select(p => GetImageCacheTag(item, p)) .Where(i => i != null) + .Take(limit) .ToList(); } @@ -649,9 +658,11 @@ namespace MediaBrowser.Server.Implementations.Dto /// The dto. /// The item. /// The owner. - /// The fields. - private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, List fields) + /// The options. + private void AttachBasicFields(BaseItemDto dto, BaseItem item, BaseItem owner, DtoOptions options) { + var fields = options.Fields; + if (fields.Contains(ItemFields.DateCreated)) { dto.DateCreated = item.DateCreated; @@ -662,7 +673,11 @@ namespace MediaBrowser.Server.Implementations.Dto dto.DisplayMediaType = item.DisplayMediaType; } - dto.IsUnidentified = item.IsUnidentified; + // Leave null if false + if (item.IsUnidentified) + { + dto.IsUnidentified = item.IsUnidentified; + } if (fields.Contains(ItemFields.Settings)) { @@ -736,10 +751,13 @@ namespace MediaBrowser.Server.Implementations.Dto dto.AspectRatio = hasAspectRatio.AspectRatio; } - var hasMetascore = item as IHasMetascore; - if (hasMetascore != null) + if (fields.Contains(ItemFields.ProductionLocations)) { - dto.Metascore = hasMetascore.Metascore; + var hasMetascore = item as IHasMetascore; + if (hasMetascore != null) + { + dto.Metascore = hasMetascore.Metascore; + } } if (fields.Contains(ItemFields.AwardSummary)) @@ -751,11 +769,19 @@ namespace MediaBrowser.Server.Implementations.Dto } } - dto.BackdropImageTags = GetBackdropImageTags(item); + var backdropLimit = options.GetImageLimit(ImageType.Backdrop); + if (backdropLimit > 0) + { + dto.BackdropImageTags = GetBackdropImageTags(item, backdropLimit); + } if (fields.Contains(ItemFields.ScreenshotImageTags)) { - dto.ScreenshotImageTags = GetScreenshotImageTags(item); + var screenshotLimit = options.GetImageLimit(ImageType.Screenshot); + if (screenshotLimit > 0) + { + dto.ScreenshotImageTags = GetScreenshotImageTags(item, screenshotLimit); + } } if (fields.Contains(ItemFields.Genres)) @@ -769,11 +795,14 @@ namespace MediaBrowser.Server.Implementations.Dto var currentItem = item; foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type))) { - var tag = GetImageCacheTag(item, image); - - if (tag != null) + if (options.GetImageLimit(image.Type) > 0) { - dto.ImageTags[image.Type] = tag; + var tag = GetImageCacheTag(item, image); + + if (tag != null) + { + dto.ImageTags[image.Type] = tag; + } } } @@ -851,14 +880,14 @@ namespace MediaBrowser.Server.Implementations.Dto } // If there are no backdrops, indicate what parent has them in case the Ui wants to allow inheritance - if (dto.BackdropImageTags.Count == 0) + if (backdropLimit > 0 && dto.BackdropImageTags.Count == 0) { var parentWithBackdrop = GetParentBackdropItem(item, owner); if (parentWithBackdrop != null) { dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop); - dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop); + dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop, backdropLimit); } } @@ -874,7 +903,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.ParentIndexNumber = item.ParentIndexNumber; // If there is no logo, indicate what parent has one in case the Ui wants to allow inheritance - if (!dto.HasLogo) + if (!dto.HasLogo && options.GetImageLimit(ImageType.Logo) > 0) { var parentWithLogo = GetParentImageItem(item, ImageType.Logo, owner); @@ -887,7 +916,7 @@ namespace MediaBrowser.Server.Implementations.Dto } // If there is no art, indicate what parent has one in case the Ui wants to allow inheritance - if (!dto.HasArtImage) + if (!dto.HasArtImage && options.GetImageLimit(ImageType.Thumb) > 0) { var parentWithImage = GetParentImageItem(item, ImageType.Art, owner); @@ -900,7 +929,7 @@ namespace MediaBrowser.Server.Implementations.Dto } // If there is no thumb, indicate what parent has one in case the Ui wants to allow inheritance - if (!dto.HasThumb) + if (!dto.HasThumb && options.GetImageLimit(ImageType.Thumb) > 0) { var parentWithImage = GetParentImageItem(item, ImageType.Thumb, owner); @@ -953,7 +982,11 @@ namespace MediaBrowser.Server.Implementations.Dto dto.Type = item.GetClientTypeName(); dto.CommunityRating = item.CommunityRating; - dto.VoteCount = item.VoteCount; + + if (fields.Contains(ItemFields.VoteCount)) + { + dto.VoteCount = item.VoteCount; + } if (item.IsFolder) { @@ -1017,8 +1050,15 @@ namespace MediaBrowser.Server.Implementations.Dto dto.IsoType = video.IsoType; dto.IsHD = video.IsHD; - dto.PartCount = video.AdditionalPartIds.Count + 1; - dto.MediaSourceCount = video.MediaSourceCount; + if (fields.Contains(ItemFields.Chapters)) + { + dto.PartCount = video.AdditionalPartIds.Count + 1; + } + + if (fields.Contains(ItemFields.MediaSourceCount)) + { + dto.MediaSourceCount = video.MediaSourceCount; + } if (fields.Contains(ItemFields.Chapters)) { @@ -1200,28 +1240,28 @@ namespace MediaBrowser.Server.Implementations.Dto } } - private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user) + private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user, DtoOptions options) { List linkedChildren = null; - if (dto.BackdropImageTags.Count == 0) + var backdropLimit = options.GetImageLimit(ImageType.Backdrop); + + if (backdropLimit > 0 && dto.BackdropImageTags.Count == 0) { - if (linkedChildren == null) - { - linkedChildren = user == null - ? folder.GetRecursiveChildren().ToList() - : folder.GetRecursiveChildren(user, true).ToList(); - } + linkedChildren = user == null + ? folder.GetRecursiveChildren().ToList() + : folder.GetRecursiveChildren(user, true).ToList(); + var parentWithBackdrop = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Backdrop).Any()); if (parentWithBackdrop != null) { dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop); - dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop); + dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop, backdropLimit); } } - if (!dto.ImageTags.ContainsKey(ImageType.Primary)) + if (!dto.ImageTags.ContainsKey(ImageType.Primary) && options.GetImageLimit(ImageType.Primary) > 0) { if (linkedChildren == null) { @@ -1380,8 +1420,9 @@ namespace MediaBrowser.Server.Implementations.Dto /// /// The dto. /// The item. + /// The fields. /// Task. - public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item) + public void AttachPrimaryImageAspectRatio(IItemDto dto, IHasImages item, List fields) { var imageInfo = item.GetImageInfo(ImageType.Primary, 0); @@ -1412,7 +1453,10 @@ namespace MediaBrowser.Server.Implementations.Dto return; } - dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height; + if (fields.Contains(ItemFields.OriginalPrimaryImageAspectRatio)) + { + dto.OriginalPrimaryImageAspectRatio = size.Width / size.Height; + } var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList(); diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 63ced8559..81751545c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -17,7 +17,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Naming.Audio; using MediaBrowser.Naming.Common; -using MediaBrowser.Naming.IO; using MediaBrowser.Naming.Video; using MediaBrowser.Server.Implementations.Library.Resolvers.TV; using MediaBrowser.Server.Implementations.Library.Validators; @@ -485,12 +484,36 @@ namespace MediaBrowser.Server.Implementations.Library if (item != null) { - ResolverHelper.SetInitialItemValues(item, args, _fileSystem); + ResolverHelper.SetInitialItemValues(item, args, _fileSystem, this); } return item; } + public Guid GetNewItemId(string key, Type type) + { + if (string.IsNullOrWhiteSpace(key)) + { + throw new ArgumentNullException("key"); + } + if (type == null) + { + throw new ArgumentNullException("type"); + } + + if (ConfigurationManager.Configuration.EnableLocalizedGuids && key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath)) + { + // Try to normalize paths located underneath program-data in an attempt to make them more portable + key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length) + .TrimStart(new[] { '/', '\\' }) + .Replace("/", "\\"); + } + + key = type.FullName + key.ToLower(); + + return key.GetMD5(); + } + public IEnumerable ReplaceVideosWithPrimaryVersions(IEnumerable items) { var dict = new Dictionary(); @@ -651,7 +674,7 @@ namespace MediaBrowser.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); - var rootFolder = GetItemById(rootFolderPath.GetMBId(typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath)); + var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath)); // Add in the plug-in folders foreach (var child in PluginFolderCreators) @@ -662,7 +685,14 @@ namespace MediaBrowser.Server.Implementations.Library { if (folder.Id == Guid.Empty) { - folder.Id = (folder.Path ?? folder.GetType().Name).GetMBId(folder.GetType()); + if (string.IsNullOrWhiteSpace(folder.Path)) + { + folder.Id = GetNewItemId(folder.GetType().Name, folder.GetType()); + } + else + { + folder.Id = GetNewItemId(folder.Path, folder.GetType()); + } } folder = GetItemById(folder.Id) as BasePluginFolder ?? folder; @@ -685,7 +715,7 @@ namespace MediaBrowser.Server.Implementations.Library Directory.CreateDirectory(userRootPath); - _userRootFolder = GetItemById(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? + _userRootFolder = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); } @@ -801,7 +831,7 @@ namespace MediaBrowser.Server.Implementations.Library Path.Combine(path, validFilename) : Path.Combine(path, subFolderPrefix, validFilename); - var id = fullPath.GetMBId(type); + var id = GetNewItemId(fullPath, type); BaseItem obj; @@ -1513,7 +1543,7 @@ namespace MediaBrowser.Server.Implementations.Library path = Path.Combine(path, _fileSystem.GetValidFilename(type)); - var id = (path + "_namedview_" + name).GetMBId(typeof(UserView)); + var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView)); var item = GetItemById(id) as UserView; @@ -1578,7 +1608,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("viewType"); } - var id = ("7_namedview_" + name + user.Id.ToString("N") + parentId).GetMBId(typeof(UserView)); + var id = GetNewItemId("7_namedview_" + name + user.Id.ToString("N") + parentId, typeof(UserView)); var path = BaseItem.GetInternalMetadataPathForId(id); diff --git a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs index 92c837932..d071fd232 100644 --- a/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs +++ b/MediaBrowser.Server.Implementations/Library/ResolverHelper.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using System; @@ -20,7 +19,7 @@ namespace MediaBrowser.Server.Implementations.Library /// The item. /// The args. /// The file system. - public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args, IFileSystem fileSystem) + public static void SetInitialItemValues(BaseItem item, ItemResolveArgs args, IFileSystem fileSystem, ILibraryManager libraryManager) { // If the resolver didn't specify this if (string.IsNullOrEmpty(item.Path)) @@ -34,7 +33,7 @@ namespace MediaBrowser.Server.Implementations.Library item.Parent = args.Parent; } - item.Id = item.Path.GetMBId(item.GetType()); + item.Id = libraryManager.GetNewItemId(item.Path, item.GetType()); // If the resolver didn't specify this if (string.IsNullOrEmpty(item.DisplayMediaType)) diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 54c584d47..ed45e890b 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -17,6 +17,7 @@ using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Users; using System; @@ -327,7 +328,10 @@ namespace MediaBrowser.Server.Implementations.Library try { - _dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user); + _dtoServiceFactory().AttachPrimaryImageAspectRatio(dto, user, new List + { + ItemFields.PrimaryImageAspectRatio + }); } catch (Exception ex) { @@ -765,5 +769,14 @@ namespace MediaBrowser.Server.Implementations.Library public DateTime ExpirationDate { get; set; } } + public UserPolicy GetUserPolicy(string userId) + { + throw new NotImplementedException(); + } + + public Task UpdateUserPolicy(string userId, UserPolicy userPolicy) + { + throw new NotImplementedException(); + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 371619c08..b3066b460 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Querying; namespace MediaBrowser.Server.Implementations.LiveTv { @@ -247,7 +248,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (imageTag != null) { dto.ImageTags[ImageType.Primary] = imageTag; - _dtoService.AttachPrimaryImageAspectRatio(dto, recording); + _dtoService.AttachPrimaryImageAspectRatio(dto, recording, new List + { + ItemFields.PrimaryImageAspectRatio + }); } if (user != null) @@ -337,7 +341,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv { dto.ImageTags[ImageType.Primary] = imageTag; - _dtoService.AttachPrimaryImageAspectRatio(dto, info); + _dtoService.AttachPrimaryImageAspectRatio(dto, info, new List + { + ItemFields.PrimaryImageAspectRatio + }); } if (currentProgram != null) @@ -401,7 +408,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (imageTag != null) { dto.ImageTags[ImageType.Primary] = imageTag; - _dtoService.AttachPrimaryImageAspectRatio(dto, item); + _dtoService.AttachPrimaryImageAspectRatio(dto, item, new List + { + ItemFields.PrimaryImageAspectRatio + }); } if (user != null) diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index e328ca2c6..6da7adee1 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -542,7 +542,7 @@ "HeaderRunningTasks": "Running Tasks", "HeaderActiveDevices": "Active Devices", "HeaderPendingInstallations": "Pending Installations", - "HeaerServerInformation": "Server Information", + "HeaderServerInformation": "Server Information", "ButtonRestartNow": "Restart Now", "ButtonRestart": "Restart", "ButtonShutdown": "Shutdown", -- cgit v1.2.3 From ab3da461130b0db2f77e7e848c4bbd1280e5524a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 12 Dec 2014 22:56:30 -0500 Subject: more sync movement --- MediaBrowser.Api/Devices/DeviceService.cs | 28 +- MediaBrowser.Api/Music/InstantMixService.cs | 17 ++ MediaBrowser.Api/Session/SessionsService.cs | 11 +- .../Collections/CollectionCreationOptions.cs | 2 + MediaBrowser.Controller/Devices/IDeviceManager.cs | 4 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 20 +- MediaBrowser.Controller/Entities/Share.cs | 15 + MediaBrowser.Controller/Library/IMusicManager.cs | 8 + .../MediaBrowser.Controller.csproj | 1 + .../Persistence/IUserRepository.cs | 6 - MediaBrowser.Controller/Playlists/Playlist.cs | 19 +- .../Providers/BaseItemXmlParser.cs | 78 +++++ MediaBrowser.Controller/Sync/ISyncManager.cs | 10 +- MediaBrowser.Controller/Sync/ISyncRepository.cs | 5 +- .../Parsers/PlaylistXmlParser.cs | 12 +- .../Savers/PlaylistXmlSaver.cs | 5 - .../Savers/XmlSaverHelpers.cs | 23 ++ .../MediaBrowser.Model.Portable.csproj | 9 + .../MediaBrowser.Model.net35.csproj | 9 + MediaBrowser.Model/Devices/DeviceQuery.cs | 17 ++ MediaBrowser.Model/Dto/BaseItemDto.cs | 6 + MediaBrowser.Model/MediaBrowser.Model.csproj | 3 + MediaBrowser.Model/Querying/ItemFields.cs | 5 + MediaBrowser.Model/Session/ClientCapabilities.cs | 5 +- MediaBrowser.Model/Sync/SyncJobItem.cs | 13 +- MediaBrowser.Model/Sync/SyncJobItemQuery.cs | 27 ++ MediaBrowser.Model/Sync/SyncJobItemStatus.cs | 12 + MediaBrowser.Model/Sync/SyncJobQuery.cs | 5 + MediaBrowser.Model/Sync/SyncJobStatus.cs | 7 +- .../BoxSets/BoxSetMetadataService.cs | 5 + .../Playlists/PlaylistMetadataService.cs | 11 +- .../Collections/CollectionManager.cs | 9 +- .../Devices/DeviceManager.cs | 28 +- .../Dto/DtoService.cs | 9 + .../Library/LibraryManager.cs | 19 +- .../Library/MusicManager.cs | 13 + .../Library/Resolvers/Movies/MovieResolver.cs | 2 +- .../Localization/JavaScript/javascript.json | 11 +- .../Localization/Server/server.json | 4 +- .../MediaBrowser.Server.Implementations.csproj | 1 + .../Playlists/ManualPlaylistsFolder.cs | 2 +- .../Playlists/PlaylistManager.cs | 9 +- .../Sync/SyncJobProcessor.cs | 334 ++++++++++++++++++++- .../Sync/SyncManager.cs | 101 +++++-- .../Sync/SyncRepository.cs | 125 ++++++-- .../Sync/SyncScheduledTask.cs | 62 ++++ .../ApplicationHost.cs | 2 +- MediaBrowser.WebDashboard/Api/PackageCreator.cs | 3 +- .../MediaBrowser.WebDashboard.csproj | 10 +- 49 files changed, 997 insertions(+), 145 deletions(-) create mode 100644 MediaBrowser.Controller/Entities/Share.cs create mode 100644 MediaBrowser.Model/Devices/DeviceQuery.cs create mode 100644 MediaBrowser.Model/Sync/SyncJobItemQuery.cs create mode 100644 MediaBrowser.Model/Sync/SyncJobItemStatus.cs create mode 100644 MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs (limited to 'MediaBrowser.Server.Implementations/Localization/Server/server.json') diff --git a/MediaBrowser.Api/Devices/DeviceService.cs b/MediaBrowser.Api/Devices/DeviceService.cs index 135397308..ab0a4a4b2 100644 --- a/MediaBrowser.Api/Devices/DeviceService.cs +++ b/MediaBrowser.Api/Devices/DeviceService.cs @@ -1,25 +1,19 @@ using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Devices; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; using ServiceStack; using ServiceStack.Web; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Api.Devices { [Route("/Devices", "GET", Summary = "Gets all devices")] [Authenticated(Roles = "Admin")] - public class GetDevices : IReturn> + public class GetDevices : DeviceQuery, IReturn> { - [ApiMember(Name = "SupportsContentUploading", Description = "SupportsContentUploading", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public bool? SupportsContentUploading { get; set; } - - [ApiMember(Name = "SupportsDeviceId", Description = "SupportsDeviceId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public bool? SupportsDeviceId { get; set; } } [Route("/Devices", "DELETE", Summary = "Deletes a device")] @@ -112,23 +106,7 @@ namespace MediaBrowser.Api.Devices public object Get(GetDevices request) { - var devices = _deviceManager.GetDevices(); - - if (request.SupportsContentUploading.HasValue) - { - var val = request.SupportsContentUploading.Value; - - devices = devices.Where(i => _deviceManager.GetCapabilities(i.Id).SupportsContentUploading == val); - } - - if (request.SupportsDeviceId.HasValue) - { - var val = request.SupportsDeviceId.Value; - - devices = devices.Where(i => _deviceManager.GetCapabilities(i.Id).SupportsDeviceId == val); - } - - return ToOptimizedResult(devices.ToList()); + return ToOptimizedResult(_deviceManager.GetDevices(request)); } public object Get(GetCameraUploads request) diff --git a/MediaBrowser.Api/Music/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs index f34242242..43fd0894b 100644 --- a/MediaBrowser.Api/Music/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Playlists; using MediaBrowser.Model.Querying; using ServiceStack; using System.Collections.Generic; @@ -20,6 +21,11 @@ namespace MediaBrowser.Api.Music { } + [Route("/Playlists/{Id}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given playlist")] + public class GetInstantMixFromPlaylist : BaseGetSimilarItemsFromItem + { + } + [Route("/Artists/{Name}/InstantMix", "GET", Summary = "Creates an instant playlist based on a given artist")] public class GetInstantMixFromArtist : BaseGetSimilarItems { @@ -109,6 +115,17 @@ namespace MediaBrowser.Api.Music return GetResult(items, user, request); } + public object Get(GetInstantMixFromPlaylist request) + { + var playlist = (Playlist)_libraryManager.GetItemById(request.Id); + + var user = _userManager.GetUserById(request.UserId.Value); + + var items = _musicManager.GetInstantMixFromPlaylist(playlist, user); + + return GetResult(items, user, request); + } + public object Get(GetInstantMixFromMusicGenre request) { var user = _userManager.GetUserById(request.UserId.Value); diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs index 551771338..df50255ab 100644 --- a/MediaBrowser.Api/Session/SessionsService.cs +++ b/MediaBrowser.Api/Session/SessionsService.cs @@ -239,8 +239,11 @@ namespace MediaBrowser.Api.Session [ApiMember(Name = "SupportsContentUploading", Description = "Determines whether camera upload is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] public bool SupportsContentUploading { get; set; } - [ApiMember(Name = "SupportsDeviceId", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] - public bool SupportsDeviceId { get; set; } + [ApiMember(Name = "SupportsSync", Description = "Determines whether sync is supported.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool SupportsSync { get; set; } + + [ApiMember(Name = "SupportsUniqueIdentifier", Description = "Determines whether the device supports a unique identifier.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool SupportsUniqueIdentifier { get; set; } } [Route("/Sessions/Logout", "POST", Summary = "Reports that a session has ended")] @@ -521,7 +524,9 @@ namespace MediaBrowser.Api.Session SupportsContentUploading = request.SupportsContentUploading, - SupportsDeviceId = request.SupportsDeviceId + SupportsSync = request.SupportsSync, + + SupportsUniqueIdentifier = request.SupportsUniqueIdentifier }); } } diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 74ae42095..4a2d39066 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -15,11 +15,13 @@ namespace MediaBrowser.Controller.Collections public Dictionary ProviderIds { get; set; } public List ItemIdList { get; set; } + public List UserIds { get; set; } public CollectionCreationOptions() { ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); ItemIdList = new List(); + UserIds = new List(); } } } diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs index af184e6e9..efd24336a 100644 --- a/MediaBrowser.Controller/Devices/IDeviceManager.cs +++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Devices; using MediaBrowser.Model.Events; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; using System; using System.Collections.Generic; @@ -58,8 +59,9 @@ namespace MediaBrowser.Controller.Devices /// /// Gets the devices. /// + /// The query. /// IEnumerable<DeviceInfo>. - IEnumerable GetDevices(); + QueryResult GetDevices(DeviceQuery query); /// /// Deletes the device. diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 731226ede..9dc600675 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -15,8 +15,10 @@ namespace MediaBrowser.Controller.Entities.Movies /// /// Class BoxSet /// - public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo, IMetadataContainer + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo, IMetadataContainer, IHasShares { + public List Shares { get; set; } + public BoxSet() { RemoteTrailers = new List(); @@ -25,6 +27,7 @@ namespace MediaBrowser.Controller.Entities.Movies DisplayOrder = ItemSortBy.PremiereDate; Keywords = new List(); + Shares = new List(); } protected override bool FilterLinkedChildrenPerUser @@ -160,5 +163,20 @@ namespace MediaBrowser.Controller.Entities.Movies progress.Report(100); } + + public override bool IsVisible(User user) + { + if (base.IsVisible(user)) + { + var userId = user.Id.ToString("N"); + + return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || + + // Need to support this for boxsets created prior to the creation of Shares + Shares.Count == 0; + } + + return false; + } } } diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs new file mode 100644 index 000000000..e194f6238 --- /dev/null +++ b/MediaBrowser.Controller/Entities/Share.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Entities +{ + public interface IHasShares + { + List Shares { get; set; } + } + + public class Share + { + public string UserId { get; set; } + public bool CanEdit { get; set; } + } +} diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 192ce2e83..f66f18401 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Playlists; using System.Collections.Generic; namespace MediaBrowser.Controller.Library @@ -28,6 +29,13 @@ namespace MediaBrowser.Controller.Library /// IEnumerable{Audio}. IEnumerable public interface IUserRepository : IRepository { - /// - /// Opens the connection to the repository - /// - /// Task. - Task Initialize(); - /// /// Deletes the user. /// diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 75e1bbde7..e48cddaaa 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -11,10 +11,17 @@ using System.Runtime.Serialization; namespace MediaBrowser.Controller.Playlists { - public class Playlist : Folder + public class Playlist : Folder, IHasShares { public string OwnerUserId { get; set; } + public List Shares { get; set; } + + public Playlist() + { + Shares = new List(); + } + [IgnoreDataMember] protected override bool FilterLinkedChildrenPerUser { @@ -166,7 +173,15 @@ namespace MediaBrowser.Controller.Playlists public override bool IsVisible(User user) { - return base.IsVisible(user) && string.Equals(user.Id.ToString("N"), OwnerUserId); + if (base.IsVisible(user)) + { + var userId = user.Id.ToString("N"); + + return Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase)) || + string.Equals(OwnerUserId, userId, StringComparison.OrdinalIgnoreCase); + } + + return false; } } } diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 307ab3cb8..a37f7eb8a 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -819,6 +819,19 @@ namespace MediaBrowser.Controller.Providers break; } + case "Shares": + { + using (var subtree = reader.ReadSubtree()) + { + var hasShares = item as IHasShares; + if (hasShares != null) + { + FetchFromSharesNode(subtree, hasShares); + } + } + break; + } + case "Format3D": { var video = item as Video; @@ -853,6 +866,71 @@ namespace MediaBrowser.Controller.Providers } } + private void FetchFromSharesNode(XmlReader reader, IHasShares item) + { + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Share": + { + using (var subtree = reader.ReadSubtree()) + { + var share = GetShareFromNode(subtree); + if (share != null) + { + item.Shares.Add(share); + } + } + break; + } + + default: + reader.Skip(); + break; + } + } + } + } + + private Share GetShareFromNode(XmlReader reader) + { + var share = new Share(); + + reader.MoveToContent(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "UserId": + { + share.UserId = reader.ReadElementContentAsString(); + break; + } + + case "CanEdit": + { + share.CanEdit = string.Equals(reader.ReadElementContentAsString(), true.ToString(), StringComparison.OrdinalIgnoreCase); + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return share; + } + private void FetchFromCountriesNode(XmlReader reader, T item) { reader.MoveToContent(); diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs index 1d5ab7d3e..31c3c0c6d 100644 --- a/MediaBrowser.Controller/Sync/ISyncManager.cs +++ b/MediaBrowser.Controller/Sync/ISyncManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; using System.Collections.Generic; @@ -27,7 +28,7 @@ namespace MediaBrowser.Controller.Sync /// The identifier. /// SyncJob. SyncJob GetJob(string id); - + /// /// Cancels the job. /// @@ -51,5 +52,12 @@ namespace MediaBrowser.Controller.Sync /// The item. /// true if XXXX, false otherwise. bool SupportsSync(BaseItem item); + + /// + /// Gets the device profile. + /// + /// The target identifier. + /// DeviceProfile. + DeviceProfile GetDeviceProfile(string targetId); } } diff --git a/MediaBrowser.Controller/Sync/ISyncRepository.cs b/MediaBrowser.Controller/Sync/ISyncRepository.cs index d0cf87182..f1bcd7f07 100644 --- a/MediaBrowser.Controller/Sync/ISyncRepository.cs +++ b/MediaBrowser.Controller/Sync/ISyncRepository.cs @@ -1,6 +1,5 @@ using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; -using System.Collections.Generic; using System.Threading.Tasks; namespace MediaBrowser.Controller.Sync @@ -66,8 +65,8 @@ namespace MediaBrowser.Controller.Sync /// /// Gets the job items. /// - /// The job identifier. + /// The query. /// IEnumerable<SyncJobItem>. - IEnumerable GetJobItems(string jobId); + QueryResult GetJobItems(SyncJobItemQuery query); } } diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs index c7f974200..a12724ff7 100644 --- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs @@ -2,7 +2,9 @@ using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Logging; +using System; using System.Collections.Generic; +using System.Linq; using System.Xml; namespace MediaBrowser.LocalMetadata.Parsers @@ -20,7 +22,15 @@ namespace MediaBrowser.LocalMetadata.Parsers { case "OwnerUserId": { - item.OwnerUserId = reader.ReadElementContentAsString(); + var userId = reader.ReadElementContentAsString(); + if (!item.Shares.Any(i => string.Equals(userId, i.UserId, StringComparison.OrdinalIgnoreCase))) + { + item.Shares.Add(new Share + { + UserId = userId, + CanEdit = true + }); + } break; } diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs index 16c437381..76ef4d4bf 100644 --- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs @@ -57,11 +57,6 @@ namespace MediaBrowser.LocalMetadata.Savers builder.Append(""); - if (!string.IsNullOrEmpty(playlist.OwnerUserId)) - { - builder.Append("" + SecurityElement.Escape(playlist.OwnerUserId) + ""); - } - if (!string.IsNullOrEmpty(playlist.PlaylistMediaType)) { builder.Append("" + SecurityElement.Escape(playlist.PlaylistMediaType) + ""); diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs index 93876f474..3e11c994b 100644 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -645,6 +645,29 @@ namespace MediaBrowser.LocalMetadata.Savers { AddLinkedChildren(playlist, builder, "PlaylistItems", "PlaylistItem"); } + + var hasShares = item as IHasShares; + if (hasShares != null) + { + + } + } + + public static void AddShares(IHasShares item, StringBuilder builder) + { + builder.Append(""); + + foreach (var share in item.Shares) + { + builder.Append(""); + + builder.Append("" + SecurityElement.Escape(share.UserId) + ""); + builder.Append("" + SecurityElement.Escape(share.CanEdit.ToString().ToLower()) + ""); + + builder.Append(""); + } + + builder.Append(""); } public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index bcd6e08f1..701d7d70b 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -275,6 +275,9 @@ Devices\DeviceOptions.cs + + Devices\DeviceQuery.cs + Devices\DevicesOptions.cs @@ -1034,6 +1037,12 @@ Sync\SyncJobItem.cs + + SyncJobItemQuery.cs + + + Sync\SyncJobItemStatus.cs + Sync\SyncJobQuery.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 55d18c1b3..9affbb199 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -240,6 +240,9 @@ Devices\DeviceOptions.cs + + Devices\DeviceQuery.cs + Devices\DevicesOptions.cs @@ -993,6 +996,12 @@ Sync\SyncJobItem.cs + + Sync\SyncJobItemQuery.cs + + + Sync\SyncJobItemStatus.cs + Sync\SyncJobQuery.cs diff --git a/MediaBrowser.Model/Devices/DeviceQuery.cs b/MediaBrowser.Model/Devices/DeviceQuery.cs new file mode 100644 index 000000000..76f7117b6 --- /dev/null +++ b/MediaBrowser.Model/Devices/DeviceQuery.cs @@ -0,0 +1,17 @@ + +namespace MediaBrowser.Model.Devices +{ + public class DeviceQuery + { + /// + /// Gets or sets a value indicating whether [supports content uploading]. + /// + /// null if [supports content uploading] contains no value, true if [supports content uploading]; otherwise, false. + public bool? SupportsContentUploading { get; set; } + /// + /// Gets or sets a value indicating whether [supports unique identifier]. + /// + /// null if [supports unique identifier] contains no value, true if [supports unique identifier]; otherwise, false. + public bool? SupportsUniqueIdentifier { get; set; } + } +} diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index b83243ba8..45f681066 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -186,6 +186,12 @@ namespace MediaBrowser.Model.Dto /// /// The genres. public List Genres { get; set; } + + /// + /// Gets or sets the series genres. + /// + /// The series genres. + public List SeriesGenres { get; set; } /// /// Gets or sets the community rating. diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 4825cb4cc..5aebe42eb 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -113,6 +113,7 @@ + @@ -365,6 +366,8 @@ + + diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index a5a906f95..19e30cd8a 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -161,6 +161,11 @@ namespace MediaBrowser.Model.Querying /// ScreenshotImageTags, + /// + /// The series genres + /// + SeriesGenres, + /// /// The series studio /// diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs index fc0d3a1fb..f2faa0545 100644 --- a/MediaBrowser.Model/Session/ClientCapabilities.cs +++ b/MediaBrowser.Model/Session/ClientCapabilities.cs @@ -13,13 +13,14 @@ namespace MediaBrowser.Model.Session public string MessageCallbackUrl { get; set; } public bool SupportsContentUploading { get; set; } - public bool SupportsDeviceId { get; set; } + public bool SupportsUniqueIdentifier { get; set; } + public bool SupportsSync { get; set; } public ClientCapabilities() { PlayableMediaTypes = new List(); SupportedCommands = new List(); - SupportsDeviceId = true; + SupportsUniqueIdentifier = true; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs index 141546eb5..063f7feb2 100644 --- a/MediaBrowser.Model/Sync/SyncJobItem.cs +++ b/MediaBrowser.Model/Sync/SyncJobItem.cs @@ -1,4 +1,5 @@ - +using System; + namespace MediaBrowser.Model.Sync { public class SyncJobItem @@ -37,12 +38,18 @@ namespace MediaBrowser.Model.Sync /// Gets or sets the status. /// /// The status. - public SyncJobStatus Status { get; set; } + public SyncJobItemStatus Status { get; set; } /// /// Gets or sets the current progress. /// /// The current progress. - public double? CurrentProgress { get; set; } + public double? Progress { get; set; } + + /// + /// Gets or sets the date created. + /// + /// The date created. + public DateTime DateCreated { get; set; } } } diff --git a/MediaBrowser.Model/Sync/SyncJobItemQuery.cs b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs new file mode 100644 index 000000000..e9af642ac --- /dev/null +++ b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs @@ -0,0 +1,27 @@ + +namespace MediaBrowser.Model.Sync +{ + public class SyncJobItemQuery + { + /// + /// Gets or sets the start index. + /// + /// The start index. + public int? StartIndex { get; set; } + /// + /// Gets or sets the limit. + /// + /// The limit. + public int? Limit { get; set; } + /// + /// Gets or sets the job identifier. + /// + /// The job identifier. + public string JobId { get; set; } + /// + /// Gets or sets a value indicating whether this instance is completed. + /// + /// null if [is completed] contains no value, true if [is completed]; otherwise, false. + public bool? IsCompleted { get; set; } + } +} diff --git a/MediaBrowser.Model/Sync/SyncJobItemStatus.cs b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs new file mode 100644 index 000000000..3d0579a3c --- /dev/null +++ b/MediaBrowser.Model/Sync/SyncJobItemStatus.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Model.Sync +{ + public enum SyncJobItemStatus + { + Queued = 0, + Converting = 1, + Transferring = 2, + Completed = 3, + Failed = 4 + } +} diff --git a/MediaBrowser.Model/Sync/SyncJobQuery.cs b/MediaBrowser.Model/Sync/SyncJobQuery.cs index 74b35186e..218b3823e 100644 --- a/MediaBrowser.Model/Sync/SyncJobQuery.cs +++ b/MediaBrowser.Model/Sync/SyncJobQuery.cs @@ -13,5 +13,10 @@ namespace MediaBrowser.Model.Sync /// /// The limit. public int? Limit { get; set; } + /// + /// Gets or sets a value indicating whether this instance is completed. + /// + /// null if [is completed] contains no value, true if [is completed]; otherwise, false. + public bool? IsCompleted { get; set; } } } diff --git a/MediaBrowser.Model/Sync/SyncJobStatus.cs b/MediaBrowser.Model/Sync/SyncJobStatus.cs index 42af96509..961ccf544 100644 --- a/MediaBrowser.Model/Sync/SyncJobStatus.cs +++ b/MediaBrowser.Model/Sync/SyncJobStatus.cs @@ -4,9 +4,8 @@ namespace MediaBrowser.Model.Sync public enum SyncJobStatus { Queued = 0, - Converting = 1, - Transferring = 2, - Completed = 3, - Cancelled = 4 + InProgress = 1, + Completed = 2, + CompletedWithError = 3 } } diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 31136b919..062519f9d 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -44,6 +44,11 @@ namespace MediaBrowser.Providers.BoxSets target.LinkedChildren = list; } + + if (replaceData || target.Shares.Count == 0) + { + target.Shares = source.Shares; + } } protected override ItemUpdateType BeforeSave(BoxSet item) diff --git a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs index 586c17d07..2e407f10c 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistMetadataService.cs @@ -7,7 +7,6 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Providers.Manager; using System.Collections.Generic; -using System.Linq; namespace MediaBrowser.Providers.Playlists { @@ -34,18 +33,14 @@ namespace MediaBrowser.Providers.Playlists target.PlaylistMediaType = source.PlaylistMediaType; } - if (replaceData || string.IsNullOrEmpty(target.OwnerUserId)) + if (replaceData || target.Shares.Count == 0) { - target.OwnerUserId = source.OwnerUserId; + target.Shares = source.Shares; } if (mergeMetadataSettings) { - var list = source.LinkedChildren.ToList(); - - list.AddRange(target.LinkedChildren); - - target.LinkedChildren = list; + target.LinkedChildren = source.LinkedChildren; } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index e346d6d01..9fee27db9 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -72,7 +72,12 @@ namespace MediaBrowser.Server.Implementations.Collections DisplayMediaType = "Collection", Path = path, IsLocked = options.IsLocked, - ProviderIds = options.ProviderIds + ProviderIds = options.ProviderIds, + Shares = options.UserIds.Select(i => new Share + { + UserId = i.ToString("N") + + }).ToList() }; await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false); @@ -156,7 +161,7 @@ namespace MediaBrowser.Server.Implementations.Collections } itemList.Add(item); - + if (currentLinkedChildren.Any(i => i.Id == itemId)) { throw new ArgumentException("Item already exists in collection"); diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs index e2c729b2d..8c67013ea 100644 --- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs +++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs @@ -6,6 +6,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Devices; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; using MediaBrowser.Model.Session; using System; using System.Collections.Generic; @@ -28,7 +29,7 @@ namespace MediaBrowser.Server.Implementations.Devices /// Occurs when [device options updated]. /// public event EventHandler> DeviceOptionsUpdated; - + public DeviceManager(IDeviceRepository repo, IUserManager userManager, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IConfigurationManager config, ILogger logger) { _repo = repo; @@ -79,9 +80,30 @@ namespace MediaBrowser.Server.Implementations.Devices return _repo.GetDevice(id); } - public IEnumerable GetDevices() + public QueryResult GetDevices(DeviceQuery query) { - return _repo.GetDevices().OrderByDescending(i => i.DateLastModified); + IEnumerable devices = _repo.GetDevices().OrderByDescending(i => i.DateLastModified); + + if (query.SupportsContentUploading.HasValue) + { + var val = query.SupportsContentUploading.Value; + + devices = devices.Where(i => GetCapabilities(i.Id).SupportsContentUploading == val); + } + + if (query.SupportsUniqueIdentifier.HasValue) + { + var val = query.SupportsUniqueIdentifier.Value; + + devices = devices.Where(i => GetCapabilities(i.Id).SupportsUniqueIdentifier == val); + } + + var array = devices.ToArray(); + return new QueryResult + { + Items = array, + TotalRecordCount = array.Length + }; } public Task DeleteDevice(string id) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index e1e8da5c5..a6f9f0675 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1142,6 +1142,15 @@ namespace MediaBrowser.Server.Implementations.Dto dto.SeasonId = episodeSeason.Id.ToString("N"); dto.SeasonName = episodeSeason.Name; } + + if (fields.Contains(ItemFields.SeriesGenres)) + { + var episodeseries = episode.Series; + if (episodeseries != null) + { + dto.SeriesGenres = episodeseries.Genres.ToList(); + } + } } // Add SeriesInfo diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index e06720192..bfdfc03ba 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -736,16 +736,27 @@ namespace MediaBrowser.Server.Implementations.Library } private UserRootFolder _userRootFolder; + private readonly object _syncLock = new object(); public Folder GetUserRootFolder() { if (_userRootFolder == null) { - var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; + lock (_syncLock) + { + if (_userRootFolder == null) + { + var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; - Directory.CreateDirectory(userRootPath); + Directory.CreateDirectory(userRootPath); - _userRootFolder = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder ?? - (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); + _userRootFolder = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder; + + if (_userRootFolder == null) + { + _userRootFolder = (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); + } + } + } } return _userRootFolder; diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index 7ffbab860..b8c29c19b 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -1,6 +1,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Playlists; using System; using System.Collections.Generic; using System.Linq; @@ -53,6 +54,18 @@ namespace MediaBrowser.Server.Implementations.Library return GetInstantMixFromGenres(genres, user); } + public IEnumerable