| 
					
				 | 
			
			
				@@ -182,6 +182,10 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Gets subtitles in a specified format. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeItemId">The (route) item id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeMediaSourceId">The (route) media source id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeIndex">The (route) subtitle stream index.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeFormat">The (route) format of the returned subtitle.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="itemId">The item id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="mediaSourceId">The media source id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="index">The subtitle stream index.</param> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -189,22 +193,32 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <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> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="startPositionTicks">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/{itemId}/{mediaSourceId}/Subtitles/{index}/Stream.{format}")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [HttpGet("Videos/{routeItemId}/routeMediaSourceId/Subtitles/{routeIndex}/Stream.{routeFormat}")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [ProducesResponseType(StatusCodes.Status200OK)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [ProducesFile("text/*")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public async Task<ActionResult> GetSubtitle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] Guid itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] string mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] int index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] string format, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] Guid routeItemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] string routeMediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] int routeIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] string routeFormat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] Guid? itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] string? mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] int? index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] string? format, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] long? endPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] bool copyTimestamps = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] bool addVttTimeMap = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] long startPositionTicks = 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Set parameters to route value if not provided via query. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            itemId ??= routeItemId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            mediaSourceId ??= routeMediaSourceId; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            index ??= routeIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            format ??= routeFormat; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (string.Equals(format, "js", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 format = "json"; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -212,9 +226,9 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (string.IsNullOrEmpty(format)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var item = (Video)_libraryManager.GetItemById(itemId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var item = (Video)_libraryManager.GetItemById(itemId.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var idString = itemId.ToString("N", CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var idString = itemId.Value.ToString("N", CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     .First(i => string.Equals(i.Id, mediaSourceId ?? idString, StringComparison.Ordinal)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -226,7 +240,7 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                await using Stream stream = await EncodeSubtitles(itemId, mediaSourceId, index, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                await using Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 using var reader = new StreamReader(stream); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var text = await reader.ReadToEndAsync().ConfigureAwait(false); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -238,9 +252,9 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return File( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 await EncodeSubtitles( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    itemId.Value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    index.Value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     format, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     startPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     endPositionTicks, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -251,30 +265,44 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Gets subtitles in a specified format. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeItemId">The (route) item id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeMediaSourceId">The (route) media source id.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeIndex">The (route) subtitle stream index.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeStartPositionTicks">The (route) start position of the subtitle in ticks.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="routeFormat">The (route) format of the returned subtitle.</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="startPositionTicks">Optional. The start position of the subtitle in ticks.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="startPositionTicks">The start position of the subtitle in ticks.</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <param name="format">The format of the returned subtitle.</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> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <response code="200">File returned.</response> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <returns>A <see cref="FileContentResult"/> with the subtitle file.</returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        [HttpGet("Videos/{itemId}/{mediaSourceId}/Subtitles/{index}/{startPositionTicks}/Stream.{format}")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        [HttpGet("Videos/{routeItemId}/{routeMediaSourceId}/Subtitles/{routeIndex}/{routeStartPositionTicks}/Stream.{routeFormat}")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [ProducesResponseType(StatusCodes.Status200OK)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         [ProducesFile("text/*")] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public Task<ActionResult> GetSubtitleWithTicks( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] Guid itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] string mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] int index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] long startPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [FromRoute, Required] string format, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] Guid routeItemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] string routeMediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] int routeIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] long routeStartPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromRoute, Required] string routeFormat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] Guid? itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] string? mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] int? index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] long? startPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [FromQuery, ParameterObsolete] string? format, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] long? endPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] bool copyTimestamps = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             [FromQuery] bool addVttTimeMap = false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return GetSubtitle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                routeItemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                routeMediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                routeIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                routeFormat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 itemId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 mediaSourceId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 index, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -282,7 +310,7 @@ namespace Jellyfin.Api.Controllers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 endPositionTicks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 copyTimestamps, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 addVttTimeMap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                startPositionTicks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                startPositionTicks ?? routeStartPositionTicks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 |