aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs46
-rw-r--r--Jellyfin.Api/Controllers/UserController.cs8
-rw-r--r--MediaBrowser.Controller/Entities/IHasShares.cs11
-rw-r--r--MediaBrowser.Controller/Entities/Share.cs13
-rw-r--r--MediaBrowser.Controller/Playlists/IPlaylistManager.cs8
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs1
-rw-r--r--MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs16
-rw-r--r--MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs20
-rw-r--r--MediaBrowser.Model/Entities/IHasShares.cs12
-rw-r--r--MediaBrowser.Model/Entities/Share.cs17
-rw-r--r--MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs39
11 files changed, 137 insertions, 54 deletions
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 2717c392b..8cba652e7 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -135,16 +135,8 @@ namespace Emby.Server.Implementations.Playlists
{
Name = name,
Path = path,
- Shares = new[]
- {
- new Share
- {
- UserId = options.UserId.Equals(default)
- ? null
- : options.UserId.ToString("N", CultureInfo.InvariantCulture),
- CanEdit = true
- }
- }
+ OwnerUserId = options.UserId,
+ Shares = options.Shares
};
playlist.SetMediaType(options.MediaType);
@@ -537,5 +529,39 @@ namespace Emby.Server.Implementations.Playlists
return _libraryManager.RootFolder.Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, TypeName, StringComparison.Ordinal)) ??
_libraryManager.GetUserRootFolder().Children.OfType<Folder>().FirstOrDefault(i => string.Equals(i.GetType().Name, TypeName, StringComparison.Ordinal));
}
+
+ public async Task RemovePlaylists(Guid userId)
+ {
+ var playlists = GetPlaylists(userId);
+ foreach (var playlist in playlists)
+ {
+ // Update owner if shared
+ var rankedShares = playlist.Shares.OrderByDescending(x => x.CanEdit).ToArray();
+ if (rankedShares.Length > 0 && Guid.TryParse(rankedShares[0].UserId, out var guid))
+ {
+ playlist.OwnerUserId = guid;
+ playlist.Shares = rankedShares.Skip(1).ToArray();
+ await playlist.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
+
+ if (playlist.IsFile)
+ {
+ SavePlaylistFile(playlist);
+ }
+ }
+ else
+ {
+ // Remove playlist if not shared
+ _libraryManager.DeleteItem(
+ playlist,
+ new DeleteOptions
+ {
+ DeleteFileLocation = false,
+ DeleteFromExternalProvider = false
+ },
+ playlist.GetParent(),
+ false);
+ }
+ }
+ }
}
}
diff --git a/Jellyfin.Api/Controllers/UserController.cs b/Jellyfin.Api/Controllers/UserController.cs
index b0973b8a1..09bf89550 100644
--- a/Jellyfin.Api/Controllers/UserController.cs
+++ b/Jellyfin.Api/Controllers/UserController.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Configuration;
@@ -41,6 +42,7 @@ public class UserController : BaseJellyfinApiController
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly IQuickConnect _quickConnectManager;
+ private readonly IPlaylistManager _playlistManager;
/// <summary>
/// Initializes a new instance of the <see cref="UserController"/> class.
@@ -53,6 +55,7 @@ public class UserController : BaseJellyfinApiController
/// <param name="config">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger"/> interface.</param>
/// <param name="quickConnectManager">Instance of the <see cref="IQuickConnect"/> interface.</param>
+ /// <param name="playlistManager">Instance of the <see cref="IPlaylistManager"/> interface.</param>
public UserController(
IUserManager userManager,
ISessionManager sessionManager,
@@ -61,7 +64,8 @@ public class UserController : BaseJellyfinApiController
IAuthorizationContext authContext,
IServerConfigurationManager config,
ILogger<UserController> logger,
- IQuickConnect quickConnectManager)
+ IQuickConnect quickConnectManager,
+ IPlaylistManager playlistManager)
{
_userManager = userManager;
_sessionManager = sessionManager;
@@ -71,6 +75,7 @@ public class UserController : BaseJellyfinApiController
_config = config;
_logger = logger;
_quickConnectManager = quickConnectManager;
+ _playlistManager = playlistManager;
}
/// <summary>
@@ -153,6 +158,7 @@ public class UserController : BaseJellyfinApiController
}
await _sessionManager.RevokeUserTokens(user.Id, null).ConfigureAwait(false);
+ await _playlistManager.RemovePlaylists(userId).ConfigureAwait(false);
await _userManager.DeleteUserAsync(userId).ConfigureAwait(false);
return NoContent();
}
diff --git a/MediaBrowser.Controller/Entities/IHasShares.cs b/MediaBrowser.Controller/Entities/IHasShares.cs
deleted file mode 100644
index e6fa27703..000000000
--- a/MediaBrowser.Controller/Entities/IHasShares.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-#nullable disable
-
-#pragma warning disable CA1819, CS1591
-
-namespace MediaBrowser.Controller.Entities
-{
- public interface IHasShares
- {
- Share[] Shares { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Entities/Share.cs b/MediaBrowser.Controller/Entities/Share.cs
deleted file mode 100644
index 64f446eef..000000000
--- a/MediaBrowser.Controller/Entities/Share.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
-namespace MediaBrowser.Controller.Entities
-{
- public class Share
- {
- public string UserId { get; set; }
-
- public bool CanEdit { get; set; }
- }
-}
diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
index f6c592070..201dadb3d 100644
--- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
+++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs
@@ -56,5 +56,13 @@ namespace MediaBrowser.Controller.Playlists
/// <param name="newIndex">The new index.</param>
/// <returns>Task.</returns>
Task MoveItemAsync(string playlistId, string entryId, int newIndex);
+
+ /// <summary>
+ /// Removed all playlists of a user.
+ /// If the playlist is shared, ownership is transferred.
+ /// </summary>
+ /// <param name="userId">The user id.</param>
+ /// <returns>Task.</returns>
+ Task RemovePlaylists(Guid userId);
}
}
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index e6bcc9ea8..2ed05a32c 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Playlists
diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
index c8912807e..a01490c96 100644
--- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
+++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs
@@ -8,6 +8,7 @@ using System.Threading;
using System.Xml;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -636,6 +637,21 @@ namespace MediaBrowser.LocalMetadata.Parsers
break;
}
+ case "OwnerUserId":
+ {
+ var val = reader.ReadElementContentAsString();
+
+ if (Guid.TryParse(val, out var guid) && !guid.Equals(Guid.Empty))
+ {
+ if (item is Playlist playlist)
+ {
+ playlist.OwnerUserId = guid;
+ }
+ }
+
+ break;
+ }
+
case "Format3D":
{
var val = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index d92b50474..1f9c562ba 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -395,6 +395,7 @@ namespace MediaBrowser.LocalMetadata.Savers
if (item is Playlist playlist && !Playlist.IsPlaylistFile(playlist.Path))
{
+ await writer.WriteElementStringAsync(null, "OwnerUserId", null, playlist.OwnerUserId.ToString("N")).ConfigureAwait(false);
await AddLinkedChildren(playlist, writer, "PlaylistItems", "PlaylistItem").ConfigureAwait(false);
}
@@ -418,16 +419,19 @@ namespace MediaBrowser.LocalMetadata.Savers
foreach (var share in item.Shares)
{
- await writer.WriteStartElementAsync(null, "Share", null).ConfigureAwait(false);
+ if (share.UserId is not null)
+ {
+ await writer.WriteStartElementAsync(null, "Share", null).ConfigureAwait(false);
- await writer.WriteElementStringAsync(null, "UserId", null, share.UserId).ConfigureAwait(false);
- await writer.WriteElementStringAsync(
- null,
- "CanEdit",
- null,
- share.CanEdit.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()).ConfigureAwait(false);
+ await writer.WriteElementStringAsync(null, "UserId", null, share.UserId).ConfigureAwait(false);
+ await writer.WriteElementStringAsync(
+ null,
+ "CanEdit",
+ null,
+ share.CanEdit.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()).ConfigureAwait(false);
- await writer.WriteEndElementAsync().ConfigureAwait(false);
+ await writer.WriteEndElementAsync().ConfigureAwait(false);
+ }
}
await writer.WriteEndElementAsync().ConfigureAwait(false);
diff --git a/MediaBrowser.Model/Entities/IHasShares.cs b/MediaBrowser.Model/Entities/IHasShares.cs
new file mode 100644
index 000000000..b34d1a037
--- /dev/null
+++ b/MediaBrowser.Model/Entities/IHasShares.cs
@@ -0,0 +1,12 @@
+namespace MediaBrowser.Model.Entities;
+
+/// <summary>
+/// Interface for access to shares.
+/// </summary>
+public interface IHasShares
+{
+ /// <summary>
+ /// Gets or sets the shares.
+ /// </summary>
+ Share[] Shares { get; set; }
+}
diff --git a/MediaBrowser.Model/Entities/Share.cs b/MediaBrowser.Model/Entities/Share.cs
new file mode 100644
index 000000000..186aad189
--- /dev/null
+++ b/MediaBrowser.Model/Entities/Share.cs
@@ -0,0 +1,17 @@
+namespace MediaBrowser.Model.Entities;
+
+/// <summary>
+/// Class to hold data on sharing permissions.
+/// </summary>
+public class Share
+{
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ public string? UserId { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the user has edit permissions.
+ /// </summary>
+ public bool CanEdit { get; set; }
+}
diff --git a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
index e8ee49403..847269716 100644
--- a/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
+++ b/MediaBrowser.Model/Playlists/PlaylistCreationRequest.cs
@@ -1,19 +1,36 @@
-#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Model.Playlists;
-namespace MediaBrowser.Model.Playlists
+/// <summary>
+/// A playlist creation request.
+/// </summary>
+public class PlaylistCreationRequest
{
- public class PlaylistCreationRequest
- {
- public string Name { get; set; }
+ /// <summary>
+ /// Gets or sets the name.
+ /// </summary>
+ public string? Name { get; set; }
+
+ /// <summary>
+ /// Gets or sets the list of items.
+ /// </summary>
+ public IReadOnlyList<Guid> ItemIdList { get; set; } = Array.Empty<Guid>();
- public IReadOnlyList<Guid> ItemIdList { get; set; } = Array.Empty<Guid>();
+ /// <summary>
+ /// Gets or sets the media type.
+ /// </summary>
+ public string? MediaType { get; set; }
- public string MediaType { get; set; }
+ /// <summary>
+ /// Gets or sets the user id.
+ /// </summary>
+ public Guid UserId { get; set; }
- public Guid UserId { get; set; }
- }
+ /// <summary>
+ /// Gets or sets the shares.
+ /// </summary>
+ public Share[]? Shares { get; set; }
}