Implement episode metadata management: add functionality to refresh episode metadata from external sources, including new API endpoints and UI integration. Enhance Show and Episode models to support additional metadata fields, and update database schema accordingly. Update ShowDetail and ShowMetadataCard components to display refreshed episode information and provide user feedback on metadata updates.
This commit is contained in:
@@ -6,6 +6,7 @@ using TeleWave.Application.Metadata;
|
||||
using TeleWave.Application.Metadata.ApplyShowMetadata;
|
||||
using TeleWave.Application.Metadata.ClearShowMetadata;
|
||||
using TeleWave.Application.Metadata.GetProviders;
|
||||
using TeleWave.Application.Metadata.RefreshEpisodes;
|
||||
using TeleWave.Application.Metadata.SearchShows;
|
||||
using TeleWave.Application.Metadata.SetShowPoster;
|
||||
using TeleWave.Application.Metadata.UpdateShowMetadata;
|
||||
@@ -39,11 +40,15 @@ public static class MetadataEndpoints
|
||||
admin.MapPut("/shows/{showId:guid}", Update).Produces(StatusCodes.Status204NoContent);
|
||||
admin.MapDelete("/shows/{showId:guid}", Clear).Produces(StatusCodes.Status204NoContent);
|
||||
admin.MapPut("/shows/{showId:guid}/poster", UploadPoster).Produces(StatusCodes.Status204NoContent);
|
||||
admin.MapPost("/shows/{showId:guid}/refresh-episodes", RefreshEpisodes).Produces<int>();
|
||||
|
||||
// Постеры отдаём публично (просто картинки, id не угадать) — чтобы работал <img src>.
|
||||
// Постеры/кадры отдаём публично (просто картинки, id не угадать) — чтобы работал <img src>.
|
||||
app.MapGet("/api/metadata/shows/{showId:guid}/poster", ServePoster)
|
||||
.WithTags("Metadata")
|
||||
.Produces(StatusCodes.Status200OK);
|
||||
app.MapGet("/api/metadata/episodes/{episodeId:guid}/still", ServeStill)
|
||||
.WithTags("Metadata")
|
||||
.Produces(StatusCodes.Status200OK);
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -126,6 +131,19 @@ public static class MetadataEndpoints
|
||||
return result.ToHttpResult();
|
||||
}
|
||||
|
||||
private static async Task<IResult> RefreshEpisodes(
|
||||
Guid showId,
|
||||
ISender sender,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var result = await sender.Send(
|
||||
new RefreshShowEpisodesMetadataCommand(showId),
|
||||
cancellationToken
|
||||
);
|
||||
return result.ToHttpResult();
|
||||
}
|
||||
|
||||
private static async Task<IResult> ServePoster(
|
||||
Guid showId,
|
||||
IAppDbContext dbContext,
|
||||
@@ -137,14 +155,30 @@ public static class MetadataEndpoints
|
||||
.Where(s => s.Id == showId)
|
||||
.Select(s => s.PosterPath)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return Results.NotFound();
|
||||
return ServeImage(path, imageStore);
|
||||
}
|
||||
|
||||
var abs = imageStore.ResolveAbsolutePath(path);
|
||||
if (abs is null)
|
||||
return Results.NotFound();
|
||||
private static async Task<IResult> ServeStill(
|
||||
Guid episodeId,
|
||||
IAppDbContext dbContext,
|
||||
IMetadataImageStore imageStore,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var path = await dbContext.Shows.AsNoTracking()
|
||||
.SelectMany(s => s.Episodes)
|
||||
.Where(e => e.Id == episodeId)
|
||||
.Select(e => e.StillPath)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
return ServeImage(path, imageStore);
|
||||
}
|
||||
|
||||
return Results.File(abs, ContentTypeFor(Path.GetExtension(abs)));
|
||||
private static IResult ServeImage(string? relativePath, IMetadataImageStore imageStore)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relativePath))
|
||||
return Results.NotFound();
|
||||
var abs = imageStore.ResolveAbsolutePath(relativePath);
|
||||
return abs is null ? Results.NotFound() : Results.File(abs, ContentTypeFor(Path.GetExtension(abs)));
|
||||
}
|
||||
|
||||
private static string ContentTypeFor(string extension) =>
|
||||
|
||||
Reference in New Issue
Block a user