From 2349c8099d04c6c0631cd33e6c74b404381946ab Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 6 Mar 2014 00:17:13 -0500 Subject: [PATCH] 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