mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add liks in the API for videos, fonts and subtitle
This commit is contained in:
parent
0652ffef68
commit
edc33f3c37
@ -25,7 +25,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// A font of an <see cref="Episode"/>.
|
||||
/// </summary>
|
||||
public class Font
|
||||
public class Font : ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// A human-readable identifier, used in the URL.
|
||||
@ -47,6 +47,9 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Link { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new empty <see cref="Font"/>.
|
||||
/// </summary>
|
||||
@ -56,12 +59,14 @@ namespace Kyoo.Abstractions.Models
|
||||
/// Create a new <see cref="Font"/> from a path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the font.</param>
|
||||
public Font(string path)
|
||||
/// <param name="episodeSlug">The slug of the episode that contains this font.</param>
|
||||
public Font(string path, string episodeSlug)
|
||||
{
|
||||
Slug = Utility.ToSlug(PathIO.GetFileNameWithoutExtension(path));
|
||||
Path = path;
|
||||
File = PathIO.GetFileName(path);
|
||||
Format = PathIO.GetExtension(path).Replace(".", string.Empty);
|
||||
Link = $"/watch/{episodeSlug}/font/{Slug}.{Format}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
// 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/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface to represent resources that should have a link field in their return values (like videos).
|
||||
/// </summary>
|
||||
public interface ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// The link to return, in most cases this should be a string.
|
||||
/// </summary>
|
||||
public object Link { get; }
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// A video, audio or subtitle track for an episode.
|
||||
/// </summary>
|
||||
public class Track : IResource
|
||||
public class Track : IResource, ILink
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
@ -66,9 +66,9 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
string type = Type.ToString().ToLower();
|
||||
string type = Type.ToString().ToLowerInvariant();
|
||||
string index = TrackIndex != 0 ? $"-{TrackIndex}" : string.Empty;
|
||||
string episode = _episodeSlug ?? Episode?.Slug ?? EpisodeID.ToString();
|
||||
string episode = _episodeSlug ?? Episode?.Slug ?? EpisodeID.ToString(CultureInfo.InvariantCulture);
|
||||
return $"{episode}.{Language ?? "und"}{index}{(IsForced ? ".forced" : string.Empty)}.{type}";
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ namespace Kyoo.Abstractions.Models
|
||||
Language = match.Groups["lang"].Value;
|
||||
if (Language == "und")
|
||||
Language = null;
|
||||
TrackIndex = match.Groups["index"].Success ? int.Parse(match.Groups["index"].Value) : 0;
|
||||
TrackIndex = match.Groups["index"].Success ? int.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture) : 0;
|
||||
IsForced = match.Groups["forced"].Success;
|
||||
Type = Enum.Parse<StreamType>(match.Groups["type"].Value, true);
|
||||
}
|
||||
@ -198,6 +198,9 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
[SerializeIgnore] private Episode _episode;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Link => Type == StreamType.Subtitle ? $"/subtitle/{Slug}" : null;
|
||||
|
||||
// Converting mkv track language to c# system language tag.
|
||||
private static string _GetLanguage(string mkvLanguage)
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// Information about tracks and display information that could be used by the player.
|
||||
/// This contains mostly data from an <see cref="Episode"/> with another form.
|
||||
/// </summary>
|
||||
public class WatchItem : CustomTypeDescriptor, IThumbnails
|
||||
public class WatchItem : CustomTypeDescriptor, IThumbnails, ILink
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the episode associated with this item.
|
||||
@ -136,6 +136,13 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
public ICollection<Chapter> Chapters { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object Link => new
|
||||
{
|
||||
Direct = $"/video/direct/{Slug}",
|
||||
Transmux = $"/video/transmux/{Slug}/master.m3u8",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="WatchItem"/> from an <see cref="Episode"/>.
|
||||
/// </summary>
|
||||
|
@ -233,7 +233,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
string path = _files.Combine(await _files.GetExtraDirectory(episode), "Attachments");
|
||||
return (await _files.ListFiles(path))
|
||||
.Select(x => new Font(x))
|
||||
.Select(x => new Font(x, episode.Slug))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ namespace Kyoo.Core.Controllers
|
||||
.FirstOrDefault(x => Utility.ToSlug(Path.GetFileNameWithoutExtension(x)) == slug);
|
||||
if (font == null)
|
||||
return null;
|
||||
return new Font(font);
|
||||
return new Font(font, episode.Slug);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
import { z } from "zod";
|
||||
import { zdate } from "~/utils/zod";
|
||||
import { ResourceP, ImagesP } from "../traits";
|
||||
import { ResourceP, ImagesP, imageFn } from "../traits";
|
||||
import { EpisodeP } from "./episode";
|
||||
|
||||
/**
|
||||
@ -59,6 +59,10 @@ export const TrackP = ResourceP.extend({
|
||||
* A user-friendly name for this track. It does not include the track type.
|
||||
*/
|
||||
displayName: z.string(),
|
||||
/*
|
||||
* The url of this track (only if this is a subtitle)..
|
||||
*/
|
||||
link: z.string().transform(imageFn).nullable(),
|
||||
});
|
||||
export type Track = z.infer<typeof TrackP>;
|
||||
|
||||
@ -78,7 +82,7 @@ export const FontP = z.object({
|
||||
/*
|
||||
* The url of the font.
|
||||
*/
|
||||
link: z.string(),
|
||||
link: z.string().transform(imageFn),
|
||||
});
|
||||
export type Font = z.infer<typeof FontP>;
|
||||
|
||||
@ -105,13 +109,6 @@ const WatchMovieP = z.preprocess(
|
||||
if (!x) return x;
|
||||
|
||||
x.name = x.title;
|
||||
x.link = {
|
||||
direct: `/api/video/${x.slug}`,
|
||||
};
|
||||
x.fonts = x.fonts?.map((y: Font) => {
|
||||
y.link = `/api/watch/${x.slug}/font/${y.slug}.${y.format}`;
|
||||
return y;
|
||||
})
|
||||
return x;
|
||||
},
|
||||
ImagesP.extend({
|
||||
@ -155,7 +152,8 @@ const WatchMovieP = z.preprocess(
|
||||
* The links to the videos of this watch item.
|
||||
*/
|
||||
link: z.object({
|
||||
direct: z.string(),
|
||||
direct: z.string().transform(imageFn),
|
||||
transmux: z.string().transform(imageFn),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
const imageFn = (url: string) => (url.startsWith("/api") ? url : `/api${url}`);
|
||||
export const imageFn = (url: string) => (url.startsWith("/api") ? url : `/api${url}`);
|
||||
|
||||
export const ImagesP = z.object({
|
||||
/**
|
||||
|
@ -21,7 +21,7 @@
|
||||
import { BoxProps } from "@mui/material";
|
||||
import { atom, useSetAtom } from "jotai";
|
||||
import { useRouter } from "next/router";
|
||||
import { RefObject, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { RefObject, useEffect, useRef } from "react";
|
||||
import { Font, Track } from "~/models/resources/watch-item";
|
||||
import { bakedAtom } from "~/utils/jotai-utils";
|
||||
// @ts-ignore
|
||||
@ -169,7 +169,7 @@ export const [_subtitleAtom, subtitleAtom] = bakedAtom<Track | null, { track: Tr
|
||||
track.kind = "subtitles";
|
||||
track.label = value.track.displayName;
|
||||
if (value.track.language) track.srclang = value.track.language;
|
||||
track.src = `subtitle/${value.track.slug}.vtt`;
|
||||
track.src = value.track.link!;
|
||||
track.className = "subtitle_container";
|
||||
track.default = true;
|
||||
track.onload = () => {
|
||||
@ -184,7 +184,7 @@ export const [_subtitleAtom, subtitleAtom] = bakedAtom<Track | null, { track: Tr
|
||||
suboctoAtom,
|
||||
new SubtitleOctopus({
|
||||
video: player.current,
|
||||
subUrl: `/api/subtitle/${value.track.slug}`,
|
||||
subUrl: value.track.link!,
|
||||
workerUrl: "/_next/static/chunks/subtitles-octopus-worker.js",
|
||||
legacyWorkerUrl: "/_next/static/chunks/subtitles-octopus-worker-legacy.js",
|
||||
fonts: value.fonts?.map((x) => x.link),
|
||||
|
Loading…
x
Reference in New Issue
Block a user