diff --git a/Jellyfin.Api/Constants/Policies.cs b/Jellyfin.Api/Constants/Policies.cs
index 53841b0c4..02fdef150 100644
--- a/Jellyfin.Api/Constants/Policies.cs
+++ b/Jellyfin.Api/Constants/Policies.cs
@@ -84,4 +84,9 @@ public static class Policies
/// Policy name for managing LiveTV.
///
public const string LiveTvManagement = "LiveTvManagement";
+
+ ///
+ /// Policy name for accessing subtitles management.
+ ///
+ public const string SubtitleManagement = "SubtitleManagement";
}
diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs
index fb89e9610..c9e256af3 100644
--- a/Jellyfin.Api/Controllers/SubtitleController.cs
+++ b/Jellyfin.Api/Controllers/SubtitleController.cs
@@ -115,7 +115,7 @@ public class SubtitleController : BaseJellyfinApiController
/// Subtitles retrieved.
/// An array of .
[HttpGet("Items/{itemId}/RemoteSearch/Subtitles/{language}")]
- [Authorize]
+ [Authorize(Policy = Policies.SubtitleManagement)]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task>> SearchRemoteSubtitles(
[FromRoute, Required] Guid itemId,
@@ -135,7 +135,7 @@ public class SubtitleController : BaseJellyfinApiController
/// Subtitle downloaded.
/// A .
[HttpPost("Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}")]
- [Authorize]
+ [Authorize(Policy = Policies.SubtitleManagement)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task DownloadRemoteSubtitles(
[FromRoute, Required] Guid itemId,
@@ -399,7 +399,7 @@ public class SubtitleController : BaseJellyfinApiController
/// Subtitle uploaded.
/// A .
[HttpPost("Videos/{itemId}/Subtitles")]
- [Authorize(Policy = Policies.RequiresElevation)]
+ [Authorize(Policy = Policies.SubtitleManagement)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task UploadSubtitle(
[FromRoute, Required] Guid itemId,
diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs
index 5c3e0338d..ea0de3016 100644
--- a/Jellyfin.Data/Entities/User.cs
+++ b/Jellyfin.Data/Entities/User.cs
@@ -505,6 +505,7 @@ namespace Jellyfin.Data.Entities
Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false));
Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false));
Permissions.Add(new Permission(PermissionKind.EnableCollectionManagement, false));
+ Permissions.Add(new Permission(PermissionKind.EnableSubtitleManagement, false));
}
///
diff --git a/Jellyfin.Data/Enums/PermissionKind.cs b/Jellyfin.Data/Enums/PermissionKind.cs
index 40280b95e..6644f0151 100644
--- a/Jellyfin.Data/Enums/PermissionKind.cs
+++ b/Jellyfin.Data/Enums/PermissionKind.cs
@@ -113,6 +113,11 @@ namespace Jellyfin.Data.Enums
///
/// Whether the user can create, modify and delete collections.
///
- EnableCollectionManagement = 21
+ EnableCollectionManagement = 21,
+
+ ///
+ /// Whether the user can edit subtitles.
+ ///
+ EnableSubtitleManagement = 22
}
}
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index b2cb589f7..edae4cfc5 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -359,6 +359,7 @@ namespace Jellyfin.Server.Implementations.Users
ForceRemoteSourceTranscoding = user.HasPermission(PermissionKind.ForceRemoteSourceTranscoding),
EnablePublicSharing = user.HasPermission(PermissionKind.EnablePublicSharing),
EnableCollectionManagement = user.HasPermission(PermissionKind.EnableCollectionManagement),
+ EnableSubtitleManagement = user.HasPermission(PermissionKind.EnableSubtitleManagement),
AccessSchedules = user.AccessSchedules.ToArray(),
BlockedTags = user.GetPreference(PreferenceKind.BlockedTags),
AllowedTags = user.GetPreference(PreferenceKind.AllowedTags),
@@ -683,6 +684,7 @@ namespace Jellyfin.Server.Implementations.Users
user.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, policy.EnableRemoteControlOfOtherUsers);
user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing);
user.SetPermission(PermissionKind.EnableCollectionManagement, policy.EnableCollectionManagement);
+ user.SetPermission(PermissionKind.EnableSubtitleManagement, policy.EnableSubtitleManagement);
user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding);
user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing);
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index cb1680558..b7e71a81d 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -82,6 +82,7 @@ namespace Jellyfin.Server.Extensions
options.AddPolicy(Policies.SyncPlayCreateGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.CreateGroup));
options.AddPolicy(Policies.SyncPlayJoinGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.JoinGroup));
options.AddPolicy(Policies.SyncPlayIsInGroup, new SyncPlayAccessRequirement(SyncPlayAccessRequirementType.IsInGroup));
+ options.AddPolicy(Policies.SubtitleManagement, new UserPermissionRequirement(PermissionKind.EnableSubtitleManagement));
options.AddPolicy(
Policies.RequiresElevation,
policy => policy.AddAuthenticationSchemes(AuthenticationSchemes.CustomAuthentication)
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index 8354c60ef..f5aff07db 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -15,6 +15,7 @@ namespace MediaBrowser.Model.Users
{
IsHidden = true;
EnableCollectionManagement = false;
+ EnableSubtitleManagement = false;
EnableContentDeletion = false;
EnableContentDeletionFromFolders = Array.Empty();
@@ -83,6 +84,13 @@ namespace MediaBrowser.Model.Users
[DefaultValue(false)]
public bool EnableCollectionManagement { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance can manage subtitles.
+ ///
+ /// true if this instance is allowed; otherwise, false.
+ [DefaultValue(false)]
+ public bool EnableSubtitleManagement { get; set; }
+
///
/// Gets or sets a value indicating whether this instance is disabled.
///