From c9cd17220a3282506620fd651acf407f5a6671ad Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Mon, 6 May 2024 03:22:21 +0200 Subject: [PATCH] Playlist fixes (#11487) --- .../Playlists/PlaylistManager.cs | 30 +++++-- .../Controllers/PlaylistsController.cs | 8 +- .../Playlists/IPlaylistManager.cs | 2 +- .../Playlists/PlaylistItemsProvider.cs | 84 +++++++++++-------- 4 files changed, 78 insertions(+), 46 deletions(-) diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 6007591b2d..8a35b96b39 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -22,7 +22,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Playlists; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using PlaylistsNET.Content; @@ -68,8 +67,14 @@ namespace Emby.Server.Implementations.Playlists public IEnumerable GetPlaylists(Guid userId) { var user = _userManager.GetUserById(userId); - - return GetPlaylistsFolder(userId).GetChildren(user, true).OfType(); + return _libraryManager.GetItemList(new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Playlist], + Recursive = true, + DtoOptions = new DtoOptions(false) + }) + .Cast() + .Where(p => p.IsVisible(user)); } public async Task CreatePlaylist(PlaylistCreationRequest request) @@ -162,6 +167,13 @@ namespace Emby.Server.Implementations.Playlists } } + private List GetUserPlaylists(Guid userId) + { + var user = _userManager.GetUserById(userId); + + return GetPlaylistsFolder(userId).GetChildren(user, true).OfType().ToList(); + } + private static string GetTargetPath(string path) { while (Directory.Exists(path)) @@ -227,7 +239,7 @@ namespace Emby.Server.Implementations.Playlists } // Update the playlist in the repository - playlist.LinkedChildren = [..playlist.LinkedChildren, ..childrenToAdd]; + playlist.LinkedChildren = [.. playlist.LinkedChildren, .. childrenToAdd]; await UpdatePlaylistInternal(playlist).ConfigureAwait(false); @@ -501,11 +513,13 @@ namespace Emby.Server.Implementations.Playlists return relativePath; } + /// public Folder GetPlaylistsFolder() { return GetPlaylistsFolder(Guid.Empty); } + /// public Folder GetPlaylistsFolder(Guid userId) { const string TypeName = "PlaylistsFolder"; @@ -517,7 +531,7 @@ namespace Emby.Server.Implementations.Playlists /// public async Task RemovePlaylistsAsync(Guid userId) { - var playlists = GetPlaylists(userId); + var playlists = GetUserPlaylists(userId); foreach (var playlist in playlists) { // Update owner if shared @@ -555,9 +569,9 @@ namespace Emby.Server.Implementations.Playlists var user = _userManager.GetUserById(request.UserId); await AddToPlaylistInternal(request.Id, request.Ids, user, new DtoOptions(false) - { - EnableImages = true - }).ConfigureAwait(false); + { + EnableImages = true + }).ConfigureAwait(false); playlist = GetPlaylistForUser(request.Id, request.UserId); } diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index abf94a32fa..63d6e1cc30 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -206,9 +206,13 @@ public class PlaylistsController : BaseJellyfinApiController return NotFound("Playlist not found"); } + if (playlist.OwnerUserId.Equals(callingUserId)) + { + return new PlaylistUserPermissions(callingUserId, true); + } + var userPermission = playlist.Shares.FirstOrDefault(s => s.UserId.Equals(userId)); - var isPermitted = playlist.OwnerUserId.Equals(callingUserId) - || playlist.Shares.Any(s => s.CanEdit && s.UserId.Equals(callingUserId)) + var isPermitted = playlist.Shares.Any(s => s.CanEdit && s.UserId.Equals(callingUserId)) || userId.Equals(callingUserId); if (!isPermitted) diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index cbe4bd87f5..038cbd2d67 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Playlists Task UpdatePlaylist(PlaylistUpdateRequest request); /// - /// Gets the playlists. + /// Gets all playlists a user has access to. /// /// The user identifier. /// IEnumerable<Playlist>. diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index 9bd36f25c3..6256bfa21e 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -50,106 +50,120 @@ namespace MediaBrowser.Providers.Playlists return Task.FromResult(ItemUpdateType.None); } - using (var stream = File.OpenRead(path)) - { - var items = GetItems(stream, extension).ToArray(); + var items = GetItems(path, extension).ToArray(); - item.LinkedChildren = items; - } + item.LinkedChildren = items; return Task.FromResult(ItemUpdateType.None); } - private IEnumerable GetItems(Stream stream, string extension) + private IEnumerable GetItems(string path, string extension) { - if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) + using (var stream = File.OpenRead(path)) { - return GetWplItems(stream); - } + if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetWplItems(stream, path); + } - if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetZplItems(stream); - } + if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetZplItems(stream, path); + } - if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetM3uItems(stream); - } + if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetM3uItems(stream, path); + } - if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetM3u8Items(stream); - } + if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetM3u8Items(stream, path); + } - if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetPlsItems(stream); + if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetPlsItems(stream, path); + } } return Enumerable.Empty(); } - private IEnumerable GetPlsItems(Stream stream) + private IEnumerable GetPlsItems(Stream stream, string path) { var content = new PlsContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { - Path = i.Path, + Path = GetPlaylistItemPath(i.Path, path), Type = LinkedChildType.Manual }); } - private IEnumerable GetM3u8Items(Stream stream) + private IEnumerable GetM3u8Items(Stream stream, string path) { var content = new M3uContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { - Path = i.Path, + Path = GetPlaylistItemPath(i.Path, path), Type = LinkedChildType.Manual }); } - private IEnumerable GetM3uItems(Stream stream) + private IEnumerable GetM3uItems(Stream stream, string path) { var content = new M3uContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { - Path = i.Path, + Path = GetPlaylistItemPath(i.Path, path), Type = LinkedChildType.Manual }); } - private IEnumerable GetZplItems(Stream stream) + private IEnumerable GetZplItems(Stream stream, string path) { var content = new ZplContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { - Path = i.Path, + Path = GetPlaylistItemPath(i.Path, path), Type = LinkedChildType.Manual }); } - private IEnumerable GetWplItems(Stream stream) + private IEnumerable GetWplItems(Stream stream, string path) { var content = new WplContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { - Path = i.Path, + Path = GetPlaylistItemPath(i.Path, path), Type = LinkedChildType.Manual }); } + private string GetPlaylistItemPath(string itemPath, string containingPlaylistFolder) + { + if (!File.Exists(itemPath)) + { + var path = Path.Combine(Path.GetDirectoryName(containingPlaylistFolder), itemPath); + if (File.Exists(path)) + { + return path; + } + } + + return itemPath; + } + public bool HasChanged(BaseItem item, IDirectoryService directoryService) { var path = item.Path; @@ -159,7 +173,7 @@ namespace MediaBrowser.Providers.Playlists var file = directoryService.GetFile(path); if (file is not null && file.LastWriteTimeUtc != item.DateModified) { - _logger.LogDebug("Refreshing {0} due to date modified timestamp change.", path); + _logger.LogDebug("Refreshing {Path} due to date modified timestamp change.", path); return true; } }