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.
23 lines
981 B
C#
23 lines
981 B
C#
using Musify.Application.Contracts;
|
|
using Musify.Domain.ValueObjects;
|
|
|
|
namespace Musify.Application.Tracks.Responses
|
|
{
|
|
/// <summary>One item of a combined local/YouTube track listing. Exactly one of
|
|
/// <see cref="Track"/> or <see cref="YouTubeSong"/> is populated: <see cref="Track"/> for
|
|
/// anything already in the catalog (local uploads and YouTube tracks provisioned earlier),
|
|
/// <see cref="YouTubeSong"/> for a live YouTube Music search hit that has not been
|
|
/// provisioned yet, so it has no track id.</summary>
|
|
public record TrackSearchItemResponse(
|
|
TrackSource Source,
|
|
TrackApplicationResponse? Track,
|
|
YouTubeSongResult? YouTubeSong)
|
|
{
|
|
public static TrackSearchItemResponse FromTrack(TrackApplicationResponse track) =>
|
|
new(track.Source, track, null);
|
|
|
|
public static TrackSearchItemResponse FromYouTubeSong(YouTubeSongResult song) =>
|
|
new(TrackSource.YouTube, null, song);
|
|
}
|
|
}
|