mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-03 05:34:23 -04:00
Automatically download/extract info on API creation (dirtyfix) (#161
* Download thumbnails automatically * Automatically extract tracks
This commit is contained in:
parent
d0db4815f1
commit
592c92785f
@ -20,7 +20,7 @@ COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
|||||||
COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj
|
COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj
|
||||||
RUN dotnet restore
|
RUN dotnet restore
|
||||||
|
|
||||||
COPY --from=transcoder /transcoder/libtranscoder.so /app
|
COPY --from=transcoder /transcoder/libtranscoder.so /app/out/bin/Kyoo.Host/Debug/net6.0/libtranscoder.so
|
||||||
|
|
||||||
WORKDIR /kyoo
|
WORKDIR /kyoo
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
@ -69,6 +69,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("Downloading image {What}", what);
|
||||||
AsyncRef<string> mime = new();
|
AsyncRef<string> mime = new();
|
||||||
await using Stream reader = await _files.GetReader(url, mime);
|
await using Stream reader = await _files.GetReader(url, mime);
|
||||||
string extension = new FileExtensionContentTypeProvider()
|
string extension = new FileExtensionContentTypeProvider()
|
||||||
|
@ -138,7 +138,7 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
||||||
[ProducesResponseType(StatusCodes.Status409Conflict, Type = typeof(ActionResult<>))]
|
[ProducesResponseType(StatusCodes.Status409Conflict, Type = typeof(ActionResult<>))]
|
||||||
public async Task<ActionResult<T>> Create([FromBody] T resource)
|
public virtual async Task<ActionResult<T>> Create([FromBody] T resource)
|
||||||
{
|
{
|
||||||
return await Repository.Create(resource);
|
return await Repository.Create(resource);
|
||||||
}
|
}
|
||||||
|
@ -153,5 +153,14 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
return GetImage(identifier, Images.Thumbnail);
|
return GetImage(identifier, Images.Thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override async Task<ActionResult<T>> Create([FromBody] T resource)
|
||||||
|
{
|
||||||
|
// TODO: Remove this method and use a websocket API to do that.
|
||||||
|
ActionResult<T> ret = await base.Create(resource);
|
||||||
|
await _thumbs.DownloadImages(ret.Value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ using Kyoo.Abstractions.Models;
|
|||||||
using Kyoo.Abstractions.Models.Attributes;
|
using Kyoo.Abstractions.Models.Attributes;
|
||||||
using Kyoo.Abstractions.Models.Permissions;
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
|
using Kyoo.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using static Kyoo.Abstractions.Models.Utils.Constants;
|
using static Kyoo.Abstractions.Models.Utils.Constants;
|
||||||
@ -76,6 +77,15 @@ namespace Kyoo.Core.Api
|
|||||||
_files = files;
|
_files = files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override async Task<ActionResult<Episode>> Create([FromBody] Episode resource)
|
||||||
|
{
|
||||||
|
// TODO: Remove this method and use a websocket API to do that.
|
||||||
|
resource.Tracks = await _transcoder.ExtractInfos(resource, false);
|
||||||
|
ActionResult<Episode> ret = await base.Create(resource);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get episode's show
|
/// Get episode's show
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -48,6 +48,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// The library manager used to modify or retrieve information in the data store.
|
/// The library manager used to modify or retrieve information in the data store.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
private readonly ITranscoder _transcoder;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="ShowApi"/>.
|
/// Create a new <see cref="ShowApi"/>.
|
||||||
@ -57,12 +58,34 @@ namespace Kyoo.Core.Api
|
|||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="files">The file manager used to send images and fonts.</param>
|
/// <param name="files">The file manager used to send images and fonts.</param>
|
||||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||||
|
/// <param name="transcoder">TODO: Remove this.</param>
|
||||||
public ShowApi(ILibraryManager libraryManager,
|
public ShowApi(ILibraryManager libraryManager,
|
||||||
IFileSystem files,
|
IFileSystem files,
|
||||||
IThumbnailsManager thumbs)
|
IThumbnailsManager thumbs,
|
||||||
|
ITranscoder transcoder)
|
||||||
: base(libraryManager.ShowRepository, files, thumbs)
|
: base(libraryManager.ShowRepository, files, thumbs)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_transcoder = transcoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override async Task<ActionResult<Show>> Create([FromBody] Show resource)
|
||||||
|
{
|
||||||
|
ActionResult<Show> ret = await base.Create(resource);
|
||||||
|
if (ret.Value.IsMovie)
|
||||||
|
{
|
||||||
|
Episode episode = new()
|
||||||
|
{
|
||||||
|
Show = ret.Value,
|
||||||
|
Title = ret.Value.Title,
|
||||||
|
Path = ret.Value.Path
|
||||||
|
};
|
||||||
|
|
||||||
|
episode.Tracks = await _transcoder.ExtractInfos(episode, false);
|
||||||
|
await _libraryManager.Create(episode);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -24,7 +24,6 @@ using System.Threading.Tasks;
|
|||||||
using Autofac;
|
using Autofac;
|
||||||
using Autofac.Extensions.DependencyInjection;
|
using Autofac.Extensions.DependencyInjection;
|
||||||
using Kyoo.Postgresql;
|
using Kyoo.Postgresql;
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -176,6 +175,7 @@ namespace Kyoo.Host
|
|||||||
.MinimumLevel.Warning()
|
.MinimumLevel.Warning()
|
||||||
.MinimumLevel.Override("Kyoo", LogEventLevel.Verbose)
|
.MinimumLevel.Override("Kyoo", LogEventLevel.Verbose)
|
||||||
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Verbose)
|
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Verbose)
|
||||||
|
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Fatal)
|
||||||
.WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code))
|
.WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code))
|
||||||
.Enrich.WithThreadId()
|
.Enrich.WithThreadId()
|
||||||
.Enrich.FromLogContext();
|
.Enrich.FromLogContext();
|
||||||
|
@ -342,8 +342,8 @@ class TheMovieDatabase(Provider):
|
|||||||
release_date=datetime.strptime(episode["air_date"], "%Y-%m-%d").date()
|
release_date=datetime.strptime(episode["air_date"], "%Y-%m-%d").date()
|
||||||
if episode["air_date"]
|
if episode["air_date"]
|
||||||
else None,
|
else None,
|
||||||
thumbnail=f"https://image.tmdb.org/t/p/original{episode['poster_path']}"
|
thumbnail=f"https://image.tmdb.org/t/p/original{episode['still_path']}"
|
||||||
if "poster_path" in episode
|
if "still_path" in episode and episode["still_path"] is not None
|
||||||
else None,
|
else None,
|
||||||
external_ids={
|
external_ids={
|
||||||
self.name: MetadataID(
|
self.name: MetadataID(
|
||||||
|
@ -41,6 +41,9 @@ class Episode:
|
|||||||
**asdict(self),
|
**asdict(self),
|
||||||
**asdict(self.translations[default_language]),
|
**asdict(self.translations[default_language]),
|
||||||
"title": self.translations[default_language].name,
|
"title": self.translations[default_language].name,
|
||||||
|
"images": {
|
||||||
|
"1": self.thumbnail,
|
||||||
|
},
|
||||||
# TODO: The back has bad external id support, we disable it for now
|
# TODO: The back has bad external id support, we disable it for now
|
||||||
"external_ids": None,
|
"external_ids": None,
|
||||||
"show": None,
|
"show": None,
|
||||||
|
@ -22,4 +22,4 @@ class Genre(str, Enum):
|
|||||||
WESTERN = "Western"
|
WESTERN = "Western"
|
||||||
|
|
||||||
def to_kyoo(self):
|
def to_kyoo(self):
|
||||||
return {"name": f"{self}"}
|
return {"name": self.value}
|
||||||
|
@ -50,12 +50,12 @@ class Movie:
|
|||||||
return {
|
return {
|
||||||
**asdict(self),
|
**asdict(self),
|
||||||
**asdict(self.translations[default_language]),
|
**asdict(self.translations[default_language]),
|
||||||
"poster": next(iter(self.translations[default_language].posters), None),
|
"images": {
|
||||||
"thumbnail": next(
|
"0": next(iter(self.translations[default_language].posters), None),
|
||||||
iter(self.translations[default_language].thumbnails), None
|
"1": next(iter(self.translations[default_language].thumbnails), None),
|
||||||
),
|
"2": next(iter(self.translations[default_language].logos), None),
|
||||||
"logo": next(iter(self.translations[default_language].logos), None),
|
"3": next(iter(self.translations[default_language].trailers), None),
|
||||||
"trailer": next(iter(self.translations[default_language].trailers), None),
|
},
|
||||||
"studio": next((x.to_kyoo() for x in self.studios), None),
|
"studio": next((x.to_kyoo() for x in self.studios), None),
|
||||||
"release_date": None,
|
"release_date": None,
|
||||||
"startAir": format_date(self.release_date),
|
"startAir": format_date(self.release_date),
|
||||||
|
@ -30,10 +30,10 @@ class Season:
|
|||||||
return {
|
return {
|
||||||
**asdict(self),
|
**asdict(self),
|
||||||
**asdict(self.translations[default_language]),
|
**asdict(self.translations[default_language]),
|
||||||
"poster": next(iter(self.translations[default_language].posters), None),
|
"images": {
|
||||||
"thumbnail": next(
|
"0": next(iter(self.translations[default_language].posters), None),
|
||||||
iter(self.translations[default_language].thumbnails), None
|
"1": next(iter(self.translations[default_language].thumbnails), None),
|
||||||
),
|
},
|
||||||
"title": self.translations[default_language].name,
|
"title": self.translations[default_language].name,
|
||||||
# TODO: The back has bad external id support, we disable it for now
|
# TODO: The back has bad external id support, we disable it for now
|
||||||
"external_ids": None,
|
"external_ids": None,
|
||||||
|
@ -52,12 +52,12 @@ class Show:
|
|||||||
return {
|
return {
|
||||||
**asdict(self),
|
**asdict(self),
|
||||||
**asdict(self.translations[default_language]),
|
**asdict(self.translations[default_language]),
|
||||||
"poster": next(iter(self.translations[default_language].posters), None),
|
"images": {
|
||||||
"thumbnail": next(
|
"0": next(iter(self.translations[default_language].posters), None),
|
||||||
iter(self.translations[default_language].thumbnails), None
|
"1": next(iter(self.translations[default_language].thumbnails), None),
|
||||||
),
|
"2": next(iter(self.translations[default_language].logos), None),
|
||||||
"logo": next(iter(self.translations[default_language].logos), None),
|
"3": next(iter(self.translations[default_language].trailers), None),
|
||||||
"trailer": next(iter(self.translations[default_language].trailers), None),
|
},
|
||||||
"studio": next((x.to_kyoo() for x in self.studios), None),
|
"studio": next((x.to_kyoo() for x in self.studios), None),
|
||||||
"title": self.translations[default_language].name,
|
"title": self.translations[default_language].name,
|
||||||
"genres": [x.to_kyoo() for x in self.genres],
|
"genres": [x.to_kyoo() for x in self.genres],
|
||||||
|
@ -12,6 +12,9 @@ class Studio:
|
|||||||
def to_kyoo(self):
|
def to_kyoo(self):
|
||||||
return {
|
return {
|
||||||
**asdict(self),
|
**asdict(self),
|
||||||
|
"images": {
|
||||||
|
"2": next(iter(self.logos), None),
|
||||||
|
},
|
||||||
# TODO: The back has bad external id support, we disable it for now
|
# TODO: The back has bad external id support, we disable it for now
|
||||||
"external_ids": None,
|
"external_ids": None,
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ def provider_cache(*args):
|
|||||||
|
|
||||||
if "event" in ic:
|
if "event" in ic:
|
||||||
await ic["event"].wait()
|
await ic["event"].wait()
|
||||||
if not ic["ret"]:
|
if "ret" not in ic:
|
||||||
raise ProviderError("Cache miss. Another error should exist")
|
raise ProviderError("Cache miss. Another error should exist")
|
||||||
return ic["ret"]
|
return ic["ret"]
|
||||||
ic["event"] = asyncio.Event()
|
ic["event"] = asyncio.Event()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user