2
0
Эх сурвалжийг харах

Add missing attributes, fix response codes, fix route parameter casing

crobibero 5 жил өмнө
parent
commit
10ddbc34ec

+ 2 - 2
Jellyfin.Api/Controllers/ConfigurationController.cs

@@ -68,7 +68,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="key">Configuration key.</param>
         /// <response code="200">Configuration returned.</response>
         /// <returns>Configuration.</returns>
-        [HttpGet("Configuration/{Key}")]
+        [HttpGet("Configuration/{key}")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         public ActionResult<object> GetNamedConfiguration([FromRoute] string key)
         {
@@ -81,7 +81,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="key">Configuration key.</param>
         /// <response code="204">Named configuration updated.</response>
         /// <returns>Update status.</returns>
-        [HttpPost("Configuration/{Key}")]
+        [HttpPost("Configuration/{key}")]
         [Authorize(Policy = Policies.RequiresElevation)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public async Task<ActionResult> UpdateNamedConfiguration([FromRoute] string key)

+ 1 - 0
Jellyfin.Api/Controllers/DevicesController.cs

@@ -133,6 +133,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the device could not be found.</returns>
         [HttpDelete]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult DeleteDevice([FromQuery, BindRequired] string id)
         {
             var existingDevice = _deviceManager.GetDevice(id);

+ 8 - 14
Jellyfin.Api/Controllers/DisplayPreferencesController.cs

@@ -1,4 +1,5 @@
 using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
 using System.Threading;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
@@ -34,9 +35,8 @@ namespace Jellyfin.Api.Controllers
         /// <param name="client">Client.</param>
         /// <response code="200">Display preferences retrieved.</response>
         /// <returns>An <see cref="OkResult"/> containing the display preferences on success, or a <see cref="NotFoundResult"/> if the display preferences could not be found.</returns>
-        [HttpGet("{DisplayPreferencesId}")]
+        [HttpGet("{displayPreferencesId}")]
         [ProducesResponseType(StatusCodes.Status200OK)]
-        [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult<DisplayPreferences> GetDisplayPreferences(
             [FromRoute] string displayPreferencesId,
             [FromQuery] [Required] string userId,
@@ -52,30 +52,24 @@ namespace Jellyfin.Api.Controllers
         /// <param name="userId">User Id.</param>
         /// <param name="client">Client.</param>
         /// <param name="displayPreferences">New Display Preferences object.</param>
-        /// <response code="200">Display preferences updated.</response>
-        /// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the display preferences could not be found.</returns>
-        [HttpPost("{DisplayPreferencesId}")]
-        [ProducesResponseType(StatusCodes.Status200OK)]
-        [ProducesResponseType(typeof(ModelStateDictionary), StatusCodes.Status400BadRequest)]
-        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        /// <response code="204">Display preferences updated.</response>
+        /// <returns>An <see cref="OkResult"/> on success.</returns>
+        [HttpPost("{displayPreferencesId}")]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "displayPreferencesId", Justification = "Imported from ServiceStack")]
         public ActionResult UpdateDisplayPreferences(
             [FromRoute] string displayPreferencesId,
             [FromQuery, BindRequired] string userId,
             [FromQuery, BindRequired] string client,
             [FromBody, BindRequired] DisplayPreferences displayPreferences)
         {
-            if (displayPreferencesId == null)
-            {
-                // TODO - refactor so parameter doesn't exist or is actually used.
-            }
-
             _displayPreferencesRepository.SaveDisplayPreferences(
                 displayPreferences,
                 userId,
                 client,
                 CancellationToken.None);
 
-            return Ok();
+            return NoContent();
         }
     }
 }

+ 3 - 3
Jellyfin.Api/Controllers/ImageByNameController.cs

@@ -58,7 +58,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Image stream retrieved.</response>
         /// <response code="404">Image not found.</response>
         /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
-        [HttpGet("General/{Name}/{Type}")]
+        [HttpGet("General/{name}/{type}")]
         [AllowAnonymous]
         [Produces(MediaTypeNames.Application.Octet)]
         [ProducesResponseType(StatusCodes.Status200OK)]
@@ -103,7 +103,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Image stream retrieved.</response>
         /// <response code="404">Image not found.</response>
         /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
-        [HttpGet("Ratings/{Theme}/{Name}")]
+        [HttpGet("Ratings/{theme}/{name}")]
         [AllowAnonymous]
         [Produces(MediaTypeNames.Application.Octet)]
         [ProducesResponseType(StatusCodes.Status200OK)]
@@ -136,7 +136,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Image stream retrieved.</response>
         /// <response code="404">Image not found.</response>
         /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
-        [HttpGet("MediaInfo/{Theme}/{Name}")]
+        [HttpGet("MediaInfo/{theme}/{name}")]
         [AllowAnonymous]
         [Produces(MediaTypeNames.Application.Octet)]
         [ProducesResponseType(StatusCodes.Status200OK)]

+ 8 - 7
Jellyfin.Api/Controllers/ItemRefreshController.cs

@@ -1,3 +1,4 @@
+using System;
 using System.ComponentModel;
 using System.Diagnostics.CodeAnalysis;
 using MediaBrowser.Controller.Library;
@@ -40,29 +41,29 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Refreshes metadata for an item.
         /// </summary>
-        /// <param name="id">Item id.</param>
+        /// <param name="itemId">Item id.</param>
         /// <param name="metadataRefreshMode">(Optional) Specifies the metadata refresh mode.</param>
         /// <param name="imageRefreshMode">(Optional) Specifies the image refresh mode.</param>
         /// <param name="replaceAllMetadata">(Optional) Determines if metadata should be replaced. Only applicable if mode is FullRefresh.</param>
         /// <param name="replaceAllImages">(Optional) Determines if images should be replaced. Only applicable if mode is FullRefresh.</param>
         /// <param name="recursive">(Unused) Indicates if the refresh should occur recursively.</param>
-        /// <response code="200">Item metadata refresh queued.</response>
+        /// <response code="204">Item metadata refresh queued.</response>
         /// <response code="404">Item to refresh not found.</response>
         /// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the item could not be found.</returns>
-        [HttpPost("{Id}/Refresh")]
+        [HttpPost("{itemId}/Refresh")]
         [Description("Refreshes metadata for an item.")]
-        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "recursive", Justification = "Imported from ServiceStack")]
         public ActionResult Post(
-            [FromRoute] string id,
+            [FromRoute] Guid itemId,
             [FromQuery] MetadataRefreshMode metadataRefreshMode = MetadataRefreshMode.None,
             [FromQuery] MetadataRefreshMode imageRefreshMode = MetadataRefreshMode.None,
             [FromQuery] bool replaceAllMetadata = false,
             [FromQuery] bool replaceAllImages = false,
             [FromQuery] bool recursive = false)
         {
-            var item = _libraryManager.GetItemById(id);
+            var item = _libraryManager.GetItemById(itemId);
             if (item == null)
             {
                 return NotFound();
@@ -82,7 +83,7 @@ namespace Jellyfin.Api.Controllers
             };
 
             _providerManager.QueueRefresh(item.Id, refreshOptions, RefreshPriority.High);
-            return Ok();
+            return NoContent();
         }
     }
 }

+ 4 - 4
Jellyfin.Api/Controllers/NotificationsController.cs

@@ -42,7 +42,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="limit">An optional limit on the number of notifications returned.</param>
         /// <response code="200">Notifications returned.</response>
         /// <returns>An <see cref="OkResult"/> containing a list of notifications.</returns>
-        [HttpGet("{UserID}")]
+        [HttpGet("{userId}")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isRead", Justification = "Imported from ServiceStack")]
@@ -63,7 +63,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="userId">The user's ID.</param>
         /// <response code="200">Summary of user's notifications returned.</response>
         /// <returns>An <cref see="OkResult"/> containing a summary of the users notifications.</returns>
-        [HttpGet("{UserID}/Summary")]
+        [HttpGet("{userId}/Summary")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
         public ActionResult<NotificationsSummaryDto> GetNotificationsSummary(
@@ -138,7 +138,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="ids">A comma-separated list of the IDs of notifications which should be set as read.</param>
         /// <response code="204">Notifications set as read.</response>
         /// <returns>A <cref see="NoContentResult"/>.</returns>
-        [HttpPost("{UserID}/Read")]
+        [HttpPost("{userId}/Read")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "ids", Justification = "Imported from ServiceStack")]
@@ -156,7 +156,7 @@ namespace Jellyfin.Api.Controllers
         /// <param name="ids">A comma-separated list of the IDs of notifications which should be set as unread.</param>
         /// <response code="204">Notifications set as unread.</response>
         /// <returns>A <cref see="NoContentResult"/>.</returns>
-        [HttpPost("{UserID}/Unread")]
+        [HttpPost("{userId}/Unread")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "userId", Justification = "Imported from ServiceStack")]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "ids", Justification = "Imported from ServiceStack")]

+ 10 - 9
Jellyfin.Api/Controllers/PackageController.cs

@@ -35,9 +35,10 @@ namespace Jellyfin.Api.Controllers
         /// </summary>
         /// <param name="name">The name of the package.</param>
         /// <param name="assemblyGuid">The GUID of the associated assembly.</param>
+        /// <response code="200">Package retrieved.</response>
         /// <returns>A <see cref="PackageInfo"/> containing package information.</returns>
-        [HttpGet("/{Name}")]
-        [ProducesResponseType(typeof(PackageInfo), StatusCodes.Status200OK)]
+        [HttpGet("/{name}")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
         public async Task<ActionResult<PackageInfo>> GetPackageInfo(
             [FromRoute] [Required] string name,
             [FromQuery] string? assemblyGuid)
@@ -54,9 +55,10 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets available packages.
         /// </summary>
+        /// <response code="200">Available packages returned.</response>
         /// <returns>An <see cref="PackageInfo"/> containing available packages information.</returns>
         [HttpGet]
-        [ProducesResponseType(typeof(PackageInfo[]), StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status200OK)]
         public async Task<IEnumerable<PackageInfo>> GetPackages()
         {
             IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false);
@@ -73,7 +75,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="204">Package found.</response>
         /// <response code="404">Package not found.</response>
         /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if the package could not be found.</returns>
-        [HttpPost("/Installed/{Name}")]
+        [HttpPost("/Installed/{name}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         [Authorize(Policy = Policies.RequiresElevation)]
@@ -102,17 +104,16 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Cancels a package installation.
         /// </summary>
-        /// <param name="id">Installation Id.</param>
+        /// <param name="packageId">Installation Id.</param>
         /// <response code="204">Installation cancelled.</response>
         /// <returns>A <see cref="NoContentResult"/> on successfully cancelling a package installation.</returns>
-        [HttpDelete("/Installing/{id}")]
+        [HttpDelete("/Installing/{packageId}")]
         [Authorize(Policy = Policies.RequiresElevation)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public IActionResult CancelPackageInstallation(
-            [FromRoute] [Required] string id)
+            [FromRoute] [Required] Guid packageId)
         {
-            _installationManager.CancelInstallation(new Guid(id));
-
+            _installationManager.CancelInstallation(packageId);
             return NoContent();
         }
     }

+ 20 - 8
Jellyfin.Api/Controllers/PluginsController.cs

@@ -11,6 +11,7 @@ using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.Updates;
 using MediaBrowser.Model.Plugins;
 using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.ModelBinding;
 
@@ -45,6 +46,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Installed plugins returned.</response>
         /// <returns>List of currently installed plugins.</returns>
         [HttpGet]
+        [ProducesResponseType(StatusCodes.Status200OK)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isAppStoreEnabled", Justification = "Imported from ServiceStack")]
         public ActionResult<IEnumerable<PluginInfo>> GetPlugins([FromRoute] bool? isAppStoreEnabled)
         {
@@ -55,11 +57,13 @@ namespace Jellyfin.Api.Controllers
         /// Uninstalls a plugin.
         /// </summary>
         /// <param name="pluginId">Plugin id.</param>
-        /// <response code="200">Plugin uninstalled.</response>
+        /// <response code="204">Plugin uninstalled.</response>
         /// <response code="404">Plugin not found.</response>
         /// <returns>An <see cref="OkResult"/> on success, or a <see cref="NotFoundResult"/> if the file could not be found.</returns>
         [HttpDelete("{pluginId}")]
         [Authorize(Policy = Policies.RequiresElevation)]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult UninstallPlugin([FromRoute] Guid pluginId)
         {
             var plugin = _appHost.Plugins.FirstOrDefault(p => p.Id == pluginId);
@@ -69,7 +73,7 @@ namespace Jellyfin.Api.Controllers
             }
 
             _installationManager.UninstallPlugin(plugin);
-            return Ok();
+            return NoContent();
         }
 
         /// <summary>
@@ -80,6 +84,8 @@ namespace Jellyfin.Api.Controllers
         /// <response code="404">Plugin not found or plugin configuration not found.</response>
         /// <returns>Plugin configuration.</returns>
         [HttpGet("{pluginId}/Configuration")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult<BasePluginConfiguration> GetPluginConfiguration([FromRoute] Guid pluginId)
         {
             if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
@@ -97,14 +103,16 @@ namespace Jellyfin.Api.Controllers
         /// Accepts plugin configuration as JSON body.
         /// </remarks>
         /// <param name="pluginId">Plugin id.</param>
-        /// <response code="200">Plugin configuration updated.</response>
-        /// <response code="200">Plugin not found or plugin does not have configuration.</response>
+        /// <response code="204">Plugin configuration updated.</response>
+        /// <response code="404">Plugin not found or plugin does not have configuration.</response>
         /// <returns>
         /// A <see cref="Task" /> that represents the asynchronous operation to update plugin configuration.
         ///    The task result contains an <see cref="OkResult"/> indicating success, or <see cref="NotFoundResult"/>
         ///    when plugin not found or plugin doesn't have configuration.
         /// </returns>
         [HttpPost("{pluginId}/Configuration")]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
         public async Task<ActionResult> UpdatePluginConfiguration([FromRoute] Guid pluginId)
         {
             if (!(_appHost.Plugins.FirstOrDefault(p => p.Id == pluginId) is IHasPluginConfiguration plugin))
@@ -116,7 +124,7 @@ namespace Jellyfin.Api.Controllers
                 .ConfigureAwait(false);
 
             plugin.UpdateConfiguration(configuration);
-            return Ok();
+            return NoContent();
         }
 
         /// <summary>
@@ -126,6 +134,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>Plugin security info.</returns>
         [Obsolete("This endpoint should not be used.")]
         [HttpGet("SecurityInfo")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
         public ActionResult<PluginSecurityInfo> GetPluginSecurityInfo()
         {
             return new PluginSecurityInfo
@@ -139,14 +148,15 @@ namespace Jellyfin.Api.Controllers
         /// Updates plugin security info.
         /// </summary>
         /// <param name="pluginSecurityInfo">Plugin security info.</param>
-        /// <response code="200">Plugin security info updated.</response>
-        /// <returns>An <see cref="OkResult"/>.</returns>
+        /// <response code="204">Plugin security info updated.</response>
+        /// <returns>An <see cref="NoContentResult"/>.</returns>
         [Obsolete("This endpoint should not be used.")]
         [HttpPost("SecurityInfo")]
         [Authorize(Policy = Policies.RequiresElevation)]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult UpdatePluginSecurityInfo([FromBody, BindRequired] PluginSecurityInfo pluginSecurityInfo)
         {
-            return Ok();
+            return NoContent();
         }
 
         /// <summary>
@@ -157,6 +167,7 @@ namespace Jellyfin.Api.Controllers
         /// <returns>Mb registration record.</returns>
         [Obsolete("This endpoint should not be used.")]
         [HttpPost("RegistrationRecords/{name}")]
+        [ProducesResponseType(StatusCodes.Status200OK)]
         public ActionResult<MBRegistrationRecord> GetRegistrationStatus([FromRoute] string name)
         {
             return new MBRegistrationRecord
@@ -178,6 +189,7 @@ namespace Jellyfin.Api.Controllers
         /// <exception cref="NotImplementedException">This endpoint is not implemented.</exception>
         [Obsolete("Paid plugins are not supported")]
         [HttpGet("/Registrations/{name}")]
+        [ProducesResponseType(StatusCodes.Status501NotImplemented)]
         public ActionResult GetRegistration([FromRoute] string name)
         {
             // TODO Once we have proper apps and plugins and decide to break compatibility with paid plugins,

+ 15 - 15
Jellyfin.Api/Controllers/RemoteImageController.cs

@@ -55,7 +55,7 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets available remote images for an item.
         /// </summary>
-        /// <param name="id">Item Id.</param>
+        /// <param name="itemId">Item Id.</param>
         /// <param name="type">The image type.</param>
         /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped from the results.</param>
         /// <param name="limit">Optional. The maximum number of records to return.</param>
@@ -64,18 +64,18 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Remote Images returned.</response>
         /// <response code="404">Item not found.</response>
         /// <returns>Remote Image Result.</returns>
-        [HttpGet("{Id}/RemoteImages")]
+        [HttpGet("{itemId}/RemoteImages")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public async Task<ActionResult<RemoteImageResult>> GetRemoteImages(
-            [FromRoute] string id,
+            [FromRoute] Guid itemId,
             [FromQuery] ImageType? type,
             [FromQuery] int? startIndex,
             [FromQuery] int? limit,
             [FromQuery] string providerName,
             [FromQuery] bool includeAllLanguages)
         {
-            var item = _libraryManager.GetItemById(id);
+            var item = _libraryManager.GetItemById(itemId);
             if (item == null)
             {
                 return NotFound();
@@ -123,16 +123,16 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets available remote image providers for an item.
         /// </summary>
-        /// <param name="id">Item Id.</param>
+        /// <param name="itemId">Item Id.</param>
         /// <response code="200">Returned remote image providers.</response>
         /// <response code="404">Item not found.</response>
         /// <returns>List of remote image providers.</returns>
-        [HttpGet("{Id}/RemoteImages/Providers")]
+        [HttpGet("{itemId}/RemoteImages/Providers")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
-        public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute] string id)
+        public ActionResult<IEnumerable<ImageProviderInfo>> GetRemoteImageProviders([FromRoute] Guid itemId)
         {
-            var item = _libraryManager.GetItemById(id);
+            var item = _libraryManager.GetItemById(itemId);
             if (item == null)
             {
                 return NotFound();
@@ -195,21 +195,21 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Downloads a remote image for an item.
         /// </summary>
-        /// <param name="id">Item Id.</param>
+        /// <param name="itemId">Item Id.</param>
         /// <param name="type">The image type.</param>
         /// <param name="imageUrl">The image url.</param>
-        /// <response code="200">Remote image downloaded.</response>
+        /// <response code="204">Remote image downloaded.</response>
         /// <response code="404">Remote image not found.</response>
         /// <returns>Download status.</returns>
-        [HttpPost("{Id}/RemoteImages/Download")]
-        [ProducesResponseType(StatusCodes.Status200OK)]
+        [HttpPost("{itemId}/RemoteImages/Download")]
+        [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public async Task<ActionResult> DownloadRemoteImage(
-            [FromRoute] string id,
+            [FromRoute] Guid itemId,
             [FromQuery, BindRequired] ImageType type,
             [FromQuery] string imageUrl)
         {
-            var item = _libraryManager.GetItemById(id);
+            var item = _libraryManager.GetItemById(itemId);
             if (item == null)
             {
                 return NotFound();
@@ -219,7 +219,7 @@ namespace Jellyfin.Api.Controllers
                 .ConfigureAwait(false);
 
             item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
-            return Ok();
+            return NoContent();
         }
 
         /// <summary>

+ 36 - 36
Jellyfin.Api/Controllers/SessionController.cs

@@ -113,16 +113,16 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Instructs a session to browse to an item or view.
         /// </summary>
-        /// <param name="id">The session Id.</param>
+        /// <param name="sessionId">The session Id.</param>
         /// <param name="itemType">The type of item to browse to.</param>
         /// <param name="itemId">The Id of the item.</param>
         /// <param name="itemName">The name of the item.</param>
         /// <response code="204">Instruction sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Viewing")]
+        [HttpPost("/Sessions/{sessionId}/Viewing")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult DisplayContent(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromQuery] string itemType,
             [FromQuery] string itemId,
             [FromQuery] string itemName)
@@ -136,7 +136,7 @@ namespace Jellyfin.Api.Controllers
 
             _sessionManager.SendBrowseCommand(
                 RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id,
-                id,
+                sessionId,
                 command,
                 CancellationToken.None);
 
@@ -146,17 +146,17 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Instructs a session to play an item.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="itemIds">The ids of the items to play, comma delimited.</param>
         /// <param name="startPositionTicks">The starting position of the first item.</param>
         /// <param name="playCommand">The type of play command to issue (PlayNow, PlayNext, PlayLast). Clients who have not yet implemented play next and play last may play now.</param>
         /// <param name="playRequest">The <see cref="PlayRequest"/>.</param>
         /// <response code="204">Instruction sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Playing")]
+        [HttpPost("/Sessions/{sessionId}/Playing")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult Play(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromQuery] Guid[] itemIds,
             [FromQuery] long? startPositionTicks,
             [FromQuery] PlayCommand playCommand,
@@ -173,7 +173,7 @@ namespace Jellyfin.Api.Controllers
 
             _sessionManager.SendPlayCommand(
                 RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id,
-                id,
+                sessionId,
                 playRequest,
                 CancellationToken.None);
 
@@ -183,19 +183,19 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Issues a playstate command to a client.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="playstateRequest">The <see cref="PlaystateRequest"/>.</param>
         /// <response code="204">Playstate command sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Playing/{command}")]
+        [HttpPost("/Sessions/{sessionId}/Playing/{command}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SendPlaystateCommand(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromBody] PlaystateRequest playstateRequest)
         {
             _sessionManager.SendPlaystateCommand(
                 RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id,
-                id,
+                sessionId,
                 playstateRequest,
                 CancellationToken.None);
 
@@ -205,14 +205,14 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Issues a system command to a client.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="command">The command to send.</param>
         /// <response code="204">System command sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/System/{Command}")]
+        [HttpPost("/Sessions/{sessionId}/System/{command}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SendSystemCommand(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromRoute] string command)
         {
             var name = command;
@@ -228,7 +228,7 @@ namespace Jellyfin.Api.Controllers
                 ControllingUserId = currentSession.UserId
             };
 
-            _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None);
+            _sessionManager.SendGeneralCommand(currentSession.Id, sessionId, generalCommand, CancellationToken.None);
 
             return NoContent();
         }
@@ -236,14 +236,14 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Issues a general command to a client.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="command">The command to send.</param>
         /// <response code="204">General command sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Command/{Command}")]
+        [HttpPost("/Sessions/{sessionId}/Command/{Command}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SendGeneralCommand(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromRoute] string command)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request);
@@ -254,7 +254,7 @@ namespace Jellyfin.Api.Controllers
                 ControllingUserId = currentSession.UserId
             };
 
-            _sessionManager.SendGeneralCommand(currentSession.Id, id, generalCommand, CancellationToken.None);
+            _sessionManager.SendGeneralCommand(currentSession.Id, sessionId, generalCommand, CancellationToken.None);
 
             return NoContent();
         }
@@ -262,14 +262,14 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Issues a full general command to a client.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="command">The <see cref="GeneralCommand"/>.</param>
         /// <response code="204">Full general command sent to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Command")]
+        [HttpPost("/Sessions/{sessionId}/Command")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SendFullGeneralCommand(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromBody, Required] GeneralCommand command)
         {
             var currentSession = RequestHelpers.GetSession(_sessionManager, _authContext, Request);
@@ -283,7 +283,7 @@ namespace Jellyfin.Api.Controllers
 
             _sessionManager.SendGeneralCommand(
                 currentSession.Id,
-                id,
+                sessionId,
                 command,
                 CancellationToken.None);
 
@@ -293,16 +293,16 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Issues a command to a client to display a message to the user.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="text">The message test.</param>
         /// <param name="header">The message header.</param>
         /// <param name="timeoutMs">The message timeout. If omitted the user will have to confirm viewing the message.</param>
         /// <response code="204">Message sent.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/Message")]
+        [HttpPost("/Sessions/{sessionId}/Message")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult SendMessageCommand(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromQuery] string text,
             [FromQuery] string header,
             [FromQuery] long? timeoutMs)
@@ -314,7 +314,7 @@ namespace Jellyfin.Api.Controllers
                 Text = text
             };
 
-            _sessionManager.SendMessageCommand(RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id, id, command, CancellationToken.None);
+            _sessionManager.SendMessageCommand(RequestHelpers.GetSession(_sessionManager, _authContext, Request).Id, sessionId, command, CancellationToken.None);
 
             return NoContent();
         }
@@ -322,34 +322,34 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Adds an additional user to a session.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="userId">The user id.</param>
         /// <response code="204">User added to session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Sessions/{id}/User/{userId}")]
+        [HttpPost("/Sessions/{sessionId}/User/{userId}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult AddUserToSession(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromRoute] Guid userId)
         {
-            _sessionManager.AddAdditionalUser(id, userId);
+            _sessionManager.AddAdditionalUser(sessionId, userId);
             return NoContent();
         }
 
         /// <summary>
         /// Removes an additional user from a session.
         /// </summary>
-        /// <param name="id">The session id.</param>
+        /// <param name="sessionId">The session id.</param>
         /// <param name="userId">The user id.</param>
         /// <response code="204">User removed from session.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpDelete("/Sessions/{id}/User/{userId}")]
+        [HttpDelete("/Sessions/{sessionId}/User/{userId}")]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public ActionResult RemoveUserFromSession(
-            [FromRoute] string id,
+            [FromRoute] string sessionId,
             [FromRoute] Guid userId)
         {
-            _sessionManager.RemoveAdditionalUser(id, userId);
+            _sessionManager.RemoveAdditionalUser(sessionId, userId);
             return NoContent();
         }
 

+ 27 - 27
Jellyfin.Api/Controllers/SubtitleController.cs

@@ -75,20 +75,20 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Deletes an external subtitle file.
         /// </summary>
-        /// <param name="id">The item id.</param>
+        /// <param name="itemId">The item id.</param>
         /// <param name="index">The index of the subtitle file.</param>
         /// <response code="204">Subtitle deleted.</response>
         /// <response code="404">Item not found.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpDelete("/Videos/{id}/Subtitles/{index}")]
+        [HttpDelete("/Videos/{itemId}/Subtitles/{index}")]
         [Authorize(Policy = Policies.RequiresElevation)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult<Task> DeleteSubtitle(
-            [FromRoute] Guid id,
+            [FromRoute] Guid itemId,
             [FromRoute] int index)
         {
-            var item = _libraryManager.GetItemById(id);
+            var item = _libraryManager.GetItemById(itemId);
 
             if (item == null)
             {
@@ -102,20 +102,20 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Search remote subtitles.
         /// </summary>
-        /// <param name="id">The item id.</param>
+        /// <param name="itemId">The item id.</param>
         /// <param name="language">The language of the subtitles.</param>
         /// <param name="isPerfectMatch">Optional. Only show subtitles which are a perfect match.</param>
         /// <response code="200">Subtitles retrieved.</response>
         /// <returns>An array of <see cref="RemoteSubtitleInfo"/>.</returns>
-        [HttpGet("/Items/{id}/RemoteSearch/Subtitles/{language}")]
+        [HttpGet("/Items/{itemId}/RemoteSearch/Subtitles/{language}")]
         [Authorize(Policy = Policies.DefaultAuthorization)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         public async Task<ActionResult<IEnumerable<RemoteSubtitleInfo>>> SearchRemoteSubtitles(
-            [FromRoute] Guid id,
+            [FromRoute] Guid itemId,
             [FromRoute] string language,
             [FromQuery] bool? isPerfectMatch)
         {
-            var video = (Video)_libraryManager.GetItemById(id);
+            var video = (Video)_libraryManager.GetItemById(itemId);
 
             return await _subtitleManager.SearchSubtitles(video, language, isPerfectMatch, CancellationToken.None).ConfigureAwait(false);
         }
@@ -123,18 +123,18 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Downloads a remote subtitle.
         /// </summary>
-        /// <param name="id">The item id.</param>
+        /// <param name="itemId">The item id.</param>
         /// <param name="subtitleId">The subtitle id.</param>
         /// <response code="204">Subtitle downloaded.</response>
         /// <returns>A <see cref="NoContentResult"/>.</returns>
-        [HttpPost("/Items/{id}/RemoteSearch/Subtitles/{subtitleId}")]
+        [HttpPost("/Items/{itemId}/RemoteSearch/Subtitles/{subtitleId}")]
         [Authorize(Policy = Policies.DefaultAuthorization)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         public async Task<ActionResult> DownloadRemoteSubtitles(
-            [FromRoute] Guid id,
+            [FromRoute] Guid itemId,
             [FromRoute] string subtitleId)
         {
-            var video = (Video)_libraryManager.GetItemById(id);
+            var video = (Video)_libraryManager.GetItemById(itemId);
 
             try
             {
@@ -171,28 +171,28 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets subtitles in a specified format.
         /// </summary>
-        /// <param name="id">The item id.</param>
+        /// <param name="itemId">The item id.</param>
         /// <param name="mediaSourceId">The media source id.</param>
         /// <param name="index">The subtitle stream index.</param>
         /// <param name="format">The format of the returned subtitle.</param>
-        /// <param name="startPositionTicks">Optional. The start position of the subtitle in ticks.</param>
         /// <param name="endPositionTicks">Optional. The end position of the subtitle in ticks.</param>
         /// <param name="copyTimestamps">Optional. Whether to copy the timestamps.</param>
         /// <param name="addVttTimeMap">Optional. Whether to add a VTT time map.</param>
+        /// <param name="startPositionTicks">Optional. The start position of the subtitle in ticks.</param>
         /// <response code="200">File returned.</response>
         /// <returns>A <see cref="FileContentResult"/> with the subtitle file.</returns>
-        [HttpGet("/Videos/{id}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")]
-        [HttpGet("/Videos/{id}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks}/Stream.{format}")]
+        [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")]
+        [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks?}/Stream.{format}")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         public async Task<ActionResult> GetSubtitle(
-            [FromRoute, Required] Guid id,
+            [FromRoute, Required] Guid itemId,
             [FromRoute, Required] string mediaSourceId,
             [FromRoute, Required] int index,
             [FromRoute, Required] string format,
-            [FromRoute] long startPositionTicks,
             [FromQuery] long? endPositionTicks,
             [FromQuery] bool copyTimestamps,
-            [FromQuery] bool addVttTimeMap)
+            [FromQuery] bool addVttTimeMap,
+            [FromRoute] long startPositionTicks = 0)
         {
             if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase))
             {
@@ -201,9 +201,9 @@ namespace Jellyfin.Api.Controllers
 
             if (string.IsNullOrEmpty(format))
             {
-                var item = (Video)_libraryManager.GetItemById(id);
+                var item = (Video)_libraryManager.GetItemById(itemId);
 
-                var idString = id.ToString("N", CultureInfo.InvariantCulture);
+                var idString = itemId.ToString("N", CultureInfo.InvariantCulture);
                 var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false)
                     .First(i => string.Equals(i.Id, mediaSourceId ?? idString, StringComparison.Ordinal));
 
@@ -216,7 +216,7 @@ namespace Jellyfin.Api.Controllers
 
             if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap)
             {
-                await using Stream stream = await EncodeSubtitles(id, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
+                await using Stream stream = await EncodeSubtitles(itemId, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
                 using var reader = new StreamReader(stream);
 
                 var text = await reader.ReadToEndAsync().ConfigureAwait(false);
@@ -228,7 +228,7 @@ namespace Jellyfin.Api.Controllers
 
             return File(
                 await EncodeSubtitles(
-                    id,
+                    itemId,
                     mediaSourceId,
                     index,
                     format,
@@ -241,23 +241,23 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets an HLS subtitle playlist.
         /// </summary>
-        /// <param name="id">The item id.</param>
+        /// <param name="itemId">The item id.</param>
         /// <param name="index">The subtitle stream index.</param>
         /// <param name="mediaSourceId">The media source id.</param>
         /// <param name="segmentLength">The subtitle segment length.</param>
         /// <response code="200">Subtitle playlist retrieved.</response>
         /// <returns>A <see cref="FileContentResult"/> with the HLS subtitle playlist.</returns>
-        [HttpGet("/Videos/{id}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")]
+        [HttpGet("/Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/subtitles.m3u8")]
         [Authorize(Policy = Policies.DefaultAuthorization)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")]
         public async Task<ActionResult> GetSubtitlePlaylist(
-            [FromRoute] Guid id,
+            [FromRoute] Guid itemId,
             [FromRoute] int index,
             [FromRoute] string mediaSourceId,
             [FromQuery, Required] int segmentLength)
         {
-            var item = (Video)_libraryManager.GetItemById(id);
+            var item = (Video)_libraryManager.GetItemById(itemId);
 
             var mediaSource = await _mediaSourceManager.GetMediaSource(item, mediaSourceId, null, false, CancellationToken.None).ConfigureAwait(false);
 

+ 37 - 37
Jellyfin.Api/Controllers/UserController.cs

@@ -105,17 +105,17 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Gets a user by Id.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <response code="200">User returned.</response>
         /// <response code="404">User not found.</response>
         /// <returns>An <see cref="UserDto"/> with information about the user or a <see cref="NotFoundResult"/> if the user was not found.</returns>
-        [HttpGet("{id}")]
+        [HttpGet("{userId}")]
         [Authorize(Policy = Policies.IgnoreSchedule)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
-        public ActionResult<UserDto> GetUserById([FromRoute] Guid id)
+        public ActionResult<UserDto> GetUserById([FromRoute] Guid userId)
         {
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (user == null)
             {
@@ -129,17 +129,17 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Deletes a user.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <response code="200">User deleted.</response>
         /// <response code="404">User not found.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="NotFoundResult"/> if the user was not found.</returns>
-        [HttpDelete("{id}")]
+        [HttpDelete("{userId}")]
         [Authorize(Policy = Policies.RequiresElevation)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
-        public ActionResult DeleteUser([FromRoute] Guid id)
+        public ActionResult DeleteUser([FromRoute] Guid userId)
         {
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (user == null)
             {
@@ -154,23 +154,23 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Authenticates a user.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="pw">The password as plain text.</param>
         /// <param name="password">The password sha1-hash.</param>
         /// <response code="200">User authenticated.</response>
         /// <response code="403">Sha1-hashed password only is not allowed.</response>
         /// <response code="404">User not found.</response>
         /// <returns>A <see cref="Task"/> containing an <see cref="AuthenticationResult"/>.</returns>
-        [HttpPost("{id}/Authenticate")]
+        [HttpPost("{userId}/Authenticate")]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public async Task<ActionResult<AuthenticationResult>> AuthenticateUser(
-            [FromRoute, Required] Guid id,
+            [FromRoute, Required] Guid userId,
             [FromQuery, BindRequired] string pw,
             [FromQuery, BindRequired] string password)
         {
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (user == null)
             {
@@ -230,27 +230,27 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Updates a user's password.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="request">The <see cref="UpdateUserPassword"/> request.</param>
         /// <response code="200">Password successfully reset.</response>
         /// <response code="403">User is not allowed to update the password.</response>
         /// <response code="404">User not found.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="ForbidResult"/> or a <see cref="NotFoundResult"/> on failure.</returns>
-        [HttpPost("{id}/Password")]
+        [HttpPost("{userId}/Password")]
         [Authorize]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public async Task<ActionResult> UpdateUserPassword(
-            [FromRoute] Guid id,
+            [FromRoute] Guid userId,
             [FromBody] UpdateUserPassword request)
         {
-            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, id, true))
+            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
             {
                 return Forbid("User is not allowed to update the password.");
             }
 
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (user == null)
             {
@@ -288,27 +288,27 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Updates a user's easy password.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="request">The <see cref="UpdateUserEasyPassword"/> request.</param>
         /// <response code="200">Password successfully reset.</response>
         /// <response code="403">User is not allowed to update the password.</response>
         /// <response code="404">User not found.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="ForbidResult"/> or a <see cref="NotFoundResult"/> on failure.</returns>
-        [HttpPost("{id}/EasyPassword")]
+        [HttpPost("{userId}/EasyPassword")]
         [Authorize]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         public ActionResult UpdateUserEasyPassword(
-            [FromRoute] Guid id,
+            [FromRoute] Guid userId,
             [FromBody] UpdateUserEasyPassword request)
         {
-            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, id, true))
+            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, true))
             {
                 return Forbid("User is not allowed to update the easy password.");
             }
 
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (user == null)
             {
@@ -330,19 +330,19 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Updates a user.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="updateUser">The updated user model.</param>
         /// <response code="204">User updated.</response>
         /// <response code="400">User information was not supplied.</response>
         /// <response code="403">User update forbidden.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="BadRequestResult"/> or a <see cref="ForbidResult"/> on failure.</returns>
-        [HttpPost("{id}")]
+        [HttpPost("{userId}")]
         [Authorize]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status400BadRequest)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         public async Task<ActionResult> UpdateUser(
-            [FromRoute] Guid id,
+            [FromRoute] Guid userId,
             [FromBody] UserDto updateUser)
         {
             if (updateUser == null)
@@ -350,12 +350,12 @@ namespace Jellyfin.Api.Controllers
                 return BadRequest();
             }
 
-            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, id, false))
+            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false))
             {
                 return Forbid("User update not allowed.");
             }
 
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             if (string.Equals(user.Username, updateUser.Name, StringComparison.Ordinal))
             {
@@ -374,19 +374,19 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Updates a user policy.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="newPolicy">The new user policy.</param>
         /// <response code="204">User policy updated.</response>
         /// <response code="400">User policy was not supplied.</response>
         /// <response code="403">User policy update forbidden.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success or a <see cref="BadRequestResult"/> or a <see cref="ForbidResult"/> on failure..</returns>
-        [HttpPost("{id}/Policy")]
+        [HttpPost("{userId}/Policy")]
         [Authorize]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status400BadRequest)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         public ActionResult UpdateUserPolicy(
-            [FromRoute] Guid id,
+            [FromRoute] Guid userId,
             [FromBody] UserPolicy newPolicy)
         {
             if (newPolicy == null)
@@ -394,7 +394,7 @@ namespace Jellyfin.Api.Controllers
                 return BadRequest();
             }
 
-            var user = _userManager.GetUserById(id);
+            var user = _userManager.GetUserById(userId);
 
             // If removing admin access
             if (!(newPolicy.IsAdministrator && user.HasPermission(PermissionKind.IsAdministrator)))
@@ -423,7 +423,7 @@ namespace Jellyfin.Api.Controllers
                 _sessionManager.RevokeUserTokens(user.Id, currentToken);
             }
 
-            _userManager.UpdatePolicy(id, newPolicy);
+            _userManager.UpdatePolicy(userId, newPolicy);
 
             return NoContent();
         }
@@ -431,25 +431,25 @@ namespace Jellyfin.Api.Controllers
         /// <summary>
         /// Updates a user configuration.
         /// </summary>
-        /// <param name="id">The user id.</param>
+        /// <param name="userId">The user id.</param>
         /// <param name="userConfig">The new user configuration.</param>
         /// <response code="204">User configuration updated.</response>
         /// <response code="403">User configuration update forbidden.</response>
         /// <returns>A <see cref="NoContentResult"/> indicating success.</returns>
-        [HttpPost("{id}/Configuration")]
+        [HttpPost("{userId}/Configuration")]
         [Authorize]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status403Forbidden)]
         public ActionResult UpdateUserConfiguration(
-            [FromRoute] Guid id,
+            [FromRoute] Guid userId,
             [FromBody] UserConfiguration userConfig)
         {
-            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, id, false))
+            if (!RequestHelpers.AssertCanUpdateUser(_authContext, HttpContext.Request, userId, false))
             {
                 return Forbid("User configuration update not allowed");
             }
 
-            _userManager.UpdateConfiguration(id, userConfig);
+            _userManager.UpdateConfiguration(userId, userConfig);
 
             return NoContent();
         }

+ 1 - 1
Jellyfin.Api/Controllers/VideoAttachmentsController.cs

@@ -44,7 +44,7 @@ namespace Jellyfin.Api.Controllers
         /// <response code="200">Attachment retrieved.</response>
         /// <response code="404">Video or attachment not found.</response>
         /// <returns>An <see cref="FileStreamResult"/> containing the attachment stream on success, or a <see cref="NotFoundResult"/> if the attachment could not be found.</returns>
-        [HttpGet("{VideoID}/{MediaSourceID}/Attachments/{Index}")]
+        [HttpGet("{videoId}/{mediaSourceId}/Attachments/{index}")]
         [Produces(MediaTypeNames.Application.Octet)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]