mirror of
				https://github.com/zoriya/Kyoo.git
				synced 2025-11-03 19:17:16 -05:00 
			
		
		
		
	Move transcoder api to /video with path b64 encoded to prevent db hit
This commit is contained in:
		
							parent
							
								
									f871f4e1bf
								
							
						
					
					
						commit
						59e1832c3e
					
				
							
								
								
									
										42
									
								
								back/src/Kyoo.Core/Controllers/Base64RouteConstraint.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								back/src/Kyoo.Core/Controllers/Base64RouteConstraint.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Kyoo - A portable and vast media library solution.
 | 
				
			||||||
 | 
					// Copyright (c) Kyoo.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// See AUTHORS.md and LICENSE file in the project root for full license information.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Kyoo is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Kyoo is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
				
			||||||
 | 
					// GNU General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Text.RegularExpressions;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Routing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Kyoo.Core.Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Base64RouteConstraint : IRouteConstraint
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static Regex Base64Reg = new("^[-A-Za-z0-9+/]*={0,3}$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <inheritdoc />
 | 
				
			||||||
 | 
						public bool Match(
 | 
				
			||||||
 | 
							HttpContext? httpContext,
 | 
				
			||||||
 | 
							IRouter? route,
 | 
				
			||||||
 | 
							string routeKey,
 | 
				
			||||||
 | 
							RouteValueDictionary values,
 | 
				
			||||||
 | 
							RouteDirection routeDirection
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return values.TryGetValue(routeKey, out object? val)
 | 
				
			||||||
 | 
								&& val is string str
 | 
				
			||||||
 | 
								&& Base64Reg.IsMatch(str);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -76,6 +76,7 @@ public static class ServiceExtensions
 | 
				
			|||||||
		services.Configure<RouteOptions>(x =>
 | 
							services.Configure<RouteOptions>(x =>
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint));
 | 
								x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint));
 | 
				
			||||||
 | 
								x.ConstraintMap.Add("base64", typeof(Base64RouteConstraint));
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		services.AddResponseCompression(x =>
 | 
							services.AddResponseCompression(x =>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,95 +0,0 @@
 | 
				
			|||||||
// Kyoo - A portable and vast media library solution.
 | 
					 | 
				
			||||||
// Copyright (c) Kyoo.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Kyoo is free software: you can redistribute it and/or modify
 | 
					 | 
				
			||||||
// it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
// the Free Software Foundation, either version 3 of the License, or
 | 
					 | 
				
			||||||
// any later version.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Kyoo is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
					 | 
				
			||||||
// GNU General Public License for more details.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using System;
 | 
					 | 
				
			||||||
using System.Collections.Generic;
 | 
					 | 
				
			||||||
using System.Threading.Tasks;
 | 
					 | 
				
			||||||
using AspNetCore.Proxy;
 | 
					 | 
				
			||||||
using AspNetCore.Proxy.Options;
 | 
					 | 
				
			||||||
using Kyoo.Abstractions.Controllers;
 | 
					 | 
				
			||||||
using Kyoo.Abstractions.Models.Permissions;
 | 
					 | 
				
			||||||
using Kyoo.Abstractions.Models.Utils;
 | 
					 | 
				
			||||||
using Kyoo.Utils;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					 | 
				
			||||||
using Microsoft.AspNetCore.Mvc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Kyoo.Core.Api;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// <summary>
 | 
					 | 
				
			||||||
/// Proxy to other services
 | 
					 | 
				
			||||||
/// </summary>
 | 
					 | 
				
			||||||
[ApiController]
 | 
					 | 
				
			||||||
[Obsolete("Use /episode/id/master.m3u8 or routes like that")]
 | 
					 | 
				
			||||||
public class ProxyApi(ILibraryManager library) : Controller
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	private Task _Proxy(string route, (string path, string route) info)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		HttpProxyOptions proxyOptions = HttpProxyOptionsBuilder
 | 
					 | 
				
			||||||
			.Instance.WithBeforeSend(
 | 
					 | 
				
			||||||
				(ctx, req) =>
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					req.Headers.Add("X-Path", info.path);
 | 
					 | 
				
			||||||
					req.Headers.Add("X-Route", info.route);
 | 
					 | 
				
			||||||
					return Task.CompletedTask;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			.WithHandleFailure(
 | 
					 | 
				
			||||||
				async (context, exception) =>
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
 | 
					 | 
				
			||||||
					await context.Response.WriteAsJsonAsync(
 | 
					 | 
				
			||||||
						new RequestError("Service unavailable")
 | 
					 | 
				
			||||||
					);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			.Build();
 | 
					 | 
				
			||||||
		return this.HttpProxyAsync($"{Transcoder.TranscoderUrl}{route}", proxyOptions);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/// <summary>
 | 
					 | 
				
			||||||
	/// Transcoder proxy
 | 
					 | 
				
			||||||
	/// </summary>
 | 
					 | 
				
			||||||
	/// <remarks>
 | 
					 | 
				
			||||||
	/// Simply proxy requests to the transcoder
 | 
					 | 
				
			||||||
	/// </remarks>
 | 
					 | 
				
			||||||
	/// <param name="rest">The path of the transcoder.</param>
 | 
					 | 
				
			||||||
	/// <returns>The return value of the transcoder.</returns>
 | 
					 | 
				
			||||||
	[Route("video/{type}/{id:id}/{**rest}")]
 | 
					 | 
				
			||||||
	[Permission("video", Kind.Read)]
 | 
					 | 
				
			||||||
	[Obsolete("Use /episode/id/master.m3u8 or routes like that")]
 | 
					 | 
				
			||||||
	public async Task Proxy(
 | 
					 | 
				
			||||||
		string type,
 | 
					 | 
				
			||||||
		Identifier id,
 | 
					 | 
				
			||||||
		string rest,
 | 
					 | 
				
			||||||
		[FromQuery] Dictionary<string, string> query
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		string path = await (
 | 
					 | 
				
			||||||
			type is "movie" or "movies"
 | 
					 | 
				
			||||||
				? id.Match(
 | 
					 | 
				
			||||||
					async id => (await library.Movies.Get(id)).Path,
 | 
					 | 
				
			||||||
					async slug => (await library.Movies.Get(slug)).Path
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
				: id.Match(
 | 
					 | 
				
			||||||
					async id => (await library.Episodes.Get(id)).Path,
 | 
					 | 
				
			||||||
					async slug => (await library.Episodes.Get(slug)).Path
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
		await _Proxy(rest + query.ToQueryString(), (path, $"{type}/{id}"));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										122
									
								
								back/src/Kyoo.Core/Views/Content/VideoApi.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								back/src/Kyoo.Core/Views/Content/VideoApi.cs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					// Kyoo - A portable and vast media library solution.
 | 
				
			||||||
 | 
					// Copyright (c) Kyoo.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// See AUTHORS.md and LICENSE file in the project root for full license information.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Kyoo is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Kyoo is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
				
			||||||
 | 
					// GNU General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using AspNetCore.Proxy;
 | 
				
			||||||
 | 
					using AspNetCore.Proxy.Options;
 | 
				
			||||||
 | 
					using Kyoo.Abstractions.Models.Attributes;
 | 
				
			||||||
 | 
					using Kyoo.Abstractions.Models.Permissions;
 | 
				
			||||||
 | 
					using Kyoo.Abstractions.Models.Utils;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
 | 
					using Microsoft.AspNetCore.Mvc;
 | 
				
			||||||
 | 
					using static Kyoo.Abstractions.Models.Utils.Constants;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Kyoo.Core.Api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Private routes of the transcoder.
 | 
				
			||||||
 | 
					/// Url for these routes will be returned from /info or /master.m3u8 routes.
 | 
				
			||||||
 | 
					/// This should not be called manually
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					[ApiController]
 | 
				
			||||||
 | 
					[Route("videos")]
 | 
				
			||||||
 | 
					[Route("video", Order = AlternativeRoute)]
 | 
				
			||||||
 | 
					[Permission("video", Kind.Read, Group = Group.Overall)]
 | 
				
			||||||
 | 
					[ApiDefinition("Video", Group = OtherGroup)]
 | 
				
			||||||
 | 
					public class VideoApi : Controller
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public static string TranscoderUrl =
 | 
				
			||||||
 | 
							Environment.GetEnvironmentVariable("TRANSCODER_URL") ?? "http://transcoder:7666";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Task _Proxy(string route)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							HttpProxyOptions proxyOptions = HttpProxyOptionsBuilder
 | 
				
			||||||
 | 
								.Instance.WithHandleFailure(
 | 
				
			||||||
 | 
									async (context, exception) =>
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
 | 
				
			||||||
 | 
										await context.Response.WriteAsJsonAsync(
 | 
				
			||||||
 | 
											new RequestError("Service unavailable")
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
								.Build();
 | 
				
			||||||
 | 
							return this.HttpProxyAsync($"{TranscoderUrl}/{route}", proxyOptions);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/direct")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						[ProducesResponseType(StatusCodes.Status206PartialContent)]
 | 
				
			||||||
 | 
						[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
				
			||||||
 | 
						public async Task GetDirectStream(string path)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/direct");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/master.m3u8")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						[ProducesResponseType(StatusCodes.Status206PartialContent)]
 | 
				
			||||||
 | 
						[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
				
			||||||
 | 
						public async Task GetMaster(string path)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/master.m3u8");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/{quality}/index.m3u8")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetVideoIndex(string path, string quality)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/{quality}/index.m3u8");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/{quality}/{segment}")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetVideoSegment(string path, string quality, string segment)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/{quality}/{segment}");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/audio/{audio}/index.m3u8")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetAudioIndex(string path, string audio)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/audio/{audio}/index.m3u8");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/audio/{audio}/{segment}")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetAudioSegment(string path, string audio, string segment)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/audio/{audio}/{segment}");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/attachment/{name}")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetAttachment(string path, string name)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/attachment/{name}");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[HttpGet("{path:base64}/subtitle/{name}")]
 | 
				
			||||||
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
 | 
						public async Task GetSubtitle(string path, string name)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							await _Proxy($"{path}/subtitle/{name}");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -17,6 +17,7 @@
 | 
				
			|||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | 
					// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using AspNetCore.Proxy;
 | 
					using AspNetCore.Proxy;
 | 
				
			||||||
using AspNetCore.Proxy.Options;
 | 
					using AspNetCore.Proxy.Options;
 | 
				
			||||||
@ -29,27 +30,13 @@ using Microsoft.AspNetCore.Mvc;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Kyoo.Core.Api;
 | 
					namespace Kyoo.Core.Api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public static class Transcoder
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	public static string TranscoderUrl =
 | 
					 | 
				
			||||||
		Environment.GetEnvironmentVariable("TRANSCODER_URL") ?? "http://transcoder:7666";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsApi<T>(repository)
 | 
					public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsApi<T>(repository)
 | 
				
			||||||
	where T : class, IResource, IThumbnails, IQuery
 | 
						where T : class, IResource, IThumbnails, IQuery
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private Task _Proxy(string route, (string path, string route) info)
 | 
						private Task _Proxy(string route)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		HttpProxyOptions proxyOptions = HttpProxyOptionsBuilder
 | 
							HttpProxyOptions proxyOptions = HttpProxyOptionsBuilder
 | 
				
			||||||
			.Instance.WithBeforeSend(
 | 
								.Instance.WithHandleFailure(
 | 
				
			||||||
				(ctx, req) =>
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					req.Headers.Add("X-Path", info.path);
 | 
					 | 
				
			||||||
					req.Headers.Add("X-Route", info.route);
 | 
					 | 
				
			||||||
					return Task.CompletedTask;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
			.WithHandleFailure(
 | 
					 | 
				
			||||||
				async (context, exception) =>
 | 
									async (context, exception) =>
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
 | 
										context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
 | 
				
			||||||
@ -59,10 +46,16 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
			.Build();
 | 
								.Build();
 | 
				
			||||||
		return this.HttpProxyAsync($"{Transcoder.TranscoderUrl}{route}", proxyOptions);
 | 
							return this.HttpProxyAsync($"{VideoApi.TranscoderUrl}/{route}", proxyOptions);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected abstract Task<(string path, string route)> GetPath(Identifier identifier);
 | 
						protected abstract Task<string> GetPath(Identifier identifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private async Task<string> _GetPath64(Identifier identifier)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							string path = await GetPath(identifier);
 | 
				
			||||||
 | 
							return Convert.ToBase64String(Encoding.UTF8.GetBytes(path));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
	/// Direct stream
 | 
						/// Direct stream
 | 
				
			||||||
@ -76,11 +69,12 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
	/// <response code="404">No episode with the given ID or slug could be found.</response>
 | 
						/// <response code="404">No episode with the given ID or slug could be found.</response>
 | 
				
			||||||
	[HttpGet("{identifier:id}/direct")]
 | 
						[HttpGet("{identifier:id}/direct")]
 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
	[ProducesResponseType(StatusCodes.Status206PartialContent)]
 | 
						[ProducesResponseType(StatusCodes.Status302Found)]
 | 
				
			||||||
	[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
						[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
				
			||||||
	public async Task GetDirectStream(Identifier identifier)
 | 
						public async Task<IActionResult> GetDirectStream(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		await _Proxy("/direct", await GetPath(identifier));
 | 
							// TODO: Remove the /api and use a proxy rewrite instead.
 | 
				
			||||||
 | 
							return Redirect($"/api/video/{await _GetPath64(identifier)}/direct");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
@ -96,39 +90,12 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
	/// <response code="404">No episode with the given ID or slug could be found.</response>
 | 
						/// <response code="404">No episode with the given ID or slug could be found.</response>
 | 
				
			||||||
	[HttpGet("{identifier:id}/master.m3u8")]
 | 
						[HttpGet("{identifier:id}/master.m3u8")]
 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
						[PartialPermission(Kind.Play)]
 | 
				
			||||||
	[ProducesResponseType(StatusCodes.Status206PartialContent)]
 | 
						[ProducesResponseType(StatusCodes.Status302Found)]
 | 
				
			||||||
	[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
						[ProducesResponseType(StatusCodes.Status404NotFound)]
 | 
				
			||||||
	public async Task GetMaster(Identifier identifier)
 | 
						public async Task<IActionResult> GetMaster(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		await _Proxy("/master.m3u8", await GetPath(identifier));
 | 
							// TODO: Remove the /api and use a proxy rewrite instead.
 | 
				
			||||||
	}
 | 
							return Redirect($"/api/video/{await _GetPath64(identifier)}/master.m3u8");
 | 
				
			||||||
 | 
					 | 
				
			||||||
	[HttpGet("{identifier:id}/{quality}/index.m3u8")]
 | 
					 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
					 | 
				
			||||||
	public async Task GetVideoIndex(Identifier identifier, string quality)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		await _Proxy($"/{quality}/index.m3u8", await GetPath(identifier));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[HttpGet("{identifier:id}/{quality}/{segment}")]
 | 
					 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
					 | 
				
			||||||
	public async Task GetVideoSegment(Identifier identifier, string quality, string segment)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		await _Proxy($"/{quality}/{segment}", await GetPath(identifier));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[HttpGet("{identifier:id}/audio/{audio}/index.m3u8")]
 | 
					 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
					 | 
				
			||||||
	public async Task GetAudioIndex(Identifier identifier, string audio)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		await _Proxy($"/audio/{audio}/index.m3u8", await GetPath(identifier));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[HttpGet("{identifier:id}/audio/{audio}/{segment}")]
 | 
					 | 
				
			||||||
	[PartialPermission(Kind.Play)]
 | 
					 | 
				
			||||||
	public async Task GetAudioSegment(Identifier identifier, string audio, string segment)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		await _Proxy($"/audio/{audio}/{segment}", await GetPath(identifier));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
@ -144,7 +111,7 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
	[PartialPermission(Kind.Read)]
 | 
						[PartialPermission(Kind.Read)]
 | 
				
			||||||
	public async Task GetInfo(Identifier identifier)
 | 
						public async Task GetInfo(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		await _Proxy("/info", await GetPath(identifier));
 | 
							await _Proxy($"{await _GetPath64(identifier)}/info");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
@ -160,7 +127,7 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
	[PartialPermission(Kind.Read)]
 | 
						[PartialPermission(Kind.Read)]
 | 
				
			||||||
	public async Task GetThumbnails(Identifier identifier)
 | 
						public async Task GetThumbnails(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		await _Proxy("/thumbnails.png", await GetPath(identifier));
 | 
							await _Proxy($"{await _GetPath64(identifier)}/thumbnails.png");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// <summary>
 | 
						/// <summary>
 | 
				
			||||||
@ -177,6 +144,6 @@ public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsAp
 | 
				
			|||||||
	[PartialPermission(Kind.Read)]
 | 
						[PartialPermission(Kind.Read)]
 | 
				
			||||||
	public async Task GetThumbnailsVtt(Identifier identifier)
 | 
						public async Task GetThumbnailsVtt(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		await _Proxy("/thumbnails.vtt", await GetPath(identifier));
 | 
							await _Proxy($"{await _GetPath64(identifier)}/thumbnails.vtt");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -210,12 +210,12 @@ public class EpisodeApi(ILibraryManager libraryManager)
 | 
				
			|||||||
		await libraryManager.WatchStatus.DeleteEpisodeStatus(id, User.GetIdOrThrow());
 | 
							await libraryManager.WatchStatus.DeleteEpisodeStatus(id, User.GetIdOrThrow());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected override async Task<(string path, string route)> GetPath(Identifier identifier)
 | 
						protected override async Task<string> GetPath(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		string path = await identifier.Match(
 | 
							string path = await identifier.Match(
 | 
				
			||||||
			async id => (await Repository.Get(id)).Path,
 | 
								async id => (await Repository.Get(id)).Path,
 | 
				
			||||||
			async slug => (await Repository.Get(slug)).Path
 | 
								async slug => (await Repository.Get(slug)).Path
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		return (path, $"/episodes/{identifier}");
 | 
							return path;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -221,12 +221,12 @@ public class MovieApi(ILibraryManager libraryManager) : TranscoderApi<Movie>(lib
 | 
				
			|||||||
		await libraryManager.WatchStatus.DeleteMovieStatus(id, User.GetIdOrThrow());
 | 
							await libraryManager.WatchStatus.DeleteMovieStatus(id, User.GetIdOrThrow());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected override async Task<(string path, string route)> GetPath(Identifier identifier)
 | 
						protected override async Task<string> GetPath(Identifier identifier)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		string path = await identifier.Match(
 | 
							string path = await identifier.Match(
 | 
				
			||||||
			async id => (await Repository.Get(id)).Path,
 | 
								async id => (await Repository.Get(id)).Path,
 | 
				
			||||||
			async slug => (await Repository.Get(slug)).Path
 | 
								async slug => (await Repository.Get(slug)).Path
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		return (path, $"/movies/{identifier}");
 | 
							return path;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user