Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playlist fixes #11487

Merged
merged 4 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions Emby.Server.Implementations/Playlists/PlaylistManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
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;
Expand Down Expand Up @@ -68,8 +67,14 @@ public Playlist GetPlaylistForUser(Guid playlistId, Guid userId)
public IEnumerable<Playlist> GetPlaylists(Guid userId)
{
var user = _userManager.GetUserById(userId);

return GetPlaylistsFolder(userId).GetChildren(user, true).OfType<Playlist>();
return _libraryManager.GetItemList(new InternalItemsQuery
{
IncludeItemTypes = [BaseItemKind.Playlist],
Recursive = true,
DtoOptions = new DtoOptions(false)
})
.Cast<Playlist>()
.Where(p => p.IsVisible(user));
}

public async Task<PlaylistCreationResult> CreatePlaylist(PlaylistCreationRequest request)
Expand Down Expand Up @@ -162,6 +167,13 @@ await AddToPlaylistInternal(playlist.Id, request.ItemIdList, user, new DtoOption
}
}

private List<Playlist> GetUserPlaylists(Guid userId)
{
var user = _userManager.GetUserById(userId);

return GetPlaylistsFolder(userId).GetChildren(user, true).OfType<Playlist>().ToList();
}

private static string GetTargetPath(string path)
{
while (Directory.Exists(path))
Expand Down Expand Up @@ -227,7 +239,7 @@ private async Task AddToPlaylistInternal(Guid playlistId, IReadOnlyCollection<Gu
}

// Update the playlist in the repository
playlist.LinkedChildren = [..playlist.LinkedChildren, ..childrenToAdd];
playlist.LinkedChildren = [.. playlist.LinkedChildren, .. childrenToAdd];

await UpdatePlaylistInternal(playlist).ConfigureAwait(false);

Expand Down Expand Up @@ -501,11 +513,13 @@ private static string MakeRelativePath(string folderPath, string fileAbsolutePat
return relativePath;
}

/// <inheritdoc />
public Folder GetPlaylistsFolder()
{
return GetPlaylistsFolder(Guid.Empty);
}

/// <inheritdoc />
public Folder GetPlaylistsFolder(Guid userId)
{
const string TypeName = "PlaylistsFolder";
Expand All @@ -517,7 +531,7 @@ public Folder GetPlaylistsFolder(Guid userId)
/// <inheritdoc />
public async Task RemovePlaylistsAsync(Guid userId)
{
var playlists = GetPlaylists(userId);
var playlists = GetUserPlaylists(userId);
foreach (var playlist in playlists)
{
// Update owner if shared
Expand Down Expand Up @@ -555,9 +569,9 @@ public async Task UpdatePlaylist(PlaylistUpdateRequest request)

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);
}
Expand Down
8 changes: 6 additions & 2 deletions Jellyfin.Api/Controllers/PlaylistsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion MediaBrowser.Controller/Playlists/IPlaylistManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public interface IPlaylistManager
Task UpdatePlaylist(PlaylistUpdateRequest request);

/// <summary>
/// Gets the playlists.
/// Gets all playlists a user has access to.
/// </summary>
/// <param name="userId">The user identifier.</param>
/// <returns>IEnumerable&lt;Playlist&gt;.</returns>
Expand Down
84 changes: 49 additions & 35 deletions MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,106 +50,120 @@ public Task<ItemUpdateType> FetchAsync(Playlist item, MetadataRefreshOptions opt
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<LinkedChild> GetItems(Stream stream, string extension)
private IEnumerable<LinkedChild> 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<LinkedChild>();
}

private IEnumerable<LinkedChild> GetPlsItems(Stream stream)
private IEnumerable<LinkedChild> 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<LinkedChild> GetM3u8Items(Stream stream)
private IEnumerable<LinkedChild> 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<LinkedChild> GetM3uItems(Stream stream)
private IEnumerable<LinkedChild> 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<LinkedChild> GetZplItems(Stream stream)
private IEnumerable<LinkedChild> 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<LinkedChild> GetWplItems(Stream stream)
private IEnumerable<LinkedChild> 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;
Expand All @@ -159,7 +173,7 @@ public bool HasChanged(BaseItem item, IDirectoryService directoryService)
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;
}
}
Expand Down
Loading