From 780016b731341c74a0b21f857bc05031e76454af Mon Sep 17 00:00:00 2001 From: anthorob Date: Sun, 18 Oct 2026 05:35:57 -0400 Subject: [PATCH] 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. --- .../http/server/MusicRoutes.java | 4 ++- .../http/server/dto/QueueResponse.java | 23 ++++--------- .../http/server/dto/SearchResponse.java | 33 +++++++++++++++++++ .../netneutrality/music/PlayOutcome.java | 2 +- .../music/SearchResultHandler.java | 2 +- 5 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 src/main/java/me/bobert/netneutrality/http/server/dto/SearchResponse.java diff --git a/src/main/java/me/bobert/netneutrality/http/server/MusicRoutes.java b/src/main/java/me/bobert/netneutrality/http/server/MusicRoutes.java index 7298a27..60eff73 100644 --- a/src/main/java/me/bobert/netneutrality/http/server/MusicRoutes.java +++ b/src/main/java/me/bobert/netneutrality/http/server/MusicRoutes.java @@ -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; diff --git a/src/main/java/me/bobert/netneutrality/http/server/dto/QueueResponse.java b/src/main/java/me/bobert/netneutrality/http/server/dto/QueueResponse.java index aaa4c88..9c03cf2 100644 --- a/src/main/java/me/bobert/netneutrality/http/server/dto/QueueResponse.java +++ b/src/main/java/me/bobert/netneutrality/http/server/dto/QueueResponse.java @@ -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. * - *

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. + *

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 tracks, - Boolean truncated, - List candidates + List tracks ) { } diff --git a/src/main/java/me/bobert/netneutrality/http/server/dto/SearchResponse.java b/src/main/java/me/bobert/netneutrality/http/server/dto/SearchResponse.java new file mode 100644 index 0000000..b97880e --- /dev/null +++ b/src/main/java/me/bobert/netneutrality/http/server/dto/SearchResponse.java @@ -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. + * + *

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 tracks, + Boolean truncated, + List candidates +) { +} diff --git a/src/main/java/me/bobert/netneutrality/music/PlayOutcome.java b/src/main/java/me/bobert/netneutrality/music/PlayOutcome.java index b4412bf..dad7fdb 100644 --- a/src/main/java/me/bobert/netneutrality/music/PlayOutcome.java +++ b/src/main/java/me/bobert/netneutrality/music/PlayOutcome.java @@ -23,7 +23,7 @@ public sealed interface PlayOutcome { record PendingTrack(String searchId, Track track) implements PlayOutcome { } - record PendingPlaylist(String searchId, List tracks, boolean truncated) implements PlayOutcome { + record PendingPlaylist(String searchId, String name, List tracks, boolean truncated) implements PlayOutcome { } record PendingSearch(String searchId, List candidates) implements PlayOutcome { diff --git a/src/main/java/me/bobert/netneutrality/music/SearchResultHandler.java b/src/main/java/me/bobert/netneutrality/music/SearchResultHandler.java index fe4c340..db98f0c 100644 --- a/src/main/java/me/bobert/netneutrality/music/SearchResultHandler.java +++ b/src/main/java/me/bobert/netneutrality/music/SearchResultHandler.java @@ -66,7 +66,7 @@ public class SearchResultHandler extends AbstractAudioLoadResultHandler { List 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