diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-08-02 22:16:37 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-08-02 22:16:37 -0400 |
| commit | 2714127d2b663b735048da6d9def08efa38f2b5f (patch) | |
| tree | b260b23486fddf75d2dfa292544c7e03c05a74ce /MediaBrowser.Server.Implementations | |
| parent | f0464dfa17d146f34849e45097085b891e51ebc8 (diff) | |
fixes #791 - Support server-side playlists
Diffstat (limited to 'MediaBrowser.Server.Implementations')
11 files changed, 202 insertions, 36 deletions
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index af1bd9427..567092cae 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -239,7 +239,7 @@ namespace MediaBrowser.Server.Implementations.Channels throw new ApplicationException("Unexpected response type encountered: " + response.ContentType); } - File.Move(response.TempFilePath, destination); + File.Copy(response.TempFilePath, destination, true); await RefreshMediaSourceItem(destination, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 6a87453ab..fe4b16645 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs @@ -162,13 +162,7 @@ namespace MediaBrowser.Server.Implementations.Collections 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 - }); + list.Add(LinkedChild.Create(item)); var supportsGrouping = item as ISupportsBoxSetGrouping; diff --git a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs index aaa02c720..b02c52874 100644 --- a/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs +++ b/MediaBrowser.Server.Implementations/Collections/ManualCollectionsFolder.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Server.Implementations.Collections public ManualCollectionsFolder() { Name = "Collections"; + DisplayMediaType = "CollectionFolder"; } public override bool IsVisible(User user) diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index afcfde556..e3a386841 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -11,6 +11,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Drawing; @@ -179,6 +180,11 @@ namespace MediaBrowser.Server.Implementations.Dto } } + if (item is Playlist) + { + AttachLinkedChildImages(dto, (Folder)item, user); + } + return dto; } @@ -819,7 +825,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.DisplayOrder = hasDisplayOrder.DisplayOrder; } - var collectionFolder = item as CollectionFolder; + var collectionFolder = item as ICollectionFolder; if (collectionFolder != null) { dto.CollectionType = collectionFolder.CollectionType; @@ -1211,6 +1217,45 @@ namespace MediaBrowser.Server.Implementations.Dto } } + private void AttachLinkedChildImages(BaseItemDto dto, Folder folder, User user) + { + List<BaseItem> linkedChildren = null; + + if (dto.BackdropImageTags.Count == 0) + { + if (linkedChildren == null) + { + linkedChildren = user == null + ? folder.GetRecursiveChildren().ToList() + : folder.GetRecursiveChildren(user, true).ToList(); + } + var parentWithBackdrop = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Backdrop).Any()); + + if (parentWithBackdrop != null) + { + dto.ParentBackdropItemId = GetDtoId(parentWithBackdrop); + dto.ParentBackdropImageTags = GetBackdropImageTags(parentWithBackdrop); + } + } + + if (!dto.ImageTags.ContainsKey(ImageType.Primary)) + { + if (linkedChildren == null) + { + linkedChildren = user == null + ? folder.GetRecursiveChildren().ToList() + : folder.GetRecursiveChildren(user, true).ToList(); + } + var parentWithImage = linkedChildren.FirstOrDefault(i => i.GetImages(ImageType.Primary).Any()); + + if (parentWithImage != null) + { + dto.ParentPrimaryImageItemId = GetDtoId(parentWithImage); + dto.ParentPrimaryImageTag = GetImageCacheTag(parentWithImage, ImageType.Primary); + } + } + } + private string GetMappedPath(IHasMetadata item) { var path = item.Path; diff --git a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs index 4e182ea88..1c4ccb141 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs @@ -75,7 +75,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization public bool IsEnabled { - get { return !GetTvOptions().IsEnabled; } + get { return GetTvOptions().IsEnabled; } } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs new file mode 100644 index 000000000..7eff53ce1 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PlaylistResolver.cs @@ -0,0 +1,38 @@ +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Playlists; +using System; +using System.IO; + +namespace MediaBrowser.Server.Implementations.Library.Resolvers +{ + public class PlaylistResolver : FolderResolver<Playlist> + { + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>BoxSet.</returns> + protected override Playlist Resolve(ItemResolveArgs args) + { + // It's a boxset if all of the following conditions are met: + // Is a Directory + // Contains [playlist] in the path + if (args.IsDirectory) + { + var filename = Path.GetFileName(args.Path); + + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1) + { + return new Playlist { Path = args.Path }; + } + } + + return null; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 3a5b91abd..3c1748ef1 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -323,6 +323,13 @@ "HeaderSelectPlayer": "Select Player:", "ButtonSelect": "Select", "ButtonNew": "New", - "MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM plugin for IE.", - "HeaderVideoError": "Video Error" + "MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM plugin for IE.", + "HeaderVideoError": "Video Error", + "ButtonAddToPlaylist": "Add to playlist", + "HeaderAddToPlaylist": "Add to Playlist", + "LabelName": "Name:", + "ButtonSubmit": "Submit", + "LabelSelectPlaylist": "Playlist:", + "OptionNewPlaylist": "New playlist...", + "MessageAddedToPlaylistSuccess": "Ok" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index caf8860fc..471620948 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -808,6 +808,8 @@ "TabNextUp": "Next Up", "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.", "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the New button to start creating Collections.", + "MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.", + "MessageNoPlaylistItemsAvailable": "This playlist is currently empty.", "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client", "ButtonDismiss": "Dismiss", "MessageLearnHowToCustomize": "Learn how to customize this page to your own personal tastes. Click your user icon in the top right corner of the screen to view and update your preferences.", @@ -915,5 +917,7 @@ "OptionProtocolHls": "Http Live Streaming", "LabelContext": "Context:", "OptionContextStreaming": "Streaming", - "OptionContextStatic": "Sync" + "OptionContextStatic": "Sync", + "ButtonAddToPlaylist": "Add to playlist", + "TabPlaylists": "Playlists" } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 8bfbc0855..c60835ee6 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -166,6 +166,7 @@ <Compile Include="Library\LibraryManager.cs" /> <Compile Include="Library\MusicManager.cs" /> <Compile Include="Library\Resolvers\PhotoResolver.cs" /> + <Compile Include="Library\Resolvers\PlaylistResolver.cs" /> <Compile Include="Library\SearchEngine.cs" /> <Compile Include="Library\ResolverHelper.cs" /> <Compile Include="Library\Resolvers\Audio\AudioResolver.cs" /> diff --git a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs index 3b46191b1..a87edde7b 100644 --- a/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs +++ b/MediaBrowser.Server.Implementations/Playlists/ManualPlaylistsFolder.cs @@ -1,5 +1,7 @@ -using MediaBrowser.Common.Configuration; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Playlists; using System.IO; using System.Linq; @@ -14,8 +16,15 @@ namespace MediaBrowser.Server.Implementations.Playlists public override bool IsVisible(User user) { - return GetChildren(user, true).Any() && - base.IsVisible(user); + return base.IsVisible(user) && GetRecursiveChildren(user, false) + .OfType<Playlist>() + .Any(i => string.Equals(i.OwnerUserId, user.Id.ToString("N"))); + } + + protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user) + { + return RecursiveChildren + .OfType<Playlist>(); } public override bool IsHidden @@ -48,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.Playlists public BasePluginFolder GetFolder() { - var path = Path.Combine(_appPaths.DataPath, "playlists"); + var path = Path.Combine(_appPaths.CachePath, "playlists"); Directory.CreateDirectory(path); diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs index 92f01305c..79b673283 100644 --- a/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs +++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistManager.cs @@ -1,8 +1,10 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -41,9 +43,6 @@ namespace MediaBrowser.Server.Implementations.Playlists { var name = options.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) + " [playlist]"; var parentFolder = GetPlaylistsFolder(null); @@ -53,7 +52,55 @@ namespace MediaBrowser.Server.Implementations.Playlists throw new ArgumentException(); } + if (string.IsNullOrWhiteSpace(options.MediaType)) + { + foreach (var itemId in options.ItemIdList) + { + var item = _libraryManager.GetItemById(itemId); + + if (item == null) + { + throw new ArgumentException("No item exists with the supplied Id"); + } + + if (!string.IsNullOrWhiteSpace(item.MediaType)) + { + options.MediaType = item.MediaType; + } + else if (item is MusicArtist || item is MusicAlbum || item is MusicGenre) + { + options.MediaType = MediaType.Audio; + } + else if (item is Genre) + { + options.MediaType = MediaType.Video; + } + else + { + var folder = item as Folder; + if (folder != null) + { + options.MediaType = folder.GetRecursiveChildren() + .Where(i => !i.IsFolder) + .Select(i => i.MediaType) + .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); + } + } + + if (!string.IsNullOrWhiteSpace(options.MediaType)) + { + break; + } + } + } + + if (string.IsNullOrWhiteSpace(options.MediaType)) + { + throw new ArgumentException("A playlist media type is required."); + } + var path = Path.Combine(parentFolder.Path, folderName); + path = GetTargetPath(path); _iLibraryMonitor.ReportFileSystemChangeBeginning(path); @@ -61,24 +108,27 @@ namespace MediaBrowser.Server.Implementations.Playlists { Directory.CreateDirectory(path); - var collection = new Playlist + var playlist = new Playlist { Name = name, Parent = parentFolder, - Path = path + Path = path, + OwnerUserId = options.UserId }; - await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false); + playlist.SetMediaType(options.MediaType); + + await parentFolder.AddChild(playlist, CancellationToken.None).ConfigureAwait(false); - await collection.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None) + await playlist.RefreshMetadata(new MetadataRefreshOptions { ForceSave = true }, CancellationToken.None) .ConfigureAwait(false); if (options.ItemIdList.Count > 0) { - await AddToPlaylist(collection.Id.ToString("N"), options.ItemIdList); + await AddToPlaylist(playlist.Id.ToString("N"), options.ItemIdList); } - return collection; + return playlist; } finally { @@ -87,11 +137,28 @@ namespace MediaBrowser.Server.Implementations.Playlists } } + private string GetTargetPath(string path) + { + while (Directory.Exists(path)) + { + path += "1"; + } + + return path; + } + + private IEnumerable<BaseItem> GetPlaylistItems(IEnumerable<string> itemIds, string playlistMediaType, User user) + { + var items = itemIds.Select(i => _libraryManager.GetItemById(i)).Where(i => i != null); + + return Playlist.GetPlaylistItems(playlistMediaType, items, user); + } + public async Task AddToPlaylist(string playlistId, IEnumerable<string> itemIds) { - var collection = _libraryManager.GetItemById(playlistId) as Playlist; + var playlist = _libraryManager.GetItemById(playlistId) as Playlist; - if (collection == null) + if (playlist == null) { throw new ArgumentException("No Playlist exists with the supplied Id"); } @@ -110,17 +177,17 @@ namespace MediaBrowser.Server.Implementations.Playlists itemList.Add(item); - list.Add(new LinkedChild - { - Type = LinkedChildType.Manual, - ItemId = item.Id - }); + list.Add(LinkedChild.Create(item)); } - collection.LinkedChildren.AddRange(list); + playlist.LinkedChildren.AddRange(list); + + await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + await playlist.RefreshMetadata(new MetadataRefreshOptions{ + + ForceSave = true - await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - await collection.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + }, CancellationToken.None).ConfigureAwait(false); } public Task RemoveFromPlaylist(string playlistId, IEnumerable<int> indeces) |
