mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-31 14:33:54 -04:00
Add playlist ACL endpoints
This commit is contained in:
parent
2e9aa146a5
commit
88b3490d17
@ -59,6 +59,11 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
_appConfig = appConfig;
|
_appConfig = appConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Playlist GetPlaylist(Guid userId, Guid playlistId)
|
||||||
|
{
|
||||||
|
return GetPlaylists(userId).Where(p => p.Id.Equals(playlistId)).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<Playlist> GetPlaylists(Guid userId)
|
public IEnumerable<Playlist> GetPlaylists(Guid userId)
|
||||||
{
|
{
|
||||||
var user = _userManager.GetUserById(userId);
|
var user = _userManager.GetUserById(userId);
|
||||||
@ -160,7 +165,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTargetPath(string path)
|
private static string GetTargetPath(string path)
|
||||||
{
|
{
|
||||||
while (Directory.Exists(path))
|
while (Directory.Exists(path))
|
||||||
{
|
{
|
||||||
@ -231,13 +236,8 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
|
|
||||||
// Update the playlist in the repository
|
// Update the playlist in the repository
|
||||||
playlist.LinkedChildren = newLinkedChildren;
|
playlist.LinkedChildren = newLinkedChildren;
|
||||||
await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// Update the playlist on disk
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
if (playlist.IsFile)
|
|
||||||
{
|
|
||||||
SavePlaylistFile(playlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh playlist metadata
|
// Refresh playlist metadata
|
||||||
_providerManager.QueueRefresh(
|
_providerManager.QueueRefresh(
|
||||||
@ -266,12 +266,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
.Select(i => i.Item1)
|
.Select(i => i.Item1)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
|
||||||
if (playlist.IsFile)
|
|
||||||
{
|
|
||||||
SavePlaylistFile(playlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
_providerManager.QueueRefresh(
|
_providerManager.QueueRefresh(
|
||||||
playlist.Id,
|
playlist.Id,
|
||||||
@ -313,14 +308,9 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
newList.Insert(newIndex, item);
|
newList.Insert(newIndex, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist.LinkedChildren = newList.ToArray();
|
playlist.LinkedChildren = [.. newList];
|
||||||
|
|
||||||
await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
|
||||||
if (playlist.IsFile)
|
|
||||||
{
|
|
||||||
SavePlaylistFile(playlist);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -430,8 +420,11 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
}
|
}
|
||||||
else if (extension.Equals(".m3u8", StringComparison.OrdinalIgnoreCase))
|
else if (extension.Equals(".m3u8", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var playlist = new M3uPlaylist();
|
var playlist = new M3uPlaylist
|
||||||
playlist.IsExtended = true;
|
{
|
||||||
|
IsExtended = true
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var child in item.GetLinkedChildren())
|
foreach (var child in item.GetLinkedChildren())
|
||||||
{
|
{
|
||||||
var entry = new M3uPlaylistEntry()
|
var entry = new M3uPlaylistEntry()
|
||||||
@ -481,7 +474,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string NormalizeItemPath(string playlistPath, string itemPath)
|
private static string NormalizeItemPath(string playlistPath, string itemPath)
|
||||||
{
|
{
|
||||||
return MakeRelativePath(Path.GetDirectoryName(playlistPath), itemPath);
|
return MakeRelativePath(Path.GetDirectoryName(playlistPath), itemPath);
|
||||||
}
|
}
|
||||||
@ -541,12 +534,7 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
{
|
{
|
||||||
playlist.OwnerUserId = guid;
|
playlist.OwnerUserId = guid;
|
||||||
playlist.Shares = rankedShares.Skip(1).ToArray();
|
playlist.Shares = rankedShares.Skip(1).ToArray();
|
||||||
await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
|
||||||
if (playlist.IsFile)
|
|
||||||
{
|
|
||||||
SavePlaylistFile(playlist);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (!playlist.OpenAccess)
|
else if (!playlist.OpenAccess)
|
||||||
{
|
{
|
||||||
@ -563,5 +551,47 @@ namespace Emby.Server.Implementations.Playlists
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ToggleOpenAccess(Guid playlistId, Guid userId)
|
||||||
|
{
|
||||||
|
var playlist = GetPlaylist(userId, playlistId);
|
||||||
|
playlist.OpenAccess = !playlist.OpenAccess;
|
||||||
|
|
||||||
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddToShares(Guid playlistId, Guid userId, Share share)
|
||||||
|
{
|
||||||
|
var playlist = GetPlaylist(userId, playlistId);
|
||||||
|
var shares = playlist.Shares.ToList();
|
||||||
|
var existingUserShare = shares.FirstOrDefault(s => s.UserId?.Equals(share.UserId, StringComparison.OrdinalIgnoreCase) ?? false);
|
||||||
|
if (existingUserShare is not null)
|
||||||
|
{
|
||||||
|
shares.Remove(existingUserShare);
|
||||||
|
}
|
||||||
|
|
||||||
|
shares.Add(share);
|
||||||
|
playlist.Shares = shares;
|
||||||
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RemoveFromShares(Guid playlistId, Guid userId, Share share)
|
||||||
|
{
|
||||||
|
var playlist = GetPlaylist(userId, playlistId);
|
||||||
|
var shares = playlist.Shares.ToList();
|
||||||
|
shares.Remove(share);
|
||||||
|
playlist.Shares = shares;
|
||||||
|
await UpdatePlaylist(playlist).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdatePlaylist(Playlist playlist)
|
||||||
|
{
|
||||||
|
await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (playlist.IsFile)
|
||||||
|
{
|
||||||
|
SavePlaylistFile(playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,128 @@ public class PlaylistsController : BaseJellyfinApiController
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a playlist's shares.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist id.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A list of <see cref="Share"/> objects.
|
||||||
|
/// </returns>
|
||||||
|
[HttpGet("{playlistId}/Shares")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public IReadOnlyList<Share> GetPlaylistShares(
|
||||||
|
[FromRoute, Required] Guid playlistId)
|
||||||
|
{
|
||||||
|
var userId = RequestHelpers.GetUserId(User, default);
|
||||||
|
|
||||||
|
var playlist = _playlistManager.GetPlaylist(userId, playlistId);
|
||||||
|
var isPermitted = playlist.OwnerUserId.Equals(userId)
|
||||||
|
|| playlist.Shares.Any(s => s.CanEdit && (s.UserId?.Equals(userId) ?? false));
|
||||||
|
|
||||||
|
return isPermitted ? playlist.Shares : new List<Share>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggles OpenAccess of a playlist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist id.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task" /> that represents the asynchronous operation to toggle OpenAccess of a playlist.
|
||||||
|
/// The task result contains an <see cref="OkResult"/> indicating success.
|
||||||
|
/// </returns>
|
||||||
|
[HttpPost("{playlistId}/ToggleOpenAccess")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> ToggleopenAccess(
|
||||||
|
[FromRoute, Required] Guid playlistId)
|
||||||
|
{
|
||||||
|
var callingUserId = RequestHelpers.GetUserId(User, default);
|
||||||
|
|
||||||
|
var playlist = _playlistManager.GetPlaylist(callingUserId, playlistId);
|
||||||
|
var isPermitted = playlist.OwnerUserId.Equals(callingUserId)
|
||||||
|
|| playlist.Shares.Any(s => s.CanEdit && (s.UserId?.Equals(callingUserId) ?? false));
|
||||||
|
|
||||||
|
if (!isPermitted)
|
||||||
|
{
|
||||||
|
return Unauthorized("Unauthorized access");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _playlistManager.ToggleOpenAccess(playlistId, callingUserId).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds shares to a playlist's shares.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist id.</param>
|
||||||
|
/// <param name="shares">The shares.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task" /> that represents the asynchronous operation to add shares to a playlist.
|
||||||
|
/// The task result contains an <see cref="OkResult"/> indicating success.
|
||||||
|
/// </returns>
|
||||||
|
[HttpPost("{playlistId}/Shares")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> AddUserToPlaylistShares(
|
||||||
|
[FromRoute, Required] Guid playlistId,
|
||||||
|
[FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Disallow)] Share[] shares)
|
||||||
|
{
|
||||||
|
var callingUserId = RequestHelpers.GetUserId(User, default);
|
||||||
|
|
||||||
|
var playlist = _playlistManager.GetPlaylist(callingUserId, playlistId);
|
||||||
|
var isPermitted = playlist.OwnerUserId.Equals(callingUserId)
|
||||||
|
|| playlist.Shares.Any(s => s.CanEdit && (s.UserId?.Equals(callingUserId) ?? false));
|
||||||
|
|
||||||
|
if (!isPermitted)
|
||||||
|
{
|
||||||
|
return Unauthorized("Unauthorized access");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var share in shares)
|
||||||
|
{
|
||||||
|
await _playlistManager.AddToShares(playlistId, callingUserId, share).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a user from a playlist's shares.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist id.</param>
|
||||||
|
/// <param name="userId">The user id.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="Task" /> that represents the asynchronous operation to delete a user from a playlist's shares.
|
||||||
|
/// The task result contains an <see cref="OkResult"/> indicating success.
|
||||||
|
/// </returns>
|
||||||
|
[HttpDelete("{playlistId}/Shares")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult> RemoveUserFromPlaylistShares(
|
||||||
|
[FromRoute, Required] Guid playlistId,
|
||||||
|
[FromBody] Guid userId)
|
||||||
|
{
|
||||||
|
var callingUserId = RequestHelpers.GetUserId(User, default);
|
||||||
|
|
||||||
|
var playlist = _playlistManager.GetPlaylist(callingUserId, playlistId);
|
||||||
|
var isPermitted = playlist.OwnerUserId.Equals(callingUserId)
|
||||||
|
|| playlist.Shares.Any(s => s.CanEdit && (s.UserId?.Equals(callingUserId) ?? false));
|
||||||
|
|
||||||
|
if (!isPermitted)
|
||||||
|
{
|
||||||
|
return Unauthorized("Unauthorized access");
|
||||||
|
}
|
||||||
|
|
||||||
|
var share = playlist.Shares.FirstOrDefault(s => s.UserId?.Equals(userId) ?? false);
|
||||||
|
|
||||||
|
if (share is null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _playlistManager.RemoveFromShares(playlistId, callingUserId, share).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds items to a playlist.
|
/// Adds items to a playlist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -54,7 +54,7 @@ internal class FixPlaylistOwner : IMigrationRoutine
|
|||||||
foreach (var playlist in playlists)
|
foreach (var playlist in playlists)
|
||||||
{
|
{
|
||||||
var shares = playlist.Shares;
|
var shares = playlist.Shares;
|
||||||
if (shares.Length > 0)
|
if (shares.Count > 0)
|
||||||
{
|
{
|
||||||
var firstEditShare = shares.First(x => x.CanEdit);
|
var firstEditShare = shares.First(x => x.CanEdit);
|
||||||
if (firstEditShare is not null && Guid.TryParse(firstEditShare.UserId, out var guid))
|
if (firstEditShare is not null && Guid.TryParse(firstEditShare.UserId, out var guid))
|
||||||
|
@ -4,12 +4,21 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Playlists;
|
using MediaBrowser.Model.Playlists;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Playlists
|
namespace MediaBrowser.Controller.Playlists
|
||||||
{
|
{
|
||||||
public interface IPlaylistManager
|
public interface IPlaylistManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the playlist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <param name="playlistId">The playlist identifier.</param>
|
||||||
|
/// <returns>Playlist.</returns>
|
||||||
|
Playlist GetPlaylist(Guid userId, Guid playlistId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the playlists.
|
/// Gets the playlists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -17,6 +26,32 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
/// <returns>IEnumerable<Playlist>.</returns>
|
/// <returns>IEnumerable<Playlist>.</returns>
|
||||||
IEnumerable<Playlist> GetPlaylists(Guid userId);
|
IEnumerable<Playlist> GetPlaylists(Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle OpenAccess policy of the playlist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist identifier.</param>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task ToggleOpenAccess(Guid playlistId, Guid userId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a share to the playlist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist identifier.</param>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <param name="share">The share.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task AddToShares(Guid playlistId, Guid userId, Share share);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rremoves a share from the playlist.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playlistId">The playlist identifier.</param>
|
||||||
|
/// <param name="userId">The user identifier.</param>
|
||||||
|
/// <param name="share">The share.</param>
|
||||||
|
/// <returns>Task.</returns>
|
||||||
|
Task RemoveFromShares(Guid playlistId, Guid userId, Share share);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the playlist.
|
/// Creates the playlist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -16,20 +16,19 @@ using MediaBrowser.Controller.Entities;
|
|||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Playlists
|
namespace MediaBrowser.Controller.Playlists
|
||||||
{
|
{
|
||||||
public class Playlist : Folder, IHasShares
|
public class Playlist : Folder, IHasShares
|
||||||
{
|
{
|
||||||
public static readonly IReadOnlyList<string> SupportedExtensions = new[]
|
public static readonly IReadOnlyList<string> SupportedExtensions =
|
||||||
{
|
[
|
||||||
".m3u",
|
".m3u",
|
||||||
".m3u8",
|
".m3u8",
|
||||||
".pls",
|
".pls",
|
||||||
".wpl",
|
".wpl",
|
||||||
".zpl"
|
".zpl"
|
||||||
};
|
];
|
||||||
|
|
||||||
public Playlist()
|
public Playlist()
|
||||||
{
|
{
|
||||||
@ -41,7 +40,7 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
|
|
||||||
public bool OpenAccess { get; set; }
|
public bool OpenAccess { get; set; }
|
||||||
|
|
||||||
public Share[] Shares { get; set; }
|
public IReadOnlyList<Share> Shares { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public bool IsFile => IsPlaylistFile(Path);
|
public bool IsFile => IsPlaylistFile(Path);
|
||||||
@ -192,9 +191,9 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IncludeItemTypes = new[] { BaseItemKind.Audio },
|
IncludeItemTypes = [BaseItemKind.Audio],
|
||||||
GenreIds = new[] { musicGenre.Id },
|
GenreIds = [musicGenre.Id],
|
||||||
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
|
OrderBy = [(ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending)],
|
||||||
DtoOptions = options
|
DtoOptions = options
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -204,9 +203,9 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IncludeItemTypes = new[] { BaseItemKind.Audio },
|
IncludeItemTypes = [BaseItemKind.Audio],
|
||||||
ArtistIds = new[] { musicArtist.Id },
|
ArtistIds = [musicArtist.Id],
|
||||||
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
|
OrderBy = [(ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending)],
|
||||||
DtoOptions = options
|
DtoOptions = options
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -217,8 +216,8 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
{
|
{
|
||||||
Recursive = true,
|
Recursive = true,
|
||||||
IsFolder = false,
|
IsFolder = false,
|
||||||
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
|
OrderBy = [(ItemSortBy.SortName, SortOrder.Ascending)],
|
||||||
MediaTypes = new[] { mediaType },
|
MediaTypes = [mediaType],
|
||||||
EnableTotalRecordCount = false,
|
EnableTotalRecordCount = false,
|
||||||
DtoOptions = options
|
DtoOptions = options
|
||||||
};
|
};
|
||||||
@ -226,7 +225,7 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
return folder.GetItemList(query);
|
return folder.GetItemList(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { item };
|
return [item];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsVisible(User user)
|
public override bool IsVisible(User user)
|
||||||
@ -248,7 +247,7 @@ namespace MediaBrowser.Controller.Playlists
|
|||||||
}
|
}
|
||||||
|
|
||||||
var shares = Shares;
|
var shares = Shares;
|
||||||
if (shares.Length == 0)
|
if (shares.Count == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace MediaBrowser.Model.Entities;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface for access to shares.
|
/// Interface for access to shares.
|
||||||
@ -8,5 +10,5 @@ public interface IHasShares
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the shares.
|
/// Gets or sets the shares.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Share[] Shares { get; set; }
|
IReadOnlyList<Share> Shares { get; set; }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user