mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Reworking the transcoder and creating a file manager
This commit is contained in:
parent
fdfd42c7c1
commit
57e49b7e83
16
Kyoo.Common/Controllers/IFileManager.cs
Normal file
16
Kyoo.Common/Controllers/IFileManager.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.IO;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public interface IFileManager
|
||||
{
|
||||
public IActionResult FileResult([NotNull] string path, bool rangeSupport = false);
|
||||
|
||||
public StreamReader GetReader([NotNull] string path);
|
||||
// TODO implement a List for directorys, a Exist to check existance and all.
|
||||
// TODO replace every use of System.IO with this to allow custom paths (like uptobox://path)
|
||||
// TODO find a way to handle Transmux/Transcode with this system.
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Watch;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public interface ITranscoder
|
||||
{
|
||||
Task<Track[]> ExtractInfos(string path);
|
||||
Task<Track[]> ExtractInfos(string path, bool reextract);
|
||||
Task<string> Transmux(Episode episode);
|
||||
Task<string> Transcode(Episode episode);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Kyoo.Models
|
||||
Video = 1,
|
||||
Audio = 2,
|
||||
Subtitle = 3,
|
||||
Font = 4
|
||||
Attachment = 4
|
||||
}
|
||||
|
||||
namespace Watch
|
||||
@ -100,7 +100,7 @@ namespace Kyoo.Models
|
||||
StreamType.Subtitle => "",
|
||||
StreamType.Video => "video.",
|
||||
StreamType.Audio => "audio.",
|
||||
StreamType.Font => "font.",
|
||||
StreamType.Attachment => "font.",
|
||||
_ => ""
|
||||
};
|
||||
string index = TrackIndex != 0 ? $"-{TrackIndex}" : string.Empty;
|
||||
|
41
Kyoo/Controllers/FileManager.cs
Normal file
41
Kyoo/Controllers/FileManager.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class FileManager : ControllerBase, IFileManager
|
||||
{
|
||||
private FileExtensionContentTypeProvider _provider;
|
||||
|
||||
private string _GetContentType(string path)
|
||||
{
|
||||
if (_provider == null)
|
||||
{
|
||||
_provider = new FileExtensionContentTypeProvider();
|
||||
_provider.Mappings[".mkv"] = "video/x-matroska";
|
||||
}
|
||||
|
||||
if (_provider.TryGetContentType(path, out string contentType))
|
||||
return contentType;
|
||||
return "video/mp4";
|
||||
}
|
||||
|
||||
public IActionResult FileResult(string path, bool range)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
if (!System.IO.File.Exists(path))
|
||||
return NotFound();
|
||||
return PhysicalFile(path, _GetContentType(path), range);
|
||||
}
|
||||
|
||||
public StreamReader GetReader(string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
return new StreamReader(path);
|
||||
}
|
||||
}
|
||||
}
|
134
Kyoo/Controllers/Transcoder.cs
Normal file
134
Kyoo/Controllers/Transcoder.cs
Normal file
@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Stream = Kyoo.Models.Watch.Stream;
|
||||
|
||||
// We use threads so tasks are not always awaited.
|
||||
#pragma warning disable 4014
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class BadTranscoderException : Exception {}
|
||||
|
||||
public class Transcoder : ITranscoder
|
||||
{
|
||||
private static class TranscoderAPI
|
||||
{
|
||||
private const string TranscoderPath = "libtranscoder.so";
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int init();
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int transmux(string path, string outpath, out float playableDuration);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int transcode(string path, string outpath, out float playableDuration);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr extract_infos(string path,
|
||||
string outpath,
|
||||
out int length,
|
||||
out int trackCount,
|
||||
bool reextracct);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void free(IntPtr ptr);
|
||||
|
||||
|
||||
public static Track[] ExtractInfos(string path, string outPath, bool reextract)
|
||||
{
|
||||
int size = Marshal.SizeOf<Stream>();
|
||||
IntPtr ptr = extract_infos(path, outPath, out int arrayLength, out int trackCount, reextract);
|
||||
IntPtr streamsPtr = ptr;
|
||||
Track[] tracks;
|
||||
|
||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||
{
|
||||
tracks = new Track[trackCount];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < arrayLength; i++)
|
||||
{
|
||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||
if (stream!.Type != StreamType.Unknown)
|
||||
{
|
||||
tracks[j] = new Track(stream);
|
||||
j++;
|
||||
}
|
||||
streamsPtr += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
tracks = Array.Empty<Track>();
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
free(ptr); // free_streams is not necesarry since the Marshal free the unmanaged pointers.
|
||||
return tracks;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly string _transmuxPath;
|
||||
private readonly string _transcodePath;
|
||||
|
||||
public Transcoder(IConfiguration config)
|
||||
{
|
||||
_transmuxPath = Path.GetFullPath(config.GetValue<string>("transmuxTempPath"));
|
||||
_transcodePath = Path.GetFullPath(config.GetValue<string>("transcodeTempPath"));
|
||||
|
||||
if (TranscoderAPI.init() != Marshal.SizeOf<Stream>())
|
||||
throw new BadTranscoderException();
|
||||
}
|
||||
|
||||
public Task<Track[]> ExtractInfos(string path, bool reextract)
|
||||
{
|
||||
string dir = Path.GetDirectoryName(path);
|
||||
if (dir == null)
|
||||
throw new ArgumentException("Invalid path.");
|
||||
dir = Path.Combine(dir, "Extra");
|
||||
return Task.Factory.StartNew(
|
||||
() => TranscoderAPI.ExtractInfos(path, dir, reextract),
|
||||
TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
public async Task<string> Transmux(Episode episode)
|
||||
{
|
||||
if (!File.Exists(episode.Path))
|
||||
throw new ArgumentException("Path does not exists. Can't transcode.");
|
||||
|
||||
string folder = Path.Combine(_transmuxPath, episode.Slug);
|
||||
string manifest = Path.Combine(folder, episode.Slug + ".m3u8");
|
||||
float playableDuration = 0;
|
||||
bool transmuxFailed = false;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
if (File.Exists(manifest))
|
||||
return manifest;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
await Console.Error.WriteLineAsync($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
string cleanManifest = manifest.Replace('\\', '/');
|
||||
transmuxFailed = TranscoderAPI.transmux(episode.Path, cleanManifest, out playableDuration) != 0;
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
while (playableDuration < 10 || !File.Exists(manifest) && !transmuxFailed)
|
||||
await Task.Delay(10);
|
||||
return transmuxFailed ? null : manifest;
|
||||
}
|
||||
|
||||
public Task<string> Transcode(Episode episode)
|
||||
{
|
||||
return Task.FromResult<string>(null); // Not implemented yet.
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers.TranscoderLink;
|
||||
#pragma warning disable 4014
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class BadTranscoderException : Exception {}
|
||||
|
||||
public class Transcoder : ITranscoder
|
||||
{
|
||||
private readonly string _transmuxPath;
|
||||
private readonly string _transcodePath;
|
||||
|
||||
public Transcoder(IConfiguration config)
|
||||
{
|
||||
_transmuxPath = Path.GetFullPath(config.GetValue<string>("transmuxTempPath"));
|
||||
_transcodePath = Path.GetFullPath(config.GetValue<string>("transcodeTempPath"));
|
||||
|
||||
if (TranscoderAPI.init() != Marshal.SizeOf<Models.Watch.Stream>())
|
||||
throw new BadTranscoderException();
|
||||
}
|
||||
|
||||
public Task<Track[]> ExtractInfos(string path)
|
||||
{
|
||||
string dir = Path.GetDirectoryName(path);
|
||||
if (dir == null)
|
||||
throw new ArgumentException("Invalid path.");
|
||||
|
||||
return Task.Factory.StartNew(() => TranscoderAPI.ExtractInfos(path, dir), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
|
||||
public async Task<string> Transmux(Episode episode)
|
||||
{
|
||||
string folder = Path.Combine(_transmuxPath, episode.Slug);
|
||||
string manifest = Path.Combine(folder, episode.Slug + ".m3u8");
|
||||
float playableDuration = 0;
|
||||
bool transmuxFailed = false;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
if (File.Exists(manifest))
|
||||
return manifest;
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
await Console.Error.WriteLineAsync($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
||||
return null;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
transmuxFailed = TranscoderAPI.transmux(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0;
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
while (playableDuration < 10 || !File.Exists(manifest) && !transmuxFailed)
|
||||
await Task.Delay(10);
|
||||
return transmuxFailed ? null : manifest;
|
||||
}
|
||||
|
||||
public Task<string> Transcode(Episode episode)
|
||||
{
|
||||
return Task.FromResult<string>(null); // Not implemented yet.
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Watch;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Kyoo.Controllers.TranscoderLink
|
||||
{
|
||||
public static class TranscoderAPI
|
||||
{
|
||||
private const string TranscoderPath = "libtranscoder.so";
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int init();
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int transmux(string path, string out_path, out float playableDuration);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern int transcode(string path, string out_path, out float playableDuration);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern IntPtr extract_infos(string path, string outpath, out int length, out int track_count);
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void free(IntPtr stream_ptr);
|
||||
|
||||
|
||||
public static Track[] ExtractInfos(string path, string outPath)
|
||||
{
|
||||
int size = Marshal.SizeOf<Stream>();
|
||||
IntPtr ptr = extract_infos(path, outPath, out int arrayLength, out int trackCount);
|
||||
IntPtr streamsPtr = ptr;
|
||||
Track[] tracks;
|
||||
|
||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||
{
|
||||
tracks = new Track[trackCount];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < arrayLength; i++)
|
||||
{
|
||||
Stream stream = Marshal.PtrToStructure<Stream>(streamsPtr);
|
||||
if (stream!.Type != StreamType.Unknown)
|
||||
{
|
||||
tracks[j] = new Track(stream);
|
||||
j++;
|
||||
}
|
||||
streamsPtr += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
tracks = Array.Empty<Track>();
|
||||
|
||||
if (ptr != IntPtr.Zero)
|
||||
free(ptr); // free_streams is not necesarry since the Marshal free the unmanaged pointers.
|
||||
return tracks;
|
||||
}
|
||||
}
|
||||
}
|
@ -158,6 +158,7 @@ namespace Kyoo
|
||||
services.AddScoped<DbContext, DatabaseContext>();
|
||||
|
||||
services.AddScoped<ILibraryManager, LibraryManager>();
|
||||
services.AddScoped<IFileManager, FileManager>();
|
||||
services.AddSingleton<ITranscoder, Transcoder>();
|
||||
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
||||
services.AddSingleton<IProviderManager, ProviderManager>();
|
||||
|
@ -359,8 +359,8 @@ namespace Kyoo.Controllers
|
||||
|
||||
private async Task<ICollection<Track>> GetTracks(Episode episode)
|
||||
{
|
||||
episode.Tracks = (await _transcoder.ExtractInfos(episode.Path))
|
||||
.Where(x => x.Type != StreamType.Font)
|
||||
episode.Tracks = (await _transcoder.ExtractInfos(episode.Path, false))
|
||||
.Where(x => x.Type != StreamType.Attachment)
|
||||
.ToArray();
|
||||
return episode.Tracks;
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ namespace Kyoo.Tasks
|
||||
if (subs)
|
||||
{
|
||||
await _library.Load(episode, x => x.Tracks);
|
||||
episode.Tracks = (await _transcoder!.ExtractInfos(episode.Path))
|
||||
.Where(x => x.Type != StreamType.Font)
|
||||
episode.Tracks = (await _transcoder!.ExtractInfos(episode.Path, true))
|
||||
.Where(x => x.Type != StreamType.Attachment)
|
||||
.Concat(episode.Tracks.Where(x => x.IsExternal))
|
||||
.ToList();
|
||||
await _library.EditEpisode(episode, false);
|
||||
|
@ -14,10 +14,12 @@ namespace Kyoo.Api
|
||||
public class SubtitleApi : ControllerBase
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IFileManager _files;
|
||||
|
||||
public SubtitleApi(ILibraryManager libraryManager)
|
||||
public SubtitleApi(ILibraryManager libraryManager, IFileManager files)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_files = files;
|
||||
}
|
||||
|
||||
|
||||
@ -39,9 +41,8 @@ namespace Kyoo.Api
|
||||
return NotFound();
|
||||
|
||||
if (subtitle.Codec == "subrip" && extension == "vtt")
|
||||
return new ConvertSubripToVtt(subtitle.Path);
|
||||
string mime = subtitle.Codec == "ass" ? "text/x-ssa" : "application/x-subrip";
|
||||
return PhysicalFile(subtitle.Path, mime);
|
||||
return new ConvertSubripToVtt(subtitle.Path, _files);
|
||||
return _files.FileResult(subtitle.Path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,27 +50,29 @@ namespace Kyoo.Api
|
||||
public class ConvertSubripToVtt : IActionResult
|
||||
{
|
||||
private readonly string _path;
|
||||
private readonly IFileManager _files;
|
||||
|
||||
public ConvertSubripToVtt(string subtitlePath)
|
||||
public ConvertSubripToVtt(string subtitlePath, IFileManager files)
|
||||
{
|
||||
_path = subtitlePath;
|
||||
_files = files;
|
||||
}
|
||||
|
||||
public async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
string line;
|
||||
List<string> lines = new List<string>();
|
||||
List<string> lines = new();
|
||||
|
||||
context.HttpContext.Response.StatusCode = 200;
|
||||
context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
|
||||
|
||||
await using (StreamWriter writer = new StreamWriter(context.HttpContext.Response.Body))
|
||||
await using (StreamWriter writer = new(context.HttpContext.Response.Body))
|
||||
{
|
||||
await writer.WriteLineAsync("WEBVTT");
|
||||
await writer.WriteLineAsync("");
|
||||
await writer.WriteLineAsync("");
|
||||
|
||||
using StreamReader reader = new StreamReader(_path);
|
||||
using StreamReader reader = _files.GetReader(_path);
|
||||
string line;
|
||||
while ((line = await reader.ReadLineAsync()) != null)
|
||||
{
|
||||
if (line == "")
|
||||
|
@ -1,12 +1,11 @@
|
||||
using Kyoo.Controllers;
|
||||
using System.IO;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
|
||||
namespace Kyoo.Api
|
||||
{
|
||||
@ -16,14 +15,18 @@ namespace Kyoo.Api
|
||||
{
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly ITranscoder _transcoder;
|
||||
private readonly IFileManager _files;
|
||||
private readonly string _transmuxPath;
|
||||
private readonly string _transcodePath;
|
||||
private FileExtensionContentTypeProvider _provider;
|
||||
|
||||
public VideoApi(ILibraryManager libraryManager, ITranscoder transcoder, IConfiguration config)
|
||||
public VideoApi(ILibraryManager libraryManager,
|
||||
ITranscoder transcoder,
|
||||
IConfiguration config,
|
||||
IFileManager files)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_transcoder = transcoder;
|
||||
_files = files;
|
||||
_transmuxPath = config.GetValue<string>("transmuxTempPath");
|
||||
_transcodePath = config.GetValue<string>("transcodeTempPath");
|
||||
}
|
||||
@ -37,19 +40,6 @@ namespace Kyoo.Api
|
||||
ctx.HttpContext.Response.Headers.Add("Expires", "0");
|
||||
}
|
||||
|
||||
private string _GetContentType(string path)
|
||||
{
|
||||
if (_provider == null)
|
||||
{
|
||||
_provider = new FileExtensionContentTypeProvider();
|
||||
_provider.Mappings[".mkv"] = "video/x-matroska";
|
||||
}
|
||||
|
||||
if (_provider.TryGetContentType(path, out string contentType))
|
||||
return contentType;
|
||||
return "video/mp4";
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}")]
|
||||
[HttpGet("direct/{showSlug}-s{seasonNumber:int}e{episodeNumber:int}")]
|
||||
@ -60,9 +50,9 @@ namespace Kyoo.Api
|
||||
return BadRequest(new {error = "Season number or episode number can not be negative."});
|
||||
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
return PhysicalFile(episode.Path, _GetContentType(episode.Path), true);
|
||||
return NotFound();
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
return _files.FileResult(episode.Path, true);
|
||||
}
|
||||
|
||||
[HttpGet("{movieSlug}")]
|
||||
@ -72,9 +62,9 @@ namespace Kyoo.Api
|
||||
{
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode != null && System.IO.File.Exists(episode.Path))
|
||||
return PhysicalFile(episode.Path, _GetContentType(episode.Path), true);
|
||||
return NotFound();
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
return _files.FileResult(episode.Path, true);
|
||||
}
|
||||
|
||||
|
||||
@ -86,12 +76,12 @@ namespace Kyoo.Api
|
||||
return BadRequest(new {error = "Season number or episode number can not be negative."});
|
||||
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
string path = await _transcoder.Transmux(episode);
|
||||
if (path == null)
|
||||
return StatusCode(500);
|
||||
return PhysicalFile(path, "application/x-mpegurl", true);
|
||||
return _files.FileResult(path, true);
|
||||
}
|
||||
|
||||
[HttpGet("transmux/{movieSlug}/master.m3u8")]
|
||||
@ -100,12 +90,12 @@ namespace Kyoo.Api
|
||||
{
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
string path = await _transcoder.Transmux(episode);
|
||||
if (path == null)
|
||||
return StatusCode(500);
|
||||
return PhysicalFile(path, "application/x-mpegurl", true);
|
||||
return _files.FileResult(path, true);
|
||||
}
|
||||
|
||||
[HttpGet("transcode/{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/master.m3u8")]
|
||||
@ -116,12 +106,12 @@ namespace Kyoo.Api
|
||||
return BadRequest(new {error = "Season number or episode number can not be negative."});
|
||||
|
||||
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
string path = await _transcoder.Transcode(episode);
|
||||
if (path == null)
|
||||
return StatusCode(500);
|
||||
return PhysicalFile(path, "application/x-mpegurl", true);
|
||||
return _files.FileResult(path, true);
|
||||
}
|
||||
|
||||
[HttpGet("transcode/{movieSlug}/master.m3u8")]
|
||||
@ -130,12 +120,12 @@ namespace Kyoo.Api
|
||||
{
|
||||
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
|
||||
|
||||
if (episode == null || !System.IO.File.Exists(episode.Path))
|
||||
if (episode == null)
|
||||
return NotFound();
|
||||
string path = await _transcoder.Transcode(episode);
|
||||
if (path == null)
|
||||
return StatusCode(500);
|
||||
return PhysicalFile(path, "application/x-mpegurl", true);
|
||||
return _files.FileResult(path, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3885dca743bbde5d83cb3816646455856fc5c316
|
||||
Subproject commit 9acd635aca92ad81f1de562e34b2c7c270bade29
|
Loading…
x
Reference in New Issue
Block a user