Combine track search with live YouTube Music results

GET /tracks now merges the local catalog page with a live YouTube Music
search (deduplicated against tracks already provisioned locally) whenever a
name filter is given, appending the YouTube hits after the local matches and
carrying a continuation token for further pages. Each item is tagged with its
source via the new TrackSearchItemResponse/TracksSearchResponse shapes,
wrapping the existing TrackApplicationResponse or a raw YouTubeSongResult so
neither type had to change.

GET /youtube/search is removed along with its now-unused handler; the
web-player's explore page, its /api/tracks proxy, and the YouTube filler
helper are updated to call the combined endpoint instead of hitting the two
separately.
This commit is contained in:
2026-09-10 09:55:58 +02:00
parent c418844178
commit 92a06a3c15
15 changed files with 266 additions and 240 deletions
@@ -19,8 +19,8 @@ public static class TrackEndpoints
group.MapGet("/", GetTracks)
.WithName("GetTracks")
.WithSummary("Get Paginated Tracks.")
.Produces<PaginatedResponse<TrackApplicationResponse>>();
.WithSummary("Get Paginated Tracks, Combined With Live YouTube Music Results When A Name Filter Is Given.")
.Produces<TracksSearchResponse>();
group.MapGet("/{id}", GetTrackById)
.WithName("GetTrackById")
@@ -86,9 +86,10 @@ public static class TrackEndpoints
CancellationToken cancellationToken,
string? name,
int pageNumber = 1,
int pageSize = 10)
int pageSize = 10,
string? youtubeContinuationToken = null)
{
var result = await mediator.Send(new GetTracksQuery(name, pageNumber, pageSize), cancellationToken);
var result = await mediator.Send(new GetTracksQuery(name, pageNumber, pageSize, youtubeContinuationToken), cancellationToken);
return result.ToHttpResult();
}
@@ -14,14 +14,6 @@ public static class YouTubeEndpoints
var group = app.MapGroup("/youtube")
.WithTags("YouTube");
group.MapGet("/search", SearchTracks)
.WithName("SearchYouTubeTracks")
.WithSummary("Search Songs On YouTube Music.")
.RequireAuthorization()
.Produces<YouTubeSearchResult>()
.Produces(StatusCodes.Status401Unauthorized)
.ProducesValidationProblem();
group.MapGet("/albums", SearchAlbums)
.WithName("SearchYouTubeAlbums")
.WithSummary("Search Albums On YouTube Music.")
@@ -83,17 +75,4 @@ public static class YouTubeEndpoints
var result = await mediator.Send(new GetYouTubeAlbumQuery(albumId), cancellationToken);
return result.ToHttpResult();
}
private static async Task<IResult> SearchTracks(
IMediator mediator,
CancellationToken cancellationToken,
string query,
string? continuation = null)
{
var result = await mediator.Send(
new SearchYouTubeTracksQuery(query, continuation ?? string.Empty),
cancellationToken);
return result.ToHttpResult();
}
}