API: Doucmenting subtitles's API

This commit is contained in:
Zoe Roux 2021-09-29 16:22:53 +02:00
parent 19023fbaf5
commit 24a45c0b72

View File

@ -22,60 +22,79 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions; using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api namespace Kyoo.Core.Api
{ {
[Route("subtitle")] /// <summary>
/// An endpoint to retrieve subtitles for a specific episode.
/// </summary>
[Route("subtitles")]
[Route("subtitle", Order = AlternativeRoute)]
[PartialPermission(nameof(SubtitleApi))]
[ApiController] [ApiController]
[ApiDefinition("Subtitles", Group = WatchGroup)]
public class SubtitleApi : ControllerBase public class SubtitleApi : ControllerBase
{ {
/// <summary>
/// The library manager used to modify or retrieve information about the data store.
/// </summary>
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
/// <summary>
/// The file manager used to send subtitles files.
/// </summary>
private readonly IFileSystem _files; private readonly IFileSystem _files;
/// <summary>
/// Create a new <see cref="SubtitleApi"/>.
/// </summary>
/// <param name="libraryManager">The library manager used to interact with the data store.</param>
/// <param name="files">The file manager used to send subtitle files.</param>
public SubtitleApi(ILibraryManager libraryManager, IFileSystem files) public SubtitleApi(ILibraryManager libraryManager, IFileSystem files)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
_files = files; _files = files;
} }
[HttpGet("{id:int}")] /// <summary>
[Permission(nameof(SubtitleApi), Kind.Read)] /// Get subtitle
public async Task<IActionResult> GetSubtitle(int id) /// </summary>
/// <remarks>
/// Get the subtitle file with the given identifier.
/// The extension is optional and can be used to ask Kyoo to convert the subtitle file on the fly.
/// </remarks>
/// <param name="identifier">
/// The ID or slug of the subtitle (the same as the corresponding <see cref="Track"/>).
/// </param>
/// <param name="extension">An optional extension for the subtitle file.</param>
/// <returns>The subtitle file</returns>
/// <response code="404">No subtitle exist with the given ID or slug.</response>
[HttpGet("{identifier:id}", Order = AlternativeRoute)]
[HttpGet("{identifier:id}.{extension}")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetSubtitle(Identifier identifier, string extension)
{ {
Track subtitle = await _libraryManager.GetOrDefault<Track>(id); Track subtitle = await identifier.Match(
return subtitle != null id => _libraryManager.GetOrDefault<Track>(id),
? _files.FileResult(subtitle.Path) slug =>
: NotFound();
}
[HttpGet("{id:int}.{extension}")]
[Permission(nameof(SubtitleApi), Kind.Read)]
public async Task<IActionResult> GetSubtitle(int id, string extension)
{ {
Track subtitle = await _libraryManager.GetOrDefault<Track>(id);
if (subtitle == null)
return NotFound();
if (subtitle.Codec == "subrip" && extension == "vtt")
return new ConvertSubripToVtt(subtitle.Path, _files);
return _files.FileResult(subtitle.Path);
}
[HttpGet("{slug}")]
[Permission(nameof(SubtitleApi), Kind.Read)]
public async Task<IActionResult> GetSubtitle(string slug)
{
string extension = null;
if (slug.Count(x => x == '.') == 3) if (slug.Count(x => x == '.') == 3)
{ {
int idx = slug.LastIndexOf('.'); int idx = slug.LastIndexOf('.');
extension = slug[(idx + 1)..]; extension = slug[(idx + 1)..];
slug = slug[..idx]; slug = slug[..idx];
} }
return _libraryManager.GetOrDefault<Track>(Track.BuildSlug(slug, StreamType.Subtitle));
});
Track subtitle = await _libraryManager.GetOrDefault<Track>(Track.BuildSlug(slug, StreamType.Subtitle));
if (subtitle == null) if (subtitle == null)
return NotFound(); return NotFound();
if (subtitle.Codec == "subrip" && extension == "vtt") if (subtitle.Codec == "subrip" && extension == "vtt")
@ -83,17 +102,37 @@ namespace Kyoo.Core.Api
return _files.FileResult(subtitle.Path); return _files.FileResult(subtitle.Path);
} }
public class ConvertSubripToVtt : IActionResult /// <summary>
/// An action result that convert a subrip subtitle to vtt.
/// </summary>
private class ConvertSubripToVtt : IActionResult
{ {
/// <summary>
/// The path of the file to convert. It can be any path supported by a <see cref="IFileSystem"/>.
/// </summary>
private readonly string _path; private readonly string _path;
/// <summary>
/// The file system used to manipulate the given file.
/// </summary>
private readonly IFileSystem _files; private readonly IFileSystem _files;
/// <summary>
/// Create a new <see cref="ConvertSubripToVtt"/>.
/// </summary>
/// <param name="subtitlePath">
/// The path of the subtitle file. It can be any path supported by the given <paramref name="files"/>.
/// </param>
/// <param name="files">
/// The file system used to interact with the file at the given <paramref name="subtitlePath"/>.
/// </param>
public ConvertSubripToVtt(string subtitlePath, IFileSystem files) public ConvertSubripToVtt(string subtitlePath, IFileSystem files)
{ {
_path = subtitlePath; _path = subtitlePath;
_files = files; _files = files;
} }
/// <inheritdoc />
public async Task ExecuteResultAsync(ActionContext context) public async Task ExecuteResultAsync(ActionContext context)
{ {
List<string> lines = new(); List<string> lines = new();
@ -127,7 +166,12 @@ namespace Kyoo.Core.Api
await context.HttpContext.Response.Body.FlushAsync(); await context.HttpContext.Response.Body.FlushAsync();
} }
private static IEnumerable<string> _ConvertBlock(IList<string> lines) /// <summary>
/// Convert a block from subrip to vtt.
/// </summary>
/// <param name="lines">All the lines in the block.</param>
/// <returns>The given block, converted to vtt.</returns>
private static IList<string> _ConvertBlock(IList<string> lines)
{ {
if (lines.Count < 3) if (lines.Count < 3)
return lines; return lines;
@ -150,8 +194,7 @@ namespace Kyoo.Core.Api
} }
if (lines[2].StartsWith("{\\an")) if (lines[2].StartsWith("{\\an"))
lines[2] = lines[2].Substring(6); lines[2] = lines[2][6..];
return lines; return lines;
} }
} }