Split QueueResponse and introduce SearchResponse

Decoupled `QueueResponse` and `SearchResponse` to better align with their distinct API endpoints and simplify response structures. Updated `PlayOutcome.PendingPlaylist` and `SearchResultHandler` to include playlist `name`, ensuring consistency across related features and improving response clarity. Adjusted OpenAPI documentation and routes to reflect the separation.
This commit is contained in:
anthorob committed 2026-10-18 05:35:57 -04:00
1 parent 01bf94c60a
commit 780016b731
5 files changed
+44 -20

No files matched your search

@@ -30,6 +30,7 @@ import me.bobert.netneutrality.http.server.dto.QueuedTrackResponse;
import me.bobert.netneutrality.http.server.dto.ReorderRequest;
import me.bobert.netneutrality.http.server.dto.ReorderResponse;
import me.bobert.netneutrality.http.server.dto.SearchRequest;
import me.bobert.netneutrality.http.server.dto.SearchResponse;
import me.bobert.netneutrality.http.server.dto.SeekRequest;
import me.bobert.netneutrality.http.server.dto.SeekResponse;
import me.bobert.netneutrality.http.server.dto.ShuffleResponse;
@@ -416,7 +417,7 @@ public final class MusicRoutes {
pathParams = @OpenApiParam(name = "guildId", description = "The Discord guild id"),
requestBody = @OpenApiRequestBody(content = @OpenApiContent(from = SearchRequest.class)),
responses = {
@OpenApiResponse(status = "200", content = @OpenApiContent(from = QueueResponse.class)),
@OpenApiResponse(status = "200", content = @OpenApiContent(from = SearchResponse.class)),
@OpenApiResponse(status = "400", content = @OpenApiContent(from = ErrorResponse.class)),
@OpenApiResponse(status = "404", content = @OpenApiContent(from = ErrorResponse.class))
}
@@ -642,6 +643,7 @@ public final class MusicRoutes {
body.put("status", "pending_playlist");
body.put("search_id", pendingPlaylist.searchId());
body.put("search_id_ttl_seconds", PendingSearchResults.ttlSeconds());
body.put("name", pendingPlaylist.name());
body.put("tracks", pendingPlaylist.tracks().stream().map(MusicRoutes::trackSummary).toList());
body.put("truncated", pendingPlaylist.truncated());
yield body;
@@ -9,28 +9,17 @@ package me.bobert.netneutrality.http.server.dto;
import java.util.List;
/**
* OpenAPI schema for the {@code /music/{guildId}/queue} and {@code /music/{guildId}/search}
* responses.
* OpenAPI schema for the {@code /music/{guildId}/queue} response.
*
* <p>Nothing is ever queued directly by {@code /music/{guildId}/search}: every resolved query is
* stashed as a pending candidate, to be confirmed via a follow-up {@code /music/{guildId}/queue}
* call carrying {@code searchId}/{@code index} (or {@code queueAll}). Fields are nullable since only a subset is
* populated depending on {@code status}: {@code queued} fills {@code track}/{@code queue_position} (confirmed
* selection), {@code queued_all} fills {@code tracks}/{@code queue_position} (confirmed bulk selection; {@code
* queue_position} is the resulting queue size), {@code pending_track} fills {@code search_id}/{@code
* search_id_ttl_seconds}/{@code track}, {@code pending_playlist} fills {@code search_id}/{@code
* search_id_ttl_seconds}/{@code tracks}/{@code truncated}, and {@code pending_search} fills {@code search_id}/{@code
* search_id_ttl_seconds}/{@code candidates}.
* {@code search_id_ttl_seconds} indicates how many seconds remain before the {@code search_id} expires.
* <p>Fields are nullable since only a subset is populated depending on {@code status}: {@code
* queued} fills {@code track}/{@code queue_position} (confirmed selection) and {@code queued_all}
* fills {@code tracks}/{@code queue_position} (confirmed bulk selection; {@code queue_position} is
* the resulting queue size).
*/
public record QueueResponse(
String status,
TrackSummaryResponse track,
Integer queue_position,
String search_id,
Long search_id_ttl_seconds,
List<TrackSummaryResponse> tracks,
Boolean truncated,
List<TrackSummaryResponse> candidates
List<TrackSummaryResponse> tracks
) {
}
@@ -0,0 +1,33 @@
package me.bobert.netneutrality.http.server.dto;
/*
* Copyright (c) anthorob
*
* https://discord.gg/qUa6zNFZsd
*/
import java.util.List;
/**
* OpenAPI schema for the {@code /music/{guildId}/search} response.
*
* <p>Nothing is ever queued directly by {@code /music/{guildId}/search}: every resolved query is
* stashed as a pending candidate, to be confirmed via a follow-up {@code /music/{guildId}/queue}
* call carrying {@code searchId}/{@code index} (or {@code queueAll}). Fields are nullable since only a
* subset is populated depending on {@code status}: {@code pending_track} fills {@code search_id}/{@code
* search_id_ttl_seconds}/{@code track}, {@code pending_playlist} fills {@code search_id}/{@code
* search_id_ttl_seconds}/{@code name}/{@code tracks}/{@code truncated}, and {@code pending_search} fills
* {@code search_id}/{@code search_id_ttl_seconds}/{@code candidates}. {@code search_id_ttl_seconds}
* indicates how many seconds remain before the {@code search_id} expires.
*/
public record SearchResponse(
String status,
String search_id,
Long search_id_ttl_seconds,
TrackSummaryResponse track,
String name,
List<TrackSummaryResponse> tracks,
Boolean truncated,
List<TrackSummaryResponse> candidates
) {
}
@@ -23,7 +23,7 @@ public sealed interface PlayOutcome {
record PendingTrack(String searchId, Track track) implements PlayOutcome {
}
record PendingPlaylist(String searchId, List<Track> tracks, boolean truncated) implements PlayOutcome {
record PendingPlaylist(String searchId, String name, List<Track> tracks, boolean truncated) implements PlayOutcome {
}
record PendingSearch(String searchId, List<Track> candidates) implements PlayOutcome {
@@ -66,7 +66,7 @@ public class SearchResultHandler extends AbstractAudioLoadResultHandler {
List<Track> candidates = truncated ? tracks.subList(0, maxPlaylistSize) : tracks;
String searchId = PendingSearchResults.put(guild.getId(), candidates);
future.complete(new PlayOutcome.PendingPlaylist(searchId, candidates, truncated));
future.complete(new PlayOutcome.PendingPlaylist(searchId, result.getInfo().getName(), candidates, truncated));
}
@Override