From 0604d180ab49e236d3aff80c7a715392ac980004 Mon Sep 17 00:00:00 2001 From: tikuf Date: Thu, 6 Mar 2014 08:46:32 +1100 Subject: [PATCH 01/31] Added Jump In - NameStartsWith --- .../UserLibrary/BaseItemsByNameService.cs | 6 ++++++ MediaBrowser.Api/UserLibrary/ItemsService.cs | 14 ++++++++++++++ MediaBrowser.Model/Querying/ItemQuery.cs | 11 +++++++++++ MediaBrowser.Model/Querying/ItemsByNameQuery.cs | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 5c2c9967e3..6f8e8a9092 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -174,6 +174,10 @@ namespace MediaBrowser.Api.UserLibrary { items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); } + if (!string.IsNullOrEmpty(request.NameStartsWith)) + { + items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0); + } if (!string.IsNullOrEmpty(request.NameLessThan)) { @@ -312,6 +316,8 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWithOrGreater { get; set; } + [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string NameStartsWith { get; set; } [ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is sorted less than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameLessThan { get; set; } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 871c9aecb4..3221813055 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -110,6 +110,11 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWithOrGreater { get; set; } + [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string NameStartsWith { get; set; } + + [ApiMember(Name = "NameLessThan", Description = "Optional filter by items whose name is equally or lesser than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public string NameLessThan { get; set; } [ApiMember(Name = "AlbumArtistStartsWithOrGreater", Description = "Optional filter by items whose album artist is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string AlbumArtistStartsWithOrGreater { get; set; } @@ -768,6 +773,15 @@ namespace MediaBrowser.Api.UserLibrary { items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); } + if (!string.IsNullOrEmpty(request.NameStartsWith)) + { + items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0); + } + + if (!string.IsNullOrEmpty(request.NameLessThan)) + { + items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1); + } if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater)) { diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index bc769b786a..354e12579c 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -217,6 +217,17 @@ namespace MediaBrowser.Model.Querying /// /// The name starts with or greater. public string NameStartsWithOrGreater { get; set; } + /// + /// Gets or sets the name starts with. + /// + /// The name starts with or greater. + public string NameStartsWith { get; set; } + + /// + /// Gets or sets the name starts with. + /// + /// The name lessthan. + public string NameLessThan { get; set; } /// /// Gets or sets the album artist starts with or greater. diff --git a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs index eafc322abd..4227dc0c59 100644 --- a/MediaBrowser.Model/Querying/ItemsByNameQuery.cs +++ b/MediaBrowser.Model/Querying/ItemsByNameQuery.cs @@ -86,6 +86,10 @@ namespace MediaBrowser.Model.Querying public string NameStartsWithOrGreater { get; set; } /// + /// Gets or sets the name starts with + /// + /// The name starts with or greater. + public string NameStartsWith { get; set; } /// Gets or sets the name less than. /// /// The name less than. From 52eca07c675b52205234076d395f1a1361e43658 Mon Sep 17 00:00:00 2001 From: tikuf Date: Thu, 6 Mar 2014 13:59:48 +1100 Subject: [PATCH 02/31] Formatting fixes --- MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs | 7 ++++--- MediaBrowser.Api/UserLibrary/ItemsService.cs | 1 + MediaBrowser.Model/Querying/ItemQuery.cs | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 6f8e8a9092..12b3fd0154 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -175,9 +175,9 @@ namespace MediaBrowser.Api.UserLibrary items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); } if (!string.IsNullOrEmpty(request.NameStartsWith)) - { - items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0); - } + { + items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0); + } if (!string.IsNullOrEmpty(request.NameLessThan)) { @@ -316,6 +316,7 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWithOrGreater { get; set; } + [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWith { get; set; } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 3221813055..b040d3dd81 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -110,6 +110,7 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWithOrGreater { get; set; } + [ApiMember(Name = "NameStartsWith", Description = "Optional filter by items whose name is sorted equally than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string NameStartsWith { get; set; } diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index 354e12579c..aee1ca947b 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -217,13 +217,14 @@ namespace MediaBrowser.Model.Querying /// /// The name starts with or greater. public string NameStartsWithOrGreater { get; set; } - /// + + /// /// Gets or sets the name starts with. /// /// The name starts with or greater. public string NameStartsWith { get; set; } - /// + /// /// Gets or sets the name starts with. /// /// The name lessthan. From 1bf4447dcef2fb5bdfd1791b01f5c06cb5361d47 Mon Sep 17 00:00:00 2001 From: Tensre Date: Wed, 5 Mar 2014 20:44:29 -0800 Subject: [PATCH 03/31] Auto-Organize Copy/Move Option, Fix for Overwrite Existing File Addition of the option in Auto-Organize to copy or move files from watch folder. Fix to use the Overwrite Existing File option from the config rather than hardcoded value. --- .../Configuration/AutoOrganize.cs | 4 ++ .../FileOrganization/EpisodeFileOrganizer.cs | 49 ++++++++++++++++--- .../FileOrganization/TvFolderOrganizer.cs | 2 +- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Model/Configuration/AutoOrganize.cs b/MediaBrowser.Model/Configuration/AutoOrganize.cs index a30aa36d8b..fe32d4a80a 100644 --- a/MediaBrowser.Model/Configuration/AutoOrganize.cs +++ b/MediaBrowser.Model/Configuration/AutoOrganize.cs @@ -19,6 +19,8 @@ namespace MediaBrowser.Model.Configuration public bool DeleteEmptyFolders { get; set; } + public bool CopyOriginalFile { get; set; } + public TvFileOrganizationOptions() { MinFileSizeMb = 50; @@ -31,6 +33,8 @@ namespace MediaBrowser.Model.Configuration MultiEpisodeNamePattern = "%sn - %sx%0e-x%0ed - %en.%ext"; SeasonFolderPattern = "Season %s"; SeasonZeroFolderName = "Season 0"; + + CopyOriginalFile = false; } } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index b91067dd76..e5ffd639bd 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -171,14 +171,27 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var fileExists = File.Exists(result.TargetPath); var otherDuplicatePaths = GetOtherDuplicatePaths(result.TargetPath, series, seasonNumber, episodeNumber, endingEpiosdeNumber); - if (!overwriteExisting && (fileExists || otherDuplicatePaths.Count > 0)) + if (!overwriteExisting) { - result.Status = FileSortingStatus.SkippedExisting; - result.StatusMessage = string.Empty; - result.DuplicatePaths = otherDuplicatePaths; - return; + if (fileExists || otherDuplicatePaths.Count > 0) + { + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = string.Empty; + result.DuplicatePaths = otherDuplicatePaths; + return; + } + + if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath)) + { + _logger.Info("File {0} already copied to new path {1}, stopping organization", sourcePath, newPath); + result.Status = FileSortingStatus.SkippedExisting; + result.StatusMessage = string.Empty; + return; + } } + + PerformFileSorting(options, result); if (overwriteExisting) @@ -266,7 +279,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization try { - if (copy) + if (copy || options.CopyOriginalFile) { File.Copy(result.OriginalPath, result.TargetPath, true); } @@ -293,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true); } - if (copy) + if (copy && !options.CopyOriginalFile) { try { @@ -439,5 +452,27 @@ namespace MediaBrowser.Server.Implementations.FileOrganization .Replace("%0e", episodeNumber.ToString("00", _usCulture)) .Replace("%00e", episodeNumber.ToString("000", _usCulture)); } + + private bool IsSameEpisode(string sourcePath, string newPath) + { + + FileInfo sourceFileInfo = new FileInfo(sourcePath); + FileInfo destinationFileInfo = new FileInfo(newPath); + + try + { + if (sourceFileInfo.Length == destinationFileInfo.Length) + { + return true; + } + } + catch (FileNotFoundException) + { + return false; + } + + return false; + + } } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs index 7edcf9739c..82bb9862c9 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager, _libraryMonitor, _providerManager); - var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false, cancellationToken).ConfigureAwait(false); + var result = await organizer.OrganizeEpisodeFile(file.FullName, options, options.OverwriteExistingEpisodes, cancellationToken).ConfigureAwait(false); if (result.Status == FileSortingStatus.Success) { From 2349c8099d04c6c0631cd33e6c74b404381946ab Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 6 Mar 2014 00:17:13 -0500 Subject: [PATCH 04/31] start on manual collection creation --- MediaBrowser.Api/MediaBrowser.Api.csproj | 4 +- MediaBrowser.Api/{ => Music}/AlbumsService.cs | 2 +- .../{ => Music}/InstantMixService.cs | 2 +- MediaBrowser.Api/TvShowsService.cs | 89 ++++++++++++++++--- .../Collections/CollectionCreationOptions.cs | 13 +++ .../Collections/ICollectionManager.cs | 31 +++++++ .../Entities/UserRootFolder.cs | 3 +- .../MediaBrowser.Controller.csproj | 2 + .../Music/MusicExternalIds.cs | 2 +- .../Collections/CollectionManager.cs | 79 ++++++++++++++++ .../EntryPoints/ExternalPortForwarding.cs | 2 + .../Resolvers/Audio/MusicAlbumResolver.cs | 2 +- .../LiveTv/ChannelImageProvider.cs | 8 +- .../LiveTv/ProgramImageProvider.cs | 8 +- .../LiveTv/RecordingImageProvider.cs | 8 +- ...MediaBrowser.Server.Implementations.csproj | 6 +- .../packages.config | 2 +- 17 files changed, 239 insertions(+), 24 deletions(-) rename MediaBrowser.Api/{ => Music}/AlbumsService.cs (99%) rename MediaBrowser.Api/{ => Music}/InstantMixService.cs (99%) create mode 100644 MediaBrowser.Controller/Collections/CollectionCreationOptions.cs create mode 100644 MediaBrowser.Controller/Collections/ICollectionManager.cs create mode 100644 MediaBrowser.Server.Implementations/Collections/CollectionManager.cs diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index bcc487a5d5..85e40eda15 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,7 +66,7 @@ Properties\SharedVersion.cs - + @@ -81,7 +81,7 @@ - + diff --git a/MediaBrowser.Api/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs similarity index 99% rename from MediaBrowser.Api/AlbumsService.cs rename to MediaBrowser.Api/Music/AlbumsService.cs index 5787ad180c..a80dd796a0 100644 --- a/MediaBrowser.Api/AlbumsService.cs +++ b/MediaBrowser.Api/Music/AlbumsService.cs @@ -8,7 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Music { [Route("/Albums/{Id}/Similar", "GET")] [Api(Description = "Finds albums similar to a given album.")] diff --git a/MediaBrowser.Api/InstantMixService.cs b/MediaBrowser.Api/Music/InstantMixService.cs similarity index 99% rename from MediaBrowser.Api/InstantMixService.cs rename to MediaBrowser.Api/Music/InstantMixService.cs index 624137677c..a8446a7ef2 100644 --- a/MediaBrowser.Api/InstantMixService.cs +++ b/MediaBrowser.Api/Music/InstantMixService.cs @@ -7,7 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Music { [Route("/Songs/{Id}/InstantMix", "GET")] [Api(Description = "Creates an instant playlist based on a given song")] diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index 629f9b2333..198e1c3839 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Api /// Class GetNextUpEpisodes /// [Route("/Shows/NextUp", "GET")] - [Api(("Gets a list of currently installed plugins"))] + [Api(("Gets a list of next up episodes"))] public class GetNextUpEpisodes : IReturn, IHasItemFields { /// @@ -53,6 +53,39 @@ namespace MediaBrowser.Api public string SeriesId { get; set; } } + [Route("/Shows/Upcoming", "GET")] + [Api(("Gets a list of upcoming episodes"))] + public class GetUpcomingEpisodes : IReturn, IHasItemFields + { + /// + /// Gets or sets the user id. + /// + /// The user id. + [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public Guid UserId { get; set; } + + /// + /// Skips over a given number of items within the results. Use for paging. + /// + /// The start index. + [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? StartIndex { get; set; } + + /// + /// The maximum number of items to return + /// + /// The limit. + [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] + public int? Limit { get; set; } + + /// + /// Fields to return within the items, in addition to basic information + /// + /// The fields. + [ApiMember(Name = "Fields", Description = "Optional. Specify additional fields of information to return in the output. This allows multiple, comma delimeted. Options: Budget, Chapters, CriticRatingSummary, DateCreated, Genres, HomePageUrl, IndexOptions, MediaStreams, Overview, OverviewHtml, ParentId, Path, People, ProviderIds, PrimaryImageAspectRatio, Revenue, SortName, Studios, Taglines, TrailerUrls", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Fields { get; set; } + } + [Route("/Shows/{Id}/Similar", "GET")] [Api(Description = "Finds tv shows similar to a given one.")] public class GetSimilarShows : BaseGetSimilarItemsFromItem @@ -85,7 +118,7 @@ namespace MediaBrowser.Api [ApiMember(Name = "SeasonId", Description = "Optional. Filter by season id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string SeasonId { get; set; } - + [ApiMember(Name = "IsMissing", Description = "Optional filter by items that are missing episodes or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? IsMissing { get; set; } @@ -186,6 +219,39 @@ namespace MediaBrowser.Api return ToOptimizedSerializedResultUsingCache(result); } + public object Get(GetUpcomingEpisodes request) + { + var user = _userManager.GetUserById(request.UserId); + + var items = GetAllLibraryItems(request.UserId, _userManager, _libraryManager) + .OfType(); + + var itemsList = _libraryManager.Sort(items, user, new[] { "PremiereDate", "AirTime", "SortName" }, SortOrder.Ascending) + .Cast() + .ToList(); + + var unairedEpisodes = itemsList.Where(i => i.IsUnaired).ToList(); + + var minPremiereDate = DateTime.Now.Date.AddDays(-1).ToUniversalTime(); + var previousEpisodes = itemsList.Where(i => !i.IsUnaired && (i.PremiereDate ?? DateTime.MinValue) >= minPremiereDate).ToList(); + + previousEpisodes.AddRange(unairedEpisodes); + + var pagedItems = ApplyPaging(previousEpisodes, request.StartIndex, request.Limit); + + var fields = request.GetItemFields().ToList(); + + var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(); + + var result = new ItemsResult + { + TotalRecordCount = itemsList.Count, + Items = returnItems + }; + + return ToOptimizedSerializedResultUsingCache(result); + } + /// /// Gets the specified request. /// @@ -198,7 +264,7 @@ namespace MediaBrowser.Api var itemsList = GetNextUpEpisodes(request) .ToList(); - var pagedItems = ApplyPaging(request, itemsList); + var pagedItems = ApplyPaging(itemsList, request.StartIndex, request.Limit); var fields = request.GetItemFields().ToList(); @@ -321,21 +387,22 @@ namespace MediaBrowser.Api /// /// Applies the paging. /// - /// The request. /// The items. + /// The start index. + /// The limit. /// IEnumerable{BaseItem}. - private IEnumerable ApplyPaging(GetNextUpEpisodes request, IEnumerable items) + private IEnumerable ApplyPaging(IEnumerable items, int? startIndex, int? limit) { // Start at - if (request.StartIndex.HasValue) + if (startIndex.HasValue) { - items = items.Skip(request.StartIndex.Value); + items = items.Skip(startIndex.Value); } // Return limit - if (request.Limit.HasValue) + if (limit.HasValue) { - items = items.Take(request.Limit.Value); + items = items.Take(limit.Value); } return items; @@ -409,7 +476,7 @@ namespace MediaBrowser.Api return items; } - + public object Get(GetEpisodes request) { var user = _userManager.GetUserById(request.UserId); @@ -435,7 +502,7 @@ namespace MediaBrowser.Api { throw new ResourceNotFoundException("No season exists with Id " + request.SeasonId); } - + episodes = season.GetEpisodes(user); } diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs new file mode 100644 index 0000000000..d26bf5b352 --- /dev/null +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -0,0 +1,13 @@ +using System; + +namespace MediaBrowser.Controller.Collections +{ + public class CollectionCreationOptions + { + public string Name { get; set; } + + public Guid ParentId { get; set; } + + public bool IsLocked { get; set; } + } +} diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs new file mode 100644 index 0000000000..a1e6b2c120 --- /dev/null +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Collections +{ + public interface ICollectionManager + { + /// + /// Creates the collection. + /// + /// The options. + /// Task. + Task CreateCollection(CollectionCreationOptions options); + + /// + /// Adds to collection. + /// + /// The collection identifier. + /// The item identifier. + /// Task. + Task AddToCollection(Guid collectionId, Guid itemId); + + /// + /// Removes from collection. + /// + /// The collection identifier. + /// The item identifier. + /// Task. + Task RemoveFromCollection(Guid collectionId, Guid itemId); + } +} diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 1829e10c72..0290fa39ad 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Providers; +using System; using System.Collections.Generic; using System.Linq; @@ -23,7 +24,7 @@ namespace MediaBrowser.Controller.Entities { var hasChanges = base.BeforeMetadataRefresh(); - if (string.Equals("default", Name, System.StringComparison.OrdinalIgnoreCase)) + if (string.Equals("default", Name, StringComparison.OrdinalIgnoreCase)) { Name = "Media Folders"; hasChanges = true; diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index ff446f2ef8..100ac9f4c4 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -68,6 +68,8 @@ Properties\SharedVersion.cs + + diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs index a25ab9deb2..a4eab1eee8 100644 --- a/MediaBrowser.Providers/Music/MusicExternalIds.cs +++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Providers.Music public bool Supports(IHasProviderIds item) { - return item is Audio || item is MusicAlbum || item is MusicArtist; + return item is Audio || item is MusicAlbum; } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs new file mode 100644 index 0000000000..da444d100a --- /dev/null +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -0,0 +1,79 @@ +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Collections +{ + public class CollectionManager : ICollectionManager + { + private readonly ILibraryManager _libraryManager; + private readonly IFileSystem _fileSystem; + private readonly ILibraryMonitor _iLibraryMonitor; + + public CollectionManager(ILibraryManager libraryManager, IFileSystem fileSystem, ILibraryMonitor iLibraryMonitor) + { + _libraryManager = libraryManager; + _fileSystem = fileSystem; + _iLibraryMonitor = iLibraryMonitor; + } + + public async Task CreateCollection(CollectionCreationOptions options) + { + var name = options.Name; + + var folderName = _fileSystem.GetValidFilename(name); + + var parentFolder = _libraryManager.GetItemById(options.ParentId) as Folder; + + if (parentFolder == null) + { + throw new ArgumentException(); + } + + var path = Path.Combine(parentFolder.Path, folderName); + + _iLibraryMonitor.ReportFileSystemChangeBeginning(path); + + try + { + Directory.CreateDirectory(path); + + var collection = new BoxSet + { + Name = name, + Parent = parentFolder, + DisplayMediaType = "Collection", + Path = path, + DontFetchMeta = options.IsLocked + }; + + await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false); + + await collection.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None) + .ConfigureAwait(false); + } + finally + { + // Refresh handled internally + _iLibraryMonitor.ReportFileSystemChangeComplete(path, false); + } + } + + public Task AddToCollection(Guid collectionId, Guid itemId) + { + throw new NotImplementedException(); + } + + public Task RemoveFromCollection(Guid collectionId, Guid itemId) + { + throw new NotImplementedException(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index c0d784fccd..ad2852a914 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -3,6 +3,8 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; using Mono.Nat; +using Mono.Nat.Enums; +using Mono.Nat.EventArgs; using System; using System.IO; using System.Text; diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index 8711715412..ac1927931f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio var collectionType = args.GetCollectionType(); - // If there's a collection type and it's not music, it can't be a series + // If there's a collection type and it's not music, don't allow it. if (!string.IsNullOrEmpty(collectionType) && !string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs index 9a13734605..83d8e4b73f 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ChannelImageProvider.cs @@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { - return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalDays >= 1; + var liveTvItem = item as LiveTvChannel; + + if (liveTvItem != null) + { + return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.HasProviderImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6; + } + return false; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs index cb7635b453..081722bb2a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/ProgramImageProvider.cs @@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { - return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 6; + var liveTvItem = item as LiveTvProgram; + + if (liveTvItem != null) + { + return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.HasProviderImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6; + } + return false; } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs index be8955d16b..7aa5dcebda 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/RecordingImageProvider.cs @@ -105,7 +105,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date) { - return !item.HasImage(ImageType.Primary) && (DateTime.UtcNow - date).TotalHours >= 3; + var liveTvItem = item as ILiveTvRecording; + + if (liveTvItem != null) + { + return !liveTvItem.HasImage(ImageType.Primary) && (liveTvItem.RecordingInfo.HasImage ?? true) && (DateTime.UtcNow - date).TotalHours >= 6; + } + return false; } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index f0b08b9233..0165cefad8 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -56,8 +56,9 @@ False ..\packages\MediaBrowser.BdInfo.1.0.0.10\lib\net35\DvdLib.dll - - ..\packages\Mono.Nat.1.1.13\lib\Net40\Mono.Nat.dll + + False + ..\packages\Mono.Nat.1.2.3\lib\Net40\Mono.Nat.dll ..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll @@ -108,6 +109,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 258e0639d3..3c984e2656 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -2,7 +2,7 @@ - + \ No newline at end of file From c85f2957d9b68bf99dbd23efb2b8421845efd157 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 6 Mar 2014 00:23:06 -0500 Subject: [PATCH 05/31] updated nuget --- MediaBrowser.Model/ApiClient/IApiClient.cs | 9 ++++++- MediaBrowser.Model/Querying/NextUpQuery.cs | 28 ++++++++++++++++++++++ Nuget/MediaBrowser.Common.Internal.nuspec | 4 ++-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 ++-- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index d4d2a81240..2a965114bf 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -346,8 +346,15 @@ namespace MediaBrowser.Model.ApiClient /// /// The query. /// Task{ItemsResult}. - Task GetNextUpAsync(NextUpQuery query); + Task GetNextUpEpisodesAsync(NextUpQuery query); + /// + /// Gets the upcoming episodes asynchronous. + /// + /// The query. + /// Task{ItemsResult}. + Task GetUpcomingEpisodesAsync(NextUpQuery query); + /// /// Gets a genre /// diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs index 4f5d47a04e..cdce2e3073 100644 --- a/MediaBrowser.Model/Querying/NextUpQuery.cs +++ b/MediaBrowser.Model/Querying/NextUpQuery.cs @@ -33,4 +33,32 @@ namespace MediaBrowser.Model.Querying /// The fields. public ItemFields[] Fields { get; set; } } + + public class UpcomingEpisodesQuery + { + /// + /// Gets or sets the user id. + /// + /// The user id. + public string UserId { get; set; } + + /// + /// Skips over a given number of items within the results. Use for paging. + /// + /// The start index. + public int? StartIndex { get; set; } + + /// + /// The maximum number of items to return + /// + /// The limit. + public int? Limit { get; set; } + + /// + /// Fields to return within the items, in addition to basic information + /// + /// The fields. + public ItemFields[] Fields { get; set; } + } + } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index e570f18d86..7bd20e7d4d 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.335 + 3.0.336 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 75b6955848..f68a427414 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.335 + 3.0.336 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 581a821068..97f4c90a03 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.335 + 3.0.336 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + From e00985d07ca3923f7f558b8592c0d092842bff5d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 10:53:23 -0500 Subject: [PATCH 06/31] #715 - Support creating/editing collections (boxsets) in web client --- MediaBrowser.Api/MediaBrowser.Api.csproj | 5 +- MediaBrowser.Api/Movies/CollectionService.cs | 80 ++++++++++++++++ .../{ => Movies}/MoviesService.cs | 2 +- .../{ => Movies}/TrailersService.cs | 2 +- MediaBrowser.Api/SearchService.cs | 6 +- .../Collections/CollectionCreationOptions.cs | 2 +- .../Collections/ICollectionManager.cs | 9 +- MediaBrowser.Controller/Entities/BaseItem.cs | 9 ++ .../Entities/BasePluginFolder.cs | 15 +-- MediaBrowser.Controller/Entities/Folder.cs | 66 +++++++++---- .../Entities/LinkedChild.cs | 4 + MediaBrowser.Model/Search/SearchQuery.cs | 4 + .../Savers/XmlSaverHelpers.cs | 39 +++++++- .../Collections/CollectionManager.cs | 92 ++++++++++++++++++- .../Collections/CollectionsDynamicFolder.cs | 55 +++++++++++ .../Library/SearchEngine.cs | 6 ++ .../LiveTv/LiveTvManager.cs | 1 + ...MediaBrowser.Server.Implementations.csproj | 14 ++- .../packages.config | 2 +- MediaBrowser.ServerApplication/App.config | 16 +++- .../ApplicationHost.cs | 5 + MediaBrowser.Tests/app.config | 2 +- .../Api/DashboardService.cs | 1 + .../MediaBrowser.WebDashboard.csproj | 8 +- 24 files changed, 390 insertions(+), 55 deletions(-) create mode 100644 MediaBrowser.Api/Movies/CollectionService.cs rename MediaBrowser.Api/{ => Movies}/MoviesService.cs (98%) rename MediaBrowser.Api/{ => Movies}/TrailersService.cs (98%) create mode 100644 MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 85e40eda15..e19fbb967f 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,6 +66,7 @@ Properties\SharedVersion.cs + @@ -91,7 +92,7 @@ - + @@ -118,7 +119,7 @@ - + diff --git a/MediaBrowser.Api/Movies/CollectionService.cs b/MediaBrowser.Api/Movies/CollectionService.cs new file mode 100644 index 0000000000..456449b7b6 --- /dev/null +++ b/MediaBrowser.Api/Movies/CollectionService.cs @@ -0,0 +1,80 @@ +using MediaBrowser.Controller.Collections; +using ServiceStack; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Movies +{ + [Route("/Collections", "POST")] + [Api(Description = "Creates a new collection")] + public class CreateCollection : IReturnVoid + { + [ApiMember(Name = "IsLocked", Description = "Whether or not to lock the new collection.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "POST")] + public bool IsLocked { get; set; } + + [ApiMember(Name = "Name", Description = "The name of the new collection.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Name { get; set; } + + [ApiMember(Name = "ParentId", Description = "Optional - create the collection within a specific folder", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + public Guid? ParentId { get; set; } + } + + [Route("/Collections/{Id}/Items", "POST")] + [Api(Description = "Adds items to a collection")] + public class AddToCollection : IReturnVoid + { + [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Ids { get; set; } + + [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid Id { get; set; } + } + + [Route("/Collections/{Id}/Items", "DELETE")] + [Api(Description = "Removes items from a collection")] + public class RemoveFromCollection : IReturnVoid + { + [ApiMember(Name = "Ids", Description = "Item id, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string Ids { get; set; } + + [ApiMember(Name = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] + public Guid Id { get; set; } + } + + public class CollectionService : BaseApiService + { + private readonly ICollectionManager _collectionManager; + + public CollectionService(ICollectionManager collectionManager) + { + _collectionManager = collectionManager; + } + + public void Post(CreateCollection request) + { + var task = _collectionManager.CreateCollection(new CollectionCreationOptions + { + IsLocked = request.IsLocked, + Name = request.Name, + ParentId = request.ParentId + }); + + Task.WaitAll(task); + } + + public void Post(AddToCollection request) + { + var task = _collectionManager.AddToCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i))); + + Task.WaitAll(task); + } + + public void Delete(RemoveFromCollection request) + { + var task = _collectionManager.RemoveFromCollection(request.Id, request.Ids.Split(',').Select(i => new Guid(i))); + + Task.WaitAll(task); + } + } +} diff --git a/MediaBrowser.Api/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs similarity index 98% rename from MediaBrowser.Api/MoviesService.cs rename to MediaBrowser.Api/Movies/MoviesService.cs index 2a99bca8b0..5d97d13e15 100644 --- a/MediaBrowser.Api/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using ServiceStack; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Movies { /// /// Class GetSimilarMovies diff --git a/MediaBrowser.Api/TrailersService.cs b/MediaBrowser.Api/Movies/TrailersService.cs similarity index 98% rename from MediaBrowser.Api/TrailersService.cs rename to MediaBrowser.Api/Movies/TrailersService.cs index ca465b5e32..4e17bc7b50 100644 --- a/MediaBrowser.Api/TrailersService.cs +++ b/MediaBrowser.Api/Movies/TrailersService.cs @@ -5,7 +5,7 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using ServiceStack; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Movies { /// /// Class GetSimilarTrailers diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index 18bd8c6956..c3da87d401 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -63,6 +63,9 @@ namespace MediaBrowser.Api [ApiMember(Name = "IncludeArtists", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool IncludeArtists { get; set; } + [ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string IncludeItemTypes { get; set; } + public GetSearchHints() { IncludeArtists = true; @@ -130,7 +133,8 @@ namespace MediaBrowser.Api IncludePeople = request.IncludePeople, IncludeStudios = request.IncludeStudios, StartIndex = request.StartIndex, - UserId = request.UserId + UserId = request.UserId, + IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',') }).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index d26bf5b352..089f9b6ad2 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Collections { public string Name { get; set; } - public Guid ParentId { get; set; } + public Guid? ParentId { get; set; } public bool IsLocked { get; set; } } diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index a1e6b2c120..d7bc178ad3 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace MediaBrowser.Controller.Collections @@ -16,16 +17,16 @@ namespace MediaBrowser.Controller.Collections /// Adds to collection. /// /// The collection identifier. - /// The item identifier. + /// The item ids. /// Task. - Task AddToCollection(Guid collectionId, Guid itemId); + Task AddToCollection(Guid collectionId, IEnumerable itemIds); /// /// Removes from collection. /// /// The collection identifier. - /// The item identifier. + /// The item ids. /// Task. - Task RemoveFromCollection(Guid collectionId, Guid itemId); + Task RemoveFromCollection(Guid collectionId, IEnumerable itemIds); } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 923673bd83..0deebeb323 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -124,6 +124,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool IsHidden + { + get + { + return false; + } + } + [IgnoreDataMember] public virtual bool IsOwnedItem { diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 8f70710003..29d66718c4 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Entities; - + namespace MediaBrowser.Controller.Entities { /// @@ -8,18 +7,6 @@ namespace MediaBrowser.Controller.Entities /// public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem { - /// - /// Gets or sets the type of the location. - /// - /// The type of the location. - public override LocationType LocationType - { - get - { - return LocationType.Virtual; - } - } - protected BasePluginFolder() { DisplayMediaType = "CollectionFolder"; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 627f657ab3..7dfe7f22e1 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -264,7 +264,7 @@ namespace MediaBrowser.Controller.Entities [IgnoreDataMember] public IEnumerable Children { - get { return ActualChildren; } + get { return ActualChildren.Where(i => !i.IsHidden); } } /// @@ -905,13 +905,6 @@ namespace MediaBrowser.Controller.Entities /// BaseItem. private BaseItem GetLinkedChild(LinkedChild info) { - if (string.IsNullOrEmpty(info.Path)) - { - throw new ArgumentException("Encountered linked child with empty path."); - } - - BaseItem item = null; - // First get using the cached Id if (info.ItemId.HasValue) { @@ -920,20 +913,19 @@ namespace MediaBrowser.Controller.Entities return null; } - item = LibraryManager.GetItemById(info.ItemId.Value); + var itemById = LibraryManager.GetItemById(info.ItemId.Value); + + if (itemById != null) + { + return itemById; + } } - // If still null, search by path - if (item == null) - { - item = LibraryManager.RootFolder.FindByPath(info.Path); - } + var item = FindLinkedChild(info); // If still null, log if (item == null) { - Logger.Warn("Unable to find linked item at {0}", info.Path); - // Don't keep searching over and over info.ItemId = Guid.Empty; } @@ -946,6 +938,43 @@ namespace MediaBrowser.Controller.Entities return item; } + private BaseItem FindLinkedChild(LinkedChild info) + { + if (!string.IsNullOrEmpty(info.Path)) + { + var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); + + if (itemByPath == null) + { + Logger.Warn("Unable to find linked item at path {0}", info.Path); + } + + return itemByPath; + } + + if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) + { + return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => + { + if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) + { + if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) + { + if (info.ItemYear.HasValue) + { + return info.ItemYear.Value == (i.ProductionYear ?? -1); + } + return true; + } + } + + return false; + }); + } + + return null; + } + protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; @@ -1106,5 +1135,10 @@ namespace MediaBrowser.Controller.Entities return GetRecursiveChildren(user).Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) .All(i => i.IsUnplayed(user)); } + + public IEnumerable GetHiddenChildren() + { + return ActualChildren.Where(i => i.IsHidden); + } } } diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index cc5f7bf38c..84af0500dd 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -9,6 +9,10 @@ namespace MediaBrowser.Controller.Entities public string Path { get; set; } public LinkedChildType Type { get; set; } + public string ItemName { get; set; } + public string ItemType { get; set; } + public int? ItemYear { get; set; } + /// /// Serves as a cache /// diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs index 87ff7af669..678dfd39d7 100644 --- a/MediaBrowser.Model/Search/SearchQuery.cs +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -33,6 +33,8 @@ namespace MediaBrowser.Model.Search public bool IncludeStudios { get; set; } public bool IncludeArtists { get; set; } + public string[] IncludeItemTypes { get; set; } + public SearchQuery() { IncludeArtists = true; @@ -40,6 +42,8 @@ namespace MediaBrowser.Model.Search IncludeMedia = true; IncludePeople = true; IncludeStudios = true; + + IncludeItemTypes = new string[] { }; } } } diff --git a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs index b8ab55db08..03fe5c8029 100644 --- a/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.Providers/Savers/XmlSaverHelpers.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; @@ -82,7 +83,8 @@ namespace MediaBrowser.Providers.Savers "TVRageId", "VoteCount", "Website", - "Zap2ItId" + "Zap2ItId", + "CollectionItems" }.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); @@ -580,6 +582,12 @@ namespace MediaBrowser.Providers.Savers builder.Append(""); } + + var folder = item as BoxSet; + if (folder != null) + { + AddCollectionItems(folder, builder); + } } public static void AddChapters(Video item, StringBuilder builder, IItemRepository repository) @@ -631,5 +639,34 @@ namespace MediaBrowser.Providers.Savers } } } + + public static void AddCollectionItems(Folder item, StringBuilder builder) + { + var items = item.LinkedChildren + .Where(i => i.Type == LinkedChildType.Manual && !string.IsNullOrWhiteSpace(i.ItemName)) + .ToList(); + + if (items.Count == 0) + { + return; + } + + builder.Append(""); + foreach (var link in items) + { + builder.Append(""); + + builder.Append("" + SecurityElement.Escape(link.ItemName) + ""); + builder.Append("" + SecurityElement.Escape(link.ItemType) + ""); + + if (link.ItemYear.HasValue) + { + builder.Append("" + SecurityElement.Escape(link.ItemYear.Value.ToString(UsCulture)) + ""); + } + + builder.Append(""); + } + builder.Append(""); + } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index da444d100a..679b629a86 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -5,7 +5,9 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -30,7 +32,7 @@ namespace MediaBrowser.Server.Implementations.Collections var folderName = _fileSystem.GetValidFilename(name); - var parentFolder = _libraryManager.GetItemById(options.ParentId) as Folder; + var parentFolder = GetParentFolder(options.ParentId); if (parentFolder == null) { @@ -66,14 +68,94 @@ namespace MediaBrowser.Server.Implementations.Collections } } - public Task AddToCollection(Guid collectionId, Guid itemId) + private Folder GetParentFolder(Guid? parentId) { - throw new NotImplementedException(); + if (parentId.HasValue) + { + if (parentId.Value == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + return _libraryManager.GetItemById(parentId.Value) as Folder; + } + + return _libraryManager.RootFolder.Children.OfType().FirstOrDefault() ?? + _libraryManager.RootFolder.GetHiddenChildren().OfType().FirstOrDefault(); } - public Task RemoveFromCollection(Guid collectionId, Guid itemId) + public async Task AddToCollection(Guid collectionId, IEnumerable ids) { - throw new NotImplementedException(); + var collection = _libraryManager.GetItemById(collectionId) as BoxSet; + + if (collection == null) + { + throw new ArgumentException("No collection exists with the supplied Id"); + } + + var list = new List(); + + foreach (var itemId in ids) + { + var item = _libraryManager.GetItemById(itemId); + + if (item == null) + { + throw new ArgumentException("No item exists with the supplied Id"); + } + + if (collection.LinkedChildren.Any(i => i.ItemId.HasValue && i.ItemId == itemId)) + { + throw new ArgumentException("Item already exists in collection"); + } + + list.Add(new LinkedChild + { + ItemName = item.Name, + ItemYear = item.ProductionYear, + ItemType = item.GetType().Name, + Type = LinkedChildType.Manual + }); + } + + collection.LinkedChildren.AddRange(list); + + await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + + await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + } + + public async Task RemoveFromCollection(Guid collectionId, IEnumerable itemIds) + { + var collection = _libraryManager.GetItemById(collectionId) as BoxSet; + + if (collection == null) + { + throw new ArgumentException("No collection exists with the supplied Id"); + } + + var list = new List(); + + foreach (var itemId in itemIds) + { + var child = collection.LinkedChildren.FirstOrDefault(i => i.ItemId.HasValue && i.ItemId.Value == itemId); + + if (child == null) + { + throw new ArgumentException("No collection title exists with the supplied Id"); + } + + list.Add(child); + } + + foreach (var child in list) + { + collection.LinkedChildren.Remove(child); + } + + await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + + await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs new file mode 100644 index 0000000000..834fbcd315 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Collections/CollectionsDynamicFolder.cs @@ -0,0 +1,55 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Entities; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Collections +{ + public class CollectionsDynamicFolder : IVirtualFolderCreator + { + private readonly IApplicationPaths _appPaths; + + public CollectionsDynamicFolder(IApplicationPaths appPaths) + { + _appPaths = appPaths; + } + + public BasePluginFolder GetFolder() + { + var path = Path.Combine(_appPaths.DataPath, "collections"); + + Directory.CreateDirectory(path); + + return new ManualCollectionsFolder + { + Path = path + }; + } + } + + public class ManualCollectionsFolder : BasePluginFolder + { + public ManualCollectionsFolder() + { + Name = "Collections"; + } + + public override bool IsVisible(User user) + { + if (!GetChildren(user, true).Any()) + { + return false; + } + + return base.IsVisible(user); + } + + public override bool IsHidden + { + get + { + return !ActualChildren.Any() || base.IsHidden; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 12686f5426..b22fd343b3 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -37,6 +37,12 @@ namespace MediaBrowser.Server.Implementations.Library var results = await GetSearchHints(inputItems, query).ConfigureAwait(false); + // Include item types + if (query.IncludeItemTypes.Length > 0) + { + results = results.Where(f => query.IncludeItemTypes.Contains(f.Item.GetType().Name, StringComparer.OrdinalIgnoreCase)); + } + var searchResultArray = results.ToArray(); results = searchResultArray; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index bd315530e1..104ebfab84 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -583,6 +583,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); programs = programList.OrderByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) + .ThenBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) .ThenBy(i => i.StartDate); if (query.Limit.HasValue) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 0165cefad8..a0df2c23ac 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -65,12 +65,9 @@ - + False - ..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.dll - - - ..\packages\System.Data.SQLite.x86.1.0.90.0\lib\net45\System.Data.SQLite.Linq.dll + ..\packages\System.Data.SQLite.Core.1.0.91.3\lib\net45\System.Data.SQLite.dll @@ -110,6 +107,7 @@ + @@ -378,6 +376,12 @@ swagger-ui\swagger-ui.min.js PreserveNewest + + Always + + + Always + diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 3c984e2656..f04536190b 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config index 53788e09af..978f318515 100644 --- a/MediaBrowser.ServerApplication/App.config +++ b/MediaBrowser.ServerApplication/App.config @@ -2,6 +2,8 @@
+ +
@@ -43,7 +45,7 @@ - + @@ -63,4 +65,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 479e07ee6c..a3a8785371 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -9,6 +9,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; +using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -36,6 +37,7 @@ using MediaBrowser.Model.Updates; using MediaBrowser.Providers.Manager; using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Implementations.BdInfo; +using MediaBrowser.Server.Implementations.Collections; using MediaBrowser.Server.Implementations.Configuration; using MediaBrowser.Server.Implementations.Drawing; using MediaBrowser.Server.Implementations.Dto; @@ -488,6 +490,9 @@ namespace MediaBrowser.ServerApplication var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger); RegisterSingleInstance(appThemeManager); + var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor); + RegisterSingleInstance(collectionManager); + LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager); RegisterSingleInstance(LiveTvManager); diff --git a/MediaBrowser.Tests/app.config b/MediaBrowser.Tests/app.config index cbc4501c5c..3359125c3b 100644 --- a/MediaBrowser.Tests/app.config +++ b/MediaBrowser.Tests/app.config @@ -4,7 +4,7 @@ - + diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index c10b17d678..19f213b2ff 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -480,6 +480,7 @@ namespace MediaBrowser.WebDashboard.Api "dashboardinfo.js", "dashboardpage.js", "directorybrowser.js", + "editcollectionitems.js", "edititemmetadata.js", "edititempeople.js", "edititemimages.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 4895d203f5..424192e283 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -213,6 +213,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -261,7 +264,7 @@ PreserveNewest - + PreserveNewest @@ -480,6 +483,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest From 546acf0ebb7edce384822770ccc6fca43fb2cc1c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 13:48:55 -0500 Subject: [PATCH 07/31] fixes #715 - Support creating/editing collections (boxsets) in web client #715 --- MediaBrowser.Api/SearchService.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 4 +- .../Entities/LinkedChild.cs | 6 +- .../Library/IUserManager.cs | 3 +- .../BoxSets/BoxSetMetadataService.cs | 10 ++ .../BoxSets/BoxSetXmlParser.cs | 129 ++++++++++++++++++ .../BoxSets/BoxSetXmlProvider.cs | 2 +- .../MediaBrowser.Providers.csproj | 1 + .../Collections/CollectionManager.cs | 34 ++++- .../Library/UserManager.cs | 9 +- .../LiveTv/LiveTvManager.cs | 4 +- 11 files changed, 184 insertions(+), 20 deletions(-) create mode 100644 MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index c3da87d401..455cf6a50c 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -134,7 +134,7 @@ namespace MediaBrowser.Api IncludeStudios = request.IncludeStudios, StartIndex = request.StartIndex, UserId = request.UserId, - IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',') + IncludeItemTypes = (request.IncludeItemTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray() }).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 7dfe7f22e1..ee371680ef 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -745,9 +745,9 @@ namespace MediaBrowser.Controller.Entities var list = new List(); - AddChildrenToList(user, includeLinkedChildren, list, false, null); + var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, null); - return list; + return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; } /// diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 84af0500dd..1ae04e40f9 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -22,8 +22,8 @@ namespace MediaBrowser.Controller.Entities public enum LinkedChildType { - Manual = 1, - Shortcut = 2 + Manual = 0, + Shortcut = 1 } public class LinkedChildComparer : IEqualityComparer @@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Entities public int GetHashCode(LinkedChild obj) { - return (obj.Path + obj.Type.ToString()).GetHashCode(); + return (obj.Path + obj.Type).GetHashCode(); } } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 0502ec4197..c3b0748cf8 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -51,9 +51,8 @@ namespace MediaBrowser.Controller.Library /// Refreshes metadata for each user /// /// The cancellation token. - /// if set to true [force]. /// Task. - Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false); + Task RefreshUsersMetadata(CancellationToken cancellationToken); /// /// Renames the user. diff --git a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs index 9547eedd94..49e616d1a2 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetMetadataService.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -37,6 +38,15 @@ namespace MediaBrowser.Providers.BoxSets protected override void MergeData(BoxSet source, BoxSet target, List lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + + if (mergeMetadataSettings) + { + var list = source.LinkedChildren.ToList(); + + list.AddRange(target.LinkedChildren.Where(i => i.Type == LinkedChildType.Shortcut)); + + target.LinkedChildren = list; + } } protected override ItemUpdateType BeforeSave(BoxSet item) diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs new file mode 100644 index 0000000000..eb3c99cef5 --- /dev/null +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlParser.cs @@ -0,0 +1,129 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Logging; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; + +namespace MediaBrowser.Providers.BoxSets +{ + public class BoxSetXmlParser : BaseItemXmlParser + { + private readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + public BoxSetXmlParser(ILogger logger) + : base(logger) + { + } + + protected override void FetchDataFromXmlNode(XmlReader reader, BoxSet item) + { + switch (reader.Name) + { + case "CollectionItems": + + using (var subReader = reader.ReadSubtree()) + { + FetchFromCollectionItemsNode(subReader, item); + } + break; + + default: + base.FetchDataFromXmlNode(reader, item); + break; + } + } + + private void FetchFromCollectionItemsNode(XmlReader reader, BoxSet item) + { + reader.MoveToContent(); + + var list = new List(); + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "CollectionItem": + { + using (var subReader = reader.ReadSubtree()) + { + var child = GetLinkedChild(subReader); + + if (child != null) + { + list.Add(child); + } + } + + break; + } + + default: + reader.Skip(); + break; + } + } + } + + item.LinkedChildren = list; + } + + private LinkedChild GetLinkedChild(XmlReader reader) + { + reader.MoveToContent(); + + var linkedItem = new LinkedChild + { + Type = LinkedChildType.Manual + }; + + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Name": + { + linkedItem.ItemName = reader.ReadElementContentAsString(); + break; + } + + case "Type": + { + linkedItem.ItemType = reader.ReadElementContentAsString(); + break; + } + + case "Year": + { + var val = reader.ReadElementContentAsString(); + + if (!string.IsNullOrWhiteSpace(val)) + { + int rval; + + if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) + { + linkedItem.ItemYear = rval; + } + } + + break; + } + + default: + reader.Skip(); + break; + } + } + } + + return string.IsNullOrWhiteSpace(linkedItem.ItemName) || string.IsNullOrWhiteSpace(linkedItem.ItemType) ? null : linkedItem; + } + } +} diff --git a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs index e9896c28ed..77ea52fa93 100644 --- a/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs +++ b/MediaBrowser.Providers/BoxSets/BoxSetXmlProvider.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.BoxSets protected override void Fetch(LocalMetadataResult result, string path, CancellationToken cancellationToken) { - new BaseItemXmlParser(_logger).Fetch(result.Item, path, cancellationToken); + new BoxSetXmlParser(_logger).Fetch(result.Item, path, cancellationToken); } protected override FileInfo GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index a5ea1b64b2..79cbdfa68b 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -75,6 +75,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 679b629a86..5a5dfdd3ef 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -148,9 +148,39 @@ namespace MediaBrowser.Server.Implementations.Collections list.Add(child); } - foreach (var child in list) + var shortcutFiles = Directory + .EnumerateFiles(collection.Path, "*", SearchOption.TopDirectoryOnly) + .Where(i => _fileSystem.IsShortcut(i)) + .ToList(); + + var shortcutFilesToDelete = list.Where(child => !string.IsNullOrWhiteSpace(child.Path) && child.Type == LinkedChildType.Shortcut) + .Select(child => shortcutFiles.FirstOrDefault(i => string.Equals(child.Path, _fileSystem.ResolveShortcut(i), StringComparison.OrdinalIgnoreCase))) + .Where(i => !string.IsNullOrWhiteSpace(i)) + .ToList(); + + foreach (var file in shortcutFilesToDelete) { - collection.LinkedChildren.Remove(child); + _iLibraryMonitor.ReportFileSystemChangeBeginning(file); + } + + try + { + foreach (var file in shortcutFilesToDelete) + { + File.Delete(file); + } + + foreach (var child in list) + { + collection.LinkedChildren.Remove(child); + } + } + finally + { + foreach (var file in shortcutFilesToDelete) + { + _iLibraryMonitor.ReportFileSystemChangeComplete(file, false); + } } await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 8654a26ce6..06028d37ec 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -189,15 +189,10 @@ namespace MediaBrowser.Server.Implementations.Library /// Refreshes metadata for each user /// /// The cancellation token. - /// if set to true [force]. /// Task. - public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) + public Task RefreshUsersMetadata(CancellationToken cancellationToken) { - var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions - { - ReplaceAllMetadata = force - - }, cancellationToken)).ToList(); + var tasks = Users.Select(user => user.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken)).ToList(); return Task.WhenAll(tasks); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 104ebfab84..7c0361a1fe 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -582,8 +582,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv .Select(i => _libraryManager.GetGenre(i)) .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); - programs = programList.OrderByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) - .ThenBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) + programs = programList.OrderBy(i => i.HasImage(ImageType.Primary) ? 0 : 1) + .ThenByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres)) .ThenBy(i => i.StartDate); if (query.Limit.HasValue) From 9b55579a855cbdd0feec0caff0398f0771edca9e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 14:31:05 -0500 Subject: [PATCH 08/31] #715 - hide New Collection button for non-admins --- .../MediaBrowser.ServerApplication.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index c3eb4fd6ab..227d0dd1d3 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -235,6 +235,12 @@ xcopy "$(TargetDir)*.dll" "$(SolutionDir)..\Deploy\Server\System" /y mkdir "$(SolutionDir)..\Deploy\Server\System\dashboard-ui" xcopy "$(TargetDir)dashboard-ui" "$(SolutionDir)..\Deploy\Server\System\dashboard-ui" /y /s +mkdir "$(SolutionDir)..\Deploy\Server\System\x86" +xcopy "$(TargetDir)x86" "$(SolutionDir)..\Deploy\Server\System\x86" /y /s + +mkdir "$(SolutionDir)..\Deploy\Server\System\x64" +xcopy "$(TargetDir)x64" "$(SolutionDir)..\Deploy\Server\System\x64" /y /s + del "$(SolutionDir)..\Deploy\MBServer.zip" "$(SolutionDir)ThirdParty\7zip\7za" a -mx9 "$(SolutionDir)..\Deploy\MBServer.zip" "$(SolutionDir)..\Deploy\Server\*" ) From f13a84e8d9f54a57fd40be3404be0ddf5ed5e2cd Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Fri, 7 Mar 2014 16:24:01 -0500 Subject: [PATCH 09/31] Add photo backdrops --- MediaBrowser.Providers/Photos/PhotoProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs index 66344d1d1a..a89919d3f8 100644 --- a/MediaBrowser.Providers/Photos/PhotoProvider.cs +++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs @@ -25,6 +25,7 @@ namespace MediaBrowser.Providers.Photos public Task FetchAsync(Photo item, IDirectoryService directoryService, CancellationToken cancellationToken) { item.SetImagePath(ImageType.Primary, item.Path); + item.SetImagePath(ImageType.Backdrop, item.Path); if (item.Path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) || item.Path.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)) { From c6bd890cb2976c4cbf5c278a5987320dcb631652 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 7 Mar 2014 23:20:31 -0500 Subject: [PATCH 10/31] refined collection editing --- .../Collections/CollectionCreationOptions.cs | 13 +++++++++++-- .../Collections/CollectionManager.cs | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 089f9b6ad2..e147e09056 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -1,13 +1,22 @@ -using System; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; namespace MediaBrowser.Controller.Collections { - public class CollectionCreationOptions + public class CollectionCreationOptions : IHasProviderIds { public string Name { get; set; } public Guid? ParentId { get; set; } public bool IsLocked { get; set; } + + public Dictionary ProviderIds { get; set; } + + public CollectionCreationOptions() + { + ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); + } } } diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 5a5dfdd3ef..1cfcef5140 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -30,7 +30,10 @@ namespace MediaBrowser.Server.Implementations.Collections { var name = options.Name; - var folderName = _fileSystem.GetValidFilename(name); + // Need to use the [boxset] suffix + // If internet metadata is not found, or if xml saving is off there will be no collection.xml + // This could cause it to get re-resolved as a plain folder + var folderName = _fileSystem.GetValidFilename(name) + " [boxset]"; var parentFolder = GetParentFolder(options.ParentId); @@ -53,7 +56,8 @@ namespace MediaBrowser.Server.Implementations.Collections Parent = parentFolder, DisplayMediaType = "Collection", Path = path, - DontFetchMeta = options.IsLocked + DontFetchMeta = options.IsLocked, + ProviderIds = options.ProviderIds }; await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false); From 1ead63b0d1a532cf828a4ed7c5310eef9c255740 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 8 Mar 2014 13:17:05 -0500 Subject: [PATCH 11/31] add column sorting to reports --- MediaBrowser.Model/ApiClient/IApiClient.cs | 63 +++++++++++++++++++ MediaBrowser.Model/Querying/ItemSortBy.cs | 3 + ...MediaBrowser.Server.Implementations.csproj | 7 ++- .../Sorting/GameSystemComparer.cs | 54 ++++++++++++++++ .../Sorting/PlayersComparer.cs | 46 ++++++++++++++ .../Sorting/StudioComparer.cs | 30 +++++++++ Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 9 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs create mode 100644 MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 2a965114bf..a0e527a99d 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -1016,6 +1016,15 @@ namespace MediaBrowser.Model.ApiClient /// Task{QueryResult{ProgramInfoDto}}. Task> GetLiveTvProgramsAsync(ProgramQuery query, CancellationToken cancellationToken); + /// + /// Gets the live tv program asynchronous. + /// + /// The identifier. + /// The user identifier. + /// The cancellation token. + /// Task{ProgramInfoDto}. + Task GetLiveTvProgramAsync(string id, string userId, CancellationToken cancellationToken); + /// /// Gets the recommended live tv programs asynchronous. /// @@ -1023,6 +1032,38 @@ namespace MediaBrowser.Model.ApiClient /// The cancellation token. /// Task{QueryResult{ProgramInfoDto}}. Task> GetRecommendedLiveTvProgramsAsync(RecommendedProgramQuery query, CancellationToken cancellationToken); + + /// + /// Creates the live tv timer asynchronous. + /// + /// The timer. + /// The cancellation token. + /// Task. + Task CreateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken); + + /// + /// Updates the live tv timer asynchronous. + /// + /// The timer. + /// The cancellation token. + /// Task. + Task UpdateLiveTvTimerAsync(TimerInfoDto timer, CancellationToken cancellationToken); + + /// + /// Creates the live tv series timer asynchronous. + /// + /// The timer. + /// The cancellation token. + /// Task. + Task CreateLiveTvSeriesTimerAsync(SeriesTimerInfoDto timer, CancellationToken cancellationToken); + + /// + /// Updates the live tv series timer asynchronous. + /// + /// The timer. + /// The cancellation token. + /// Task. + Task UpdateLiveTvSeriesTimerAsync(SeriesTimerInfoDto timer, CancellationToken cancellationToken); /// /// Gets the live tv timer asynchronous. @@ -1071,5 +1112,27 @@ namespace MediaBrowser.Model.ApiClient /// The cancellation token. /// Task. Task DeleteLiveTvRecordingAsync(string id, CancellationToken cancellationToken); + + /// + /// Gets the default timer information. + /// + /// The cancellation token. + /// Task{SeriesTimerInfoDto}. + Task GetDefaultLiveTvTimerInfo(CancellationToken cancellationToken); + + /// + /// Gets the live tv guide information. + /// + /// The cancellation token. + /// Task{GuideInfo}. + Task GetLiveTvGuideInfo(CancellationToken cancellationToken); + + /// + /// Gets the default timer information. + /// + /// The program identifier. + /// The cancellation token. + /// Task{SeriesTimerInfoDto}. + Task GetDefaultLiveTvTimerInfo(string programId, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs index 09b8f0e18f..b07db396a0 100644 --- a/MediaBrowser.Model/Querying/ItemSortBy.cs +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -86,5 +86,8 @@ namespace MediaBrowser.Model.Querying public const string VideoBitRate = "VideoBitRate"; public const string AirTime = "AirTime"; public const string Metascore = "Metascore"; + public const string Studio = "Studio"; + public const string Players = "Players"; + public const string GameSystem = "GameSystem"; } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index a0df2c23ac..78902f0dcc 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -225,6 +225,7 @@ + @@ -233,6 +234,7 @@ + @@ -246,6 +248,7 @@ + @@ -376,10 +379,10 @@ swagger-ui\swagger-ui.min.js PreserveNewest - + Always - + Always diff --git a/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs b/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs new file mode 100644 index 0000000000..eb83b98e97 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/GameSystemComparer.cs @@ -0,0 +1,54 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Querying; +using System; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class GameSystemComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Gets the value. + /// + /// The x. + /// System.String. + private string GetValue(BaseItem x) + { + var game = x as Game; + + if (game != null) + { + return game.GameSystem; + } + + var system = x as GameSystem; + + if (system != null) + { + return system.GameSystemName; + } + + return string.Empty; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.GameSystem; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs new file mode 100644 index 0000000000..5bcd080d7b --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/PlayersComparer.cs @@ -0,0 +1,46 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Querying; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class PlayersComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return GetValue(x).CompareTo(GetValue(y)); + } + + /// + /// Gets the value. + /// + /// The x. + /// System.String. + private int GetValue(BaseItem x) + { + var game = x as Game; + + if (game != null) + { + return game.PlayersSupported ?? 0; + } + + return 0; + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Players; } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs b/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs new file mode 100644 index 0000000000..83ab4dfc26 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sorting/StudioComparer.cs @@ -0,0 +1,30 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Querying; +using System.Linq; + +namespace MediaBrowser.Server.Implementations.Sorting +{ + public class StudioComparer : IBaseItemComparer + { + /// + /// Compares the specified x. + /// + /// The x. + /// The y. + /// System.Int32. + public int Compare(BaseItem x, BaseItem y) + { + return AlphanumComparator.CompareValues(x.Studios.FirstOrDefault() ?? string.Empty, y.Studios.FirstOrDefault() ?? string.Empty); + } + + /// + /// Gets the name. + /// + /// The name. + public string Name + { + get { return ItemSortBy.Studio; } + } + } +} diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 7bd20e7d4d..3e548e6252 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.336 + 3.0.339 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index f68a427414..5b81a046e5 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.336 + 3.0.339 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 97f4c90a03..bf8bfd1575 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.336 + 3.0.339 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + From b7b8cb508431635ff777bcf59d4ab25785471e4f Mon Sep 17 00:00:00 2001 From: 7illusions Date: Sat, 8 Mar 2014 22:36:12 +0100 Subject: [PATCH 12/31] Added UserId To API Remotecontrol-calls --- MediaBrowser.Api/SessionsService.cs | 47 ++++++++++++++++++- .../MediaBrowser.Model.Portable.csproj | 7 ++- MediaBrowser.Model/Session/BrowseRequest.cs | 4 ++ MediaBrowser.Model/Session/MessageCommand.cs | 5 +- MediaBrowser.Model/Session/PlayRequest.cs | 12 +++++ .../Session/PlaystateCommand.cs | 3 ++ 6 files changed, 74 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index f662e38170..562e455259 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -46,6 +46,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid Id { get; set; } + /// + /// Gets or sets the UserId. + /// + /// The id. + [ApiMember(Name = "UserId", Description = "The controlling User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid UserId { get; set; } + //TODO IsRequired = false shall be changed to true once the clients has been updated and the new ApiClient is in use + /// /// Artist, Genre, Studio, Person, or any kind of BaseItem /// @@ -88,6 +96,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid Id { get; set; } + /// + /// Gets or sets the UserId. + /// + /// The id. + [ApiMember(Name = "UserId", Description = "The controlling User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid UserId { get; set; } + //TODO IsRequired = false shall be changed to true once the clients has been updated and the new ApiClient is in use + /// /// Artist, Genre, Studio, Person, or any kind of BaseItem /// @@ -121,6 +137,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid Id { get; set; } + /// + /// Gets or sets the UserId. + /// + /// The id. + [ApiMember(Name = "UserId", Description = "The controlling User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid UserId { get; set; } + //TODO IsRequired = false shall be changed to true once the clients has been updated and the new ApiClient is in use + /// /// Gets or sets the position to seek to /// @@ -146,6 +170,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid Id { get; set; } + /// + /// Gets or sets the UserId. + /// + /// The id. + [ApiMember(Name = "UserId", Description = "The controlling User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid UserId { get; set; } + //TODO IsRequired = false shall be changed to true once the clients has been updated and the new ApiClient is in use + /// /// Gets or sets the command. /// @@ -165,6 +197,14 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] public Guid Id { get; set; } + /// + /// Gets or sets the UserId. + /// + /// The id. + [ApiMember(Name = "UserId", Description = "The controlling User Id", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "POST")] + public Guid UserId { get; set; } + //TODO IsRequired = false shall be changed to true once the clients has been updated and the new ApiClient is in use + [ApiMember(Name = "Text", Description = "The message text.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string Text { get; set; } @@ -270,9 +310,10 @@ namespace MediaBrowser.Api } public void Post(SendPlaystateCommand request) - { + { var command = new PlaystateRequest { + UserId = request.UserId, Command = request.Command, SeekPositionTicks = request.SeekPositionTicks }; @@ -290,6 +331,7 @@ namespace MediaBrowser.Api { var command = new BrowseRequest { + UserId = request.UserId, Context = request.Context, ItemId = request.ItemId, ItemName = request.ItemName, @@ -321,6 +363,7 @@ namespace MediaBrowser.Api var command = new MessageCommand { Header = string.IsNullOrEmpty(request.Header) ? "Message from Server" : request.Header, + UserId = request.UserId, TimeoutMs = request.TimeoutMs, Text = request.Text }; @@ -339,7 +382,7 @@ namespace MediaBrowser.Api var command = new PlayRequest { ItemIds = request.ItemIds.Split(',').ToArray(), - + UserId = request.UserId, PlayCommand = request.PlayCommand, StartPositionTicks = request.StartPositionTicks }; diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 04296de355..ccc05492ca 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -11,12 +11,17 @@ MediaBrowser.Model MediaBrowser.Model v4.0 - Profile104 + Profile158 512 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\ true ..\packages\Fody.1.19.1.0 + + + + + 4.0 true diff --git a/MediaBrowser.Model/Session/BrowseRequest.cs b/MediaBrowser.Model/Session/BrowseRequest.cs index abb3a30abf..03241860c8 100644 --- a/MediaBrowser.Model/Session/BrowseRequest.cs +++ b/MediaBrowser.Model/Session/BrowseRequest.cs @@ -1,4 +1,6 @@  +using System; + namespace MediaBrowser.Model.Session { /// @@ -12,6 +14,8 @@ namespace MediaBrowser.Model.Session /// The type of the item. public string ItemType { get; set; } + public Guid UserId { get; set; } + /// /// Gets or sets the item id. /// diff --git a/MediaBrowser.Model/Session/MessageCommand.cs b/MediaBrowser.Model/Session/MessageCommand.cs index 5ab5808151..754c057faa 100644 --- a/MediaBrowser.Model/Session/MessageCommand.cs +++ b/MediaBrowser.Model/Session/MessageCommand.cs @@ -1,8 +1,11 @@  +using System; namespace MediaBrowser.Model.Session { public class MessageCommand - { + { + public Guid UserId { get; set; } + public string Header { get; set; } public string Text { get; set; } diff --git a/MediaBrowser.Model/Session/PlayRequest.cs b/MediaBrowser.Model/Session/PlayRequest.cs index c9bb586931..239fb65729 100644 --- a/MediaBrowser.Model/Session/PlayRequest.cs +++ b/MediaBrowser.Model/Session/PlayRequest.cs @@ -1,4 +1,5 @@  +using System; namespace MediaBrowser.Model.Session { /// @@ -6,6 +7,11 @@ namespace MediaBrowser.Model.Session /// public class PlayRequest { + public PlayRequest() + { + + } + /// /// Gets or sets the item ids. /// @@ -23,6 +29,12 @@ namespace MediaBrowser.Model.Session /// /// The play command. public PlayCommand PlayCommand { get; set; } + + /// + /// Gets or sets the play command. + /// + /// The play command. + public Guid UserId { get; set; } } /// diff --git a/MediaBrowser.Model/Session/PlaystateCommand.cs b/MediaBrowser.Model/Session/PlaystateCommand.cs index 7e85d9d276..68e80c4521 100644 --- a/MediaBrowser.Model/Session/PlaystateCommand.cs +++ b/MediaBrowser.Model/Session/PlaystateCommand.cs @@ -1,4 +1,5 @@  +using System; namespace MediaBrowser.Model.Session { /// @@ -34,6 +35,8 @@ namespace MediaBrowser.Model.Session public class PlaystateRequest { + public Guid UserId { get; set; } + public PlaystateCommand Command { get; set; } public long? SeekPositionTicks { get; set; } From 1c90611cf3c08829831f2ff8e071b884fc44acff Mon Sep 17 00:00:00 2001 From: 7illusions Date: Sun, 9 Mar 2014 08:33:48 +0100 Subject: [PATCH 13/31] Updated IApicClient With UserId --- MediaBrowser.Model/ApiClient/IApiClient.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index a0e527a99d..2924898693 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -572,17 +572,18 @@ namespace MediaBrowser.Model.ApiClient /// Instructs antoher client to browse to a library item. /// /// The session id. + /// The controlling user id. /// The id of the item to browse to. /// The name of the item to browse to. /// The type of the item to browse to. /// Optional ui context (movies, music, tv, games, etc). The client is free to ignore this. /// Task. - Task SendBrowseCommandAsync(string sessionId, string itemId, string itemName, string itemType, string context); + Task SendBrowseCommandAsync(string sessionId, string userId, string itemId, string itemName, string itemType, string context); /// /// Sends the playstate command async. /// - /// The session id. + /// The session id. /// The request. /// Task. Task SendPlaystateCommandAsync(string sessionId, PlaystateRequest request); From d49494476770b3c0a091841bd3bbd44862fb8137 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 9 Mar 2014 18:14:44 -0400 Subject: [PATCH 14/31] calculate item by name counts on the fly --- MediaBrowser.Api/BaseApiService.cs | 5 +- .../DefaultTheme/DefaultThemeService.cs | 6 +- .../Playback/BaseStreamingService.cs | 81 ++++++------ MediaBrowser.Api/SearchService.cs | 6 +- .../UserLibrary/ArtistsService.cs | 14 +-- .../UserLibrary/BaseItemsByNameService.cs | 38 +++--- .../UserLibrary/GameGenresService.cs | 9 +- MediaBrowser.Api/UserLibrary/GenresService.cs | 9 +- .../UserLibrary/MusicGenresService.cs | 9 +- .../UserLibrary/PersonsService.cs | 9 +- .../UserLibrary/StudiosService.cs | 9 +- MediaBrowser.Api/UserLibrary/YearsService.cs | 19 +-- .../Channels/ChannelItemInfo.cs | 67 ++++++++++ MediaBrowser.Controller/Channels/IChannel.cs | 57 +++++++++ .../Channels/IChannelManager.cs | 12 ++ MediaBrowser.Controller/Dto/IDtoService.cs | 21 ++++ .../Entities/Audio/Audio.cs | 18 +++ .../Entities/Audio/MusicArtist.cs | 11 +- .../Entities/Audio/MusicGenre.cs | 18 ++- MediaBrowser.Controller/Entities/GameGenre.cs | 17 ++- MediaBrowser.Controller/Entities/Genre.cs | 18 ++- .../Entities/IItemByName.cs | 38 ++---- MediaBrowser.Controller/Entities/Person.cs | 17 ++- MediaBrowser.Controller/Entities/Studio.cs | 18 ++- MediaBrowser.Controller/Entities/Year.cs | 29 +++-- .../Library/ILibraryManager.cs | 13 -- .../LiveTv/ILiveTvManager.cs | 7 -- .../LiveTv/LiveTvChannel.cs | 15 +-- .../MediaBrowser.Controller.csproj | 3 + MediaBrowser.Model/Querying/ItemSortBy.cs | 7 -- .../Dto/DtoService.cs | 64 ++++++---- .../Library/LibraryManager.cs | 9 +- .../Library/SearchEngine.cs | 4 +- .../Library/Validators/ArtistsValidator.cs | 45 +------ .../Library/Validators/GameGenresValidator.cs | 62 ++------- .../Library/Validators/GenresValidator.cs | 62 ++------- .../Validators/MusicGenresValidator.cs | 73 ++--------- .../Library/Validators/PeoplePostScanTask.cs | 103 +-------------- .../Library/Validators/PeopleValidator.cs | 6 +- .../Library/Validators/StudiosValidator.cs | 65 ++-------- .../LiveTv/LiveTvManager.cs | 118 ++++++++++++------ ...MediaBrowser.Server.Implementations.csproj | 7 -- .../Sorting/AlbumCountComparer.cs | 71 ----------- .../Sorting/EpisodeCountComparer.cs | 71 ----------- .../Sorting/MovieCountComparer.cs | 71 ----------- .../Sorting/MusicVideoCountComparer.cs | 71 ----------- .../Sorting/SeriesCountComparer.cs | 71 ----------- .../Sorting/SongCountComparer.cs | 71 ----------- .../Sorting/TrailerCountComparer.cs | 71 ----------- 49 files changed, 518 insertions(+), 1197 deletions(-) create mode 100644 MediaBrowser.Controller/Channels/ChannelItemInfo.cs create mode 100644 MediaBrowser.Controller/Channels/IChannel.cs create mode 100644 MediaBrowser.Controller/Channels/IChannelManager.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/AlbumCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/EpisodeCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/MovieCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/MusicVideoCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/SeriesCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/SongCountComparer.cs delete mode 100644 MediaBrowser.Server.Implementations/Sorting/TrailerCountComparer.cs diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 5fba539fe5..08686b43a8 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -164,7 +164,10 @@ namespace MediaBrowser.Api return name; } - return libraryManager.GetAllArtists() + return libraryManager.RootFolder.RecursiveChildren + .OfType