diff --git a/README.md b/README.md index 75d63f3..19dbebd 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,10 @@ Images are published to `ghcr.io/madeofpendletonwool/syncphony`: `:main` tracks 6. Heart the songs you love as they play. When the host taps **End the night** (or the room goes quiet for two hours), the most-hearted song is crowned **song of the night**, on everyone's phone and the big screen, and it's kept with the night's recap. 7. Then play the night's **Wrapped**: who brought the most, whose songs got the hearts, the genres and decades, whose tastes matched. Share it as an image, and **save tonight's playlist** to your **Library**, shared with the room, to play it again any time. The big screen plays the Wrapped on its own. Playlists live in Syncphony, so one can hold songs from everyone's services ([ADR 0016](docs/adr/0016-playlists-and-wrapped.md)). +## Finding music you don't have + +The **Discover** tab is yours alone, outside any room. Make a set of artists you love ("Moody post-rock", "90s alt"), and it fills with songs near them that aren't on your own Navidrome, each saying which of your artists it's near. Play a 30-second preview, open the whole song on YouTube, give it a thumb, or say an artist isn't for you. Your library is only used to skip what you have, never to guess your taste ([ADR 0017](docs/adr/0017-personal-discovery.md)). + What works where (and what doesn't yet) is in [docs/player-mode.md](docs/player-mode.md). ## Roadmap diff --git a/api/openapi.yaml b/api/openapi.yaml index 9a22175..9c29bec 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -2883,6 +2883,390 @@ paths: default: $ref: "#/components/responses/Error" + # --- Personal discovery (ADR 0017) ------------------------------------------ + + /me/discover/sets: + get: + operationId: listDiscoverySets + summary: Your discovery sets + description: | + Seed sets (ADR 0017): named lists of artists, each its own feed of + music you don't have yet. Yours alone, most recently changed first. + Guests have no discovery. + tags: [discover] + responses: + "200": + description: Sets + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DiscoverySetSummary" + default: + $ref: "#/components/responses/Error" + post: + operationId: createDiscoverySet + summary: Make a discovery set + description: With seed artists, if given. At most 50 sets, of 50 artists each (`too_many`). + tags: [discover] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateDiscoverySetRequest" + responses: + "201": + description: The set + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySet" + default: + $ref: "#/components/responses/Error" + + /me/discover/sets/{setId}: + parameters: + - $ref: "#/components/parameters/DiscoverySetId" + get: + operationId: getDiscoverySet + summary: A discovery set and its artists + tags: [discover] + responses: + "200": + description: The set + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySet" + default: + $ref: "#/components/responses/Error" + patch: + operationId: updateDiscoverySet + summary: Rename a set, or change how far it explores and which feeds it shows + tags: [discover] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateDiscoverySetRequest" + responses: + "200": + description: The set + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySet" + default: + $ref: "#/components/responses/Error" + delete: + operationId: deleteDiscoverySet + summary: Delete a discovery set + description: Its thumbs stay. A song you turned down stays down. + tags: [discover] + responses: + "204": + description: Deleted + default: + $ref: "#/components/responses/Error" + + /me/discover/sets/{setId}/artists: + parameters: + - $ref: "#/components/parameters/DiscoverySetId" + post: + operationId: addDiscoverySetArtist + summary: Add a seed artist to a set + description: | + Any artist, whether or not it's in your library. Adding one that's + there already changes nothing. + tags: [discover] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySeed" + responses: + "200": + description: The set + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySet" + default: + $ref: "#/components/responses/Error" + + /me/discover/sets/{setId}/artists/{artistKey}: + parameters: + - $ref: "#/components/parameters/DiscoverySetId" + - name: artistKey + in: path + required: true + schema: + type: string + delete: + operationId: removeDiscoverySetArtist + summary: Take a seed artist out of a set + tags: [discover] + responses: + "200": + description: The set + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoverySet" + default: + $ref: "#/components/responses/Error" + + /me/discover/sets/{setId}/feed: + parameters: + - $ref: "#/components/parameters/DiscoverySetId" + get: + operationId: getDiscoveryFeed + summary: A page of a set's feed + description: | + Songs near the set's seeds that you don't have: not on your own + Navidrome links, not turned down, not by an artist you blocked. + Each says which seeds it's near. A feed is built at most every 10 + minutes (or now, with `refresh`), within 15 seconds; artists the + music graph didn't know yet are fetched for next time. What you + thumb down or block leaves every page at once. + tags: [discover] + parameters: + - name: cursor + in: query + description: The previous page's `next`. + schema: + type: string + - name: refresh + in: query + description: Build the feed again now, for the first page. + schema: + type: boolean + responses: + "200": + description: A page + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoveryFeed" + default: + $ref: "#/components/responses/Error" + + /me/discover/feedback: + post: + operationId: postDiscoveryFeedback + summary: Thumbs up or down on a song + description: | + A thumbs-down hides the song from all your feeds, for good; a later + thumbs-up replaces it. Thumbs here never touch a room's DJ. + tags: [discover] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoveryFeedbackRequest" + responses: + "204": + description: Kept + default: + $ref: "#/components/responses/Error" + + /me/discover/blocks: + get: + operationId: listDiscoveryBlocks + summary: Artists you said aren't for you + tags: [discover] + responses: + "200": + description: Blocked artists + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DiscoveryBlock" + default: + $ref: "#/components/responses/Error" + post: + operationId: blockDiscoveryArtist + summary: Not for me + description: Keeps an artist out of every one of your feeds. + tags: [discover] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/BlockDiscoveryArtistRequest" + responses: + "200": + description: The block + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoveryBlock" + default: + $ref: "#/components/responses/Error" + + /me/discover/blocks/{artistKey}: + parameters: + - name: artistKey + in: path + required: true + schema: + type: string + delete: + operationId: unblockDiscoveryArtist + summary: Let a blocked artist back into your feeds + tags: [discover] + responses: + "204": + description: Unblocked + default: + $ref: "#/components/responses/Error" + + /me/discover/artists: + get: + operationId: searchDiscoveryArtists + summary: Find artists to seed a set with + description: | + Any artist, from Deezer, not only ones in your library. Without + Deezer it offers the name as typed, which seeds as well as any. + tags: [discover] + parameters: + - name: q + in: query + required: true + schema: + type: string + maxLength: 200 + responses: + "200": + description: Artists + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DiscoveryArtist" + default: + $ref: "#/components/responses/Error" + + /me/discover/library: + get: + operationId: getDiscoveryLibrary + summary: How far your library is indexed + description: | + Discovery leaves out what's on your own Navidrome links. They're + indexed the first time you ask, then daily. + tags: [discover] + responses: + "200": + description: The index + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoveryLibrary" + default: + $ref: "#/components/responses/Error" + post: + operationId: refreshDiscoveryLibrary + summary: Index your library again now + description: In the background; you just added music, say. + tags: [discover] + responses: + "202": + description: Started + content: + application/json: + schema: + $ref: "#/components/schemas/DiscoveryLibrary" + default: + $ref: "#/components/responses/Error" + + /me/discover/preview/{deezerTrackId}: + parameters: + - name: deezerTrackId + in: path + required: true + schema: + type: integer + format: int64 + minimum: 1 + get: + operationId: getDiscoveryPreview + summary: A song's 30-second preview + description: | + Deezer's preview, through the server: its URL is asked for fresh + each time (Deezer's expire) and never kept, and the browser never + talks to Deezer. Supports byte ranges. `not_found` if Deezer has + no preview of the song, or Deezer is off. + tags: [discover] + parameters: + - name: Range + in: header + schema: + type: string + example: bytes=0- + responses: + "200": + description: The preview + content: + audio/*: + schema: + type: string + format: binary + "206": + description: Part of the preview (see Content-Range) + content: + audio/*: + schema: + type: string + format: binary + default: + $ref: "#/components/responses/Error" + + /me/discover/images/{kind}/{imageId}: + parameters: + - name: kind + in: path + required: true + schema: + type: string + enum: [cover, artist] + - name: imageId + in: path + required: true + schema: + type: string + pattern: "^[0-9a-f]{32}$" + get: + operationId: getDiscoveryImage + summary: A cover or artist picture from Deezer, through the server + tags: [discover] + parameters: + - name: size + in: query + description: Wanted width in pixels; a hint. + schema: + type: integer + minimum: 0 + maximum: 1000 + responses: + "200": + description: The image + content: + image/*: + schema: + type: string + format: binary + default: + $ref: "#/components/responses/Error" + /rooms/{roomId}/games/round: parameters: - $ref: "#/components/parameters/RoomId" @@ -3939,6 +4323,13 @@ components: schema: type: string + DiscoverySetId: + name: setId + in: path + required: true + schema: + type: string + QueueGameId: name: gameId in: path @@ -7837,3 +8228,241 @@ components: $ref: "#/components/schemas/RoomPermissionsChange" skipVotePercent: $ref: "#/components/schemas/SkipVotePercent" + + DiscoveryMode: + type: string + description: | + Which feeds a set shows: `deep` cuts (anything new to you), `fresh` + releases (coming), or `both`. + enum: [deep, fresh, both] + x-enum-varnames: [DiscoveryModeDeep, DiscoveryModeFresh, DiscoveryModeBoth] + + DiscoverySetSummary: + type: object + required: [id, name, explore, mode, artistCount, createdAt, updatedAt] + properties: + id: + type: string + name: + type: string + explore: + type: integer + minimum: 0 + maximum: 100 + mode: + $ref: "#/components/schemas/DiscoveryMode" + artistCount: + type: integer + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + DiscoverySet: + type: object + required: [id, name, explore, mode, artists, createdAt, updatedAt] + properties: + id: + type: string + name: + type: string + explore: + type: integer + minimum: 0 + maximum: 100 + description: How far the feed strays from the seeds, and toward less-known artists. + mode: + $ref: "#/components/schemas/DiscoveryMode" + artists: + type: array + items: + $ref: "#/components/schemas/DiscoverySetArtist" + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + DiscoverySetArtist: + type: object + required: [key, name, addedFrom, addedAt] + properties: + key: + type: string + description: Their MBID, else their simplified name. Removes them from the set. + name: + type: string + mbid: + type: string + addedFrom: + type: string + enum: [manual, thumb, starred, room] + addedAt: + type: string + format: date-time + + DiscoverySeed: + type: object + required: [name] + properties: + name: + type: string + minLength: 1 + maxLength: 200 + mbid: + type: string + + CreateDiscoverySetRequest: + type: object + required: [name] + properties: + name: + type: string + minLength: 1 + maxLength: 100 + artists: + type: array + maxItems: 50 + items: + $ref: "#/components/schemas/DiscoverySeed" + + UpdateDiscoverySetRequest: + type: object + properties: + name: + type: string + minLength: 1 + maxLength: 100 + explore: + type: integer + minimum: 0 + maximum: 100 + mode: + $ref: "#/components/schemas/DiscoveryMode" + + DiscoveryItem: + type: object + description: A song you don't have, near a set's seeds. + required: [key, title, artist, because, seed] + properties: + key: + type: string + title: + type: string + artist: + type: string + album: + type: string + mbid: + type: string + isrc: + type: string + deezerId: + type: integer + format: int64 + description: The song on Deezer, for its preview. Absent when it isn't there, or isn't found yet. + cover: + type: string + description: Its cover's image ID, for getDiscoveryImage (kind `cover`). + because: + type: array + description: The seed artists it's near, nearest first. + items: + type: string + seed: + type: boolean + description: Whether it's a seed artist's own song. + + DiscoveryLibrary: + type: object + description: How far your library (your own Navidrome links) is indexed. + required: [links, songs, building] + properties: + links: + type: integer + songs: + type: integer + builtAt: + type: string + format: date-time + building: + type: boolean + + DiscoveryFeed: + type: object + required: [items, library, noGraph] + properties: + items: + type: array + items: + $ref: "#/components/schemas/DiscoveryItem" + next: + type: string + description: The cursor for the next page. Absent at the end. + library: + $ref: "#/components/schemas/DiscoveryLibrary" + noGraph: + type: boolean + description: The server knows nothing of how music relates (no sources are on), so feeds are empty. + + DiscoveryFeedbackRequest: + type: object + required: [kind, title, artist] + properties: + kind: + type: string + enum: [up, down] + setId: + type: string + description: The set whose feed it was in. + title: + type: string + minLength: 1 + artist: + type: string + minLength: 1 + mbid: + type: string + isrc: + type: string + deezerId: + type: integer + format: int64 + + DiscoveryBlock: + type: object + required: [key, name, createdAt] + properties: + key: + type: string + name: + type: string + createdAt: + type: string + format: date-time + + BlockDiscoveryArtistRequest: + type: object + required: [name] + properties: + name: + type: string + minLength: 1 + maxLength: 200 + + DiscoveryArtist: + type: object + required: [name] + properties: + name: + type: string + fans: + type: integer + format: int64 + description: Fans on Deezer, a measure of how well known. + picture: + type: string + description: Their picture's image ID, for getDiscoveryImage (kind `artist`). diff --git a/docs/adr/0017-personal-discovery.md b/docs/adr/0017-personal-discovery.md new file mode 100644 index 0000000..7a72f97 --- /dev/null +++ b/docs/adr/0017-personal-discovery.md @@ -0,0 +1,55 @@ +# ADR 0017: Personal discovery + +- **Status:** accepted +- **Date:** 2026-10-13 +- **Issues:** MAD-814 (Phase 12), stage 1: MAD-815..819 + +## Context + +Phase 12 adds a way to find music you **don't have yet**, the way Google Play Music's "new releases for you" did. Everything stays on the server. You hear a 30-second preview, follow a link out to YouTube for the whole song, and later (stage 4) keep what you like on a Want list until it turns up in your library. + +The obvious seed is your library. It's the wrong one. A Navidrome library holds plenty of music its owner doesn't love, so recommending from it recommends the wrong things. Syncphony's own history is still short, too. + +## Decision + +### Library ≠ taste + +- **Taste comes from seed sets you build by hand.** A set is a named list of artists ("Moody post-rock", "90s alt"). Each one is its own feed. A seed can be any artist, not just one in your library: artist search asks Deezer, and the name as typed seeds as well as any. +- **The library is only a filter.** `internal/library` indexes the songs on each user's **own** links that can list their whole library (Navidrome's, through the optional `provider.Cataloger`). Shared links and Spotify aren't indexed, since what's on your own server is what you have. Anything there is left out at song level (ISRC, MBID, or artist and title as `internal/match` normalizes them) or release level (artist and album). It's never filtered at artist level, so a new album by an artist you own still shows. `KnowsArtist` is there for showing (the stage 2 map dims owned artists), never for filtering. +- **The index** lists the library with `search3` and an empty query, 500 songs a page. That's a request per 500 songs, where walking artists and albums takes one per album. It's kept in memory per link, for lookups well under a millisecond, and in SQLite (`library_indexes`, gzipped keys) so a restart doesn't rebuild it. A link is first indexed when its user opens Discover. After that it's rebuilt daily, or on demand. A rebuild is skipped while Navidrome's `getScanStatus.lastScan` hasn't changed. Builds run one at a time, in the background. + +### Sets are personal + +Migration 00029 adds `discovery_sets` (explore 0–100, default 40; mode `deep`, `fresh` or `both`), `discovery_set_artists` (unique on the set and the artist's key: their MBID, else their simplified name), `discovery_feedback` (one thumb per user and song; the latest wins), `discovery_blocks` (the global "not for me") and `want_items` (filled from stage 4 on; the feed already leaves them out). Every query takes the user. Another user's set is `not_found`, and guests get `forbidden`. Shared sets come later. + +### The feed + +`internal/discover` walks the music graph (`musicgraph`, ADR 0012) out from a set's seeds. It works the way the DJ's walk does (`dj/candidates.go`), but it's its own walk. The DJ's is built around a room's members and what they've heard. This one starts from seeds, and it inverts the DJ's "playable on your links" rule into "not in your library". + +- **Overlap.** An artist's pull is the sum of how near it is to each seed, raised by half for each seed past the first (×1.5 near two seeds, ×2 near three). An artist near three seeds beats one that's very near just one. A set with explore at 35 or more takes a second step, damped, from the nearest new artists. +- **Songs.** The 40 nearest artists' top songs, plus the seeds' own songs at half pull (deep cuts). Live takes, remixes and demos are dropped. So are songs you have, turned down or want, and artists you blocked. +- **Popularity.** Deezer's rank and fan counts make a song's popularity. At a low explore, popularity counts for a song. At a high one it counts against it, so the feed leans toward less-known artists. +- **Variety.** The feed is split into pages of 20. On each page the seeds take turns, each giving its best song left, and no artist has more than two songs, as with suggestions (ADR 0010). +- **Why.** Each song names the seeds it's near: "Near Slowdive and Hum". +- **Bounded.** A build takes at most 15 seconds. It fetches up to 12 artists the graph hasn't cached, seeds first, and warms the rest for next time. A built feed is kept 10 minutes per set, and rebuilt sooner if the set changes or you ask (`refresh=true`). What you have, turned down or blocked is checked again as each page is served, so a thumbs-down leaves every page at once. + +### Previews through the server + +Deezer's 30-second MP3s are signed and expire, so their URLs are never stored. `GET /me/discover/preview/{deezerTrackId}` asks Deezer for the track each time and proxies the MP3 with byte ranges, the way songs are proxied. It uses the same Deezer client and rate limit as the music graph, and only accepts audio from Deezer's CDN. Covers and artist pictures come through `GET /me/discover/images/{kind}/{imageId}` the same way. The browser never talks to Deezer. + +Top songs from Deezer carry their Deezer ID, album and cover (`musicgraph.SongRef`). A song that only another source listed is looked up on Deezer once (`artist:"x" track:"y"`, then a looser search) when its page is first served. The result goes in `deezer_songs`, a miss included, and a miss is looked up again after 30 days. A song with no preview still offers the YouTube link. + +### The full song: a YouTube search link + +"Open on YouTube" links to `https://www.youtube.com/results?search_query= ` in a new tab. It needs no API key, no embed and no yt-dlp. There are no store or buy links. + +### Feedback stays out of rooms + +Discovery thumbs and blocks never reach a room's DJ (`dj_affinity`), and a room's skips never touch a set. Stage 1 stores thumbs-up. Stage 4 turns them into Want-list entries and growing sets. + +## Consequences + +- A **Discover** tab joins the app shell, outside any room. Its preview player plays locally, one song at a time, and leaves the room's playback and Media Session alone. +- Discovery needs at least one music graph source for feeds, and Deezer (on by default) for previews and artist pictures. Without a source, feeds say so (`noGraph`). +- An index holds keys, not songs: tens of bytes a song. A 50,000-song library is a few MB in memory, and less on disk. +- Until a user's library is first indexed, the feed can show songs they have. The tab shows indexing as it happens. diff --git a/server/cmd/syncphony/main.go b/server/cmd/syncphony/main.go index 8acafa9..0aa0a52 100644 --- a/server/cmd/syncphony/main.go +++ b/server/cmd/syncphony/main.go @@ -24,9 +24,11 @@ import ( "github.com/madeofpendletonwool/syncphony/server/internal/backup" "github.com/madeofpendletonwool/syncphony/server/internal/clips" "github.com/madeofpendletonwool/syncphony/server/internal/config" + "github.com/madeofpendletonwool/syncphony/server/internal/discover" "github.com/madeofpendletonwool/syncphony/server/internal/dj" "github.com/madeofpendletonwool/syncphony/server/internal/games" "github.com/madeofpendletonwool/syncphony/server/internal/httpapi" + "github.com/madeofpendletonwool/syncphony/server/internal/library" "github.com/madeofpendletonwool/syncphony/server/internal/linernotes" "github.com/madeofpendletonwool/syncphony/server/internal/links" "github.com/madeofpendletonwool/syncphony/server/internal/lyrics" @@ -241,7 +243,7 @@ func run() error { } else { slog.Info("MusicBrainz is off: artwork comes only from linked services, and there are no liner notes") } - graph := newMusicGraph(cfg, db, mb, userAgent) + graph, deezer := newMusicGraph(cfg, db, mb, userAgent) if len(graph.Sources()) > 0 { go graph.Run(ctx) go repairMusicGraph(ctx, graph) @@ -373,6 +375,20 @@ func run() error { if len(graph.Sources()) > 0 { api.Graph = graph } + // Personal discovery (ADR 0017): seed sets, minus what's in your library. + lib := library.New(db, a.links) + go lib.Run(ctx) + api.Library = lib + api.Discover = discover.New(db) + api.Discover.Library = lib + if len(graph.Sources()) > 0 { + api.Discover.Graph = graph + } + if deezer != nil { + api.Deezer, api.Discover.Deezer = deezer, deezer + } else { + slog.Info("Deezer is off: discovery has no previews") + } go sweep(ctx, db, accounts, roomSvc, lyricsSvc, mb, notes, graph, beatMaps) go tick(ctx, api, nightSvc) mux := http.NewServeMux() @@ -434,9 +450,11 @@ func tick(ctx context.Context, api *httpapi.Server, ns *nights.Service) { } // newMusicGraph sets up the DJ's music knowledge (ADR 0012) from the -// sources that are configured. -func newMusicGraph(cfg config.Config, db *store.Store, mb *musicbrainz.Service, userAgent string) *musicgraph.Service { +// sources that are configured. It returns Deezer too, if it's on, for +// discovery's previews (ADR 0017), which share its rate limit. +func newMusicGraph(cfg config.Config, db *store.Store, mb *musicbrainz.Service, userAgent string) (*musicgraph.Service, *musicgraph.Deezer) { var sources []musicgraph.Source + var deezer *musicgraph.Deezer if cfg.LastFMKey != "" { sources = append(sources, musicgraph.NewLastFM(musicgraph.LastFMOptions{Key: cfg.LastFMKey, UserAgent: userAgent})) } else { @@ -448,7 +466,8 @@ func newMusicGraph(cfg config.Config, db *store.Store, mb *musicbrainz.Service, })) } if cfg.DeezerURL != "" { - sources = append(sources, musicgraph.NewDeezer(musicgraph.DeezerOptions{BaseURL: cfg.DeezerURL, UserAgent: userAgent})) + deezer = musicgraph.NewDeezer(musicgraph.DeezerOptions{BaseURL: cfg.DeezerURL, UserAgent: userAgent}) + sources = append(sources, deezer) } opts := musicgraph.Options{} if mb != nil { @@ -462,7 +481,7 @@ func newMusicGraph(cfg config.Config, db *store.Store, mb *musicbrainz.Service, } else { slog.Info("music knowledge is off: no sources are configured") } - return graph + return graph, deezer } // repairMusicGraph fetches again the music knowledge cached while a source diff --git a/server/internal/discover/discover.go b/server/internal/discover/discover.go new file mode 100644 index 0000000..97049bb --- /dev/null +++ b/server/internal/discover/discover.go @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Package discover finds music a user doesn't have yet (MAD-817, ADR +// 0017). Taste comes from seed sets the user builds by hand: named lists +// of artists, each its own feed. The feed walks the music graph out from a +// set's seeds, as the DJ does, and keeps the songs the user doesn't +// already have (internal/library), hasn't turned down, and isn't blocking. +// +// It's personal: every set, thumb and block is one user's, and none of it +// touches a room. A thumbs-down here doesn't steer a room's DJ, and a skip +// in a room doesn't touch a set. +package discover + +import ( + "context" + "database/sql" + "errors" + "strings" + "sync" + "time" + "unicode/utf8" + + "github.com/madeofpendletonwool/syncphony/server/internal/library" + "github.com/madeofpendletonwool/syncphony/server/internal/musicgraph" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// Errors returned by Service. +var ( + ErrNotFound = errors.New("discovery set not found") + // ErrTooMany is a user with as many sets, or a set with as many + // artists, as they can have. + ErrTooMany = errors.New("that's as many as there can be") +) + +// InvalidInputError is a bad request, such as an empty name. +type InvalidInputError struct{ Message string } + +func (e *InvalidInputError) Error() string { return e.Message } + +// Limits. +const ( + MaxSets = 50 + MaxArtists = 50 + MaxName = 100 + // DefaultExplore is a new set's explore, 0 to 100. + DefaultExplore = 40 +) + +// Modes: which feeds a set shows. +const ( + ModeDeep = "deep" + ModeFresh = "fresh" + ModeBoth = "both" +) + +// Where a seed artist came from. +const ( + FromManual = "manual" + FromThumb = "thumb" + FromStarred = "starred" + FromRoom = "room" +) + +// Thumbs. +const ( + ThumbUp = "up" + ThumbDown = "down" +) + +// Graph is what's known about how music relates. musicgraph.Service is one. +type Graph interface { + CachedArtist(ctx context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, bool, error) + Artist(ctx context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, error) + WarmArtist(as ...musicgraph.ArtistRef) +} + +// Library says what a user already has. library.Service is one. +type Library interface { + For(ctx context.Context, userID string) (*library.Owned, error) +} + +// Deezer finds songs and artists on Deezer. musicgraph.Deezer is one. +type Deezer interface { + FindTrack(ctx context.Context, s musicgraph.SongRef) (musicgraph.DeezerTrack, error) + SearchArtists(ctx context.Context, q string, limit int) ([]musicgraph.DeezerArtist, error) +} + +// Service keeps users' seed sets and makes their feeds. +type Service struct { + db *store.Store + // Graph is the music graph. Nil makes every feed empty. + Graph Graph + // Library is what users have. Nil leaves nothing out. + Library Library + // Deezer finds songs' previews and artists by name. Nil means no + // previews, and artist search only offers the name typed. + Deezer Deezer + // Now is the clock. Default store.Now. + Now func() time.Time + // BuildFor bounds building a feed; what's found by then is the feed. + // Default 15s. + BuildFor time.Duration + // KeepFor is how long a built feed is kept. Default 10 minutes. + KeepFor time.Duration + + mu sync.Mutex + feeds map[string]*feed +} + +// New returns a Service. +func New(db *store.Store) *Service { + return &Service{db: db, Now: store.Now, BuildFor: 15 * time.Second, KeepFor: 10 * time.Minute, feeds: map[string]*feed{}} +} + +// Set is a seed set and its artists, in the order they were added. +type Set struct { + store.DiscoverySet + Artists []store.DiscoverySetArtist +} + +// Summary is a set in a list. +type Summary = store.ListDiscoverySetsRow + +// ArtistKey is how a seed artist is kept: their MBID, else their +// simplified name. +func ArtistKey(name, mbid string) string { + if mbid = strings.ToLower(strings.TrimSpace(mbid)); mbid != "" { + return mbid + } + return library.ArtistKey(name) +} + +// SongKey is how a song is kept: its simplified artist and title. +func SongKey(artist, title string) string { return library.SongKey(artist, title) } + +func cleanName(name string) (string, error) { + name = strings.Join(strings.Fields(name), " ") + switch { + case name == "": + return "", &InvalidInputError{"a name is needed"} + case utf8.RuneCountInString(name) > MaxName: + return "", &InvalidInputError{"that name is too long"} + } + return name, nil +} + +func checkMode(mode string) error { + switch mode { + case ModeDeep, ModeFresh, ModeBoth: + return nil + } + return &InvalidInputError{"mode is deep, fresh or both"} +} + +func checkExplore(explore int) error { + if explore < 0 || explore > 100 { + return &InvalidInputError{"explore is 0 to 100"} + } + return nil +} + +// Sets lists a user's sets, most recently changed first. +func (s *Service) Sets(ctx context.Context, userID string) ([]Summary, error) { + return s.db.ListDiscoverySets(ctx, userID) +} + +// Seed is an artist to add to a set. +type Seed struct { + Name, MBID string +} + +// Create makes a set, with seeds if given. +func (s *Service) Create(ctx context.Context, userID, name string, seeds []Seed) (Set, error) { + name, err := cleanName(name) + if err != nil { + return Set{}, err + } + if len(seeds) > MaxArtists { + return Set{}, ErrTooMany + } + have, err := s.db.ListDiscoverySets(ctx, userID) + if err != nil { + return Set{}, err + } + if len(have) >= MaxSets { + return Set{}, ErrTooMany + } + set, err := s.db.CreateDiscoverySet(ctx, store.CreateDiscoverySetParams{ + ID: store.NewID(), UserID: userID, Name: name, Explore: DefaultExplore, Mode: ModeBoth, Now: s.Now(), + }) + if err != nil { + return Set{}, err + } + for _, a := range seeds { + if err := s.addArtist(ctx, set.ID, a, FromManual); err != nil { + return Set{}, err + } + } + return s.Get(ctx, userID, set.ID) +} + +// Get returns one of a user's sets. +func (s *Service) Get(ctx context.Context, userID, setID string) (Set, error) { + row, err := s.db.GetDiscoverySet(ctx, store.GetDiscoverySetParams{ID: setID, UserID: userID}) + if store.IsNotFound(err) { + return Set{}, ErrNotFound + } else if err != nil { + return Set{}, err + } + artists, err := s.db.ListDiscoverySetArtists(ctx, setID) + if err != nil { + return Set{}, err + } + return Set{DiscoverySet: row, Artists: artists}, nil +} + +// Changes are what Update changes; nil leaves a field as it is. +type Changes struct { + Name *string + Explore *int + Mode *string +} + +// Update renames a set, or changes its explore or mode. +func (s *Service) Update(ctx context.Context, userID, setID string, c Changes) (Set, error) { + set, err := s.Get(ctx, userID, setID) + if err != nil { + return Set{}, err + } + p := store.UpdateDiscoverySetParams{ + ID: setID, UserID: userID, Name: set.Name, Explore: set.Explore, Mode: set.Mode, UpdatedAt: s.Now(), + } + if c.Name != nil { + if p.Name, err = cleanName(*c.Name); err != nil { + return Set{}, err + } + } + if c.Explore != nil { + if err := checkExplore(*c.Explore); err != nil { + return Set{}, err + } + p.Explore = int64(*c.Explore) + } + if c.Mode != nil { + if err := checkMode(*c.Mode); err != nil { + return Set{}, err + } + p.Mode = *c.Mode + } + if err := s.db.UpdateDiscoverySet(ctx, p); err != nil { + return Set{}, err + } + return s.Get(ctx, userID, setID) +} + +// Delete deletes a set. Its thumbs stay: a song turned down stays down. +func (s *Service) Delete(ctx context.Context, userID, setID string) error { + n, err := s.db.DeleteDiscoverySet(ctx, store.DeleteDiscoverySetParams{ID: setID, UserID: userID}) + if err != nil { + return err + } + if n == 0 { + return ErrNotFound + } + s.forget(setID) + return nil +} + +// AddArtist adds a seed artist to a set. Adding one that's there already +// changes nothing. +func (s *Service) AddArtist(ctx context.Context, userID, setID string, a Seed) (Set, error) { + set, err := s.Get(ctx, userID, setID) + if err != nil { + return Set{}, err + } + if len(set.Artists) >= MaxArtists { + return Set{}, ErrTooMany + } + if err := s.addArtist(ctx, setID, a, FromManual); err != nil { + return Set{}, err + } + if err := s.touch(ctx, setID); err != nil { + return Set{}, err + } + return s.Get(ctx, userID, setID) +} + +func (s *Service) addArtist(ctx context.Context, setID string, a Seed, from string) error { + name := strings.Join(strings.Fields(a.Name), " ") + key := ArtistKey(name, a.MBID) + if name == "" || key == "" || utf8.RuneCountInString(name) > MaxName*2 { + return &InvalidInputError{"an artist's name is needed"} + } + mbid := strings.ToLower(strings.TrimSpace(a.MBID)) + return s.db.AddDiscoverySetArtist(ctx, store.AddDiscoverySetArtistParams{ + SetID: setID, ArtistKey: key, Name: name, Mbid: sql.NullString{String: mbid, Valid: mbid != ""}, + AddedFrom: from, AddedAt: s.Now(), + }) +} + +// RemoveArtist takes a seed artist out of a set, by their key. +func (s *Service) RemoveArtist(ctx context.Context, userID, setID, key string) (Set, error) { + if _, err := s.Get(ctx, userID, setID); err != nil { + return Set{}, err + } + n, err := s.db.RemoveDiscoverySetArtist(ctx, store.RemoveDiscoverySetArtistParams{SetID: setID, ArtistKey: key}) + if err != nil { + return Set{}, err + } + if n == 0 { + return Set{}, ErrNotFound + } + if err := s.touch(ctx, setID); err != nil { + return Set{}, err + } + return s.Get(ctx, userID, setID) +} + +// touch marks a set changed, so its feed is built again. +func (s *Service) touch(ctx context.Context, setID string) error { + return s.db.TouchDiscoverySet(ctx, store.TouchDiscoverySetParams{UpdatedAt: s.Now(), ID: setID}) +} + +// Song is a song given a thumb. +type Song struct { + Title, Artist string + MBID, ISRC string + DeezerID int64 +} + +// Thumb records a thumbs-up or -down on a song, from a set's feed if +// setID is given. A thumbs-down hides the song from every one of the +// user's feeds, for good; a later thumbs-up replaces it. +func (s *Service) Thumb(ctx context.Context, userID, setID, kind string, song Song) error { + if kind != ThumbUp && kind != ThumbDown { + return &InvalidInputError{"a thumb is up or down"} + } + key := SongKey(song.Artist, song.Title) + if strings.TrimSpace(song.Title) == "" || strings.TrimSpace(song.Artist) == "" || strings.HasPrefix(key, "\x00") { + return &InvalidInputError{"a song's title and artist are needed"} + } + if setID != "" { + if _, err := s.Get(ctx, userID, setID); err != nil { + return err + } + } + return s.db.PutDiscoveryFeedback(ctx, store.PutDiscoveryFeedbackParams{ + ID: store.NewID(), UserID: userID, SetID: sql.NullString{String: setID, Valid: setID != ""}, Kind: kind, + SongKey: key, Title: song.Title, Artist: song.Artist, + Mbid: sql.NullString{String: song.MBID, Valid: song.MBID != ""}, + Isrc: sql.NullString{String: song.ISRC, Valid: song.ISRC != ""}, + DeezerID: sql.NullInt64{Int64: song.DeezerID, Valid: song.DeezerID != 0}, + CreatedAt: s.Now(), + }) +} + +// Block keeps an artist out of every one of the user's feeds. +func (s *Service) Block(ctx context.Context, userID, name string) (store.DiscoveryBlock, error) { + name = strings.Join(strings.Fields(name), " ") + key := library.ArtistKey(name) + if key == "" { + return store.DiscoveryBlock{}, &InvalidInputError{"an artist's name is needed"} + } + b := store.DiscoveryBlock{UserID: userID, ArtistKey: key, Name: name, CreatedAt: s.Now()} + return b, s.db.BlockDiscoveryArtist(ctx, store.BlockDiscoveryArtistParams(b)) +} + +// Unblock lets a blocked artist back in, by their key. +func (s *Service) Unblock(ctx context.Context, userID, key string) error { + n, err := s.db.UnblockDiscoveryArtist(ctx, store.UnblockDiscoveryArtistParams{UserID: userID, ArtistKey: key}) + if err != nil { + return err + } + if n == 0 { + return ErrNotFound + } + return nil +} + +// Blocks lists the artists a user blocked. +func (s *Service) Blocks(ctx context.Context, userID string) ([]store.DiscoveryBlock, error) { + return s.db.ListDiscoveryBlocks(ctx, userID) +} + +// Artist is an artist found by name, to add as a seed. +type Artist struct { + Name string + // Fans is how many fans they have on Deezer, Picture their picture's + // ID there; zero if unknown. + Fans int64 + Picture string +} + +// SearchArtists finds artists to seed a set with: any artist, not just +// ones in the user's library. Without Deezer, or when it fails, it offers +// the name as typed, which works as a seed as well as any. +func (s *Service) SearchArtists(ctx context.Context, q string) ([]Artist, error) { + q = strings.Join(strings.Fields(q), " ") + if q == "" { + return []Artist{}, nil + } + typed := []Artist{{Name: q}} + if s.Deezer == nil { + return typed, nil + } + found, err := s.Deezer.SearchArtists(ctx, q, 10) + if err != nil || len(found) == 0 { + return typed, nil //nolint:nilerr // the name as typed is still a seed + } + out := make([]Artist, 0, len(found)) + for _, a := range found { + out = append(out, Artist{Name: a.Name, Fans: a.Fans, Picture: a.Picture}) + } + return out, nil +} + +// LibraryStatus reports how far a user's library is indexed. +func (s *Service) LibraryStatus(ctx context.Context, userID string) (library.Status, error) { + if s.Library == nil { + return library.Status{}, nil + } + o, err := s.Library.For(ctx, userID) + if err != nil { + return library.Status{}, err + } + return o.Status(), nil +} diff --git a/server/internal/discover/discover_test.go b/server/internal/discover/discover_test.go new file mode 100644 index 0000000..2d6b8c0 --- /dev/null +++ b/server/internal/discover/discover_test.go @@ -0,0 +1,464 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package discover_test + +import ( + "context" + "errors" + "fmt" + "path/filepath" + "slices" + "strings" + "sync" + "testing" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/discover" + "github.com/madeofpendletonwool/syncphony/server/internal/library" + "github.com/madeofpendletonwool/syncphony/server/internal/match" + "github.com/madeofpendletonwool/syncphony/server/internal/musicgraph" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// graph is a music graph of made-up artists, each with five top songs. +type graph struct { + mu sync.Mutex + artists map[string]musicgraph.Artist + fetched []string + warmed []string +} + +func (g *graph) find(a musicgraph.ArtistRef) (musicgraph.Artist, bool) { + out, ok := g.artists[match.Simplify(a.Name)] + return out, ok +} + +func (g *graph) CachedArtist(_ context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, bool, error) { + g.mu.Lock() + defer g.mu.Unlock() + out, ok := g.find(a) + if !ok { + return musicgraph.Artist{}, false, nil + } + return out, true, nil +} + +func (g *graph) Artist(_ context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, error) { + g.mu.Lock() + defer g.mu.Unlock() + g.fetched = append(g.fetched, a.Name) + return musicgraph.Artist{}, provider.ErrNotFound +} + +func (g *graph) WarmArtist(as ...musicgraph.ArtistRef) { + g.mu.Lock() + defer g.mu.Unlock() + for _, a := range as { + g.warmed = append(g.warmed, a.Name) + } +} + +// artist adds an artist like others (name: score). +func (g *graph) artist(name string, fans int64, similar ...any) { + a := musicgraph.Artist{Ref: musicgraph.ArtistRef{Name: name}, Fans: fans} + for i := 0; i+1 < len(similar); i += 2 { + a.Similar = append(a.Similar, musicgraph.Similar{Artist: musicgraph.ArtistRef{Name: similar[i].(string)}, Score: similar[i+1].(float64)}) + } + for i := range 5 { + a.Top = append(a.Top, musicgraph.Song{ + SongRef: musicgraph.SongRef{Title: fmt.Sprintf("%s song %d", name, i+1), Artist: a.Ref, Album: name + " LP", DeezerID: int64(len(name)*100 + i)}, + Score: 1 - float64(i)*0.2, + }) + } + g.artists[match.Simplify(name)] = a +} + +// owned stands in for the library. +type owned struct{ o *library.Owned } + +func (l owned) For(context.Context, string) (*library.Owned, error) { return l.o, nil } + +type env struct { + db *store.Store + svc *discover.Service + graph *graph + alice string + bob string +} + +func newEnv(t *testing.T) *env { + t.Helper() + db, err := store.Open(t.Context(), filepath.Join(t.TempDir(), "test.db")) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { db.Close() }) + e := &env{db: db, graph: &graph{artists: map[string]musicgraph.Artist{}}} + for _, name := range []string{"alice", "bob"} { + u, err := db.CreateUser(t.Context(), store.CreateUserParams{ + ID: store.NewID(), Username: name, DisplayName: name, Color: "#000", Role: store.RoleMember, CreatedAt: store.Now(), + }) + if err != nil { + t.Fatal(err) + } + if name == "alice" { + e.alice = u.ID + } else { + e.bob = u.ID + } + } + // Slowdive, Hum and Duster: shoegaze and space rock. Swirlies is near + // all three; Ride only near Slowdive, if nearer it. + g := e.graph + g.artist("Slowdive", 900_000, "Ride", 0.9, "Swirlies", 0.6, "Lush", 0.5, "Chapterhouse", 0.45, "Hum", 0.4, "Pale Saints", 0.4) + g.artist("Hum", 300_000, "Failure", 0.8, "Swirlies", 0.6, "Shiner", 0.5, "Quicksand", 0.4, "Duster", 0.3) + g.artist("Duster", 200_000, "Codeine", 0.7, "Swirlies", 0.5, "Bedhead", 0.5, "Low", 0.4, "Failure", 0.2) + for _, a := range []string{"Ride", "Swirlies", "Lush", "Chapterhouse", "Pale Saints", "Failure", "Shiner", "Quicksand", "Codeine", "Bedhead", "Low"} { + g.artist(a, 100_000) + } + e.svc = discover.New(db) + e.svc.Graph = g + return e +} + +func (e *env) set(t *testing.T, seeds ...string) discover.Set { + t.Helper() + var ss []discover.Seed + for _, s := range seeds { + ss = append(ss, discover.Seed{Name: s}) + } + set, err := e.svc.Create(t.Context(), e.alice, "Moody", ss) + if err != nil { + t.Fatal(err) + } + return set +} + +func artists(items []discover.Item) []string { + var out []string + for _, it := range items { + if !slices.Contains(out, it.Artist) { + out = append(out, it.Artist) + } + } + return out +} + +func TestOverlapRanksFirst(t *testing.T) { + e := newEnv(t) + set := e.set(t, "Slowdive", "Hum", "Duster") + f, err := e.svc.Feed(t.Context(), e.alice, set.ID, "", false) + if err != nil { + t.Fatal(err) + } + if len(f.Items) != discover.PageSize || f.Next == "" { + t.Fatalf("page of %d, next %q", len(f.Items), f.Next) + } + // Swirlies is near all three seeds: their hit leads, though Ride is + // nearer Slowdive than Swirlies is to anyone. + first := f.Items[0] + if first.Artist != "Swirlies" || first.Title != "Swirlies song 1" { + t.Errorf("first: %+v", first) + } + if len(first.Because) != 2 || !slices.Contains([]string{"Slowdive", "Hum"}, first.Because[0]) { + t.Errorf("because: %v", first.Because) + } + // Seeds take turns, and no artist has more than two songs a page. + count := map[string]int{} + for _, it := range f.Items { + count[it.Artist]++ + if count[it.Artist] > 2 { + t.Errorf("%s has %d songs on the first page", it.Artist, count[it.Artist]) + } + } + got := artists(f.Items) + for _, want := range []string{"Ride", "Failure", "Codeine"} { + if !slices.Contains(got, want) { + t.Errorf("no %s on the first page: %v", want, got) + } + } + // The whole feed: 20+ songs, seeds' own deep cuts among them. + all := e.all(t, set.ID) + if len(all) < 20 { + t.Fatalf("%d songs in all", len(all)) + } + if !slices.ContainsFunc(all, func(it discover.Item) bool { return it.Seed && it.Artist == "Hum" }) { + t.Error("no songs of the seeds' own") + } + keys := map[string]bool{} + for _, it := range all { + if keys[it.Key] { + t.Errorf("%s twice", it.Title) + } + keys[it.Key] = true + } +} + +// all reads every page of a feed. +func (e *env) all(t *testing.T, setID string) []discover.Item { + t.Helper() + var out []discover.Item + cursor := "" + for range 100 { + f, err := e.svc.Feed(t.Context(), e.alice, setID, cursor, false) + if err != nil { + t.Fatal(err) + } + out = append(out, f.Items...) + if cursor = f.Next; cursor == "" { + return out + } + } + t.Fatal("the feed never ends") + return nil +} + +func TestOwnedSongsAreLeftOut(t *testing.T) { + e := newEnv(t) + credit := func(name string) []provider.ArtistCredit { return []provider.ArtistCredit{{Name: name}} } + e.svc.Library = owned{library.Holding( + provider.Track{Title: "Swirlies Song 1 - 2009 Remaster", Artists: credit("Swirlies"), Album: provider.AlbumCredit{Title: "Odds"}}, + provider.Track{Title: "Anything", Artists: credit("Ride"), Album: provider.AlbumCredit{Title: "Ride LP"}}, + )} + set := e.set(t, "Slowdive", "Hum", "Duster") + all := e.all(t, set.ID) + for _, it := range all { + if it.Title == "Swirlies song 1" { + t.Error("a song alice has") + } + if it.Artist == "Ride" { + t.Errorf("a song off a release alice has: %s", it.Title) + } + } + // Having one song of an artist's doesn't hide the rest. + if !slices.ContainsFunc(all, func(it discover.Item) bool { return it.Title == "Swirlies song 2" }) { + t.Error("Swirlies' other songs were left out too") + } +} + +func TestThumbsDownIsForGood(t *testing.T) { + e := newEnv(t) + set := e.set(t, "Slowdive", "Hum") + other := e.set(t, "Duster") + f, _ := e.svc.Feed(t.Context(), e.alice, set.ID, "", false) + down := f.Items[0] + if err := e.svc.Thumb(t.Context(), e.alice, set.ID, discover.ThumbDown, discover.Song{Title: down.Title, Artist: down.Artist}); err != nil { + t.Fatal(err) + } + for _, id := range []string{set.ID, other.ID} { + for _, it := range e.all(t, id) { + if it.Key == down.Key { + t.Errorf("%s still in a feed after a thumbs-down", it.Title) + } + } + } + // Not for bob: thumbs are personal. (Bob can't read alice's set.) + if _, err := e.svc.Feed(t.Context(), e.bob, set.ID, "", false); !errors.Is(err, discover.ErrNotFound) { + t.Errorf("bob read alice's feed: %v", err) + } + // Blocking an artist leaves out every song of theirs. + if _, err := e.svc.Block(t.Context(), e.alice, "Failure"); err != nil { + t.Fatal(err) + } + for _, it := range e.all(t, set.ID) { + if it.Artist == "Failure" { + t.Fatalf("a blocked artist's song: %s", it.Title) + } + } + if err := e.svc.Unblock(t.Context(), e.alice, "failure"); err != nil { + t.Fatal(err) + } + if !slices.ContainsFunc(e.all(t, set.ID), func(it discover.Item) bool { return it.Artist == "Failure" }) { + t.Error("unblocking didn't bring them back") + } +} + +func TestExploreLeansObscure(t *testing.T) { + e := newEnv(t) + // Two artists just as near Low: one famous, one not. + e.graph.artist("Low", 500_000, "Big Band", 0.8, "Small Band", 0.8) + e.graph.artist("Big Band", 9_000_000) + e.graph.artist("Small Band", 300) + set := e.set(t, "Low") + firstOf := func(explore int) string { + if _, err := e.svc.Update(t.Context(), e.alice, set.ID, discover.Changes{Explore: &explore}); err != nil { + t.Fatal(err) + } + f, err := e.svc.Feed(t.Context(), e.alice, set.ID, "", false) + if err != nil { + t.Fatal(err) + } + return f.Items[0].Artist + } + if got := firstOf(0); got != "Big Band" { + t.Errorf("explore 0 leads with %s", got) + } + if got := firstOf(100); got != "Small Band" { + t.Errorf("explore 100 leads with %s", got) + } +} + +func TestFeedIsKeptAndRebuilt(t *testing.T) { + e := newEnv(t) + now := time.Date(2026, 10, 13, 12, 0, 0, 0, time.UTC) + e.svc.Now = func() time.Time { return now } + set := e.set(t, "Hum") + first, _ := e.svc.Feed(t.Context(), e.alice, set.ID, "", false) + // The graph learns more; the kept feed doesn't, until it's rebuilt. + e.graph.artist("Hum", 300_000, "Failure", 0.8, "Swirlies", 0.6, "Duster", 0.3, "Hum Newcomer", 0.95) + e.graph.artist("Hum Newcomer", 1000) + has := func(f discover.Feed) bool { return slices.Contains(artists(f.Items), "Hum Newcomer") } + if f, _ := e.svc.Feed(t.Context(), e.alice, set.ID, "", false); has(f) || len(f.Items) != len(first.Items) { + t.Error("rebuilt before it went stale") + } + if f, _ := e.svc.Feed(t.Context(), e.alice, set.ID, "", true); !has(f) { + t.Error("refresh didn't rebuild") + } + e.graph.artist("Hum", 300_000, "Failure", 0.8) + now = now.Add(11 * time.Minute) + if f, _ := e.svc.Feed(t.Context(), e.alice, set.ID, "", false); has(f) { + t.Error("not rebuilt after going stale") + } +} + +func TestArtistsMissingFromTheGraphAreFetchedOrWarmed(t *testing.T) { + e := newEnv(t) + set := e.set(t, "Hum", "Unknown Seed") + if _, err := e.svc.Feed(t.Context(), e.alice, set.ID, "", false); err != nil { + t.Fatal(err) + } + if !slices.Contains(e.graph.fetched, "Unknown Seed") { + t.Errorf("fetched %v", e.graph.fetched) + } +} + +func TestSets(t *testing.T) { + e := newEnv(t) + ctx := t.Context() + set, err := e.svc.Create(ctx, e.alice, " 90s alt ", []discover.Seed{{Name: "Hum"}, {Name: " hum "}}) + if err != nil { + t.Fatal(err) + } + if set.Name != "90s alt" || len(set.Artists) != 1 || set.Explore != discover.DefaultExplore || set.Mode != discover.ModeBoth { + t.Fatalf("created: %+v", set) + } + if _, err := e.svc.Create(ctx, e.alice, " ", nil); !isInvalid(err) { + t.Errorf("no name: %v", err) + } + set, err = e.svc.AddArtist(ctx, e.alice, set.ID, discover.Seed{Name: "Failure", MBID: "ABC-123"}) + if err != nil || len(set.Artists) != 2 || set.Artists[1].ArtistKey != "abc-123" { + t.Fatalf("added: %+v %v", set.Artists, err) + } + if _, err := e.svc.AddArtist(ctx, e.bob, set.ID, discover.Seed{Name: "Low"}); !errors.Is(err, discover.ErrNotFound) { + t.Errorf("bob added to alice's set: %v", err) + } + if set, err = e.svc.RemoveArtist(ctx, e.alice, set.ID, "hum"); err != nil || len(set.Artists) != 1 { + t.Fatalf("removed: %+v %v", set.Artists, err) + } + mode, explore, name := "fresh", 101, "Renamed" + if _, err := e.svc.Update(ctx, e.alice, set.ID, discover.Changes{Explore: &explore}); !isInvalid(err) { + t.Errorf("explore 101: %v", err) + } + explore = 80 + if set, err = e.svc.Update(ctx, e.alice, set.ID, discover.Changes{Mode: &mode, Explore: &explore, Name: &name}); err != nil || set.Mode != "fresh" || set.Explore != 80 || set.Name != "Renamed" { + t.Fatalf("updated: %+v %v", set, err) + } + if err := e.svc.Delete(ctx, e.bob, set.ID); !errors.Is(err, discover.ErrNotFound) { + t.Errorf("bob deleted alice's set: %v", err) + } + if err := e.svc.Delete(ctx, e.alice, set.ID); err != nil { + t.Fatal(err) + } + if sets, _ := e.svc.Sets(ctx, e.alice); len(sets) != 0 { + t.Errorf("sets after deleting: %+v", sets) + } + if err := e.svc.Thumb(ctx, e.alice, "", "sideways", discover.Song{Title: "x", Artist: "y"}); !isInvalid(err) { + t.Errorf("a sideways thumb: %v", err) + } +} + +func TestSearchArtistsOffersWhatWasTyped(t *testing.T) { + e := newEnv(t) + got, err := e.svc.SearchArtists(t.Context(), " my friend's band ") + if err != nil || len(got) != 1 || got[0].Name != "my friend's band" { + t.Fatalf("%+v %v", got, err) + } + e.svc.Deezer = deezer{} + if got, _ := e.svc.SearchArtists(t.Context(), "hum"); len(got) != 2 || got[0].Name != "Hum" || got[0].Fans == 0 { + t.Errorf("from Deezer: %+v", got) + } +} + +func TestPreviewsAreFoundOnce(t *testing.T) { + e := newEnv(t) + // Last.fm-only songs: no Deezer IDs. + a := e.graph.artists["hum"] + for i := range a.Top { + a.Top[i].DeezerID = 0 + } + e.graph.artists["hum"] = a + d := &countingDeezer{} + e.svc.Deezer = d + set := e.set(t, "Hum") + f, err := e.svc.Feed(t.Context(), e.alice, set.ID, "", false) + if err != nil { + t.Fatal(err) + } + for _, it := range f.Items { + if it.Artist != "Hum" { + continue + } + if it.Title == "Hum song 2" { + if it.DeezerID != 0 { + t.Errorf("a song Deezer hasn't: %+v", it) + } + } else if it.DeezerID != 77 || it.Cover != "c0ffee" { + t.Errorf("not found on Deezer: %+v", it) + } + } + n := d.n() + if _, err := e.svc.Feed(t.Context(), e.alice, set.ID, "", true); err != nil { + t.Fatal(err) + } + if d.n() != n { + t.Errorf("searched Deezer again: %d, then %d", n, d.n()) + } +} + +type deezer struct{} + +func (deezer) FindTrack(context.Context, musicgraph.SongRef) (musicgraph.DeezerTrack, error) { + return musicgraph.DeezerTrack{}, provider.ErrNotFound +} + +func (deezer) SearchArtists(context.Context, string, int) ([]musicgraph.DeezerArtist, error) { + return []musicgraph.DeezerArtist{{ID: 1, Name: "Hum", Fans: 300_000}, {ID: 2, Name: "Hum (Ambient)"}}, nil +} + +type countingDeezer struct { + deezer + mu sync.Mutex + calls int +} + +func (d *countingDeezer) n() int { + d.mu.Lock() + defer d.mu.Unlock() + return d.calls +} + +func (d *countingDeezer) FindTrack(_ context.Context, s musicgraph.SongRef) (musicgraph.DeezerTrack, error) { + d.mu.Lock() + d.calls++ + d.mu.Unlock() + if strings.HasSuffix(s.Title, "song 2") { + return musicgraph.DeezerTrack{}, provider.ErrNotFound + } + return musicgraph.DeezerTrack{ID: 77, Title: s.Title, Artist: s.Artist.Name, Cover: "c0ffee", HasPreview: true}, nil +} + +func isInvalid(err error) bool { + var inv *discover.InvalidInputError + return errors.As(err, &inv) +} diff --git a/server/internal/discover/feed.go b/server/internal/discover/feed.go new file mode 100644 index 0000000..104d957 --- /dev/null +++ b/server/internal/discover/feed.go @@ -0,0 +1,567 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package discover + +import ( + "cmp" + "context" + "errors" + "log/slog" + "math" + "slices" + "strconv" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/library" + "github.com/madeofpendletonwool/syncphony/server/internal/match" + "github.com/madeofpendletonwool/syncphony/server/internal/musicgraph" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// How far a feed reaches. +const ( + // PageSize is how many songs a page of a feed holds. + PageSize = 20 + // perArtist is the most songs of one artist on a page. + perArtist = 2 + // maxFetches is how many artists that aren't cached a build fetches, + // seeds first; the rest are warmed for next time. + maxFetches = 12 + // similarPerSeed and similarPerHop2 are how many of an artist's + // similar artists the walk follows, one step out and two. + similarPerSeed = 40 + similarPerHop2 = 15 + // hop2From is how many of the nearest new artists the second step + // starts from, when the set explores (exploreHop2 or more). + hop2From = 10 + exploreHop2 = 0.35 + hop2Damping = 0.6 + // overlapBonus is how much more an artist near several seeds counts, + // for each seed past the first. + overlapBonus = 0.5 + // songArtists is how many of the nearest artists' songs are in a + // feed, songsPerArtist of each. + songArtists = 40 + songsPerArtist = 10 + // seedPull is how near a seed's own songs count, against the nearest + // new artist's: deep cuts of the seeds, among the new names. + seedPull = 0.5 + // maxItems bounds a feed. + maxItems = 400 + // resolvePerPage is how many songs without a Deezer ID a page looks + // up, within resolveFor; the rest show without a preview this time. + resolvePerPage = 12 + resolveFor = 6 * time.Second + // missAgain is how long a song Deezer didn't have waits to be looked + // up again. + missAgain = 30 * 24 * time.Hour +) + +// Item is a song in a feed. +type Item struct { + // Key is how the song is compared (SongKey). + Key string + Title, Artist string + // Album is its album's title, when known. + Album string + MBID, ISRC string + // DeezerID is the song on Deezer, for its preview and cover; 0 if + // it isn't known to be there. + DeezerID int64 + // Cover is the Deezer cover image's ID, when known. + Cover string + // Because are the seed artists it's near, nearest first. + Because []string + // Seed is whether it's a seed artist's own song. + Seed bool + Score float64 +} + +// Feed is a page of a set's feed. +type Feed struct { + Items []Item + // Next is the cursor for the next page, or "" at the end. + Next string + // Library is how far the user's library is indexed: until it's done, + // songs they have can show up. + Library library.Status + // NoGraph is whether the server knows nothing of how music relates + // (no sources are on), so feeds are empty. + NoGraph bool +} + +// feed is a set's built feed, kept KeepFor. +type feed struct { + builtAt time.Time + // setAt is the set's updated_at when built: a change rebuilds it. + setAt time.Time + pages [][]Item + // done is closed once it's built. + done chan struct{} +} + +func (s *Service) forget(setID string) { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.feeds, setID) +} + +// Feed returns a page of a set's feed, at cursor ("" for the first +// page). The feed is built at most every KeepFor, or now if refresh is +// set; songs the user has, turned down, blocked or wants are left out of +// every page as it's served, so a thumbs-down takes a song out at once. +func (s *Service) Feed(ctx context.Context, userID, setID, cursor string, refresh bool) (Feed, error) { + set, err := s.Get(ctx, userID, setID) + if err != nil { + return Feed{}, err + } + page := 0 + if cursor != "" { + if page, err = strconv.Atoi(cursor); err != nil || page < 0 { + return Feed{}, &InvalidInputError{"bad cursor"} + } + } + out := Feed{Items: []Item{}, NoGraph: s.Graph == nil} + f := s.items(ctx, userID, set, refresh && page == 0) + keep, status, err := s.filter(ctx, userID) + if err != nil { + return Feed{}, err + } + out.Library = status + s.mu.Lock() + // A page whose songs were all left out since it was built is skipped. + for ; page < len(f.pages) && len(out.Items) == 0; page++ { + for _, it := range f.pages[page] { + if keep(it) { + out.Items = append(out.Items, it) + } + } + } + if page < len(f.pages) { + out.Next = strconv.Itoa(page) + } + s.mu.Unlock() + s.resolve(ctx, f, out.Items) + return out, nil +} + +// items returns a set's feed, building it if it isn't kept or is stale. +// Only one build of a set runs at a time; others wait for it. +func (s *Service) items(ctx context.Context, userID string, set Set, refresh bool) *feed { + now := s.Now() + s.mu.Lock() + f, ok := s.feeds[set.ID] + fresh := ok && !refresh && f.setAt.Equal(set.UpdatedAt) && (f.builtAt.IsZero() || now.Sub(f.builtAt) < s.KeepFor) + if fresh { + s.mu.Unlock() + select { + case <-f.done: + return f + case <-ctx.Done(): + return &feed{} // gave up waiting for someone else's build + } + } + f = &feed{setAt: set.UpdatedAt, done: make(chan struct{})} + s.feeds[set.ID] = f + s.mu.Unlock() + pages := s.build(ctx, userID, set) + s.mu.Lock() + f.pages, f.builtAt = pages, s.Now() + s.mu.Unlock() + close(f.done) + return f +} + +// filter returns what says whether a song may be shown to a user, now: +// not one they have, turned down, want already, or by an artist they +// blocked. +func (s *Service) filter(ctx context.Context, userID string) (func(Item) bool, library.Status, error) { + var owned *library.Owned + var status library.Status + if s.Library != nil { + o, err := s.Library.For(ctx, userID) + if err != nil { + return nil, status, err + } + owned, status = o, o.Status() + } + down := map[string]bool{} + fb, err := s.db.ListDiscoveryFeedback(ctx, userID) + if err != nil { + return nil, status, err + } + for _, f := range fb { + if f.Kind == ThumbDown { + down[f.SongKey] = true + } + } + blocked := map[string]bool{} + bs, err := s.db.ListDiscoveryBlocks(ctx, userID) + if err != nil { + return nil, status, err + } + for _, b := range bs { + blocked[b.ArtistKey] = true + } + wanted := map[string]bool{} + ws, err := s.db.ListWantItems(ctx, userID) + if err != nil { + return nil, status, err + } + for _, w := range ws { + if w.Kind == "track" { + wanted[w.ItemKey] = true + } + } + return func(it Item) bool { + return !down[it.Key] && !wanted[it.Key] && !blocked[library.ArtistKey(it.Artist)] && + !owned.Has(library.Song{Artist: it.Artist, Title: it.Title, ISRC: it.ISRC, MBID: it.MBID}) && + !owned.HasRelease(it.Artist, it.Album) + }, status, nil +} + +// node is an artist the walk reached. +type node struct { + ref musicgraph.ArtistRef + // near is how near each seed (by key) they are, 0 to 1. + near map[string]float64 + hop int + seed bool +} + +// pull is how near the set an artist is: the sum of how near each seed +// is, more for being near several. +func (n *node) pull() float64 { + sum := 0.0 + for _, v := range n.near { + sum += v + } + return sum * (1 + overlapBonus*float64(max(len(n.near)-1, 0))) +} + +// because names the seeds an artist is nearest, nearest first: two at most. +func (n *node) because(names map[string]string) []string { + keys := make([]string, 0, len(n.near)) + for k := range n.near { + keys = append(keys, k) + } + slices.SortFunc(keys, func(a, b string) int { + if c := cmp.Compare(n.near[b], n.near[a]); c != 0 { + return c + } + return cmp.Compare(a, b) + }) + out := make([]string, 0, 2) + for _, k := range keys[:min(len(keys), 2)] { + out = append(out, names[k]) + } + return out +} + +// build walks the graph out from a set's seeds and returns its songs in +// pages, best first and taking turns between the seeds, without songs the +// user has or turned down, within BuildFor. +func (s *Service) build(ctx context.Context, userID string, set Set) [][]Item { + if s.Graph == nil || len(set.Artists) == 0 { + return nil + } + ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), s.BuildFor) + defer cancel() + explore := float64(set.Explore) / 100 + keep, _, err := s.filter(ctx, userID) + if err != nil { + slog.Warn("discover: reading what to leave out", "set", set.ID, "err", err) + keep = func(Item) bool { return true } + } + + known := map[string]musicgraph.Artist{} + var missing []musicgraph.ArtistRef + fetches := 0 + lookup := func(ref musicgraph.ArtistRef) (musicgraph.Artist, bool) { + k := library.ArtistKey(ref.Name) + if a, ok := known[k]; ok { + return a, true + } + a, ok, err := s.Graph.CachedArtist(ctx, ref) + if !ok && err == nil && fetches < maxFetches && ctx.Err() == nil { + fetches++ + a, err = s.Graph.Artist(ctx, ref) + ok = err == nil + } + switch { + case ok && err == nil: + known[k] = a + return a, true + case !ok && err == nil: + missing = append(missing, ref) + case !errors.Is(err, provider.ErrNotFound) && ctx.Err() == nil: + slog.Debug("discover: looking up an artist", "artist", ref.Name, "err", err) + } + return musicgraph.Artist{}, false + } + + names := map[string]string{} + nodes := map[string]*node{} + reach := func(ref musicgraph.ArtistRef, seed string, near float64, hop int) { + k := library.ArtistKey(ref.Name) + if k == "" { + return + } + n, ok := nodes[k] + if !ok { + n = &node{ref: ref, near: map[string]float64{}, hop: hop} + nodes[k] = n + } + n.near[seed] = max(n.near[seed], near) + n.hop = min(n.hop, hop) + n.ref.MBID = cmp.Or(n.ref.MBID, ref.MBID) + } + var seeds []*node + for _, sa := range set.Artists { + ref := musicgraph.ArtistRef{Name: sa.Name, MBID: sa.Mbid.String} + k := library.ArtistKey(sa.Name) + names[k] = sa.Name + n := &node{ref: ref, near: map[string]float64{k: 1}, seed: true} + seeds = append(seeds, n) + a, ok := lookup(ref) + if !ok { + continue + } + for _, sim := range a.Similar[:min(len(a.Similar), similarPerSeed)] { + reach(sim.Artist, k, sim.Score, 1) + } + } + for _, n := range seeds { + delete(nodes, library.ArtistKey(n.ref.Name)) // a seed isn't a new artist + } + // A second step, for a set that explores: from the nearest new + // artists, as far as they lead from the seed they're nearest. + if explore >= exploreHop2 { + step := ranked(nodes) + for _, n := range step[:min(len(step), hop2From)] { + a, ok := lookup(n.ref) + if !ok { + continue + } + seed, pull := strongest(n.near) + for _, sim := range a.Similar[:min(len(a.Similar), similarPerHop2)] { + if _, isSeed := names[library.ArtistKey(sim.Artist.Name)]; isSeed { + continue + } + reach(sim.Artist, seed, pull*sim.Score*hop2Damping, 2) + } + } + } + + // Songs: the nearest artists' top songs, and the seeds' own. + near := ranked(nodes) + near = near[:min(len(near), songArtists)] + top := 0.0 + for _, n := range near { + top = max(top, n.pull()) + } + var items []Item + taken := map[string]bool{} + add := func(n *node, pull float64) { + a, ok := lookup(n.ref) + if !ok { + return + } + fame := famous(a.Fans) + because := n.because(names) + for _, so := range a.Top[:min(len(a.Top), songsPerArtist)] { + artist := cmp.Or(so.Artist.Name, n.ref.Name) + if _, variants := match.Title(so.Title); len(variants) > 0 || so.Title == "" { + continue // live takes, remixes, demos + } + it := Item{ + Key: SongKey(artist, so.Title), Title: so.Title, Artist: artist, Album: so.Album, + MBID: so.MBID, ISRC: so.ISRC, DeezerID: so.DeezerID, Cover: so.Cover, + Because: because, Seed: n.seed, + } + if taken[it.Key] || !keep(it) { + continue + } + taken[it.Key] = true + pop := fame + if so.Rank > 0 { + pop = 0.6*so.Rank + 0.4*fame + } + it.Score = score(pull, pop, so.Score, explore) + items = append(items, it) + } + } + for _, n := range near { + if ctx.Err() != nil { + break + } + add(n, n.pull()/top) + } + for _, n := range seeds { + if ctx.Err() != nil { + break + } + add(n, seedPull) + } + if len(missing) > 0 { + s.Graph.WarmArtist(missing...) + } + return arrange(items) +} + +// famous is how well known an artist is, from their fans on Deezer, 0 to +// 1: ten million fans is as famous as it gets. Unknown is middling. +func famous(fans int64) float64 { + if fans <= 0 { + return 0.5 + } + return min(math.Log10(float64(fans))/7, 1) +} + +// score ranks a song: how near the set its artist is, how much of a hit +// it is among the artist's own, and how well known it is, which counts +// for it at a low explore and against it at a high one. +func score(pull, pop, hit, explore float64) float64 { + lean := (1-explore)*pop + explore*(1-pop) + return pull * (0.5 + 0.5*lean) * (0.6 + 0.4*hit) +} + +func strongest(near map[string]float64) (string, float64) { + var best string + pull := -1.0 + for k, v := range near { + if v > pull || (v == pull && k < best) { + best, pull = k, v + } + } + return best, pull +} + +// ranked returns nodes nearest the set first. +func ranked(nodes map[string]*node) []*node { + out := make([]*node, 0, len(nodes)) + for _, n := range nodes { + out = append(out, n) + } + slices.SortFunc(out, func(a, b *node) int { + if c := cmp.Compare(b.pull(), a.pull()); c != 0 { + return c + } + return cmp.Compare(a.ref.Name, b.ref.Name) + }) + return out +} + +// arrange splits a feed's songs into pages: on each, the seeds take +// turns, each giving its best song left (by the seed it's nearest), and +// no artist has more than perArtist songs. So a set of a few seeds +// doesn't fill its first page with one seed's neighbors. +func arrange(items []Item) [][]Item { + type group struct { + best float64 + items []Item + } + bySeed := map[string]*group{} + var groups []*group + for _, it := range items[:min(len(items), maxItems)] { + k := "" + if len(it.Because) > 0 { + k = it.Because[0] + } + g, ok := bySeed[k] + if !ok { + g = &group{} + bySeed[k] = g + groups = append(groups, g) + } + g.items = append(g.items, it) + } + for _, g := range groups { + slices.SortStableFunc(g.items, func(a, b Item) int { return cmp.Compare(b.Score, a.Score) }) + g.best = g.items[0].Score + } + slices.SortStableFunc(groups, func(a, b *group) int { return cmp.Compare(b.best, a.best) }) + + var pages [][]Item + for { + count := map[string]int{} + var page []Item + for progress := true; progress && len(page) < PageSize; { + progress = false + for _, g := range groups { + if len(page) == PageSize { + break + } + i := slices.IndexFunc(g.items, func(it Item) bool { return count[library.ArtistKey(it.Artist)] < perArtist }) + if i < 0 { + continue + } + it := g.items[i] + g.items = slices.Delete(g.items, i, i+1) + count[library.ArtistKey(it.Artist)]++ + page = append(page, it) + progress = true + } + } + if len(page) == 0 { + return pages + } + pages = append(pages, page) + } +} + +// resolve finds the Deezer IDs of a page's songs that have none, so they +// can play a preview: from the database, or by searching Deezer once. +// What it finds is kept in the feed too. +func (s *Service) resolve(ctx context.Context, f *feed, items []Item) { + if s.Deezer == nil { + return + } + ctx, cancel := context.WithTimeout(ctx, resolveFor) + defer cancel() + now := s.Now() + searched := 0 + for i := range items { + it := &items[i] + if it.DeezerID != 0 { + continue + } + row, err := s.db.GetDeezerSong(ctx, it.Key) + switch { + case err == nil && (row.DeezerID != 0 || now.Sub(row.CheckedAt) < missAgain): + case (err == nil || store.IsNotFound(err)) && searched < resolvePerPage && ctx.Err() == nil: + searched++ + row = store.DeezerSong{SongKey: it.Key, CheckedAt: now} + t, err := s.Deezer.FindTrack(ctx, musicgraph.SongRef{Title: it.Title, Artist: musicgraph.ArtistRef{Name: it.Artist}, ISRC: it.ISRC}) + switch { + case err == nil: + row.DeezerID, row.Album, row.Cover = t.ID, t.Album, t.Cover + case !errors.Is(err, provider.ErrNotFound): + continue // Deezer's down: try again next time + } + if err := s.db.PutDeezerSong(ctx, store.PutDeezerSongParams(row)); err != nil { + slog.Warn("discover: keeping a song's Deezer ID", "err", err) + } + default: + continue + } + it.DeezerID, it.Album, it.Cover = row.DeezerID, cmp.Or(it.Album, row.Album), cmp.Or(it.Cover, row.Cover) + } + // Keep what was found, for the next time the page is served. + found := map[string]Item{} + for _, it := range items { + if it.DeezerID != 0 { + found[it.Key] = it + } + } + s.mu.Lock() + defer s.mu.Unlock() + for _, page := range f.pages { + for i, it := range page { + if r, ok := found[it.Key]; ok && it.DeezerID == 0 { + page[i].DeezerID, page[i].Album, page[i].Cover = r.DeezerID, r.Album, r.Cover + } + } + } +} diff --git a/server/internal/httpapi/accounts_test.go b/server/internal/httpapi/accounts_test.go index 4ce2e76..e6ca6e9 100644 --- a/server/internal/httpapi/accounts_test.go +++ b/server/internal/httpapi/accounts_test.go @@ -28,6 +28,7 @@ import ( "github.com/madeofpendletonwool/syncphony/server/internal/avatar" "github.com/madeofpendletonwool/syncphony/server/internal/backup" "github.com/madeofpendletonwool/syncphony/server/internal/clips" + "github.com/madeofpendletonwool/syncphony/server/internal/discover" "github.com/madeofpendletonwool/syncphony/server/internal/dj" "github.com/madeofpendletonwool/syncphony/server/internal/games" "github.com/madeofpendletonwool/syncphony/server/internal/httpapi" @@ -147,7 +148,7 @@ func newEnv(t *testing.T) *env { t.Cleanup(pilot.Close) api := &httpapi.Server{ Version: "test", StartedAt: e.clock(), Admin: e.server, Backups: e.backups, Auth: e.svc, Links: e.links, Lyrics: ly, LinerNotes: notes, Artwork: art, Palettes: e.palettes, BeatMaps: beatMaps, Rooms: e.rooms, Queue: qs, Playback: e.playback, Nights: e.nights, Playlists: playlists.New(db, e.rooms, e.links), Games: e.games, Bus: e.bus, Presence: presence, - Suggest: suggest.New(db, e.rooms, e.links), Autopilot: pilot, + Suggest: suggest.New(db, e.rooms, e.links), Autopilot: pilot, Discover: discover.New(db), BaseURL: e.base, PingEvery: 50 * time.Millisecond, } if ff := (transcode.FFmpeg{}); ff.Available() { diff --git a/server/internal/httpapi/api.gen.go b/server/internal/httpapi/api.gen.go index 106e0e0..f0aa92a 100644 --- a/server/internal/httpapi/api.gen.go +++ b/server/internal/httpapi/api.gen.go @@ -113,22 +113,22 @@ func (e AwardKind) Valid() bool { // Defines values for BackupKind. const ( - Manual BackupKind = "manual" - PreRestore BackupKind = "pre-restore" - PreUpgrade BackupKind = "pre-upgrade" - Scheduled BackupKind = "scheduled" + BackupKindManual BackupKind = "manual" + BackupKindPreRestore BackupKind = "pre-restore" + BackupKindPreUpgrade BackupKind = "pre-upgrade" + BackupKindScheduled BackupKind = "scheduled" ) // Valid indicates whether the value is a known member of the BackupKind enum. func (e BackupKind) Valid() bool { switch e { - case Manual: + case BackupKindManual: return true - case PreRestore: + case BackupKindPreRestore: return true - case PreUpgrade: + case BackupKindPreUpgrade: return true - case Scheduled: + case BackupKindScheduled: return true default: return false @@ -180,6 +180,69 @@ func (e BeginDisplayPairingRequestKind) Valid() bool { } } +// Defines values for DiscoveryFeedbackRequestKind. +const ( + DiscoveryFeedbackRequestKindDown DiscoveryFeedbackRequestKind = "down" + DiscoveryFeedbackRequestKindUp DiscoveryFeedbackRequestKind = "up" +) + +// Valid indicates whether the value is a known member of the DiscoveryFeedbackRequestKind enum. +func (e DiscoveryFeedbackRequestKind) Valid() bool { + switch e { + case DiscoveryFeedbackRequestKindDown: + return true + case DiscoveryFeedbackRequestKindUp: + return true + default: + return false + } +} + +// Defines values for DiscoveryMode. +const ( + DiscoveryModeBoth DiscoveryMode = "both" + DiscoveryModeDeep DiscoveryMode = "deep" + DiscoveryModeFresh DiscoveryMode = "fresh" +) + +// Valid indicates whether the value is a known member of the DiscoveryMode enum. +func (e DiscoveryMode) Valid() bool { + switch e { + case DiscoveryModeBoth: + return true + case DiscoveryModeDeep: + return true + case DiscoveryModeFresh: + return true + default: + return false + } +} + +// Defines values for DiscoverySetArtistAddedFrom. +const ( + DiscoverySetArtistAddedFromManual DiscoverySetArtistAddedFrom = "manual" + DiscoverySetArtistAddedFromRoom DiscoverySetArtistAddedFrom = "room" + DiscoverySetArtistAddedFromStarred DiscoverySetArtistAddedFrom = "starred" + DiscoverySetArtistAddedFromThumb DiscoverySetArtistAddedFrom = "thumb" +) + +// Valid indicates whether the value is a known member of the DiscoverySetArtistAddedFrom enum. +func (e DiscoverySetArtistAddedFrom) Valid() bool { + switch e { + case DiscoverySetArtistAddedFromManual: + return true + case DiscoverySetArtistAddedFromRoom: + return true + case DiscoverySetArtistAddedFromStarred: + return true + case DiscoverySetArtistAddedFromThumb: + return true + default: + return false + } +} + // Defines values for DisplayPairingInfoKind. const ( DisplayPairingInfoKindBox DisplayPairingInfoKind = "box" @@ -1881,6 +1944,11 @@ type BeginPairingRequest struct { Provider *string `json:"provider,omitempty"` } +// BlockDiscoveryArtistRequest defines model for BlockDiscoveryArtistRequest. +type BlockDiscoveryArtistRequest struct { + Name string `json:"name"` +} + // Ceremony defines model for Ceremony. type Ceremony struct { // CeremonyId Pass back to the matching finish endpoint within 5 minutes. @@ -1915,6 +1983,12 @@ type ClearedLane struct { Removed []string `json:"removed"` } +// CreateDiscoverySetRequest defines model for CreateDiscoverySetRequest. +type CreateDiscoverySetRequest struct { + Artists *[]DiscoverySeed `json:"artists,omitempty"` + Name string `json:"name"` +} + // CreateGuestPassRequest defines model for CreateGuestPassRequest. type CreateGuestPassRequest struct { // ExpiresAt When the pass, and everyone who joins with it, expires: e.g. the @@ -2013,6 +2087,137 @@ type DeleteMeRequest struct { Password *string `json:"password,omitempty"` } +// DiscoveryArtist defines model for DiscoveryArtist. +type DiscoveryArtist struct { + // Fans Fans on Deezer, a measure of how well known. + Fans *int64 `json:"fans,omitempty"` + Name string `json:"name"` + + // Picture Their picture's image ID, for getDiscoveryImage (kind `artist`). + Picture *string `json:"picture,omitempty"` +} + +// DiscoveryBlock defines model for DiscoveryBlock. +type DiscoveryBlock struct { + CreatedAt time.Time `json:"createdAt"` + Key string `json:"key"` + Name string `json:"name"` +} + +// DiscoveryFeed defines model for DiscoveryFeed. +type DiscoveryFeed struct { + Items []DiscoveryItem `json:"items"` + + // Library How far your library (your own Navidrome links) is indexed. + Library DiscoveryLibrary `json:"library"` + + // Next The cursor for the next page. Absent at the end. + Next *string `json:"next,omitempty"` + + // NoGraph The server knows nothing of how music relates (no sources are on), so feeds are empty. + NoGraph bool `json:"noGraph"` +} + +// DiscoveryFeedbackRequest defines model for DiscoveryFeedbackRequest. +type DiscoveryFeedbackRequest struct { + Artist string `json:"artist"` + DeezerId *int64 `json:"deezerId,omitempty"` + Isrc *string `json:"isrc,omitempty"` + Kind DiscoveryFeedbackRequestKind `json:"kind"` + Mbid *string `json:"mbid,omitempty"` + + // SetId The set whose feed it was in. + SetId *string `json:"setId,omitempty"` + Title string `json:"title"` +} + +// DiscoveryFeedbackRequestKind defines model for DiscoveryFeedbackRequest.Kind. +type DiscoveryFeedbackRequestKind string + +// DiscoveryItem A song you don't have, near a set's seeds. +type DiscoveryItem struct { + Album *string `json:"album,omitempty"` + Artist string `json:"artist"` + + // Because The seed artists it's near, nearest first. + Because []string `json:"because"` + + // Cover Its cover's image ID, for getDiscoveryImage (kind `cover`). + Cover *string `json:"cover,omitempty"` + + // DeezerId The song on Deezer, for its preview. Absent when it isn't there, or isn't found yet. + DeezerId *int64 `json:"deezerId,omitempty"` + Isrc *string `json:"isrc,omitempty"` + Key string `json:"key"` + Mbid *string `json:"mbid,omitempty"` + + // Seed Whether it's a seed artist's own song. + Seed bool `json:"seed"` + Title string `json:"title"` +} + +// DiscoveryLibrary How far your library (your own Navidrome links) is indexed. +type DiscoveryLibrary struct { + Building bool `json:"building"` + BuiltAt *time.Time `json:"builtAt,omitempty"` + Links int `json:"links"` + Songs int `json:"songs"` +} + +// DiscoveryMode Which feeds a set shows: `deep` cuts (anything new to you), `fresh` +// releases (coming), or `both`. +type DiscoveryMode string + +// DiscoverySeed defines model for DiscoverySeed. +type DiscoverySeed struct { + Mbid *string `json:"mbid,omitempty"` + Name string `json:"name"` +} + +// DiscoverySet defines model for DiscoverySet. +type DiscoverySet struct { + Artists []DiscoverySetArtist `json:"artists"` + CreatedAt time.Time `json:"createdAt"` + + // Explore How far the feed strays from the seeds, and toward less-known artists. + Explore int `json:"explore"` + Id string `json:"id"` + + // Mode Which feeds a set shows: `deep` cuts (anything new to you), `fresh` + // releases (coming), or `both`. + Mode DiscoveryMode `json:"mode"` + Name string `json:"name"` + UpdatedAt time.Time `json:"updatedAt"` +} + +// DiscoverySetArtist defines model for DiscoverySetArtist. +type DiscoverySetArtist struct { + AddedAt time.Time `json:"addedAt"` + AddedFrom DiscoverySetArtistAddedFrom `json:"addedFrom"` + + // Key Their MBID, else their simplified name. Removes them from the set. + Key string `json:"key"` + Mbid *string `json:"mbid,omitempty"` + Name string `json:"name"` +} + +// DiscoverySetArtistAddedFrom defines model for DiscoverySetArtist.AddedFrom. +type DiscoverySetArtistAddedFrom string + +// DiscoverySetSummary defines model for DiscoverySetSummary. +type DiscoverySetSummary struct { + ArtistCount int `json:"artistCount"` + CreatedAt time.Time `json:"createdAt"` + Explore int `json:"explore"` + Id string `json:"id"` + + // Mode Which feeds a set shows: `deep` cuts (anything new to you), `fresh` + // releases (coming), or `both`. + Mode DiscoveryMode `json:"mode"` + Name string `json:"name"` + UpdatedAt time.Time `json:"updatedAt"` +} + // Display defines model for Display. type Display struct { // Audio It may play the room's audio, as the speaker. @@ -4277,6 +4482,16 @@ type TransferRoomRequest struct { UserId string `json:"userId"` } +// UpdateDiscoverySetRequest defines model for UpdateDiscoverySetRequest. +type UpdateDiscoverySetRequest struct { + Explore *int `json:"explore,omitempty"` + + // Mode Which feeds a set shows: `deep` cuts (anything new to you), `fresh` + // releases (coming), or `both`. + Mode *DiscoveryMode `json:"mode,omitempty"` + Name *string `json:"name,omitempty"` +} + // UpdateDisplayRequest defines model for UpdateDisplayRequest. type UpdateDisplayRequest struct { Audio bool `json:"audio"` @@ -4423,6 +4638,9 @@ type UserSession struct { // Username 2 to 32 characters: lowercase letters, digits, `.`, `_` and `-`. type Username = string +// DiscoverySetId defines model for DiscoverySetId. +type DiscoverySetId = string + // InviteCode defines model for InviteCode. type InviteCode = string @@ -4498,6 +4716,31 @@ type GetPlaylistTracksParams struct { Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` } +// SearchDiscoveryArtistsParams defines parameters for SearchDiscoveryArtists. +type SearchDiscoveryArtistsParams struct { + Q string `form:"q" json:"q"` +} + +// GetDiscoveryImageParams defines parameters for GetDiscoveryImage. +type GetDiscoveryImageParams struct { + // Size Wanted width in pixels; a hint. + Size *int `form:"size,omitempty" json:"size,omitempty"` +} + +// GetDiscoveryPreviewParams defines parameters for GetDiscoveryPreview. +type GetDiscoveryPreviewParams struct { + Range *string `json:"Range,omitempty"` +} + +// GetDiscoveryFeedParams defines parameters for GetDiscoveryFeed. +type GetDiscoveryFeedParams struct { + // Cursor The previous page's `next`. + Cursor *string `form:"cursor,omitempty" json:"cursor,omitempty"` + + // Refresh Build the feed again now, for the first page. + Refresh *bool `form:"refresh,omitempty" json:"refresh,omitempty"` +} + // RenamePasskeyJSONBody defines parameters for RenamePasskey. type RenamePasskeyJSONBody struct { Name string `json:"name"` @@ -4668,6 +4911,21 @@ type UpdateMeJSONRequestBody = ProfileUpdate // DeleteMeJSONRequestBody defines body for DeleteMe for application/json ContentType. type DeleteMeJSONRequestBody = DeleteMeRequest +// BlockDiscoveryArtistJSONRequestBody defines body for BlockDiscoveryArtist for application/json ContentType. +type BlockDiscoveryArtistJSONRequestBody = BlockDiscoveryArtistRequest + +// PostDiscoveryFeedbackJSONRequestBody defines body for PostDiscoveryFeedback for application/json ContentType. +type PostDiscoveryFeedbackJSONRequestBody = DiscoveryFeedbackRequest + +// CreateDiscoverySetJSONRequestBody defines body for CreateDiscoverySet for application/json ContentType. +type CreateDiscoverySetJSONRequestBody = CreateDiscoverySetRequest + +// UpdateDiscoverySetJSONRequestBody defines body for UpdateDiscoverySet for application/json ContentType. +type UpdateDiscoverySetJSONRequestBody = UpdateDiscoverySetRequest + +// AddDiscoverySetArtistJSONRequestBody defines body for AddDiscoverySetArtist for application/json ContentType. +type AddDiscoverySetArtistJSONRequestBody = DiscoverySeed + // FinishAddPasskeyJSONRequestBody defines body for FinishAddPasskey for application/json ContentType. type FinishAddPasskeyJSONRequestBody = FinishCeremony @@ -4934,6 +5192,57 @@ type ServerInterface interface { // DeleteMe Delete your account // (POST /me/delete) DeleteMe(w http.ResponseWriter, r *http.Request) + // SearchDiscoveryArtists Find artists to seed a set with + // (GET /me/discover/artists) + SearchDiscoveryArtists(w http.ResponseWriter, r *http.Request, params SearchDiscoveryArtistsParams) + // ListDiscoveryBlocks Artists you said aren't for you + // (GET /me/discover/blocks) + ListDiscoveryBlocks(w http.ResponseWriter, r *http.Request) + // BlockDiscoveryArtist Not for me + // (POST /me/discover/blocks) + BlockDiscoveryArtist(w http.ResponseWriter, r *http.Request) + // UnblockDiscoveryArtist Let a blocked artist back into your feeds + // (DELETE /me/discover/blocks/{artistKey}) + UnblockDiscoveryArtist(w http.ResponseWriter, r *http.Request, artistKey string) + // PostDiscoveryFeedback Thumbs up or down on a song + // (POST /me/discover/feedback) + PostDiscoveryFeedback(w http.ResponseWriter, r *http.Request) + // GetDiscoveryImage A cover or artist picture from Deezer, through the server + // (GET /me/discover/images/{kind}/{imageId}) + GetDiscoveryImage(w http.ResponseWriter, r *http.Request, kind string, imageId string, params GetDiscoveryImageParams) + // GetDiscoveryLibrary How far your library is indexed + // (GET /me/discover/library) + GetDiscoveryLibrary(w http.ResponseWriter, r *http.Request) + // RefreshDiscoveryLibrary Index your library again now + // (POST /me/discover/library) + RefreshDiscoveryLibrary(w http.ResponseWriter, r *http.Request) + // GetDiscoveryPreview A song's 30-second preview + // (GET /me/discover/preview/{deezerTrackId}) + GetDiscoveryPreview(w http.ResponseWriter, r *http.Request, deezerTrackId int64, params GetDiscoveryPreviewParams) + // ListDiscoverySets Your discovery sets + // (GET /me/discover/sets) + ListDiscoverySets(w http.ResponseWriter, r *http.Request) + // CreateDiscoverySet Make a discovery set + // (POST /me/discover/sets) + CreateDiscoverySet(w http.ResponseWriter, r *http.Request) + // DeleteDiscoverySet Delete a discovery set + // (DELETE /me/discover/sets/{setId}) + DeleteDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) + // GetDiscoverySet A discovery set and its artists + // (GET /me/discover/sets/{setId}) + GetDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) + // UpdateDiscoverySet Rename a set, or change how far it explores and which feeds it shows + // (PATCH /me/discover/sets/{setId}) + UpdateDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) + // AddDiscoverySetArtist Add a seed artist to a set + // (POST /me/discover/sets/{setId}/artists) + AddDiscoverySetArtist(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) + // RemoveDiscoverySetArtist Take a seed artist out of a set + // (DELETE /me/discover/sets/{setId}/artists/{artistKey}) + RemoveDiscoverySetArtist(w http.ResponseWriter, r *http.Request, setId DiscoverySetId, artistKey string) + // GetDiscoveryFeed A page of a set's feed + // (GET /me/discover/sets/{setId}/feed) + GetDiscoveryFeed(w http.ResponseWriter, r *http.Request, setId DiscoverySetId, params GetDiscoveryFeedParams) // ListPasskeys Your passkeys // (GET /me/passkeys) ListPasskeys(w http.ResponseWriter, r *http.Request) @@ -6597,11 +6906,30 @@ func (siw *ServerInterfaceWrapper) DeleteMe(w http.ResponseWriter, r *http.Reque handler.ServeHTTP(w, r) } -// ListPasskeys operation middleware -func (siw *ServerInterfaceWrapper) ListPasskeys(w http.ResponseWriter, r *http.Request) { +// SearchDiscoveryArtists operation middleware +func (siw *ServerInterfaceWrapper) SearchDiscoveryArtists(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // Parameter object where we will unmarshal all parameters from the context + var params SearchDiscoveryArtistsParams + + // ------------- Required query parameter "q" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "q", r.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "q"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "q", Err: err}) + } + return + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListPasskeys(w, r) + siw.Handler.SearchDiscoveryArtists(w, r, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6611,11 +6939,11 @@ func (siw *ServerInterfaceWrapper) ListPasskeys(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// BeginAddPasskey operation middleware -func (siw *ServerInterfaceWrapper) BeginAddPasskey(w http.ResponseWriter, r *http.Request) { +// ListDiscoveryBlocks operation middleware +func (siw *ServerInterfaceWrapper) ListDiscoveryBlocks(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.BeginAddPasskey(w, r) + siw.Handler.ListDiscoveryBlocks(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6625,11 +6953,11 @@ func (siw *ServerInterfaceWrapper) BeginAddPasskey(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// FinishAddPasskey operation middleware -func (siw *ServerInterfaceWrapper) FinishAddPasskey(w http.ResponseWriter, r *http.Request) { +// BlockDiscoveryArtist operation middleware +func (siw *ServerInterfaceWrapper) BlockDiscoveryArtist(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FinishAddPasskey(w, r) + siw.Handler.BlockDiscoveryArtist(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6639,23 +6967,23 @@ func (siw *ServerInterfaceWrapper) FinishAddPasskey(w http.ResponseWriter, r *ht handler.ServeHTTP(w, r) } -// DeletePasskey operation middleware -func (siw *ServerInterfaceWrapper) DeletePasskey(w http.ResponseWriter, r *http.Request) { +// UnblockDiscoveryArtist operation middleware +func (siw *ServerInterfaceWrapper) UnblockDiscoveryArtist(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "artistKey" ------------- + var artistKey string - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "artistKey", r.PathValue("artistKey"), &artistKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "artistKey", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeletePasskey(w, r, id) + siw.Handler.UnblockDiscoveryArtist(w, r, artistKey) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6665,23 +6993,62 @@ func (siw *ServerInterfaceWrapper) DeletePasskey(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// RenamePasskey operation middleware -func (siw *ServerInterfaceWrapper) RenamePasskey(w http.ResponseWriter, r *http.Request) { +// PostDiscoveryFeedback operation middleware +func (siw *ServerInterfaceWrapper) PostDiscoveryFeedback(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.PostDiscoveryFeedback(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// GetDiscoveryImage operation middleware +func (siw *ServerInterfaceWrapper) GetDiscoveryImage(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "kind" ------------- + var kind string - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "kind", r.PathValue("kind"), &kind, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "kind", Err: err}) + return + } + + // ------------- Path parameter "imageId" ------------- + var imageId string + + err = runtime.BindStyledParameterWithOptions("simple", "imageId", r.PathValue("imageId"), &imageId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "imageId", Err: err}) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetDiscoveryImageParams + + // ------------- Optional query parameter "size" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RenamePasskey(w, r, id) + siw.Handler.GetDiscoveryImage(w, r, kind, imageId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6691,11 +7058,11 @@ func (siw *ServerInterfaceWrapper) RenamePasskey(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// DeletePassword operation middleware -func (siw *ServerInterfaceWrapper) DeletePassword(w http.ResponseWriter, r *http.Request) { +// GetDiscoveryLibrary operation middleware +func (siw *ServerInterfaceWrapper) GetDiscoveryLibrary(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeletePassword(w, r) + siw.Handler.GetDiscoveryLibrary(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6705,11 +7072,11 @@ func (siw *ServerInterfaceWrapper) DeletePassword(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// SetPassword operation middleware -func (siw *ServerInterfaceWrapper) SetPassword(w http.ResponseWriter, r *http.Request) { +// RefreshDiscoveryLibrary operation middleware +func (siw *ServerInterfaceWrapper) RefreshDiscoveryLibrary(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.SetPassword(w, r) + siw.Handler.RefreshDiscoveryLibrary(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6719,11 +7086,47 @@ func (siw *ServerInterfaceWrapper) SetPassword(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// BeginReauth operation middleware -func (siw *ServerInterfaceWrapper) BeginReauth(w http.ResponseWriter, r *http.Request) { +// GetDiscoveryPreview operation middleware +func (siw *ServerInterfaceWrapper) GetDiscoveryPreview(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // ------------- Path parameter "deezerTrackId" ------------- + var deezerTrackId int64 + + err = runtime.BindStyledParameterWithOptions("simple", "deezerTrackId", r.PathValue("deezerTrackId"), &deezerTrackId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deezerTrackId", Err: err}) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetDiscoveryPreviewParams + + headers := r.Header + + // ------------- Optional header parameter "Range" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("Range")]; found { + var Range string + n := len(valueList) + if n != 1 { + siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "Range", Count: n}) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "Range", valueList[0], &Range, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "Range", Err: err}) + return + } + + params.Range = &Range + + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.BeginReauth(w, r) + siw.Handler.GetDiscoveryPreview(w, r, deezerTrackId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6733,11 +7136,11 @@ func (siw *ServerInterfaceWrapper) BeginReauth(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// RevokeOtherSessions operation middleware -func (siw *ServerInterfaceWrapper) RevokeOtherSessions(w http.ResponseWriter, r *http.Request) { +// ListDiscoverySets operation middleware +func (siw *ServerInterfaceWrapper) ListDiscoverySets(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RevokeOtherSessions(w, r) + siw.Handler.ListDiscoverySets(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6747,11 +7150,11 @@ func (siw *ServerInterfaceWrapper) RevokeOtherSessions(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// ListMySessions operation middleware -func (siw *ServerInterfaceWrapper) ListMySessions(w http.ResponseWriter, r *http.Request) { +// CreateDiscoverySet operation middleware +func (siw *ServerInterfaceWrapper) CreateDiscoverySet(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListMySessions(w, r) + siw.Handler.CreateDiscoverySet(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6761,23 +7164,23 @@ func (siw *ServerInterfaceWrapper) ListMySessions(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// RevokeMySession operation middleware -func (siw *ServerInterfaceWrapper) RevokeMySession(w http.ResponseWriter, r *http.Request) { +// DeleteDiscoverySet operation middleware +func (siw *ServerInterfaceWrapper) DeleteDiscoverySet(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RevokeMySession(w, r, id) + siw.Handler.DeleteDiscoverySet(w, r, setId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6787,11 +7190,23 @@ func (siw *ServerInterfaceWrapper) RevokeMySession(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// BeginPairing operation middleware -func (siw *ServerInterfaceWrapper) BeginPairing(w http.ResponseWriter, r *http.Request) { +// GetDiscoverySet operation middleware +func (siw *ServerInterfaceWrapper) GetDiscoverySet(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId + + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) + return + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.BeginPairing(w, r) + siw.Handler.GetDiscoverySet(w, r, setId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6801,23 +7216,23 @@ func (siw *ServerInterfaceWrapper) BeginPairing(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// PollPairing operation middleware -func (siw *ServerInterfaceWrapper) PollPairing(w http.ResponseWriter, r *http.Request) { +// UpdateDiscoverySet operation middleware +func (siw *ServerInterfaceWrapper) UpdateDiscoverySet(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.PollPairing(w, r, id) + siw.Handler.UpdateDiscoverySet(w, r, setId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6827,25 +7242,23 @@ func (siw *ServerInterfaceWrapper) PollPairing(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// ListSavedPlaylists operation middleware -func (siw *ServerInterfaceWrapper) ListSavedPlaylists(w http.ResponseWriter, r *http.Request) { +// AddDiscoverySetArtist operation middleware +func (siw *ServerInterfaceWrapper) AddDiscoverySetArtist(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListSavedPlaylists(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } + var err error + _ = err - handler.ServeHTTP(w, r) -} + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId -// CreateSavedPlaylist operation middleware -func (siw *ServerInterfaceWrapper) CreateSavedPlaylist(w http.ResponseWriter, r *http.Request) { + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) + return + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CreateSavedPlaylist(w, r) + siw.Handler.AddDiscoverySetArtist(w, r, setId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6855,23 +7268,32 @@ func (siw *ServerInterfaceWrapper) CreateSavedPlaylist(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// DeleteSavedPlaylist operation middleware -func (siw *ServerInterfaceWrapper) DeleteSavedPlaylist(w http.ResponseWriter, r *http.Request) { +// RemoveDiscoverySetArtist operation middleware +func (siw *ServerInterfaceWrapper) RemoveDiscoverySetArtist(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) + return + } + + // ------------- Path parameter "artistKey" ------------- + var artistKey string + + err = runtime.BindStyledParameterWithOptions("simple", "artistKey", r.PathValue("artistKey"), &artistKey, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "artistKey", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeleteSavedPlaylist(w, r, playlistId) + siw.Handler.RemoveDiscoverySetArtist(w, r, setId, artistKey) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6881,49 +7303,52 @@ func (siw *ServerInterfaceWrapper) DeleteSavedPlaylist(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// GetSavedPlaylist operation middleware -func (siw *ServerInterfaceWrapper) GetSavedPlaylist(w http.ResponseWriter, r *http.Request) { +// GetDiscoveryFeed operation middleware +func (siw *ServerInterfaceWrapper) GetDiscoveryFeed(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId + // ------------- Path parameter "setId" ------------- + var setId DiscoverySetId - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "setId", r.PathValue("setId"), &setId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setId", Err: err}) return } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetSavedPlaylist(w, r, playlistId) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} + // Parameter object where we will unmarshal all parameters from the context + var params GetDiscoveryFeedParams -// UpdateSavedPlaylist operation middleware -func (siw *ServerInterfaceWrapper) UpdateSavedPlaylist(w http.ResponseWriter, r *http.Request) { + // ------------- Optional query parameter "cursor" ------------- - var err error - _ = err + err = runtime.BindQueryParameterWithOptions("form", true, false, "cursor", r.URL.Query(), ¶ms.Cursor, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "cursor"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "cursor", Err: err}) + } + return + } - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId + // ------------- Optional query parameter "refresh" ------------- - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "refresh", r.URL.Query(), ¶ms.Refresh, runtime.BindQueryParameterOptions{Type: "boolean", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "refresh"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "refresh", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UpdateSavedPlaylist(w, r, playlistId) + siw.Handler.GetDiscoveryFeed(w, r, setId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6933,23 +7358,11 @@ func (siw *ServerInterfaceWrapper) UpdateSavedPlaylist(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// AddSavedPlaylistSongs operation middleware -func (siw *ServerInterfaceWrapper) AddSavedPlaylistSongs(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId - - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) - return - } +// ListPasskeys operation middleware +func (siw *ServerInterfaceWrapper) ListPasskeys(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddSavedPlaylistSongs(w, r, playlistId) + siw.Handler.ListPasskeys(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6959,32 +7372,25 @@ func (siw *ServerInterfaceWrapper) AddSavedPlaylistSongs(w http.ResponseWriter, handler.ServeHTTP(w, r) } -// RemoveSavedPlaylistSong operation middleware -func (siw *ServerInterfaceWrapper) RemoveSavedPlaylistSong(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err +// BeginAddPasskey operation middleware +func (siw *ServerInterfaceWrapper) BeginAddPasskey(w http.ResponseWriter, r *http.Request) { - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.BeginAddPasskey(w, r) + })) - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // ------------- Path parameter "songId" ------------- - var songId PlaylistSongId + handler.ServeHTTP(w, r) +} - err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) - return - } +// FinishAddPasskey operation middleware +func (siw *ServerInterfaceWrapper) FinishAddPasskey(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RemoveSavedPlaylistSong(w, r, playlistId, songId) + siw.Handler.FinishAddPasskey(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -6994,48 +7400,23 @@ func (siw *ServerInterfaceWrapper) RemoveSavedPlaylistSong(w http.ResponseWriter handler.ServeHTTP(w, r) } -// GetSavedPlaylistSongArtwork operation middleware -func (siw *ServerInterfaceWrapper) GetSavedPlaylistSongArtwork(w http.ResponseWriter, r *http.Request) { +// DeletePasskey operation middleware +func (siw *ServerInterfaceWrapper) DeletePasskey(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId - - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) - return - } - - // ------------- Path parameter "songId" ------------- - var songId PlaylistSongId - - err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) - return - } - - // Parameter object where we will unmarshal all parameters from the context - var params GetSavedPlaylistSongArtworkParams - - // ------------- Optional query parameter "size" ------------- + // ------------- Path parameter "id" ------------- + var id string - err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetSavedPlaylistSongArtwork(w, r, playlistId, songId, params) + siw.Handler.DeletePasskey(w, r, id) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7045,32 +7426,37 @@ func (siw *ServerInterfaceWrapper) GetSavedPlaylistSongArtwork(w http.ResponseWr handler.ServeHTTP(w, r) } -// MoveSavedPlaylistSong operation middleware -func (siw *ServerInterfaceWrapper) MoveSavedPlaylistSong(w http.ResponseWriter, r *http.Request) { +// RenamePasskey operation middleware +func (siw *ServerInterfaceWrapper) RenamePasskey(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "playlistId" ------------- - var playlistId PlaylistId + // ------------- Path parameter "id" ------------- + var id string - err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) return } - // ------------- Path parameter "songId" ------------- - var songId PlaylistSongId + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RenamePasskey(w, r, id) + })) - err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } + handler.ServeHTTP(w, r) +} + +// DeletePassword operation middleware +func (siw *ServerInterfaceWrapper) DeletePassword(w http.ResponseWriter, r *http.Request) { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.MoveSavedPlaylistSong(w, r, playlistId, songId) + siw.Handler.DeletePassword(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7080,11 +7466,11 @@ func (siw *ServerInterfaceWrapper) MoveSavedPlaylistSong(w http.ResponseWriter, handler.ServeHTTP(w, r) } -// ListProviders operation middleware -func (siw *ServerInterfaceWrapper) ListProviders(w http.ResponseWriter, r *http.Request) { +// SetPassword operation middleware +func (siw *ServerInterfaceWrapper) SetPassword(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListProviders(w, r) + siw.Handler.SetPassword(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7094,30 +7480,25 @@ func (siw *ServerInterfaceWrapper) ListProviders(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// GetRandomTracks operation middleware -func (siw *ServerInterfaceWrapper) GetRandomTracks(w http.ResponseWriter, r *http.Request) { +// BeginReauth operation middleware +func (siw *ServerInterfaceWrapper) BeginReauth(w http.ResponseWriter, r *http.Request) { - var err error - _ = err + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.BeginReauth(w, r) + })) - // Parameter object where we will unmarshal all parameters from the context - var params GetRandomTracksParams + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } - // ------------- Optional query parameter "limit" ------------- + handler.ServeHTTP(w, r) +} - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } - return - } +// RevokeOtherSessions operation middleware +func (siw *ServerInterfaceWrapper) RevokeOtherSessions(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRandomTracks(w, r, params) + siw.Handler.RevokeOtherSessions(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7127,11 +7508,11 @@ func (siw *ServerInterfaceWrapper) GetRandomTracks(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// ListResetLinks operation middleware -func (siw *ServerInterfaceWrapper) ListResetLinks(w http.ResponseWriter, r *http.Request) { +// ListMySessions operation middleware +func (siw *ServerInterfaceWrapper) ListMySessions(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListResetLinks(w, r) + siw.Handler.ListMySessions(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7141,23 +7522,23 @@ func (siw *ServerInterfaceWrapper) ListResetLinks(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// GetResetLink operation middleware -func (siw *ServerInterfaceWrapper) GetResetLink(w http.ResponseWriter, r *http.Request) { +// RevokeMySession operation middleware +func (siw *ServerInterfaceWrapper) RevokeMySession(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "code" ------------- - var code ResetCode + // ------------- Path parameter "id" ------------- + var id string - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetResetLink(w, r, code) + siw.Handler.RevokeMySession(w, r, id) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7167,23 +7548,11 @@ func (siw *ServerInterfaceWrapper) GetResetLink(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// BeginResetPasskey operation middleware -func (siw *ServerInterfaceWrapper) BeginResetPasskey(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "code" ------------- - var code ResetCode - - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) - return - } +// BeginPairing operation middleware +func (siw *ServerInterfaceWrapper) BeginPairing(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.BeginResetPasskey(w, r, code) + siw.Handler.BeginPairing(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7193,23 +7562,23 @@ func (siw *ServerInterfaceWrapper) BeginResetPasskey(w http.ResponseWriter, r *h handler.ServeHTTP(w, r) } -// FinishResetPasskey operation middleware -func (siw *ServerInterfaceWrapper) FinishResetPasskey(w http.ResponseWriter, r *http.Request) { +// PollPairing operation middleware +func (siw *ServerInterfaceWrapper) PollPairing(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "code" ------------- - var code ResetCode + // ------------- Path parameter "id" ------------- + var id string - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.FinishResetPasskey(w, r, code) + siw.Handler.PollPairing(w, r, id) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7219,23 +7588,11 @@ func (siw *ServerInterfaceWrapper) FinishResetPasskey(w http.ResponseWriter, r * handler.ServeHTTP(w, r) } -// ResetPassword operation middleware -func (siw *ServerInterfaceWrapper) ResetPassword(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "code" ------------- - var code ResetCode - - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) - return - } +// ListSavedPlaylists operation middleware +func (siw *ServerInterfaceWrapper) ListSavedPlaylists(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ResetPassword(w, r, code) + siw.Handler.ListSavedPlaylists(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7245,23 +7602,11 @@ func (siw *ServerInterfaceWrapper) ResetPassword(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// GetRoomInvite operation middleware -func (siw *ServerInterfaceWrapper) GetRoomInvite(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "code" ------------- - var code string - - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) - return - } +// CreateSavedPlaylist operation middleware +func (siw *ServerInterfaceWrapper) CreateSavedPlaylist(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRoomInvite(w, r, code) + siw.Handler.CreateSavedPlaylist(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7271,51 +7616,23 @@ func (siw *ServerInterfaceWrapper) GetRoomInvite(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// UseRoomInvite operation middleware -func (siw *ServerInterfaceWrapper) UseRoomInvite(w http.ResponseWriter, r *http.Request) { +// DeleteSavedPlaylist operation middleware +func (siw *ServerInterfaceWrapper) DeleteSavedPlaylist(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "code" ------------- - var code string + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UseRoomInvite(w, r, code) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// ListRooms operation middleware -func (siw *ServerInterfaceWrapper) ListRooms(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListRooms(w, r) - })) - - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) - } - - handler.ServeHTTP(w, r) -} - -// CreateRoom operation middleware -func (siw *ServerInterfaceWrapper) CreateRoom(w http.ResponseWriter, r *http.Request) { - - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CreateRoom(w, r) + siw.Handler.DeleteSavedPlaylist(w, r, playlistId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7325,23 +7642,23 @@ func (siw *ServerInterfaceWrapper) CreateRoom(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// DeleteRoom operation middleware -func (siw *ServerInterfaceWrapper) DeleteRoom(w http.ResponseWriter, r *http.Request) { +// GetSavedPlaylist operation middleware +func (siw *ServerInterfaceWrapper) GetSavedPlaylist(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.DeleteRoom(w, r, roomId) + siw.Handler.GetSavedPlaylist(w, r, playlistId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7351,23 +7668,23 @@ func (siw *ServerInterfaceWrapper) DeleteRoom(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// GetRoom operation middleware -func (siw *ServerInterfaceWrapper) GetRoom(w http.ResponseWriter, r *http.Request) { +// UpdateSavedPlaylist operation middleware +func (siw *ServerInterfaceWrapper) UpdateSavedPlaylist(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRoom(w, r, roomId) + siw.Handler.UpdateSavedPlaylist(w, r, playlistId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7377,23 +7694,23 @@ func (siw *ServerInterfaceWrapper) GetRoom(w http.ResponseWriter, r *http.Reques handler.ServeHTTP(w, r) } -// UpdateRoom operation middleware -func (siw *ServerInterfaceWrapper) UpdateRoom(w http.ResponseWriter, r *http.Request) { +// AddSavedPlaylistSongs operation middleware +func (siw *ServerInterfaceWrapper) AddSavedPlaylistSongs(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UpdateRoom(w, r, roomId) + siw.Handler.AddSavedPlaylistSongs(w, r, playlistId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7403,23 +7720,32 @@ func (siw *ServerInterfaceWrapper) UpdateRoom(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// JoinRoomAsAdmin operation middleware -func (siw *ServerInterfaceWrapper) JoinRoomAsAdmin(w http.ResponseWriter, r *http.Request) { +// RemoveSavedPlaylistSong operation middleware +func (siw *ServerInterfaceWrapper) RemoveSavedPlaylistSong(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + return + } + + // ------------- Path parameter "songId" ------------- + var songId PlaylistSongId + + err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.JoinRoomAsAdmin(w, r, roomId) + siw.Handler.RemoveSavedPlaylistSong(w, r, playlistId, songId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7429,52 +7755,48 @@ func (siw *ServerInterfaceWrapper) JoinRoomAsAdmin(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// GetRoomArtistPlays operation middleware -func (siw *ServerInterfaceWrapper) GetRoomArtistPlays(w http.ResponseWriter, r *http.Request) { +// GetSavedPlaylistSongArtwork operation middleware +func (siw *ServerInterfaceWrapper) GetSavedPlaylistSongArtwork(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) return } - // Parameter object where we will unmarshal all parameters from the context - var params GetRoomArtistPlaysParams - - // ------------- Required query parameter "name" ------------- + // ------------- Path parameter "songId" ------------- + var songId PlaylistSongId - err = runtime.BindQueryParameterWithOptions("form", true, true, "name", r.URL.Query(), ¶ms.Name, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "name"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) return } - // ------------- Optional query parameter "limit" ------------- + // Parameter object where we will unmarshal all parameters from the context + var params GetSavedPlaylistSongArtworkParams - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + // ------------- Optional query parameter "size" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { var requiredError *runtime.RequiredParameterError if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRoomArtistPlays(w, r, roomId, params) + siw.Handler.GetSavedPlaylistSongArtwork(w, r, playlistId, songId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7484,23 +7806,32 @@ func (siw *ServerInterfaceWrapper) GetRoomArtistPlays(w http.ResponseWriter, r * handler.ServeHTTP(w, r) } -// ListDisplays operation middleware -func (siw *ServerInterfaceWrapper) ListDisplays(w http.ResponseWriter, r *http.Request) { +// MoveSavedPlaylistSong operation middleware +func (siw *ServerInterfaceWrapper) MoveSavedPlaylistSong(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "playlistId" ------------- + var playlistId PlaylistId - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "playlistId", r.PathValue("playlistId"), &playlistId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "playlistId", Err: err}) + return + } + + // ------------- Path parameter "songId" ------------- + var songId PlaylistSongId + + err = runtime.BindStyledParameterWithOptions("simple", "songId", r.PathValue("songId"), &songId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "songId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListDisplays(w, r, roomId) + siw.Handler.MoveSavedPlaylistSong(w, r, playlistId, songId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7510,23 +7841,11 @@ func (siw *ServerInterfaceWrapper) ListDisplays(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// PairDisplay operation middleware -func (siw *ServerInterfaceWrapper) PairDisplay(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } +// ListProviders operation middleware +func (siw *ServerInterfaceWrapper) ListProviders(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.PairDisplay(w, r, roomId) + siw.Handler.ListProviders(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7536,32 +7855,30 @@ func (siw *ServerInterfaceWrapper) PairDisplay(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// LookupDisplayPairing operation middleware -func (siw *ServerInterfaceWrapper) LookupDisplayPairing(w http.ResponseWriter, r *http.Request) { +// GetRandomTracks operation middleware +func (siw *ServerInterfaceWrapper) GetRandomTracks(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } + // Parameter object where we will unmarshal all parameters from the context + var params GetRandomTracksParams - // ------------- Path parameter "code" ------------- - var code string + // ------------- Optional query parameter "limit" ------------- - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.LookupDisplayPairing(w, r, roomId, code) + siw.Handler.GetRandomTracks(w, r, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7571,32 +7888,11 @@ func (siw *ServerInterfaceWrapper) LookupDisplayPairing(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// UnpairDisplay operation middleware -func (siw *ServerInterfaceWrapper) UnpairDisplay(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } - - // ------------- Path parameter "displayId" ------------- - var displayId string - - err = runtime.BindStyledParameterWithOptions("simple", "displayId", r.PathValue("displayId"), &displayId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "displayId", Err: err}) - return - } +// ListResetLinks operation middleware +func (siw *ServerInterfaceWrapper) ListResetLinks(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UnpairDisplay(w, r, roomId, displayId) + siw.Handler.ListResetLinks(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7606,32 +7902,23 @@ func (siw *ServerInterfaceWrapper) UnpairDisplay(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// UpdateDisplay operation middleware -func (siw *ServerInterfaceWrapper) UpdateDisplay(w http.ResponseWriter, r *http.Request) { +// GetResetLink operation middleware +func (siw *ServerInterfaceWrapper) GetResetLink(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } - - // ------------- Path parameter "displayId" ------------- - var displayId string + // ------------- Path parameter "code" ------------- + var code ResetCode - err = runtime.BindStyledParameterWithOptions("simple", "displayId", r.PathValue("displayId"), &displayId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "displayId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UpdateDisplay(w, r, roomId, displayId) + siw.Handler.GetResetLink(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7641,32 +7928,23 @@ func (siw *ServerInterfaceWrapper) UpdateDisplay(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// GetGameClip operation middleware -func (siw *ServerInterfaceWrapper) GetGameClip(w http.ResponseWriter, r *http.Request) { +// BeginResetPasskey operation middleware +func (siw *ServerInterfaceWrapper) BeginResetPasskey(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } - - // ------------- Path parameter "clipId" ------------- - var clipId string + // ------------- Path parameter "code" ------------- + var code ResetCode - err = runtime.BindStyledParameterWithOptions("simple", "clipId", r.PathValue("clipId"), &clipId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "clipId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetGameClip(w, r, roomId, clipId) + siw.Handler.BeginResetPasskey(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7676,23 +7954,23 @@ func (siw *ServerInterfaceWrapper) GetGameClip(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// GetQueueGames operation middleware -func (siw *ServerInterfaceWrapper) GetQueueGames(w http.ResponseWriter, r *http.Request) { +// FinishResetPasskey operation middleware +func (siw *ServerInterfaceWrapper) FinishResetPasskey(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "code" ------------- + var code ResetCode - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueGames(w, r, roomId) + siw.Handler.FinishResetPasskey(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7702,23 +7980,23 @@ func (siw *ServerInterfaceWrapper) GetQueueGames(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// StartQueueGame operation middleware -func (siw *ServerInterfaceWrapper) StartQueueGame(w http.ResponseWriter, r *http.Request) { +// ResetPassword operation middleware +func (siw *ServerInterfaceWrapper) ResetPassword(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId + // ------------- Path parameter "code" ------------- + var code ResetCode - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.StartQueueGame(w, r, roomId) + siw.Handler.ResetPassword(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7728,32 +8006,23 @@ func (siw *ServerInterfaceWrapper) StartQueueGame(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// CloseQueueGame operation middleware -func (siw *ServerInterfaceWrapper) CloseQueueGame(w http.ResponseWriter, r *http.Request) { +// GetRoomInvite operation middleware +func (siw *ServerInterfaceWrapper) GetRoomInvite(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } - - // ------------- Path parameter "gameId" ------------- - var gameId QueueGameId + // ------------- Path parameter "code" ------------- + var code string - err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CloseQueueGame(w, r, roomId, gameId) + siw.Handler.GetRoomInvite(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7763,32 +8032,23 @@ func (siw *ServerInterfaceWrapper) CloseQueueGame(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// EnterQueueGame operation middleware -func (siw *ServerInterfaceWrapper) EnterQueueGame(w http.ResponseWriter, r *http.Request) { +// UseRoomInvite operation middleware +func (siw *ServerInterfaceWrapper) UseRoomInvite(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } - - // ------------- Path parameter "gameId" ------------- - var gameId QueueGameId + // ------------- Path parameter "code" ------------- + var code string - err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.EnterQueueGame(w, r, roomId, gameId) + siw.Handler.UseRoomInvite(w, r, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7798,41 +8058,25 @@ func (siw *ServerInterfaceWrapper) EnterQueueGame(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// WithdrawQueueGameEntry operation middleware -func (siw *ServerInterfaceWrapper) WithdrawQueueGameEntry(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err - - // ------------- Path parameter "roomId" ------------- - var roomId RoomId - - err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) - return - } +// ListRooms operation middleware +func (siw *ServerInterfaceWrapper) ListRooms(w http.ResponseWriter, r *http.Request) { - // ------------- Path parameter "gameId" ------------- - var gameId QueueGameId + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListRooms(w, r) + })) - err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // ------------- Path parameter "itemId" ------------- - var itemId string + handler.ServeHTTP(w, r) +} - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } +// CreateRoom operation middleware +func (siw *ServerInterfaceWrapper) CreateRoom(w http.ResponseWriter, r *http.Request) { handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.WithdrawQueueGameEntry(w, r, roomId, gameId, itemId) + siw.Handler.CreateRoom(w, r) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7842,8 +8086,8 @@ func (siw *ServerInterfaceWrapper) WithdrawQueueGameEntry(w http.ResponseWriter, handler.ServeHTTP(w, r) } -// HintQueueGame operation middleware -func (siw *ServerInterfaceWrapper) HintQueueGame(w http.ResponseWriter, r *http.Request) { +// DeleteRoom operation middleware +func (siw *ServerInterfaceWrapper) DeleteRoom(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -7857,17 +8101,8 @@ func (siw *ServerInterfaceWrapper) HintQueueGame(w http.ResponseWriter, r *http. return } - // ------------- Path parameter "gameId" ------------- - var gameId QueueGameId - - err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.HintQueueGame(w, r, roomId, gameId) + siw.Handler.DeleteRoom(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7877,8 +8112,8 @@ func (siw *ServerInterfaceWrapper) HintQueueGame(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// GetGameRound operation middleware -func (siw *ServerInterfaceWrapper) GetGameRound(w http.ResponseWriter, r *http.Request) { +// GetRoom operation middleware +func (siw *ServerInterfaceWrapper) GetRoom(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -7893,7 +8128,7 @@ func (siw *ServerInterfaceWrapper) GetGameRound(w http.ResponseWriter, r *http.R } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetGameRound(w, r, roomId) + siw.Handler.GetRoom(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7903,8 +8138,8 @@ func (siw *ServerInterfaceWrapper) GetGameRound(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// StartGameRound operation middleware -func (siw *ServerInterfaceWrapper) StartGameRound(w http.ResponseWriter, r *http.Request) { +// UpdateRoom operation middleware +func (siw *ServerInterfaceWrapper) UpdateRoom(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -7919,7 +8154,7 @@ func (siw *ServerInterfaceWrapper) StartGameRound(w http.ResponseWriter, r *http } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.StartGameRound(w, r, roomId) + siw.Handler.UpdateRoom(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7929,8 +8164,8 @@ func (siw *ServerInterfaceWrapper) StartGameRound(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// AnswerGameRound operation middleware -func (siw *ServerInterfaceWrapper) AnswerGameRound(w http.ResponseWriter, r *http.Request) { +// JoinRoomAsAdmin operation middleware +func (siw *ServerInterfaceWrapper) JoinRoomAsAdmin(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -7944,17 +8179,8 @@ func (siw *ServerInterfaceWrapper) AnswerGameRound(w http.ResponseWriter, r *htt return } - // ------------- Path parameter "roundId" ------------- - var roundId string - - err = runtime.BindStyledParameterWithOptions("simple", "roundId", r.PathValue("roundId"), &roundId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roundId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AnswerGameRound(w, r, roomId, roundId) + siw.Handler.JoinRoomAsAdmin(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -7964,8 +8190,8 @@ func (siw *ServerInterfaceWrapper) AnswerGameRound(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// GetGameRoundArtwork operation middleware -func (siw *ServerInterfaceWrapper) GetGameRoundArtwork(w http.ResponseWriter, r *http.Request) { +// GetRoomArtistPlays operation middleware +func (siw *ServerInterfaceWrapper) GetRoomArtistPlays(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -7979,33 +8205,37 @@ func (siw *ServerInterfaceWrapper) GetGameRoundArtwork(w http.ResponseWriter, r return } - // ------------- Path parameter "roundId" ------------- - var roundId string + // Parameter object where we will unmarshal all parameters from the context + var params GetRoomArtistPlaysParams - err = runtime.BindStyledParameterWithOptions("simple", "roundId", r.PathValue("roundId"), &roundId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + // ------------- Required query parameter "name" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "name", r.URL.Query(), ¶ms.Name, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roundId", Err: err}) + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "name"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err}) + } return } - // Parameter object where we will unmarshal all parameters from the context - var params GetGameRoundArtworkParams - - // ------------- Optional query parameter "size" ------------- + // ------------- Optional query parameter "limit" ------------- - err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { var requiredError *runtime.RequiredParameterError if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetGameRoundArtwork(w, r, roomId, roundId, params) + siw.Handler.GetRoomArtistPlays(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8015,8 +8245,8 @@ func (siw *ServerInterfaceWrapper) GetGameRoundArtwork(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// GetGameScores operation middleware -func (siw *ServerInterfaceWrapper) GetGameScores(w http.ResponseWriter, r *http.Request) { +// ListDisplays operation middleware +func (siw *ServerInterfaceWrapper) ListDisplays(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8031,7 +8261,7 @@ func (siw *ServerInterfaceWrapper) GetGameScores(w http.ResponseWriter, r *http. } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetGameScores(w, r, roomId) + siw.Handler.ListDisplays(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8041,8 +8271,8 @@ func (siw *ServerInterfaceWrapper) GetGameScores(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// RevokeGuestPass operation middleware -func (siw *ServerInterfaceWrapper) RevokeGuestPass(w http.ResponseWriter, r *http.Request) { +// PairDisplay operation middleware +func (siw *ServerInterfaceWrapper) PairDisplay(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8057,7 +8287,7 @@ func (siw *ServerInterfaceWrapper) RevokeGuestPass(w http.ResponseWriter, r *htt } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RevokeGuestPass(w, r, roomId) + siw.Handler.PairDisplay(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8067,8 +8297,8 @@ func (siw *ServerInterfaceWrapper) RevokeGuestPass(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// GetGuestPass operation middleware -func (siw *ServerInterfaceWrapper) GetGuestPass(w http.ResponseWriter, r *http.Request) { +// LookupDisplayPairing operation middleware +func (siw *ServerInterfaceWrapper) LookupDisplayPairing(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8082,8 +8312,17 @@ func (siw *ServerInterfaceWrapper) GetGuestPass(w http.ResponseWriter, r *http.R return } + // ------------- Path parameter "code" ------------- + var code string + + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetGuestPass(w, r, roomId) + siw.Handler.LookupDisplayPairing(w, r, roomId, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8093,8 +8332,8 @@ func (siw *ServerInterfaceWrapper) GetGuestPass(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// CreateGuestPass operation middleware -func (siw *ServerInterfaceWrapper) CreateGuestPass(w http.ResponseWriter, r *http.Request) { +// UnpairDisplay operation middleware +func (siw *ServerInterfaceWrapper) UnpairDisplay(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8108,8 +8347,17 @@ func (siw *ServerInterfaceWrapper) CreateGuestPass(w http.ResponseWriter, r *htt return } + // ------------- Path parameter "displayId" ------------- + var displayId string + + err = runtime.BindStyledParameterWithOptions("simple", "displayId", r.PathValue("displayId"), &displayId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "displayId", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CreateGuestPass(w, r, roomId) + siw.Handler.UnpairDisplay(w, r, roomId, displayId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8119,8 +8367,8 @@ func (siw *ServerInterfaceWrapper) CreateGuestPass(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// ListGuests operation middleware -func (siw *ServerInterfaceWrapper) ListGuests(w http.ResponseWriter, r *http.Request) { +// UpdateDisplay operation middleware +func (siw *ServerInterfaceWrapper) UpdateDisplay(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8134,8 +8382,17 @@ func (siw *ServerInterfaceWrapper) ListGuests(w http.ResponseWriter, r *http.Req return } + // ------------- Path parameter "displayId" ------------- + var displayId string + + err = runtime.BindStyledParameterWithOptions("simple", "displayId", r.PathValue("displayId"), &displayId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "displayId", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListGuests(w, r, roomId) + siw.Handler.UpdateDisplay(w, r, roomId, displayId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8145,8 +8402,8 @@ func (siw *ServerInterfaceWrapper) ListGuests(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// KickGuest operation middleware -func (siw *ServerInterfaceWrapper) KickGuest(w http.ResponseWriter, r *http.Request) { +// GetGameClip operation middleware +func (siw *ServerInterfaceWrapper) GetGameClip(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8160,17 +8417,17 @@ func (siw *ServerInterfaceWrapper) KickGuest(w http.ResponseWriter, r *http.Requ return } - // ------------- Path parameter "userId" ------------- - var userId string + // ------------- Path parameter "clipId" ------------- + var clipId string - err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "clipId", r.PathValue("clipId"), &clipId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "clipId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.KickGuest(w, r, roomId, userId) + siw.Handler.GetGameClip(w, r, roomId, clipId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8180,8 +8437,8 @@ func (siw *ServerInterfaceWrapper) KickGuest(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } -// GetHistory operation middleware -func (siw *ServerInterfaceWrapper) GetHistory(w http.ResponseWriter, r *http.Request) { +// GetQueueGames operation middleware +func (siw *ServerInterfaceWrapper) GetQueueGames(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8195,50 +8452,34 @@ func (siw *ServerInterfaceWrapper) GetHistory(w http.ResponseWriter, r *http.Req return } - // Parameter object where we will unmarshal all parameters from the context - var params GetHistoryParams - - // ------------- Optional query parameter "limit" ------------- + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetQueueGames(w, r, roomId) + })) - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // ------------- Optional query parameter "before" ------------- + handler.ServeHTTP(w, r) +} - err = runtime.BindQueryParameterWithOptions("form", true, false, "before", r.URL.Query(), ¶ms.Before, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "before"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "before", Err: err}) - } - return - } +// StartQueueGame operation middleware +func (siw *ServerInterfaceWrapper) StartQueueGame(w http.ResponseWriter, r *http.Request) { - // ------------- Optional query parameter "userId" ------------- + var err error + _ = err - err = runtime.BindQueryParameterWithOptions("form", true, false, "userId", r.URL.Query(), ¶ms.UserId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "userId"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetHistory(w, r, roomId, params) + siw.Handler.StartQueueGame(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8248,8 +8489,8 @@ func (siw *ServerInterfaceWrapper) GetHistory(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// ListRoomInvites operation middleware -func (siw *ServerInterfaceWrapper) ListRoomInvites(w http.ResponseWriter, r *http.Request) { +// CloseQueueGame operation middleware +func (siw *ServerInterfaceWrapper) CloseQueueGame(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8263,8 +8504,17 @@ func (siw *ServerInterfaceWrapper) ListRoomInvites(w http.ResponseWriter, r *htt return } + // ------------- Path parameter "gameId" ------------- + var gameId QueueGameId + + err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListRoomInvites(w, r, roomId) + siw.Handler.CloseQueueGame(w, r, roomId, gameId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8274,8 +8524,8 @@ func (siw *ServerInterfaceWrapper) ListRoomInvites(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// CreateRoomInvite operation middleware -func (siw *ServerInterfaceWrapper) CreateRoomInvite(w http.ResponseWriter, r *http.Request) { +// EnterQueueGame operation middleware +func (siw *ServerInterfaceWrapper) EnterQueueGame(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8289,8 +8539,17 @@ func (siw *ServerInterfaceWrapper) CreateRoomInvite(w http.ResponseWriter, r *ht return } + // ------------- Path parameter "gameId" ------------- + var gameId QueueGameId + + err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CreateRoomInvite(w, r, roomId) + siw.Handler.EnterQueueGame(w, r, roomId, gameId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8300,8 +8559,8 @@ func (siw *ServerInterfaceWrapper) CreateRoomInvite(w http.ResponseWriter, r *ht handler.ServeHTTP(w, r) } -// RevokeRoomInvite operation middleware -func (siw *ServerInterfaceWrapper) RevokeRoomInvite(w http.ResponseWriter, r *http.Request) { +// WithdrawQueueGameEntry operation middleware +func (siw *ServerInterfaceWrapper) WithdrawQueueGameEntry(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8315,17 +8574,26 @@ func (siw *ServerInterfaceWrapper) RevokeRoomInvite(w http.ResponseWriter, r *ht return } - // ------------- Path parameter "code" ------------- - var code string + // ------------- Path parameter "gameId" ------------- + var gameId QueueGameId - err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + return + } + + // ------------- Path parameter "itemId" ------------- + var itemId string + + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RevokeRoomInvite(w, r, roomId, code) + siw.Handler.WithdrawQueueGameEntry(w, r, roomId, gameId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8335,8 +8603,8 @@ func (siw *ServerInterfaceWrapper) RevokeRoomInvite(w http.ResponseWriter, r *ht handler.ServeHTTP(w, r) } -// ClearLane operation middleware -func (siw *ServerInterfaceWrapper) ClearLane(w http.ResponseWriter, r *http.Request) { +// HintQueueGame operation middleware +func (siw *ServerInterfaceWrapper) HintQueueGame(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8350,8 +8618,17 @@ func (siw *ServerInterfaceWrapper) ClearLane(w http.ResponseWriter, r *http.Requ return } + // ------------- Path parameter "gameId" ------------- + var gameId QueueGameId + + err = runtime.BindStyledParameterWithOptions("simple", "gameId", r.PathValue("gameId"), &gameId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "gameId", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ClearLane(w, r, roomId) + siw.Handler.HintQueueGame(w, r, roomId, gameId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8361,8 +8638,8 @@ func (siw *ServerInterfaceWrapper) ClearLane(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } -// ListRoomMembers operation middleware -func (siw *ServerInterfaceWrapper) ListRoomMembers(w http.ResponseWriter, r *http.Request) { +// GetGameRound operation middleware +func (siw *ServerInterfaceWrapper) GetGameRound(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8377,7 +8654,7 @@ func (siw *ServerInterfaceWrapper) ListRoomMembers(w http.ResponseWriter, r *htt } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListRoomMembers(w, r, roomId) + siw.Handler.GetGameRound(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8387,8 +8664,8 @@ func (siw *ServerInterfaceWrapper) ListRoomMembers(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// RemoveRoomMember operation middleware -func (siw *ServerInterfaceWrapper) RemoveRoomMember(w http.ResponseWriter, r *http.Request) { +// StartGameRound operation middleware +func (siw *ServerInterfaceWrapper) StartGameRound(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8402,17 +8679,8 @@ func (siw *ServerInterfaceWrapper) RemoveRoomMember(w http.ResponseWriter, r *ht return } - // ------------- Path parameter "userId" ------------- - var userId string - - err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RemoveRoomMember(w, r, roomId, userId) + siw.Handler.StartGameRound(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8422,8 +8690,8 @@ func (siw *ServerInterfaceWrapper) RemoveRoomMember(w http.ResponseWriter, r *ht handler.ServeHTTP(w, r) } -// AddRoomMember operation middleware -func (siw *ServerInterfaceWrapper) AddRoomMember(w http.ResponseWriter, r *http.Request) { +// AnswerGameRound operation middleware +func (siw *ServerInterfaceWrapper) AnswerGameRound(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8437,17 +8705,17 @@ func (siw *ServerInterfaceWrapper) AddRoomMember(w http.ResponseWriter, r *http. return } - // ------------- Path parameter "userId" ------------- - var userId string + // ------------- Path parameter "roundId" ------------- + var roundId string - err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "roundId", r.PathValue("roundId"), &roundId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roundId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddRoomMember(w, r, roomId, userId) + siw.Handler.AnswerGameRound(w, r, roomId, roundId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8457,8 +8725,8 @@ func (siw *ServerInterfaceWrapper) AddRoomMember(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// ListNights operation middleware -func (siw *ServerInterfaceWrapper) ListNights(w http.ResponseWriter, r *http.Request) { +// GetGameRoundArtwork operation middleware +func (siw *ServerInterfaceWrapper) GetGameRoundArtwork(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8472,24 +8740,33 @@ func (siw *ServerInterfaceWrapper) ListNights(w http.ResponseWriter, r *http.Req return } + // ------------- Path parameter "roundId" ------------- + var roundId string + + err = runtime.BindStyledParameterWithOptions("simple", "roundId", r.PathValue("roundId"), &roundId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roundId", Err: err}) + return + } + // Parameter object where we will unmarshal all parameters from the context - var params ListNightsParams + var params GetGameRoundArtworkParams - // ------------- Optional query parameter "limit" ------------- + // ------------- Optional query parameter "size" ------------- - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { var requiredError *runtime.RequiredParameterError if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListNights(w, r, roomId, params) + siw.Handler.GetGameRoundArtwork(w, r, roomId, roundId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8499,8 +8776,8 @@ func (siw *ServerInterfaceWrapper) ListNights(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// EndNight operation middleware -func (siw *ServerInterfaceWrapper) EndNight(w http.ResponseWriter, r *http.Request) { +// GetGameScores operation middleware +func (siw *ServerInterfaceWrapper) GetGameScores(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8515,7 +8792,7 @@ func (siw *ServerInterfaceWrapper) EndNight(w http.ResponseWriter, r *http.Reque } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.EndNight(w, r, roomId) + siw.Handler.GetGameScores(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8525,8 +8802,8 @@ func (siw *ServerInterfaceWrapper) EndNight(w http.ResponseWriter, r *http.Reque handler.ServeHTTP(w, r) } -// TransferRoom operation middleware -func (siw *ServerInterfaceWrapper) TransferRoom(w http.ResponseWriter, r *http.Request) { +// RevokeGuestPass operation middleware +func (siw *ServerInterfaceWrapper) RevokeGuestPass(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8541,7 +8818,7 @@ func (siw *ServerInterfaceWrapper) TransferRoom(w http.ResponseWriter, r *http.R } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.TransferRoom(w, r, roomId) + siw.Handler.RevokeGuestPass(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8551,8 +8828,8 @@ func (siw *ServerInterfaceWrapper) TransferRoom(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// GetPlayback operation middleware -func (siw *ServerInterfaceWrapper) GetPlayback(w http.ResponseWriter, r *http.Request) { +// GetGuestPass operation middleware +func (siw *ServerInterfaceWrapper) GetGuestPass(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8567,7 +8844,7 @@ func (siw *ServerInterfaceWrapper) GetPlayback(w http.ResponseWriter, r *http.Re } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetPlayback(w, r, roomId) + siw.Handler.GetGuestPass(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8577,8 +8854,8 @@ func (siw *ServerInterfaceWrapper) GetPlayback(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// ControlPlayback operation middleware -func (siw *ServerInterfaceWrapper) ControlPlayback(w http.ResponseWriter, r *http.Request) { +// CreateGuestPass operation middleware +func (siw *ServerInterfaceWrapper) CreateGuestPass(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8593,7 +8870,7 @@ func (siw *ServerInterfaceWrapper) ControlPlayback(w http.ResponseWriter, r *htt } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ControlPlayback(w, r, roomId) + siw.Handler.CreateGuestPass(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8603,8 +8880,8 @@ func (siw *ServerInterfaceWrapper) ControlPlayback(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// ReleasePlayer operation middleware -func (siw *ServerInterfaceWrapper) ReleasePlayer(w http.ResponseWriter, r *http.Request) { +// ListGuests operation middleware +func (siw *ServerInterfaceWrapper) ListGuests(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8618,24 +8895,43 @@ func (siw *ServerInterfaceWrapper) ReleasePlayer(w http.ResponseWriter, r *http. return } - // Parameter object where we will unmarshal all parameters from the context - var params ReleasePlayerParams + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListGuests(w, r, roomId) + })) - // ------------- Required query parameter "deviceId" ------------- + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } - err = runtime.BindQueryParameterWithOptions("form", true, true, "deviceId", r.URL.Query(), ¶ms.DeviceId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + handler.ServeHTTP(w, r) +} + +// KickGuest operation middleware +func (siw *ServerInterfaceWrapper) KickGuest(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "deviceId"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deviceId", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } + + // ------------- Path parameter "userId" ------------- + var userId string + + err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ReleasePlayer(w, r, roomId, params) + siw.Handler.KickGuest(w, r, roomId, userId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8645,8 +8941,8 @@ func (siw *ServerInterfaceWrapper) ReleasePlayer(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// ClaimPlayer operation middleware -func (siw *ServerInterfaceWrapper) ClaimPlayer(w http.ResponseWriter, r *http.Request) { +// GetHistory operation middleware +func (siw *ServerInterfaceWrapper) GetHistory(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8660,8 +8956,50 @@ func (siw *ServerInterfaceWrapper) ClaimPlayer(w http.ResponseWriter, r *http.Re return } + // Parameter object where we will unmarshal all parameters from the context + var params GetHistoryParams + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } + return + } + + // ------------- Optional query parameter "before" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "before", r.URL.Query(), ¶ms.Before, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "before"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "before", Err: err}) + } + return + } + + // ------------- Optional query parameter "userId" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "userId", r.URL.Query(), ¶ms.UserId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "userId"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) + } + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ClaimPlayer(w, r, roomId) + siw.Handler.GetHistory(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8671,8 +9009,8 @@ func (siw *ServerInterfaceWrapper) ClaimPlayer(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// ReportPlayback operation middleware -func (siw *ServerInterfaceWrapper) ReportPlayback(w http.ResponseWriter, r *http.Request) { +// ListRoomInvites operation middleware +func (siw *ServerInterfaceWrapper) ListRoomInvites(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8687,7 +9025,7 @@ func (siw *ServerInterfaceWrapper) ReportPlayback(w http.ResponseWriter, r *http } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ReportPlayback(w, r, roomId) + siw.Handler.ListRoomInvites(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8697,8 +9035,8 @@ func (siw *ServerInterfaceWrapper) ReportPlayback(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// SaveNightPlaylist operation middleware -func (siw *ServerInterfaceWrapper) SaveNightPlaylist(w http.ResponseWriter, r *http.Request) { +// CreateRoomInvite operation middleware +func (siw *ServerInterfaceWrapper) CreateRoomInvite(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8713,7 +9051,7 @@ func (siw *ServerInterfaceWrapper) SaveNightPlaylist(w http.ResponseWriter, r *h } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.SaveNightPlaylist(w, r, roomId) + siw.Handler.CreateRoomInvite(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8723,8 +9061,8 @@ func (siw *ServerInterfaceWrapper) SaveNightPlaylist(w http.ResponseWriter, r *h handler.ServeHTTP(w, r) } -// GetQueue operation middleware -func (siw *ServerInterfaceWrapper) GetQueue(w http.ResponseWriter, r *http.Request) { +// RevokeRoomInvite operation middleware +func (siw *ServerInterfaceWrapper) RevokeRoomInvite(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8738,8 +9076,17 @@ func (siw *ServerInterfaceWrapper) GetQueue(w http.ResponseWriter, r *http.Reque return } + // ------------- Path parameter "code" ------------- + var code string + + err = runtime.BindStyledParameterWithOptions("simple", "code", r.PathValue("code"), &code, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "code", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueue(w, r, roomId) + siw.Handler.RevokeRoomInvite(w, r, roomId, code) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8749,8 +9096,8 @@ func (siw *ServerInterfaceWrapper) GetQueue(w http.ResponseWriter, r *http.Reque handler.ServeHTTP(w, r) } -// AddToQueue operation middleware -func (siw *ServerInterfaceWrapper) AddToQueue(w http.ResponseWriter, r *http.Request) { +// ClearLane operation middleware +func (siw *ServerInterfaceWrapper) ClearLane(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8765,7 +9112,7 @@ func (siw *ServerInterfaceWrapper) AddToQueue(w http.ResponseWriter, r *http.Req } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.AddToQueue(w, r, roomId) + siw.Handler.ClearLane(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8775,8 +9122,8 @@ func (siw *ServerInterfaceWrapper) AddToQueue(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// RestoreQueueItems operation middleware -func (siw *ServerInterfaceWrapper) RestoreQueueItems(w http.ResponseWriter, r *http.Request) { +// ListRoomMembers operation middleware +func (siw *ServerInterfaceWrapper) ListRoomMembers(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8791,7 +9138,7 @@ func (siw *ServerInterfaceWrapper) RestoreQueueItems(w http.ResponseWriter, r *h } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RestoreQueueItems(w, r, roomId) + siw.Handler.ListRoomMembers(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8801,8 +9148,8 @@ func (siw *ServerInterfaceWrapper) RestoreQueueItems(w http.ResponseWriter, r *h handler.ServeHTTP(w, r) } -// RemoveQueueItem operation middleware -func (siw *ServerInterfaceWrapper) RemoveQueueItem(w http.ResponseWriter, r *http.Request) { +// RemoveRoomMember operation middleware +func (siw *ServerInterfaceWrapper) RemoveRoomMember(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8816,17 +9163,17 @@ func (siw *ServerInterfaceWrapper) RemoveQueueItem(w http.ResponseWriter, r *htt return } - // ------------- Path parameter "itemId" ------------- - var itemId string + // ------------- Path parameter "userId" ------------- + var userId string - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RemoveQueueItem(w, r, roomId, itemId) + siw.Handler.RemoveRoomMember(w, r, roomId, userId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8836,8 +9183,8 @@ func (siw *ServerInterfaceWrapper) RemoveQueueItem(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// MoveQueueItem operation middleware -func (siw *ServerInterfaceWrapper) MoveQueueItem(w http.ResponseWriter, r *http.Request) { +// AddRoomMember operation middleware +func (siw *ServerInterfaceWrapper) AddRoomMember(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8851,17 +9198,17 @@ func (siw *ServerInterfaceWrapper) MoveQueueItem(w http.ResponseWriter, r *http. return } - // ------------- Path parameter "itemId" ------------- - var itemId string + // ------------- Path parameter "userId" ------------- + var userId string - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "userId", r.PathValue("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.MoveQueueItem(w, r, roomId, itemId) + siw.Handler.AddRoomMember(w, r, roomId, userId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8871,8 +9218,8 @@ func (siw *ServerInterfaceWrapper) MoveQueueItem(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// GetQueueItemArtwork operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemArtwork(w http.ResponseWriter, r *http.Request) { +// ListNights operation middleware +func (siw *ServerInterfaceWrapper) ListNights(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8886,33 +9233,24 @@ func (siw *ServerInterfaceWrapper) GetQueueItemArtwork(w http.ResponseWriter, r return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - // Parameter object where we will unmarshal all parameters from the context - var params GetQueueItemArtworkParams + var params ListNightsParams - // ------------- Optional query parameter "size" ------------- + // ------------- Optional query parameter "limit" ------------- - err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { var requiredError *runtime.RequiredParameterError if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemArtwork(w, r, roomId, itemId, params) + siw.Handler.ListNights(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8922,8 +9260,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemArtwork(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// GetQueueItemBeatMap operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemBeatMap(w http.ResponseWriter, r *http.Request) { +// EndNight operation middleware +func (siw *ServerInterfaceWrapper) EndNight(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8937,17 +9275,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemBeatMap(w http.ResponseWriter, r return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemBeatMap(w, r, roomId, itemId) + siw.Handler.EndNight(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8957,8 +9286,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemBeatMap(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// UnheartSong operation middleware -func (siw *ServerInterfaceWrapper) UnheartSong(w http.ResponseWriter, r *http.Request) { +// TransferRoom operation middleware +func (siw *ServerInterfaceWrapper) TransferRoom(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -8972,17 +9301,8 @@ func (siw *ServerInterfaceWrapper) UnheartSong(w http.ResponseWriter, r *http.Re return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UnheartSong(w, r, roomId, itemId) + siw.Handler.TransferRoom(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -8992,8 +9312,8 @@ func (siw *ServerInterfaceWrapper) UnheartSong(w http.ResponseWriter, r *http.Re handler.ServeHTTP(w, r) } -// GetHearts operation middleware -func (siw *ServerInterfaceWrapper) GetHearts(w http.ResponseWriter, r *http.Request) { +// GetPlayback operation middleware +func (siw *ServerInterfaceWrapper) GetPlayback(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9007,17 +9327,8 @@ func (siw *ServerInterfaceWrapper) GetHearts(w http.ResponseWriter, r *http.Requ return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetHearts(w, r, roomId, itemId) + siw.Handler.GetPlayback(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9027,8 +9338,8 @@ func (siw *ServerInterfaceWrapper) GetHearts(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } -// HeartSong operation middleware -func (siw *ServerInterfaceWrapper) HeartSong(w http.ResponseWriter, r *http.Request) { +// ControlPlayback operation middleware +func (siw *ServerInterfaceWrapper) ControlPlayback(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9042,17 +9353,8 @@ func (siw *ServerInterfaceWrapper) HeartSong(w http.ResponseWriter, r *http.Requ return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.HeartSong(w, r, roomId, itemId) + siw.Handler.ControlPlayback(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9062,8 +9364,8 @@ func (siw *ServerInterfaceWrapper) HeartSong(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } -// GetQueueItemLinerNotes operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemLinerNotes(w http.ResponseWriter, r *http.Request) { +// ReleasePlayer operation middleware +func (siw *ServerInterfaceWrapper) ReleasePlayer(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9077,17 +9379,24 @@ func (siw *ServerInterfaceWrapper) GetQueueItemLinerNotes(w http.ResponseWriter, return } - // ------------- Path parameter "itemId" ------------- - var itemId string + // Parameter object where we will unmarshal all parameters from the context + var params ReleasePlayerParams - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + // ------------- Required query parameter "deviceId" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "deviceId", r.URL.Query(), ¶ms.DeviceId, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "deviceId"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deviceId", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemLinerNotes(w, r, roomId, itemId) + siw.Handler.ReleasePlayer(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9097,8 +9406,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemLinerNotes(w http.ResponseWriter, handler.ServeHTTP(w, r) } -// GetQueueItemLyrics operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemLyrics(w http.ResponseWriter, r *http.Request) { +// ClaimPlayer operation middleware +func (siw *ServerInterfaceWrapper) ClaimPlayer(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9112,17 +9421,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemLyrics(w http.ResponseWriter, r * return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemLyrics(w, r, roomId, itemId) + siw.Handler.ClaimPlayer(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9132,8 +9432,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemLyrics(w http.ResponseWriter, r * handler.ServeHTTP(w, r) } -// GetQueueItemPalette operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemPalette(w http.ResponseWriter, r *http.Request) { +// ReportPlayback operation middleware +func (siw *ServerInterfaceWrapper) ReportPlayback(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9147,17 +9447,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemPalette(w http.ResponseWriter, r return } - // ------------- Path parameter "itemId" ------------- - var itemId string - - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return - } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemPalette(w, r, roomId, itemId) + siw.Handler.ReportPlayback(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9167,8 +9458,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemPalette(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// GetQueueItemSimilar operation middleware -func (siw *ServerInterfaceWrapper) GetQueueItemSimilar(w http.ResponseWriter, r *http.Request) { +// SaveNightPlaylist operation middleware +func (siw *ServerInterfaceWrapper) SaveNightPlaylist(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9182,33 +9473,34 @@ func (siw *ServerInterfaceWrapper) GetQueueItemSimilar(w http.ResponseWriter, r return } - // ------------- Path parameter "itemId" ------------- - var itemId string + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.SaveNightPlaylist(w, r, roomId) + })) - err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // Parameter object where we will unmarshal all parameters from the context - var params GetQueueItemSimilarParams + handler.ServeHTTP(w, r) +} - // ------------- Optional query parameter "limit" ------------- +// GetQueue operation middleware +func (siw *ServerInterfaceWrapper) GetQueue(w http.ResponseWriter, r *http.Request) { - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + var err error + _ = err + + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetQueueItemSimilar(w, r, roomId, itemId, params) + siw.Handler.GetQueue(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9218,8 +9510,8 @@ func (siw *ServerInterfaceWrapper) GetQueueItemSimilar(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// SendReaction operation middleware -func (siw *ServerInterfaceWrapper) SendReaction(w http.ResponseWriter, r *http.Request) { +// AddToQueue operation middleware +func (siw *ServerInterfaceWrapper) AddToQueue(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9234,7 +9526,7 @@ func (siw *ServerInterfaceWrapper) SendReaction(w http.ResponseWriter, r *http.R } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.SendReaction(w, r, roomId) + siw.Handler.AddToQueue(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9244,8 +9536,8 @@ func (siw *ServerInterfaceWrapper) SendReaction(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// GetRoomRecap operation middleware -func (siw *ServerInterfaceWrapper) GetRoomRecap(w http.ResponseWriter, r *http.Request) { +// RestoreQueueItems operation middleware +func (siw *ServerInterfaceWrapper) RestoreQueueItems(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9259,37 +9551,43 @@ func (siw *ServerInterfaceWrapper) GetRoomRecap(w http.ResponseWriter, r *http.R return } - // Parameter object where we will unmarshal all parameters from the context - var params GetRoomRecapParams + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RestoreQueueItems(w, r, roomId) + })) - // ------------- Required query parameter "from" ------------- + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } - err = runtime.BindQueryParameterWithOptions("form", true, true, "from", r.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + handler.ServeHTTP(w, r) +} + +// RemoveQueueItem operation middleware +func (siw *ServerInterfaceWrapper) RemoveQueueItem(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "from"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "from", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } - // ------------- Required query parameter "to" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, true, "to", r.URL.Query(), ¶ms.To, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "to"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "to", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRoomRecap(w, r, roomId, params) + siw.Handler.RemoveQueueItem(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9299,8 +9597,8 @@ func (siw *ServerInterfaceWrapper) GetRoomRecap(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// ListSessions operation middleware -func (siw *ServerInterfaceWrapper) ListSessions(w http.ResponseWriter, r *http.Request) { +// MoveQueueItem operation middleware +func (siw *ServerInterfaceWrapper) MoveQueueItem(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9314,24 +9612,17 @@ func (siw *ServerInterfaceWrapper) ListSessions(w http.ResponseWriter, r *http.R return } - // Parameter object where we will unmarshal all parameters from the context - var params ListSessionsParams - - // ------------- Optional query parameter "limit" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListSessions(w, r, roomId, params) + siw.Handler.MoveQueueItem(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9341,8 +9632,8 @@ func (siw *ServerInterfaceWrapper) ListSessions(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// GetRoomStats operation middleware -func (siw *ServerInterfaceWrapper) GetRoomStats(w http.ResponseWriter, r *http.Request) { +// GetQueueItemArtwork operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemArtwork(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9356,37 +9647,33 @@ func (siw *ServerInterfaceWrapper) GetRoomStats(w http.ResponseWriter, r *http.R return } - // Parameter object where we will unmarshal all parameters from the context - var params GetRoomStatsParams - - // ------------- Optional query parameter "from" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, false, "from", r.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "from"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "from", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } - // ------------- Optional query parameter "to" ------------- + // Parameter object where we will unmarshal all parameters from the context + var params GetQueueItemArtworkParams - err = runtime.BindQueryParameterWithOptions("form", true, false, "to", r.URL.Query(), ¶ms.To, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + // ------------- Optional query parameter "size" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "size", r.URL.Query(), ¶ms.Size, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { var requiredError *runtime.RequiredParameterError if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "to"}) + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "size"}) } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "to", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "size", Err: err}) } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetRoomStats(w, r, roomId, params) + siw.Handler.GetQueueItemArtwork(w, r, roomId, itemId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9396,8 +9683,8 @@ func (siw *ServerInterfaceWrapper) GetRoomStats(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } -// StreamQueueItem operation middleware -func (siw *ServerInterfaceWrapper) StreamQueueItem(w http.ResponseWriter, r *http.Request) { +// GetQueueItemBeatMap operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemBeatMap(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9420,71 +9707,43 @@ func (siw *ServerInterfaceWrapper) StreamQueueItem(w http.ResponseWriter, r *htt return } - // Parameter object where we will unmarshal all parameters from the context - var params StreamQueueItemParams - - // ------------- Optional query parameter "accept" ------------- + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetQueueItemBeatMap(w, r, roomId, itemId) + })) - err = runtime.BindQueryParameterWithOptions("form", true, false, "accept", r.URL.Query(), ¶ms.Accept, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "accept"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "accept", Err: err}) - } - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // ------------- Optional query parameter "maxBitrate" ------------- + handler.ServeHTTP(w, r) +} - err = runtime.BindQueryParameterWithOptions("form", true, false, "maxBitrate", r.URL.Query(), ¶ms.MaxBitrate, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "maxBitrate"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "maxBitrate", Err: err}) - } - return - } +// UnheartSong operation middleware +func (siw *ServerInterfaceWrapper) UnheartSong(w http.ResponseWriter, r *http.Request) { - // ------------- Optional query parameter "start" ------------- + var err error + _ = err - err = runtime.BindQueryParameterWithOptions("form", true, false, "start", r.URL.Query(), ¶ms.Start, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "start"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "start", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } - headers := r.Header - - // ------------- Optional header parameter "Range" ------------- - if valueList, found := headers[http.CanonicalHeaderKey("Range")]; found { - var Range string - n := len(valueList) - if n != 1 { - siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "Range", Count: n}) - return - } - - err = runtime.BindStyledParameterWithOptions("simple", "Range", valueList[0], &Range, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""}) - if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "Range", Err: err}) - return - } - - params.Range = &Range + // ------------- Path parameter "itemId" ------------- + var itemId string + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.StreamQueueItem(w, r, roomId, itemId, params) + siw.Handler.UnheartSong(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9494,8 +9753,8 @@ func (siw *ServerInterfaceWrapper) StreamQueueItem(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// GetSuggestions operation middleware -func (siw *ServerInterfaceWrapper) GetSuggestions(w http.ResponseWriter, r *http.Request) { +// GetHearts operation middleware +func (siw *ServerInterfaceWrapper) GetHearts(w http.ResponseWriter, r *http.Request) { var err error _ = err @@ -9509,63 +9768,52 @@ func (siw *ServerInterfaceWrapper) GetSuggestions(w http.ResponseWriter, r *http return } - // Parameter object where we will unmarshal all parameters from the context - var params GetSuggestionsParams - - // ------------- Optional query parameter "scope" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, false, "scope", r.URL.Query(), ¶ms.Scope, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "scope"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "scope", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } - // ------------- Optional query parameter "source" ------------- + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetHearts(w, r, roomId, itemId) + })) - err = runtime.BindQueryParameterWithOptions("form", true, false, "source", r.URL.Query(), ¶ms.Source, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "source"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "source", Err: err}) - } - return + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - // ------------- Optional query parameter "limit" ------------- + handler.ServeHTTP(w, r) +} - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) +// HeartSong operation middleware +func (siw *ServerInterfaceWrapper) HeartSong(w http.ResponseWriter, r *http.Request) { + + var err error + _ = err + + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } - // ------------- Optional query parameter "refresh" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, false, "refresh", r.URL.Query(), ¶ms.Refresh, runtime.BindQueryParameterOptions{Type: "boolean", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "refresh"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "refresh", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetSuggestions(w, r, roomId, params) + siw.Handler.HeartSong(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9575,56 +9823,32 @@ func (siw *ServerInterfaceWrapper) GetSuggestions(w http.ResponseWriter, r *http handler.ServeHTTP(w, r) } -// Search operation middleware -func (siw *ServerInterfaceWrapper) Search(w http.ResponseWriter, r *http.Request) { +// GetQueueItemLinerNotes operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemLinerNotes(w http.ResponseWriter, r *http.Request) { var err error _ = err - // Parameter object where we will unmarshal all parameters from the context - var params SearchParams - - // ------------- Required query parameter "q" ------------- - - err = runtime.BindQueryParameterWithOptions("form", true, true, "q", r.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) - if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "q"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "q", Err: err}) - } - return - } - - // ------------- Optional query parameter "limit" ------------- + // ------------- Path parameter "roomId" ------------- + var roomId RoomId - err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } - // ------------- Optional query parameter "publicPlaylists" ------------- + // ------------- Path parameter "itemId" ------------- + var itemId string - err = runtime.BindQueryParameterWithOptions("form", true, false, "publicPlaylists", r.URL.Query(), ¶ms.PublicPlaylists, runtime.BindQueryParameterOptions{Type: "boolean", Format: ""}) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - var requiredError *runtime.RequiredParameterError - if errors.As(err, &requiredError) { - siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "publicPlaylists"}) - } else { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "publicPlaylists", Err: err}) - } + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.Search(w, r, params) + siw.Handler.GetQueueItemLinerNotes(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9634,25 +9858,32 @@ func (siw *ServerInterfaceWrapper) Search(w http.ResponseWriter, r *http.Request handler.ServeHTTP(w, r) } -// GetServerSettings operation middleware -func (siw *ServerInterfaceWrapper) GetServerSettings(w http.ResponseWriter, r *http.Request) { +// GetQueueItemLyrics operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemLyrics(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetServerSettings(w, r) - })) + var err error + _ = err - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return } - handler.ServeHTTP(w, r) -} + // ------------- Path parameter "itemId" ------------- + var itemId string -// UpdateServerSettings operation middleware -func (siw *ServerInterfaceWrapper) UpdateServerSettings(w http.ResponseWriter, r *http.Request) { + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + return + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UpdateServerSettings(w, r) + siw.Handler.GetQueueItemLyrics(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9662,25 +9893,32 @@ func (siw *ServerInterfaceWrapper) UpdateServerSettings(w http.ResponseWriter, r handler.ServeHTTP(w, r) } -// ListUserAudit operation middleware -func (siw *ServerInterfaceWrapper) ListUserAudit(w http.ResponseWriter, r *http.Request) { +// GetQueueItemPalette operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemPalette(w http.ResponseWriter, r *http.Request) { - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListUserAudit(w, r) - })) + var err error + _ = err - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + // ------------- Path parameter "roomId" ------------- + var roomId RoomId + + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return } - handler.ServeHTTP(w, r) -} + // ------------- Path parameter "itemId" ------------- + var itemId string -// ListUsers operation middleware -func (siw *ServerInterfaceWrapper) ListUsers(w http.ResponseWriter, r *http.Request) { + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + return + } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.ListUsers(w, r) + siw.Handler.GetQueueItemPalette(w, r, roomId, itemId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9690,49 +9928,48 @@ func (siw *ServerInterfaceWrapper) ListUsers(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } -// RemoveUser operation middleware -func (siw *ServerInterfaceWrapper) RemoveUser(w http.ResponseWriter, r *http.Request) { +// GetQueueItemSimilar operation middleware +func (siw *ServerInterfaceWrapper) GetQueueItemSimilar(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "roomId" ------------- + var roomId RoomId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } - handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RemoveUser(w, r, id) - })) + // ------------- Path parameter "itemId" ------------- + var itemId string - for _, middleware := range siw.HandlerMiddlewares { - handler = middleware(handler) + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + return } - handler.ServeHTTP(w, r) -} - -// UpdateUser operation middleware -func (siw *ServerInterfaceWrapper) UpdateUser(w http.ResponseWriter, r *http.Request) { - - var err error - _ = err + // Parameter object where we will unmarshal all parameters from the context + var params GetQueueItemSimilarParams - // ------------- Path parameter "id" ------------- - var id string + // ------------- Optional query parameter "limit" ------------- - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.UpdateUser(w, r, id) + siw.Handler.GetQueueItemSimilar(w, r, roomId, itemId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9742,23 +9979,23 @@ func (siw *ServerInterfaceWrapper) UpdateUser(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } -// GetUserAvatar operation middleware -func (siw *ServerInterfaceWrapper) GetUserAvatar(w http.ResponseWriter, r *http.Request) { +// SendReaction operation middleware +func (siw *ServerInterfaceWrapper) SendReaction(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "roomId" ------------- + var roomId RoomId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetUserAvatar(w, r, id) + siw.Handler.SendReaction(w, r, roomId) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9768,23 +10005,52 @@ func (siw *ServerInterfaceWrapper) GetUserAvatar(w http.ResponseWriter, r *http. handler.ServeHTTP(w, r) } -// RevokeResetLink operation middleware -func (siw *ServerInterfaceWrapper) RevokeResetLink(w http.ResponseWriter, r *http.Request) { +// GetRoomRecap operation middleware +func (siw *ServerInterfaceWrapper) GetRoomRecap(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "roomId" ------------- + var roomId RoomId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetRoomRecapParams + + // ------------- Required query parameter "from" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "from", r.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "from"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "from", Err: err}) + } + return + } + + // ------------- Required query parameter "to" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, true, "to", r.URL.Query(), ¶ms.To, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "to"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "to", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.RevokeResetLink(w, r, id) + siw.Handler.GetRoomRecap(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9794,23 +10060,39 @@ func (siw *ServerInterfaceWrapper) RevokeResetLink(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -// CreateResetLink operation middleware -func (siw *ServerInterfaceWrapper) CreateResetLink(w http.ResponseWriter, r *http.Request) { +// ListSessions operation middleware +func (siw *ServerInterfaceWrapper) ListSessions(w http.ResponseWriter, r *http.Request) { var err error _ = err - // ------------- Path parameter "id" ------------- - var id string + // ------------- Path parameter "roomId" ------------- + var roomId RoomId - err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) if err != nil { - siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params ListSessionsParams + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } return } handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.CreateResetLink(w, r, id) + siw.Handler.ListSessions(w, r, roomId, params) })) for _, middleware := range siw.HandlerMiddlewares { @@ -9820,987 +10102,829 @@ func (siw *ServerInterfaceWrapper) CreateResetLink(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } -type UnescapedCookieParamError struct { - ParamName string - Err error -} - -func (e *UnescapedCookieParamError) Error() string { - return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) -} +// GetRoomStats operation middleware +func (siw *ServerInterfaceWrapper) GetRoomStats(w http.ResponseWriter, r *http.Request) { -func (e *UnescapedCookieParamError) Unwrap() error { - return e.Err -} + var err error + _ = err -type UnmarshalingParamError struct { - ParamName string - Err error -} + // ------------- Path parameter "roomId" ------------- + var roomId RoomId -func (e *UnmarshalingParamError) Error() string { - return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) -} + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } -func (e *UnmarshalingParamError) Unwrap() error { - return e.Err -} + // Parameter object where we will unmarshal all parameters from the context + var params GetRoomStatsParams -type RequiredParamError struct { - ParamName string -} + // ------------- Optional query parameter "from" ------------- -func (e *RequiredParamError) Error() string { - return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) -} + err = runtime.BindQueryParameterWithOptions("form", true, false, "from", r.URL.Query(), ¶ms.From, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "from"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "from", Err: err}) + } + return + } -type RequiredHeaderError struct { - ParamName string - Err error -} + // ------------- Optional query parameter "to" ------------- -func (e *RequiredHeaderError) Error() string { - return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) -} + err = runtime.BindQueryParameterWithOptions("form", true, false, "to", r.URL.Query(), ¶ms.To, runtime.BindQueryParameterOptions{Type: "string", Format: "date-time"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "to"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "to", Err: err}) + } + return + } -func (e *RequiredHeaderError) Unwrap() error { - return e.Err -} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetRoomStats(w, r, roomId, params) + })) -type InvalidParamFormatError struct { - ParamName string - Err error -} + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } -func (e *InvalidParamFormatError) Error() string { - return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) + handler.ServeHTTP(w, r) } -func (e *InvalidParamFormatError) Unwrap() error { - return e.Err -} +// StreamQueueItem operation middleware +func (siw *ServerInterfaceWrapper) StreamQueueItem(w http.ResponseWriter, r *http.Request) { -type TooManyValuesForParamError struct { - ParamName string - Count int -} + var err error + _ = err -func (e *TooManyValuesForParamError) Error() string { - return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) -} + // ------------- Path parameter "roomId" ------------- + var roomId RoomId -// Handler creates http.Handler with routing matching OpenAPI spec. -func Handler(si ServerInterface) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{}) -} + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } -// ServeMux is an abstraction of [http.ServeMux]. -type ServeMux interface { - HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) - http.Handler -} + // ------------- Path parameter "itemId" ------------- + var itemId string -type StdHTTPServerOptions struct { - BaseURL string - BaseRouter ServeMux - Middlewares []MiddlewareFunc - ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} + err = runtime.BindStyledParameterWithOptions("simple", "itemId", r.PathValue("itemId"), &itemId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "itemId", Err: err}) + return + } -// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. -func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{ - BaseRouter: m, - }) -} + // Parameter object where we will unmarshal all parameters from the context + var params StreamQueueItemParams -func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { - return HandlerWithOptions(si, StdHTTPServerOptions{ - BaseURL: baseURL, - BaseRouter: m, - }) -} + // ------------- Optional query parameter "accept" ------------- -// HandlerWithOptions creates http.Handler with additional options -func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { - m := options.BaseRouter - - if m == nil { - m = http.NewServeMux() + err = runtime.BindQueryParameterWithOptions("form", true, false, "accept", r.URL.Query(), ¶ms.Accept, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "accept"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "accept", Err: err}) + } + return } - if options.ErrorHandlerFunc == nil { - options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) + + // ------------- Optional query parameter "maxBitrate" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "maxBitrate", r.URL.Query(), ¶ms.MaxBitrate, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "maxBitrate"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "maxBitrate", Err: err}) } + return } - wrapper := ServerInterfaceWrapper{ - Handler: si, - HandlerMiddlewares: options.Middlewares, - ErrorHandlerFunc: options.ErrorHandlerFunc, + // ------------- Optional query parameter "start" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "start", r.URL.Query(), ¶ms.Start, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "start"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "start", Err: err}) + } + return } - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/healthz", wrapper.GetHealth) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/invites/{code}", wrapper.DeleteInvite) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/invites/{code}", wrapper.GetInvite) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup", wrapper.Signup) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup/passkey/begin", wrapper.BeginPasskeySignup) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup/passkey/finish", wrapper.FinishPasskeySignup) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/login", wrapper.Login) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/passkey/begin", wrapper.BeginPasskeyLogin) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/passkey/finish", wrapper.FinishPasskeyLogin) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/logout", wrapper.Logout) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/reset-links/{code}", wrapper.GetResetLink) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/password", wrapper.ResetPassword) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/passkey/begin", wrapper.BeginResetPasskey) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/passkey/finish", wrapper.FinishResetPasskey) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me", wrapper.GetMe) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/me", wrapper.UpdateMe) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/password", wrapper.DeletePassword) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/me/password", wrapper.SetPassword) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/passkeys", wrapper.ListPasskeys) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/passkeys/begin", wrapper.BeginAddPasskey) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/passkeys/finish", wrapper.FinishAddPasskey) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/passkeys/{id}", wrapper.DeletePasskey) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/me/passkeys/{id}", wrapper.RenamePasskey) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/me/avatar", wrapper.UploadAvatar) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/reauth/begin", wrapper.BeginReauth) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/delete", wrapper.DeleteMe) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/sessions", wrapper.RevokeOtherSessions) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/sessions", wrapper.ListMySessions) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/sessions/{id}", wrapper.RevokeMySession) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/server-settings", wrapper.GetServerSettings) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/server-settings", wrapper.UpdateServerSettings) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/server", wrapper.GetServerInfo) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/backups", wrapper.GetBackups) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/admin/backups", wrapper.CreateBackup) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/admin/backups/schedule", wrapper.UpdateBackupSchedule) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/backups/{name}", wrapper.DeleteBackup) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/backups/{name}", wrapper.DownloadBackup) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/restore", wrapper.CancelRestore) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/admin/restore", wrapper.StageRestore) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/links", wrapper.ListAllLinks) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/rooms", wrapper.ListActiveRooms) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/rooms/{roomId}/taste", wrapper.GetRoomTaste) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/sessions", wrapper.ListAllSessions) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/sessions/{id}", wrapper.RevokeSession) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/users", wrapper.ListUsers) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/users/{id}", wrapper.RemoveUser) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/users/{id}", wrapper.UpdateUser) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/user-audit", wrapper.ListUserAudit) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/users/{id}/avatar", wrapper.GetUserAvatar) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/users/{id}/reset-link", wrapper.RevokeResetLink) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/users/{id}/reset-link", wrapper.CreateResetLink) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/reset-links", wrapper.ListResetLinks) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/invites", wrapper.ListInvites) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/invites", wrapper.CreateInvite) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/providers", wrapper.ListProviders) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links", wrapper.ListLinks) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/links", wrapper.CreateLink) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/links/{id}", wrapper.Unlink) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/links/{id}", wrapper.UpdateLink) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/links/{id}", wrapper.Relink) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/pairings", wrapper.BeginPairing) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/pairings/{id}", wrapper.PollPairing) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/links/oauth", wrapper.BeginOAuthLink) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/oauth/callback", wrapper.CompleteOAuthLink) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/search", wrapper.Search) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/albums/{albumId}", wrapper.GetAlbum) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/tracks/{trackId}/lyrics", wrapper.GetTrackLyrics) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}", wrapper.GetArtist) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/about", wrapper.GetArtistAbout) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/tracks", wrapper.GetArtistTracks) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/related", wrapper.GetArtistRelated) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/elsewhere", wrapper.GetArtistElsewhere) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/shuffle", wrapper.GetArtistShuffle) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/albums/{albumId}/about", wrapper.GetAlbumAbout) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/genre", wrapper.GetGenre) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/playlists", wrapper.ListPlaylists) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/playlists/{playlistId}/tracks", wrapper.GetPlaylistTracks) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/random-tracks", wrapper.GetRandomTracks) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/collection", wrapper.GetCollection) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artwork", wrapper.GetLinkArtwork) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue", wrapper.GetQueue) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/queue", wrapper.AddToQueue) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/queue/restore", wrapper.RestoreQueueItems) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/lane", wrapper.ClearLane) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/stats", wrapper.GetRoomStats) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/sessions", wrapper.ListSessions) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/artist-plays", wrapper.GetRoomArtistPlays) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/history", wrapper.GetHistory) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/suggestions", wrapper.GetSuggestions) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}", wrapper.RemoveQueueItem) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}", wrapper.MoveQueueItem) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/similar", wrapper.GetQueueItemSimilar) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/artwork", wrapper.GetQueueItemArtwork) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/palette", wrapper.GetQueueItemPalette) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/beatmap", wrapper.GetQueueItemBeatMap) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/lyrics", wrapper.GetQueueItemLyrics) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/liner-notes", wrapper.GetQueueItemLinerNotes) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/reactions", wrapper.SendReaction) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/displays", wrapper.ListDisplays) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/displays", wrapper.PairDisplay) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/displays/{displayId}", wrapper.UnpairDisplay) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}/displays/{displayId}", wrapper.UpdateDisplay) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/displays/pairing/{code}", wrapper.LookupDisplayPairing) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/display/pairing", wrapper.PollDisplayPairing) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/display/pairing", wrapper.BeginDisplayPairing) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/display", wrapper.LeaveDisplay) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/display", wrapper.GetDisplay) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.UnheartSong) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.GetHearts) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.HeartSong) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/nights", wrapper.ListNights) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/nights", wrapper.EndNight) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/recap", wrapper.GetRoomRecap) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/playlists", wrapper.SaveNightPlaylist) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists", wrapper.ListSavedPlaylists) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/playlists", wrapper.CreateSavedPlaylist) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.DeleteSavedPlaylist) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.GetSavedPlaylist) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.UpdateSavedPlaylist) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/playlists/{playlistId}/songs", wrapper.AddSavedPlaylistSongs) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}", wrapper.RemoveSavedPlaylistSong) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}/position", wrapper.MoveSavedPlaylistSong) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}/artwork", wrapper.GetSavedPlaylistSongArtwork) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/round", wrapper.GetGameRound) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/rounds", wrapper.StartGameRound) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/rounds/{roundId}/answers", wrapper.AnswerGameRound) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/rounds/{roundId}/artwork", wrapper.GetGameRoundArtwork) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/clips/{clipId}", wrapper.GetGameClip) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/scores", wrapper.GetGameScores) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/queue", wrapper.GetQueueGames) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue", wrapper.StartQueueGame) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/entries", wrapper.EnterQueueGame) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/entries/{itemId}", wrapper.WithdrawQueueGameEntry) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/hint", wrapper.HintQueueGame) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/close", wrapper.CloseQueueGame) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.RevokeGuestPass) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.GetGuestPass) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.CreateGuestPass) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/guests", wrapper.ListGuests) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/guests/{userId}", wrapper.KickGuest) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/guest/{token}", wrapper.GetGuestInvite) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/guest/{token}", wrapper.JoinAsGuest) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms", wrapper.ListRooms) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms", wrapper.CreateRoom) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}", wrapper.DeleteRoom) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}", wrapper.GetRoom) - m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}", wrapper.UpdateRoom) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/owner", wrapper.TransferRoom) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/members", wrapper.ListRoomMembers) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/members/{userId}", wrapper.RemoveRoomMember) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/members/{userId}", wrapper.AddRoomMember) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/admin-join", wrapper.JoinRoomAsAdmin) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/invites", wrapper.ListRoomInvites) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/invites", wrapper.CreateRoomInvite) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/invites/{code}", wrapper.RevokeRoomInvite) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/room-invites/{code}", wrapper.GetRoomInvite) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/room-invites/{code}", wrapper.UseRoomInvite) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/playback", wrapper.GetPlayback) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/playback", wrapper.ControlPlayback) - m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/player", wrapper.ReleasePlayer) - m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/player", wrapper.ClaimPlayer) - m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/player/report", wrapper.ReportPlayback) - m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/stream/{itemId}", wrapper.StreamQueueItem) + headers := r.Header - return m -} + // ------------- Optional header parameter "Range" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("Range")]; found { + var Range string + n := len(valueList) + if n != 1 { + siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "Range", Count: n}) + return + } -type CeremonyJSONResponse Ceremony + err = runtime.BindStyledParameterWithOptions("simple", "Range", valueList[0], &Range, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "Range", Err: err}) + return + } -type ErrorJSONResponse Error + params.Range = &Range -type SignedInResponseHeaders struct { - SetCookie *string -} -type SignedInJSONResponse struct { - Body Me + } - Headers SignedInResponseHeaders -} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.StreamQueueItem(w, r, roomId, itemId, params) + })) -type GetBackupsRequestObject struct { -} + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } -type GetBackupsResponseObject interface { - VisitGetBackupsResponse(w http.ResponseWriter) error + handler.ServeHTTP(w, r) } -type GetBackups200JSONResponse BackupStatus +// GetSuggestions operation middleware +func (siw *ServerInterfaceWrapper) GetSuggestions(w http.ResponseWriter, r *http.Request) { -func (response GetBackups200JSONResponse) VisitGetBackupsResponse(w http.ResponseWriter) error { + var err error + _ = err - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} + // ------------- Path parameter "roomId" ------------- + var roomId RoomId -type GetBackupsdefaultJSONResponse struct { - Body Error - StatusCode int -} + err = runtime.BindStyledParameterWithOptions("simple", "roomId", r.PathValue("roomId"), &roomId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "roomId", Err: err}) + return + } -func (response GetBackupsdefaultJSONResponse) VisitGetBackupsResponse(w http.ResponseWriter) error { + // Parameter object where we will unmarshal all parameters from the context + var params GetSuggestionsParams - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} + // ------------- Optional query parameter "scope" ------------- -type CreateBackupRequestObject struct { -} + err = runtime.BindQueryParameterWithOptions("form", true, false, "scope", r.URL.Query(), ¶ms.Scope, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "scope"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "scope", Err: err}) + } + return + } -type CreateBackupResponseObject interface { - VisitCreateBackupResponse(w http.ResponseWriter) error -} + // ------------- Optional query parameter "source" ------------- -type CreateBackup201JSONResponse Backup + err = runtime.BindQueryParameterWithOptions("form", true, false, "source", r.URL.Query(), ¶ms.Source, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "source"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "source", Err: err}) + } + return + } -func (response CreateBackup201JSONResponse) VisitCreateBackupResponse(w http.ResponseWriter) error { + // ------------- Optional query parameter "limit" ------------- - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) - _, err := buf.WriteTo(w) - return err -} -type CreateBackupdefaultJSONResponse struct { - Body Error - StatusCode int -} + // ------------- Optional query parameter "refresh" ------------- -func (response CreateBackupdefaultJSONResponse) VisitCreateBackupResponse(w http.ResponseWriter) error { + err = runtime.BindQueryParameterWithOptions("form", true, false, "refresh", r.URL.Query(), ¶ms.Refresh, runtime.BindQueryParameterOptions{Type: "boolean", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "refresh"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "refresh", Err: err}) + } + return + } - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetSuggestions(w, r, roomId, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type UpdateBackupScheduleRequestObject struct { - Body *UpdateBackupScheduleJSONRequestBody + handler.ServeHTTP(w, r) } -type UpdateBackupScheduleResponseObject interface { - VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error -} +// Search operation middleware +func (siw *ServerInterfaceWrapper) Search(w http.ResponseWriter, r *http.Request) { -type UpdateBackupSchedule200JSONResponse BackupSchedule + var err error + _ = err -func (response UpdateBackupSchedule200JSONResponse) VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error { + // Parameter object where we will unmarshal all parameters from the context + var params SearchParams - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} + // ------------- Required query parameter "q" ------------- -type UpdateBackupScheduledefaultJSONResponse struct { - Body Error - StatusCode int -} + err = runtime.BindQueryParameterWithOptions("form", true, true, "q", r.URL.Query(), ¶ms.Q, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "q"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "q", Err: err}) + } + return + } -func (response UpdateBackupScheduledefaultJSONResponse) VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error { + // ------------- Optional query parameter "limit" ------------- - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + } + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type DeleteBackupRequestObject struct { - Name string `json:"name"` -} + // ------------- Optional query parameter "publicPlaylists" ------------- -type DeleteBackupResponseObject interface { - VisitDeleteBackupResponse(w http.ResponseWriter) error -} + err = runtime.BindQueryParameterWithOptions("form", true, false, "publicPlaylists", r.URL.Query(), ¶ms.PublicPlaylists, runtime.BindQueryParameterOptions{Type: "boolean", Format: ""}) + if err != nil { + var requiredError *runtime.RequiredParameterError + if errors.As(err, &requiredError) { + siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "publicPlaylists"}) + } else { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "publicPlaylists", Err: err}) + } + return + } -type DeleteBackup204Response struct { -} + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.Search(w, r, params) + })) -func (response DeleteBackup204Response) VisitDeleteBackupResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } -type DeleteBackupdefaultJSONResponse struct { - Body Error - StatusCode int + handler.ServeHTTP(w, r) } -func (response DeleteBackupdefaultJSONResponse) VisitDeleteBackupResponse(w http.ResponseWriter) error { +// GetServerSettings operation middleware +func (siw *ServerInterfaceWrapper) GetServerSettings(w http.ResponseWriter, r *http.Request) { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetServerSettings(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type DownloadBackupRequestObject struct { - Name string `json:"name"` + handler.ServeHTTP(w, r) } -type DownloadBackupResponseObject interface { - VisitDownloadBackupResponse(w http.ResponseWriter) error -} +// UpdateServerSettings operation middleware +func (siw *ServerInterfaceWrapper) UpdateServerSettings(w http.ResponseWriter, r *http.Request) { -type DownloadBackup200ApplicationvndSqlite3Response struct { - Body io.Reader - ContentLength int64 + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateServerSettings(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) } -func (response DownloadBackup200ApplicationvndSqlite3Response) VisitDownloadBackupResponse(w http.ResponseWriter) error { +// ListUserAudit operation middleware +func (siw *ServerInterfaceWrapper) ListUserAudit(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/vnd.sqlite3") - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(200) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListUserAudit(w, r) + })) - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - _, err := io.Copy(w, response.Body) - return err -} -type DownloadBackupdefaultJSONResponse struct { - Body Error - StatusCode int + handler.ServeHTTP(w, r) } -func (response DownloadBackupdefaultJSONResponse) VisitDownloadBackupResponse(w http.ResponseWriter) error { +// ListUsers operation middleware +func (siw *ServerInterfaceWrapper) ListUsers(w http.ResponseWriter, r *http.Request) { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListUsers(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type ListAllLinksRequestObject struct { + handler.ServeHTTP(w, r) } -type ListAllLinksResponseObject interface { - VisitListAllLinksResponse(w http.ResponseWriter) error -} +// RemoveUser operation middleware +func (siw *ServerInterfaceWrapper) RemoveUser(w http.ResponseWriter, r *http.Request) { -type ListAllLinks200JSONResponse []ServiceLink + var err error + _ = err -func (response ListAllLinks200JSONResponse) VisitListAllLinksResponse(w http.ResponseWriter) error { + // ------------- Path parameter "id" ------------- + var id string - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type ListAllLinksdefaultJSONResponse struct { - Body Error - StatusCode int -} -func (response ListAllLinksdefaultJSONResponse) VisitListAllLinksResponse(w http.ResponseWriter) error { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RemoveUser(w, r, id) + })) - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type CancelRestoreRequestObject struct { + handler.ServeHTTP(w, r) } -type CancelRestoreResponseObject interface { - VisitCancelRestoreResponse(w http.ResponseWriter) error -} +// UpdateUser operation middleware +func (siw *ServerInterfaceWrapper) UpdateUser(w http.ResponseWriter, r *http.Request) { -type CancelRestore204Response struct { -} + var err error + _ = err -func (response CancelRestore204Response) VisitCancelRestoreResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} + // ------------- Path parameter "id" ------------- + var id string -type CancelRestoredefaultJSONResponse struct { - Body Error - StatusCode int -} + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return + } -func (response CancelRestoredefaultJSONResponse) VisitCancelRestoreResponse(w http.ResponseWriter) error { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateUser(w, r, id) + })) - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type StageRestoreRequestObject struct { - Body *StageRestoreJSONRequestBody + handler.ServeHTTP(w, r) } -type StageRestoreResponseObject interface { - VisitStageRestoreResponse(w http.ResponseWriter) error -} +// GetUserAvatar operation middleware +func (siw *ServerInterfaceWrapper) GetUserAvatar(w http.ResponseWriter, r *http.Request) { -type StageRestore200JSONResponse PendingRestore + var err error + _ = err -func (response StageRestore200JSONResponse) VisitStageRestoreResponse(w http.ResponseWriter) error { + // ------------- Path parameter "id" ------------- + var id string - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type StageRestoredefaultJSONResponse struct { - Body Error - StatusCode int -} -func (response StageRestoredefaultJSONResponse) VisitStageRestoreResponse(w http.ResponseWriter) error { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetUserAvatar(w, r, id) + })) - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type ListActiveRoomsRequestObject struct { + handler.ServeHTTP(w, r) } -type ListActiveRoomsResponseObject interface { - VisitListActiveRoomsResponse(w http.ResponseWriter) error -} +// RevokeResetLink operation middleware +func (siw *ServerInterfaceWrapper) RevokeResetLink(w http.ResponseWriter, r *http.Request) { -type ListActiveRooms200JSONResponse []RoomActivity + var err error + _ = err -func (response ListActiveRooms200JSONResponse) VisitListActiveRoomsResponse(w http.ResponseWriter) error { + // ------------- Path parameter "id" ------------- + var id string - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type ListActiveRoomsdefaultJSONResponse struct { - Body Error - StatusCode int -} -func (response ListActiveRoomsdefaultJSONResponse) VisitListActiveRoomsResponse(w http.ResponseWriter) error { + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RevokeResetLink(w, r, id) + })) - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type GetRoomTasteRequestObject struct { - RoomId RoomId `json:"roomId"` + handler.ServeHTTP(w, r) } -type GetRoomTasteResponseObject interface { - VisitGetRoomTasteResponse(w http.ResponseWriter) error -} +// CreateResetLink operation middleware +func (siw *ServerInterfaceWrapper) CreateResetLink(w http.ResponseWriter, r *http.Request) { -type GetRoomTaste200JSONResponse RoomTaste + var err error + _ = err -func (response GetRoomTaste200JSONResponse) VisitGetRoomTasteResponse(w http.ResponseWriter) error { + // ------------- Path parameter "id" ------------- + var id string - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "", ValueIsUnescaped: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err}) + return } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateResetLink(w, r, id) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) } -type GetRoomTastedefaultJSONResponse struct { - Body Error - StatusCode int +type UnescapedCookieParamError struct { + ParamName string + Err error } -func (response GetRoomTastedefaultJSONResponse) VisitGetRoomTasteResponse(w http.ResponseWriter) error { +func (e *UnescapedCookieParamError) Error() string { + return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName) +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err +func (e *UnescapedCookieParamError) Unwrap() error { + return e.Err } -type GetServerInfoRequestObject struct { +type UnmarshalingParamError struct { + ParamName string + Err error } -type GetServerInfoResponseObject interface { - VisitGetServerInfoResponse(w http.ResponseWriter) error +func (e *UnmarshalingParamError) Error() string { + return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error()) } -type GetServerInfo200JSONResponse ServerInfo +func (e *UnmarshalingParamError) Unwrap() error { + return e.Err +} -func (response GetServerInfo200JSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error { +type RequiredParamError struct { + ParamName string +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type GetServerInfodefaultJSONResponse struct { - Body Error - StatusCode int -} - -func (response GetServerInfodefaultJSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} - -type ListAllSessionsRequestObject struct { -} - -type ListAllSessionsResponseObject interface { - VisitListAllSessionsResponse(w http.ResponseWriter) error -} - -type ListAllSessions200JSONResponse []UserSession - -func (response ListAllSessions200JSONResponse) VisitListAllSessionsResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type ListAllSessionsdefaultJSONResponse struct { - Body Error - StatusCode int -} - -func (response ListAllSessionsdefaultJSONResponse) VisitListAllSessionsResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} - -type RevokeSessionRequestObject struct { - Id string `json:"id"` -} - -type RevokeSessionResponseObject interface { - VisitRevokeSessionResponse(w http.ResponseWriter) error -} - -type RevokeSession204Response struct { -} - -func (response RevokeSession204Response) VisitRevokeSessionResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (e *RequiredParamError) Error() string { + return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName) } -type RevokeSessiondefaultJSONResponse struct { - Body Error - StatusCode int +type RequiredHeaderError struct { + ParamName string + Err error } -func (response RevokeSessiondefaultJSONResponse) VisitRevokeSessionResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err +func (e *RequiredHeaderError) Error() string { + return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName) } -type LoginRequestObject struct { - Body *LoginJSONRequestBody +func (e *RequiredHeaderError) Unwrap() error { + return e.Err } -type LoginResponseObject interface { - VisitLoginResponse(w http.ResponseWriter) error +type InvalidParamFormatError struct { + ParamName string + Err error } -type Login200JSONResponse struct{ SignedInJSONResponse } - -func (response Login200JSONResponse) VisitLoginResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (e *InvalidParamFormatError) Error() string { + return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error()) } -type LogindefaultJSONResponse struct { - Body Error - StatusCode int +func (e *InvalidParamFormatError) Unwrap() error { + return e.Err } -func (response LogindefaultJSONResponse) VisitLoginResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err +type TooManyValuesForParamError struct { + ParamName string + Count int } -type LogoutRequestObject struct { +func (e *TooManyValuesForParamError) Error() string { + return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count) } -type LogoutResponseObject interface { - VisitLogoutResponse(w http.ResponseWriter) error +// Handler creates http.Handler with routing matching OpenAPI spec. +func Handler(si ServerInterface) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{}) } -type Logout204ResponseHeaders struct { - SetCookie *string +// ServeMux is an abstraction of [http.ServeMux]. +type ServeMux interface { + HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) + http.Handler } -type Logout204Response struct { - Headers Logout204ResponseHeaders +type StdHTTPServerOptions struct { + BaseURL string + BaseRouter ServeMux + Middlewares []MiddlewareFunc + ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) } -func (response Logout204Response) VisitLogoutResponse(w http.ResponseWriter) error { - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(204) - return nil +// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux. +func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{ + BaseRouter: m, + }) } -type LogoutdefaultJSONResponse struct { - Body Error - StatusCode int +func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler { + return HandlerWithOptions(si, StdHTTPServerOptions{ + BaseURL: baseURL, + BaseRouter: m, + }) } -func (response LogoutdefaultJSONResponse) VisitLogoutResponse(w http.ResponseWriter) error { +// HandlerWithOptions creates http.Handler with additional options +func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler { + m := options.BaseRouter - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + if m == nil { + m = http.NewServeMux() } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} - -type BeginPasskeyLoginRequestObject struct { -} - -type BeginPasskeyLoginResponseObject interface { - VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error -} - -type BeginPasskeyLogin200JSONResponse struct{ CeremonyJSONResponse } - -func (response BeginPasskeyLogin200JSONResponse) VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + if options.ErrorHandlerFunc == nil { + options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type BeginPasskeyLogindefaultJSONResponse struct { - Body Error - StatusCode int -} - -func (response BeginPasskeyLogindefaultJSONResponse) VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + wrapper := ServerInterfaceWrapper{ + Handler: si, + HandlerMiddlewares: options.Middlewares, + ErrorHandlerFunc: options.ErrorHandlerFunc, } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err -} -type FinishPasskeyLoginRequestObject struct { - Body *FinishPasskeyLoginJSONRequestBody -} - -type FinishPasskeyLoginResponseObject interface { - VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error -} - -type FinishPasskeyLogin200JSONResponse struct{ SignedInJSONResponse } - -func (response FinishPasskeyLogin200JSONResponse) VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/healthz", wrapper.GetHealth) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/invites/{code}", wrapper.DeleteInvite) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/invites/{code}", wrapper.GetInvite) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup", wrapper.Signup) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup/passkey/begin", wrapper.BeginPasskeySignup) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/signup/passkey/finish", wrapper.FinishPasskeySignup) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/login", wrapper.Login) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/passkey/begin", wrapper.BeginPasskeyLogin) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/passkey/finish", wrapper.FinishPasskeyLogin) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/auth/logout", wrapper.Logout) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/reset-links/{code}", wrapper.GetResetLink) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/password", wrapper.ResetPassword) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/passkey/begin", wrapper.BeginResetPasskey) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reset-links/{code}/passkey/finish", wrapper.FinishResetPasskey) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me", wrapper.GetMe) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/me", wrapper.UpdateMe) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/password", wrapper.DeletePassword) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/me/password", wrapper.SetPassword) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/passkeys", wrapper.ListPasskeys) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/passkeys/begin", wrapper.BeginAddPasskey) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/passkeys/finish", wrapper.FinishAddPasskey) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/passkeys/{id}", wrapper.DeletePasskey) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/me/passkeys/{id}", wrapper.RenamePasskey) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/me/avatar", wrapper.UploadAvatar) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/reauth/begin", wrapper.BeginReauth) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/delete", wrapper.DeleteMe) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/sessions", wrapper.RevokeOtherSessions) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/sessions", wrapper.ListMySessions) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/sessions/{id}", wrapper.RevokeMySession) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/server-settings", wrapper.GetServerSettings) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/server-settings", wrapper.UpdateServerSettings) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/server", wrapper.GetServerInfo) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/backups", wrapper.GetBackups) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/admin/backups", wrapper.CreateBackup) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/admin/backups/schedule", wrapper.UpdateBackupSchedule) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/backups/{name}", wrapper.DeleteBackup) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/backups/{name}", wrapper.DownloadBackup) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/restore", wrapper.CancelRestore) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/admin/restore", wrapper.StageRestore) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/links", wrapper.ListAllLinks) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/rooms", wrapper.ListActiveRooms) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/rooms/{roomId}/taste", wrapper.GetRoomTaste) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/admin/sessions", wrapper.ListAllSessions) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/admin/sessions/{id}", wrapper.RevokeSession) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/users", wrapper.ListUsers) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/users/{id}", wrapper.RemoveUser) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/users/{id}", wrapper.UpdateUser) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/user-audit", wrapper.ListUserAudit) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/users/{id}/avatar", wrapper.GetUserAvatar) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/users/{id}/reset-link", wrapper.RevokeResetLink) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/users/{id}/reset-link", wrapper.CreateResetLink) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/reset-links", wrapper.ListResetLinks) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/invites", wrapper.ListInvites) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/invites", wrapper.CreateInvite) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/providers", wrapper.ListProviders) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links", wrapper.ListLinks) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/links", wrapper.CreateLink) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/links/{id}", wrapper.Unlink) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/links/{id}", wrapper.UpdateLink) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/links/{id}", wrapper.Relink) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/pairings", wrapper.BeginPairing) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/pairings/{id}", wrapper.PollPairing) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/links/oauth", wrapper.BeginOAuthLink) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/oauth/callback", wrapper.CompleteOAuthLink) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/search", wrapper.Search) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/albums/{albumId}", wrapper.GetAlbum) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/tracks/{trackId}/lyrics", wrapper.GetTrackLyrics) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}", wrapper.GetArtist) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/about", wrapper.GetArtistAbout) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/tracks", wrapper.GetArtistTracks) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/related", wrapper.GetArtistRelated) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/elsewhere", wrapper.GetArtistElsewhere) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artists/{artistId}/shuffle", wrapper.GetArtistShuffle) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/albums/{albumId}/about", wrapper.GetAlbumAbout) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/genre", wrapper.GetGenre) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/playlists", wrapper.ListPlaylists) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/playlists/{playlistId}/tracks", wrapper.GetPlaylistTracks) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/random-tracks", wrapper.GetRandomTracks) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/collection", wrapper.GetCollection) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/links/{id}/artwork", wrapper.GetLinkArtwork) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue", wrapper.GetQueue) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/queue", wrapper.AddToQueue) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/queue/restore", wrapper.RestoreQueueItems) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/lane", wrapper.ClearLane) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/stats", wrapper.GetRoomStats) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/sessions", wrapper.ListSessions) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/artist-plays", wrapper.GetRoomArtistPlays) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/history", wrapper.GetHistory) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/suggestions", wrapper.GetSuggestions) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}", wrapper.RemoveQueueItem) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}", wrapper.MoveQueueItem) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/similar", wrapper.GetQueueItemSimilar) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/artwork", wrapper.GetQueueItemArtwork) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/palette", wrapper.GetQueueItemPalette) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/beatmap", wrapper.GetQueueItemBeatMap) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/lyrics", wrapper.GetQueueItemLyrics) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/liner-notes", wrapper.GetQueueItemLinerNotes) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/reactions", wrapper.SendReaction) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/displays", wrapper.ListDisplays) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/displays", wrapper.PairDisplay) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/displays/{displayId}", wrapper.UnpairDisplay) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}/displays/{displayId}", wrapper.UpdateDisplay) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/displays/pairing/{code}", wrapper.LookupDisplayPairing) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/display/pairing", wrapper.PollDisplayPairing) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/display/pairing", wrapper.BeginDisplayPairing) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/display", wrapper.LeaveDisplay) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/display", wrapper.GetDisplay) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.UnheartSong) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.GetHearts) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/queue/{itemId}/hearts", wrapper.HeartSong) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/nights", wrapper.ListNights) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/nights", wrapper.EndNight) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/recap", wrapper.GetRoomRecap) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/playlists", wrapper.SaveNightPlaylist) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists", wrapper.ListSavedPlaylists) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/playlists", wrapper.CreateSavedPlaylist) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.DeleteSavedPlaylist) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.GetSavedPlaylist) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/playlists/{playlistId}", wrapper.UpdateSavedPlaylist) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/playlists/{playlistId}/songs", wrapper.AddSavedPlaylistSongs) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}", wrapper.RemoveSavedPlaylistSong) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}/position", wrapper.MoveSavedPlaylistSong) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/playlists/{playlistId}/songs/{songId}/artwork", wrapper.GetSavedPlaylistSongArtwork) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/sets", wrapper.ListDiscoverySets) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/discover/sets", wrapper.CreateDiscoverySet) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/discover/sets/{setId}", wrapper.DeleteDiscoverySet) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/sets/{setId}", wrapper.GetDiscoverySet) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/me/discover/sets/{setId}", wrapper.UpdateDiscoverySet) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/discover/sets/{setId}/artists", wrapper.AddDiscoverySetArtist) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/discover/sets/{setId}/artists/{artistKey}", wrapper.RemoveDiscoverySetArtist) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/sets/{setId}/feed", wrapper.GetDiscoveryFeed) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/discover/feedback", wrapper.PostDiscoveryFeedback) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/blocks", wrapper.ListDiscoveryBlocks) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/discover/blocks", wrapper.BlockDiscoveryArtist) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/me/discover/blocks/{artistKey}", wrapper.UnblockDiscoveryArtist) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/artists", wrapper.SearchDiscoveryArtists) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/library", wrapper.GetDiscoveryLibrary) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/me/discover/library", wrapper.RefreshDiscoveryLibrary) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/preview/{deezerTrackId}", wrapper.GetDiscoveryPreview) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/me/discover/images/{kind}/{imageId}", wrapper.GetDiscoveryImage) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/round", wrapper.GetGameRound) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/rounds", wrapper.StartGameRound) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/rounds/{roundId}/answers", wrapper.AnswerGameRound) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/rounds/{roundId}/artwork", wrapper.GetGameRoundArtwork) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/clips/{clipId}", wrapper.GetGameClip) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/scores", wrapper.GetGameScores) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/games/queue", wrapper.GetQueueGames) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue", wrapper.StartQueueGame) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/entries", wrapper.EnterQueueGame) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/entries/{itemId}", wrapper.WithdrawQueueGameEntry) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/hint", wrapper.HintQueueGame) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/games/queue/{gameId}/close", wrapper.CloseQueueGame) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.RevokeGuestPass) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.GetGuestPass) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/guest-pass", wrapper.CreateGuestPass) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/guests", wrapper.ListGuests) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/guests/{userId}", wrapper.KickGuest) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/guest/{token}", wrapper.GetGuestInvite) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/guest/{token}", wrapper.JoinAsGuest) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms", wrapper.ListRooms) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms", wrapper.CreateRoom) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}", wrapper.DeleteRoom) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}", wrapper.GetRoom) + m.HandleFunc(http.MethodPatch+" "+options.BaseURL+"/rooms/{roomId}", wrapper.UpdateRoom) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/owner", wrapper.TransferRoom) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/members", wrapper.ListRoomMembers) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/members/{userId}", wrapper.RemoveRoomMember) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/members/{userId}", wrapper.AddRoomMember) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/admin-join", wrapper.JoinRoomAsAdmin) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/invites", wrapper.ListRoomInvites) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/invites", wrapper.CreateRoomInvite) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/invites/{code}", wrapper.RevokeRoomInvite) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/room-invites/{code}", wrapper.GetRoomInvite) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/room-invites/{code}", wrapper.UseRoomInvite) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/playback", wrapper.GetPlayback) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/playback", wrapper.ControlPlayback) + m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/rooms/{roomId}/player", wrapper.ReleasePlayer) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/rooms/{roomId}/player", wrapper.ClaimPlayer) + m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/rooms/{roomId}/player/report", wrapper.ReportPlayback) + m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/rooms/{roomId}/stream/{itemId}", wrapper.StreamQueueItem) -type FinishPasskeyLogindefaultJSONResponse struct { - Body Error - StatusCode int + return m } -func (response FinishPasskeyLogindefaultJSONResponse) VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error { +type CeremonyJSONResponse Ceremony - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) - return err +type ErrorJSONResponse Error + +type SignedInResponseHeaders struct { + SetCookie *string } +type SignedInJSONResponse struct { + Body Me -type SignupRequestObject struct { - Body *SignupJSONRequestBody + Headers SignedInResponseHeaders } -type SignupResponseObject interface { - VisitSignupResponse(w http.ResponseWriter) error +type GetBackupsRequestObject struct { } -type Signup201JSONResponse struct{ SignedInJSONResponse } +type GetBackupsResponseObject interface { + VisitGetBackupsResponse(w http.ResponseWriter) error +} -func (response Signup201JSONResponse) VisitSignupResponse(w http.ResponseWriter) error { +type GetBackups200JSONResponse BackupStatus + +func (response GetBackups200JSONResponse) VisitGetBackupsResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type SignupdefaultJSONResponse struct { +type GetBackupsdefaultJSONResponse struct { Body Error StatusCode int } -func (response SignupdefaultJSONResponse) VisitSignupResponse(w http.ResponseWriter) error { +func (response GetBackupsdefaultJSONResponse) VisitGetBackupsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -10812,34 +10936,33 @@ func (response SignupdefaultJSONResponse) VisitSignupResponse(w http.ResponseWri return err } -type BeginPasskeySignupRequestObject struct { - Body *BeginPasskeySignupJSONRequestBody +type CreateBackupRequestObject struct { } -type BeginPasskeySignupResponseObject interface { - VisitBeginPasskeySignupResponse(w http.ResponseWriter) error +type CreateBackupResponseObject interface { + VisitCreateBackupResponse(w http.ResponseWriter) error } -type BeginPasskeySignup200JSONResponse struct{ CeremonyJSONResponse } +type CreateBackup201JSONResponse Backup -func (response BeginPasskeySignup200JSONResponse) VisitBeginPasskeySignupResponse(w http.ResponseWriter) error { +func (response CreateBackup201JSONResponse) VisitCreateBackupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type BeginPasskeySignupdefaultJSONResponse struct { +type CreateBackupdefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginPasskeySignupdefaultJSONResponse) VisitBeginPasskeySignupResponse(w http.ResponseWriter) error { +func (response CreateBackupdefaultJSONResponse) VisitCreateBackupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -10851,37 +10974,34 @@ func (response BeginPasskeySignupdefaultJSONResponse) VisitBeginPasskeySignupRes return err } -type FinishPasskeySignupRequestObject struct { - Body *FinishPasskeySignupJSONRequestBody +type UpdateBackupScheduleRequestObject struct { + Body *UpdateBackupScheduleJSONRequestBody } -type FinishPasskeySignupResponseObject interface { - VisitFinishPasskeySignupResponse(w http.ResponseWriter) error +type UpdateBackupScheduleResponseObject interface { + VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error } -type FinishPasskeySignup201JSONResponse struct{ SignedInJSONResponse } +type UpdateBackupSchedule200JSONResponse BackupSchedule -func (response FinishPasskeySignup201JSONResponse) VisitFinishPasskeySignupResponse(w http.ResponseWriter) error { +func (response UpdateBackupSchedule200JSONResponse) VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type FinishPasskeySignupdefaultJSONResponse struct { +type UpdateBackupScheduledefaultJSONResponse struct { Body Error StatusCode int } -func (response FinishPasskeySignupdefaultJSONResponse) VisitFinishPasskeySignupResponse(w http.ResponseWriter) error { +func (response UpdateBackupScheduledefaultJSONResponse) VisitUpdateBackupScheduleResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -10893,27 +11013,28 @@ func (response FinishPasskeySignupdefaultJSONResponse) VisitFinishPasskeySignupR return err } -type LeaveDisplayRequestObject struct { +type DeleteBackupRequestObject struct { + Name string `json:"name"` } -type LeaveDisplayResponseObject interface { - VisitLeaveDisplayResponse(w http.ResponseWriter) error +type DeleteBackupResponseObject interface { + VisitDeleteBackupResponse(w http.ResponseWriter) error } -type LeaveDisplay204Response struct { +type DeleteBackup204Response struct { } -func (response LeaveDisplay204Response) VisitLeaveDisplayResponse(w http.ResponseWriter) error { +func (response DeleteBackup204Response) VisitDeleteBackupResponse(w http.ResponseWriter) error { w.WriteHeader(204) return nil } -type LeaveDisplaydefaultJSONResponse struct { +type DeleteBackupdefaultJSONResponse struct { Body Error StatusCode int } -func (response LeaveDisplaydefaultJSONResponse) VisitLeaveDisplayResponse(w http.ResponseWriter) error { +func (response DeleteBackupdefaultJSONResponse) VisitDeleteBackupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -10925,33 +11046,40 @@ func (response LeaveDisplaydefaultJSONResponse) VisitLeaveDisplayResponse(w http return err } -type GetDisplayRequestObject struct { +type DownloadBackupRequestObject struct { + Name string `json:"name"` } -type GetDisplayResponseObject interface { - VisitGetDisplayResponse(w http.ResponseWriter) error +type DownloadBackupResponseObject interface { + VisitDownloadBackupResponse(w http.ResponseWriter) error } -type GetDisplay200JSONResponse DisplayMe +type DownloadBackup200ApplicationvndSqlite3Response struct { + Body io.Reader + ContentLength int64 +} -func (response GetDisplay200JSONResponse) VisitGetDisplayResponse(w http.ResponseWriter) error { +func (response DownloadBackup200ApplicationvndSqlite3Response) VisitDownloadBackupResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + w.Header().Set("Content-Type", "application/vnd.sqlite3") + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - _, err := buf.WriteTo(w) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) return err } -type GetDisplaydefaultJSONResponse struct { +type DownloadBackupdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetDisplaydefaultJSONResponse) VisitGetDisplayResponse(w http.ResponseWriter) error { +func (response DownloadBackupdefaultJSONResponse) VisitDownloadBackupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -10963,16 +11091,16 @@ func (response GetDisplaydefaultJSONResponse) VisitGetDisplayResponse(w http.Res return err } -type PollDisplayPairingRequestObject struct { +type ListAllLinksRequestObject struct { } -type PollDisplayPairingResponseObject interface { - VisitPollDisplayPairingResponse(w http.ResponseWriter) error +type ListAllLinksResponseObject interface { + VisitListAllLinksResponse(w http.ResponseWriter) error } -type PollDisplayPairing200JSONResponse DisplayPairingStatus +type ListAllLinks200JSONResponse []ServiceLink -func (response PollDisplayPairing200JSONResponse) VisitPollDisplayPairingResponse(w http.ResponseWriter) error { +func (response ListAllLinks200JSONResponse) VisitListAllLinksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -10984,12 +11112,12 @@ func (response PollDisplayPairing200JSONResponse) VisitPollDisplayPairingRespons return err } -type PollDisplayPairingdefaultJSONResponse struct { +type ListAllLinksdefaultJSONResponse struct { Body Error StatusCode int } -func (response PollDisplayPairingdefaultJSONResponse) VisitPollDisplayPairingResponse(w http.ResponseWriter) error { +func (response ListAllLinksdefaultJSONResponse) VisitListAllLinksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11001,34 +11129,27 @@ func (response PollDisplayPairingdefaultJSONResponse) VisitPollDisplayPairingRes return err } -type BeginDisplayPairingRequestObject struct { - Body *BeginDisplayPairingJSONRequestBody +type CancelRestoreRequestObject struct { } -type BeginDisplayPairingResponseObject interface { - VisitBeginDisplayPairingResponse(w http.ResponseWriter) error +type CancelRestoreResponseObject interface { + VisitCancelRestoreResponse(w http.ResponseWriter) error } -type BeginDisplayPairing201JSONResponse DisplayPairing - -func (response BeginDisplayPairing201JSONResponse) VisitBeginDisplayPairingResponse(w http.ResponseWriter) error { +type CancelRestore204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) - _, err := buf.WriteTo(w) - return err +func (response CancelRestore204Response) VisitCancelRestoreResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type BeginDisplayPairingdefaultJSONResponse struct { +type CancelRestoredefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginDisplayPairingdefaultJSONResponse) VisitBeginDisplayPairingResponse(w http.ResponseWriter) error { +func (response CancelRestoredefaultJSONResponse) VisitCancelRestoreResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11040,17 +11161,17 @@ func (response BeginDisplayPairingdefaultJSONResponse) VisitBeginDisplayPairingR return err } -type GetGuestInviteRequestObject struct { - Token string `json:"token"` +type StageRestoreRequestObject struct { + Body *StageRestoreJSONRequestBody } -type GetGuestInviteResponseObject interface { - VisitGetGuestInviteResponse(w http.ResponseWriter) error +type StageRestoreResponseObject interface { + VisitStageRestoreResponse(w http.ResponseWriter) error } -type GetGuestInvite200JSONResponse GuestInvite +type StageRestore200JSONResponse PendingRestore -func (response GetGuestInvite200JSONResponse) VisitGetGuestInviteResponse(w http.ResponseWriter) error { +func (response StageRestore200JSONResponse) VisitStageRestoreResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11062,12 +11183,12 @@ func (response GetGuestInvite200JSONResponse) VisitGetGuestInviteResponse(w http return err } -type GetGuestInvitedefaultJSONResponse struct { +type StageRestoredefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGuestInvitedefaultJSONResponse) VisitGetGuestInviteResponse(w http.ResponseWriter) error { +func (response StageRestoredefaultJSONResponse) VisitStageRestoreResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11079,38 +11200,33 @@ func (response GetGuestInvitedefaultJSONResponse) VisitGetGuestInviteResponse(w return err } -type JoinAsGuestRequestObject struct { - Token string `json:"token"` - Body *JoinAsGuestJSONRequestBody +type ListActiveRoomsRequestObject struct { } -type JoinAsGuestResponseObject interface { - VisitJoinAsGuestResponse(w http.ResponseWriter) error +type ListActiveRoomsResponseObject interface { + VisitListActiveRoomsResponse(w http.ResponseWriter) error } -type JoinAsGuest201JSONResponse struct{ SignedInJSONResponse } +type ListActiveRooms200JSONResponse []RoomActivity -func (response JoinAsGuest201JSONResponse) VisitJoinAsGuestResponse(w http.ResponseWriter) error { +func (response ListActiveRooms200JSONResponse) VisitListActiveRoomsResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type JoinAsGuestdefaultJSONResponse struct { +type ListActiveRoomsdefaultJSONResponse struct { Body Error StatusCode int } -func (response JoinAsGuestdefaultJSONResponse) VisitJoinAsGuestResponse(w http.ResponseWriter) error { +func (response ListActiveRoomsdefaultJSONResponse) VisitListActiveRoomsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11122,16 +11238,17 @@ func (response JoinAsGuestdefaultJSONResponse) VisitJoinAsGuestResponse(w http.R return err } -type GetHealthRequestObject struct { +type GetRoomTasteRequestObject struct { + RoomId RoomId `json:"roomId"` } -type GetHealthResponseObject interface { - VisitGetHealthResponse(w http.ResponseWriter) error +type GetRoomTasteResponseObject interface { + VisitGetRoomTasteResponse(w http.ResponseWriter) error } -type GetHealth200JSONResponse Health +type GetRoomTaste200JSONResponse RoomTaste -func (response GetHealth200JSONResponse) VisitGetHealthResponse(w http.ResponseWriter) error { +func (response GetRoomTaste200JSONResponse) VisitGetRoomTasteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11143,16 +11260,33 @@ func (response GetHealth200JSONResponse) VisitGetHealthResponse(w http.ResponseW return err } -type ListInvitesRequestObject struct { +type GetRoomTastedefaultJSONResponse struct { + Body Error + StatusCode int } -type ListInvitesResponseObject interface { - VisitListInvitesResponse(w http.ResponseWriter) error +func (response GetRoomTastedefaultJSONResponse) VisitGetRoomTasteResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err } -type ListInvites200JSONResponse []Invite +type GetServerInfoRequestObject struct { +} -func (response ListInvites200JSONResponse) VisitListInvitesResponse(w http.ResponseWriter) error { +type GetServerInfoResponseObject interface { + VisitGetServerInfoResponse(w http.ResponseWriter) error +} + +type GetServerInfo200JSONResponse ServerInfo + +func (response GetServerInfo200JSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11164,12 +11298,12 @@ func (response ListInvites200JSONResponse) VisitListInvitesResponse(w http.Respo return err } -type ListInvitesdefaultJSONResponse struct { +type GetServerInfodefaultJSONResponse struct { Body Error StatusCode int } -func (response ListInvitesdefaultJSONResponse) VisitListInvitesResponse(w http.ResponseWriter) error { +func (response GetServerInfodefaultJSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11181,34 +11315,33 @@ func (response ListInvitesdefaultJSONResponse) VisitListInvitesResponse(w http.R return err } -type CreateInviteRequestObject struct { - Body *CreateInviteJSONRequestBody +type ListAllSessionsRequestObject struct { } -type CreateInviteResponseObject interface { - VisitCreateInviteResponse(w http.ResponseWriter) error +type ListAllSessionsResponseObject interface { + VisitListAllSessionsResponse(w http.ResponseWriter) error } -type CreateInvite201JSONResponse Invite +type ListAllSessions200JSONResponse []UserSession -func (response CreateInvite201JSONResponse) VisitCreateInviteResponse(w http.ResponseWriter) error { +func (response ListAllSessions200JSONResponse) VisitListAllSessionsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateInvitedefaultJSONResponse struct { +type ListAllSessionsdefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateInvitedefaultJSONResponse) VisitCreateInviteResponse(w http.ResponseWriter) error { +func (response ListAllSessionsdefaultJSONResponse) VisitListAllSessionsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11220,28 +11353,28 @@ func (response CreateInvitedefaultJSONResponse) VisitCreateInviteResponse(w http return err } -type DeleteInviteRequestObject struct { - Code InviteCode `json:"code"` +type RevokeSessionRequestObject struct { + Id string `json:"id"` } -type DeleteInviteResponseObject interface { - VisitDeleteInviteResponse(w http.ResponseWriter) error +type RevokeSessionResponseObject interface { + VisitRevokeSessionResponse(w http.ResponseWriter) error } -type DeleteInvite204Response struct { +type RevokeSession204Response struct { } -func (response DeleteInvite204Response) VisitDeleteInviteResponse(w http.ResponseWriter) error { +func (response RevokeSession204Response) VisitRevokeSessionResponse(w http.ResponseWriter) error { w.WriteHeader(204) return nil } -type DeleteInvitedefaultJSONResponse struct { +type RevokeSessiondefaultJSONResponse struct { Body Error StatusCode int } -func (response DeleteInvitedefaultJSONResponse) VisitDeleteInviteResponse(w http.ResponseWriter) error { +func (response RevokeSessiondefaultJSONResponse) VisitRevokeSessionResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11253,34 +11386,37 @@ func (response DeleteInvitedefaultJSONResponse) VisitDeleteInviteResponse(w http return err } -type GetInviteRequestObject struct { - Code InviteCode `json:"code"` +type LoginRequestObject struct { + Body *LoginJSONRequestBody } -type GetInviteResponseObject interface { - VisitGetInviteResponse(w http.ResponseWriter) error +type LoginResponseObject interface { + VisitLoginResponse(w http.ResponseWriter) error } -type GetInvite200JSONResponse InviteInfo +type Login200JSONResponse struct{ SignedInJSONResponse } -func (response GetInvite200JSONResponse) VisitGetInviteResponse(w http.ResponseWriter) error { +func (response Login200JSONResponse) VisitLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type GetInvitedefaultJSONResponse struct { +type LogindefaultJSONResponse struct { Body Error StatusCode int } -func (response GetInvitedefaultJSONResponse) VisitGetInviteResponse(w http.ResponseWriter) error { +func (response LogindefaultJSONResponse) VisitLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11292,34 +11428,35 @@ func (response GetInvitedefaultJSONResponse) VisitGetInviteResponse(w http.Respo return err } -type ListLinksRequestObject struct { - Params ListLinksParams +type LogoutRequestObject struct { } -type ListLinksResponseObject interface { - VisitListLinksResponse(w http.ResponseWriter) error +type LogoutResponseObject interface { + VisitLogoutResponse(w http.ResponseWriter) error } -type ListLinks200JSONResponse []ServiceLink +type Logout204ResponseHeaders struct { + SetCookie *string +} -func (response ListLinks200JSONResponse) VisitListLinksResponse(w http.ResponseWriter) error { +type Logout204Response struct { + Headers Logout204ResponseHeaders +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err +func (response Logout204Response) VisitLogoutResponse(w http.ResponseWriter) error { + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err + w.WriteHeader(204) + return nil } -type ListLinksdefaultJSONResponse struct { +type LogoutdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListLinksdefaultJSONResponse) VisitListLinksResponse(w http.ResponseWriter) error { +func (response LogoutdefaultJSONResponse) VisitLogoutResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11331,34 +11468,33 @@ func (response ListLinksdefaultJSONResponse) VisitListLinksResponse(w http.Respo return err } -type CreateLinkRequestObject struct { - Body *CreateLinkJSONRequestBody +type BeginPasskeyLoginRequestObject struct { } -type CreateLinkResponseObject interface { - VisitCreateLinkResponse(w http.ResponseWriter) error +type BeginPasskeyLoginResponseObject interface { + VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error } -type CreateLink201JSONResponse ServiceLink +type BeginPasskeyLogin200JSONResponse struct{ CeremonyJSONResponse } -func (response CreateLink201JSONResponse) VisitCreateLinkResponse(w http.ResponseWriter) error { +func (response BeginPasskeyLogin200JSONResponse) VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateLinkdefaultJSONResponse struct { +type BeginPasskeyLogindefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateLinkdefaultJSONResponse) VisitCreateLinkResponse(w http.ResponseWriter) error { +func (response BeginPasskeyLogindefaultJSONResponse) VisitBeginPasskeyLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11370,36 +11506,37 @@ func (response CreateLinkdefaultJSONResponse) VisitCreateLinkResponse(w http.Res return err } -type BeginOAuthLinkRequestObject struct { - Body *BeginOAuthLinkJSONRequestBody +type FinishPasskeyLoginRequestObject struct { + Body *FinishPasskeyLoginJSONRequestBody } -type BeginOAuthLinkResponseObject interface { - VisitBeginOAuthLinkResponse(w http.ResponseWriter) error +type FinishPasskeyLoginResponseObject interface { + VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error } -type BeginOAuthLink200JSONResponse struct { - AuthUrl string `json:"authUrl"` -} +type FinishPasskeyLogin200JSONResponse struct{ SignedInJSONResponse } -func (response BeginOAuthLink200JSONResponse) VisitBeginOAuthLinkResponse(w http.ResponseWriter) error { +func (response FinishPasskeyLogin200JSONResponse) VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type BeginOAuthLinkdefaultJSONResponse struct { +type FinishPasskeyLogindefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginOAuthLinkdefaultJSONResponse) VisitBeginOAuthLinkResponse(w http.ResponseWriter) error { +func (response FinishPasskeyLogindefaultJSONResponse) VisitFinishPasskeyLoginResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11411,52 +11548,37 @@ func (response BeginOAuthLinkdefaultJSONResponse) VisitBeginOAuthLinkResponse(w return err } -type CompleteOAuthLinkRequestObject struct { - Params CompleteOAuthLinkParams +type SignupRequestObject struct { + Body *SignupJSONRequestBody } -type CompleteOAuthLinkResponseObject interface { - VisitCompleteOAuthLinkResponse(w http.ResponseWriter) error +type SignupResponseObject interface { + VisitSignupResponse(w http.ResponseWriter) error } -type CompleteOAuthLink303ResponseHeaders struct { - Location *string -} +type Signup201JSONResponse struct{ SignedInJSONResponse } -type CompleteOAuthLink303Response struct { - Headers CompleteOAuthLink303ResponseHeaders -} +func (response Signup201JSONResponse) VisitSignupResponse(w http.ResponseWriter) error { -func (response CompleteOAuthLink303Response) VisitCompleteOAuthLinkResponse(w http.ResponseWriter) error { - if response.Headers.Location != nil { - w.Header().Set("Location", fmt.Sprint(*response.Headers.Location)) + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err } - w.WriteHeader(303) - return nil -} - -type UnlinkRequestObject struct { - Id string `json:"id"` -} - -type UnlinkResponseObject interface { - VisitUnlinkResponse(w http.ResponseWriter) error -} - -type Unlink204Response struct { -} - -func (response Unlink204Response) VisitUnlinkResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil + w.Header().Set("Content-Type", "application/json") + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } + w.WriteHeader(201) + _, err := buf.WriteTo(w) + return err } -type UnlinkdefaultJSONResponse struct { +type SignupdefaultJSONResponse struct { Body Error StatusCode int } -func (response UnlinkdefaultJSONResponse) VisitUnlinkResponse(w http.ResponseWriter) error { +func (response SignupdefaultJSONResponse) VisitSignupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11468,18 +11590,17 @@ func (response UnlinkdefaultJSONResponse) VisitUnlinkResponse(w http.ResponseWri return err } -type UpdateLinkRequestObject struct { - Id string `json:"id"` - Body *UpdateLinkJSONRequestBody +type BeginPasskeySignupRequestObject struct { + Body *BeginPasskeySignupJSONRequestBody } -type UpdateLinkResponseObject interface { - VisitUpdateLinkResponse(w http.ResponseWriter) error +type BeginPasskeySignupResponseObject interface { + VisitBeginPasskeySignupResponse(w http.ResponseWriter) error } -type UpdateLink200JSONResponse ServiceLink +type BeginPasskeySignup200JSONResponse struct{ CeremonyJSONResponse } -func (response UpdateLink200JSONResponse) VisitUpdateLinkResponse(w http.ResponseWriter) error { +func (response BeginPasskeySignup200JSONResponse) VisitBeginPasskeySignupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11491,12 +11612,12 @@ func (response UpdateLink200JSONResponse) VisitUpdateLinkResponse(w http.Respons return err } -type UpdateLinkdefaultJSONResponse struct { +type BeginPasskeySignupdefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateLinkdefaultJSONResponse) VisitUpdateLinkResponse(w http.ResponseWriter) error { +func (response BeginPasskeySignupdefaultJSONResponse) VisitBeginPasskeySignupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11508,35 +11629,37 @@ func (response UpdateLinkdefaultJSONResponse) VisitUpdateLinkResponse(w http.Res return err } -type RelinkRequestObject struct { - Id string `json:"id"` - Body *RelinkJSONRequestBody +type FinishPasskeySignupRequestObject struct { + Body *FinishPasskeySignupJSONRequestBody } -type RelinkResponseObject interface { - VisitRelinkResponse(w http.ResponseWriter) error +type FinishPasskeySignupResponseObject interface { + VisitFinishPasskeySignupResponse(w http.ResponseWriter) error } -type Relink200JSONResponse ServiceLink +type FinishPasskeySignup201JSONResponse struct{ SignedInJSONResponse } -func (response Relink200JSONResponse) VisitRelinkResponse(w http.ResponseWriter) error { +func (response FinishPasskeySignup201JSONResponse) VisitFinishPasskeySignupResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type RelinkdefaultJSONResponse struct { +type FinishPasskeySignupdefaultJSONResponse struct { Body Error StatusCode int } -func (response RelinkdefaultJSONResponse) VisitRelinkResponse(w http.ResponseWriter) error { +func (response FinishPasskeySignupdefaultJSONResponse) VisitFinishPasskeySignupResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11548,35 +11671,27 @@ func (response RelinkdefaultJSONResponse) VisitRelinkResponse(w http.ResponseWri return err } -type GetAlbumRequestObject struct { - Id string `json:"id"` - AlbumId string `json:"albumId"` +type LeaveDisplayRequestObject struct { } -type GetAlbumResponseObject interface { - VisitGetAlbumResponse(w http.ResponseWriter) error +type LeaveDisplayResponseObject interface { + VisitLeaveDisplayResponse(w http.ResponseWriter) error } -type GetAlbum200JSONResponse AlbumDetail - -func (response GetAlbum200JSONResponse) VisitGetAlbumResponse(w http.ResponseWriter) error { +type LeaveDisplay204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response LeaveDisplay204Response) VisitLeaveDisplayResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type GetAlbumdefaultJSONResponse struct { +type LeaveDisplaydefaultJSONResponse struct { Body Error StatusCode int } -func (response GetAlbumdefaultJSONResponse) VisitGetAlbumResponse(w http.ResponseWriter) error { +func (response LeaveDisplaydefaultJSONResponse) VisitLeaveDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11588,18 +11703,16 @@ func (response GetAlbumdefaultJSONResponse) VisitGetAlbumResponse(w http.Respons return err } -type GetAlbumAboutRequestObject struct { - Id string `json:"id"` - AlbumId string `json:"albumId"` +type GetDisplayRequestObject struct { } -type GetAlbumAboutResponseObject interface { - VisitGetAlbumAboutResponse(w http.ResponseWriter) error +type GetDisplayResponseObject interface { + VisitGetDisplayResponse(w http.ResponseWriter) error } -type GetAlbumAbout200JSONResponse AlbumAbout +type GetDisplay200JSONResponse DisplayMe -func (response GetAlbumAbout200JSONResponse) VisitGetAlbumAboutResponse(w http.ResponseWriter) error { +func (response GetDisplay200JSONResponse) VisitGetDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11611,12 +11724,12 @@ func (response GetAlbumAbout200JSONResponse) VisitGetAlbumAboutResponse(w http.R return err } -type GetAlbumAboutdefaultJSONResponse struct { +type GetDisplaydefaultJSONResponse struct { Body Error StatusCode int } -func (response GetAlbumAboutdefaultJSONResponse) VisitGetAlbumAboutResponse(w http.ResponseWriter) error { +func (response GetDisplaydefaultJSONResponse) VisitGetDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11628,18 +11741,16 @@ func (response GetAlbumAboutdefaultJSONResponse) VisitGetAlbumAboutResponse(w ht return err } -type GetArtistRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` +type PollDisplayPairingRequestObject struct { } -type GetArtistResponseObject interface { - VisitGetArtistResponse(w http.ResponseWriter) error +type PollDisplayPairingResponseObject interface { + VisitPollDisplayPairingResponse(w http.ResponseWriter) error } -type GetArtist200JSONResponse ArtistDetail +type PollDisplayPairing200JSONResponse DisplayPairingStatus -func (response GetArtist200JSONResponse) VisitGetArtistResponse(w http.ResponseWriter) error { +func (response PollDisplayPairing200JSONResponse) VisitPollDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11651,12 +11762,12 @@ func (response GetArtist200JSONResponse) VisitGetArtistResponse(w http.ResponseW return err } -type GetArtistdefaultJSONResponse struct { +type PollDisplayPairingdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistdefaultJSONResponse) VisitGetArtistResponse(w http.ResponseWriter) error { +func (response PollDisplayPairingdefaultJSONResponse) VisitPollDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11668,35 +11779,34 @@ func (response GetArtistdefaultJSONResponse) VisitGetArtistResponse(w http.Respo return err } -type GetArtistAboutRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` +type BeginDisplayPairingRequestObject struct { + Body *BeginDisplayPairingJSONRequestBody } -type GetArtistAboutResponseObject interface { - VisitGetArtistAboutResponse(w http.ResponseWriter) error +type BeginDisplayPairingResponseObject interface { + VisitBeginDisplayPairingResponse(w http.ResponseWriter) error } -type GetArtistAbout200JSONResponse ArtistAbout +type BeginDisplayPairing201JSONResponse DisplayPairing -func (response GetArtistAbout200JSONResponse) VisitGetArtistAboutResponse(w http.ResponseWriter) error { +func (response BeginDisplayPairing201JSONResponse) VisitBeginDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type GetArtistAboutdefaultJSONResponse struct { +type BeginDisplayPairingdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistAboutdefaultJSONResponse) VisitGetArtistAboutResponse(w http.ResponseWriter) error { +func (response BeginDisplayPairingdefaultJSONResponse) VisitBeginDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11708,18 +11818,17 @@ func (response GetArtistAboutdefaultJSONResponse) VisitGetArtistAboutResponse(w return err } -type GetArtistElsewhereRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` +type GetGuestInviteRequestObject struct { + Token string `json:"token"` } -type GetArtistElsewhereResponseObject interface { - VisitGetArtistElsewhereResponse(w http.ResponseWriter) error +type GetGuestInviteResponseObject interface { + VisitGetGuestInviteResponse(w http.ResponseWriter) error } -type GetArtistElsewhere200JSONResponse []ArtistElsewhere +type GetGuestInvite200JSONResponse GuestInvite -func (response GetArtistElsewhere200JSONResponse) VisitGetArtistElsewhereResponse(w http.ResponseWriter) error { +func (response GetGuestInvite200JSONResponse) VisitGetGuestInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11731,12 +11840,12 @@ func (response GetArtistElsewhere200JSONResponse) VisitGetArtistElsewhereRespons return err } -type GetArtistElsewheredefaultJSONResponse struct { +type GetGuestInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistElsewheredefaultJSONResponse) VisitGetArtistElsewhereResponse(w http.ResponseWriter) error { +func (response GetGuestInvitedefaultJSONResponse) VisitGetGuestInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11748,35 +11857,38 @@ func (response GetArtistElsewheredefaultJSONResponse) VisitGetArtistElsewhereRes return err } -type GetArtistRelatedRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` +type JoinAsGuestRequestObject struct { + Token string `json:"token"` + Body *JoinAsGuestJSONRequestBody } -type GetArtistRelatedResponseObject interface { - VisitGetArtistRelatedResponse(w http.ResponseWriter) error +type JoinAsGuestResponseObject interface { + VisitJoinAsGuestResponse(w http.ResponseWriter) error } -type GetArtistRelated200JSONResponse RelatedMusic +type JoinAsGuest201JSONResponse struct{ SignedInJSONResponse } -func (response GetArtistRelated200JSONResponse) VisitGetArtistRelatedResponse(w http.ResponseWriter) error { +func (response JoinAsGuest201JSONResponse) VisitJoinAsGuestResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type GetArtistRelateddefaultJSONResponse struct { +type JoinAsGuestdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistRelateddefaultJSONResponse) VisitGetArtistRelatedResponse(w http.ResponseWriter) error { +func (response JoinAsGuestdefaultJSONResponse) VisitJoinAsGuestResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11788,19 +11900,16 @@ func (response GetArtistRelateddefaultJSONResponse) VisitGetArtistRelatedRespons return err } -type GetArtistShuffleRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` - Params GetArtistShuffleParams +type GetHealthRequestObject struct { } -type GetArtistShuffleResponseObject interface { - VisitGetArtistShuffleResponse(w http.ResponseWriter) error +type GetHealthResponseObject interface { + VisitGetHealthResponse(w http.ResponseWriter) error } -type GetArtistShuffle200JSONResponse []TrackResult +type GetHealth200JSONResponse Health -func (response GetArtistShuffle200JSONResponse) VisitGetArtistShuffleResponse(w http.ResponseWriter) error { +func (response GetHealth200JSONResponse) VisitGetHealthResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11812,12 +11921,33 @@ func (response GetArtistShuffle200JSONResponse) VisitGetArtistShuffleResponse(w return err } -type GetArtistShuffledefaultJSONResponse struct { +type ListInvitesRequestObject struct { +} + +type ListInvitesResponseObject interface { + VisitListInvitesResponse(w http.ResponseWriter) error +} + +type ListInvites200JSONResponse []Invite + +func (response ListInvites200JSONResponse) VisitListInvitesResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ListInvitesdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistShuffledefaultJSONResponse) VisitGetArtistShuffleResponse(w http.ResponseWriter) error { +func (response ListInvitesdefaultJSONResponse) VisitListInvitesResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11829,35 +11959,34 @@ func (response GetArtistShuffledefaultJSONResponse) VisitGetArtistShuffleRespons return err } -type GetArtistTracksRequestObject struct { - Id string `json:"id"` - ArtistId string `json:"artistId"` +type CreateInviteRequestObject struct { + Body *CreateInviteJSONRequestBody } -type GetArtistTracksResponseObject interface { - VisitGetArtistTracksResponse(w http.ResponseWriter) error +type CreateInviteResponseObject interface { + VisitCreateInviteResponse(w http.ResponseWriter) error } -type GetArtistTracks200JSONResponse ArtistTracks +type CreateInvite201JSONResponse Invite -func (response GetArtistTracks200JSONResponse) VisitGetArtistTracksResponse(w http.ResponseWriter) error { +func (response CreateInvite201JSONResponse) VisitCreateInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type GetArtistTracksdefaultJSONResponse struct { +type CreateInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetArtistTracksdefaultJSONResponse) VisitGetArtistTracksResponse(w http.ResponseWriter) error { +func (response CreateInvitedefaultJSONResponse) VisitCreateInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11869,42 +11998,28 @@ func (response GetArtistTracksdefaultJSONResponse) VisitGetArtistTracksResponse( return err } -type GetLinkArtworkRequestObject struct { - Id string `json:"id"` - Params GetLinkArtworkParams +type DeleteInviteRequestObject struct { + Code InviteCode `json:"code"` } -type GetLinkArtworkResponseObject interface { - VisitGetLinkArtworkResponse(w http.ResponseWriter) error +type DeleteInviteResponseObject interface { + VisitDeleteInviteResponse(w http.ResponseWriter) error } -type GetLinkArtwork200ImageResponse struct { - Body io.Reader - ContentType string - ContentLength int64 +type DeleteInvite204Response struct { } -func (response GetLinkArtwork200ImageResponse) VisitGetLinkArtworkResponse(w http.ResponseWriter) error { - - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(200) - - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() - } - _, err := io.Copy(w, response.Body) - return err +func (response DeleteInvite204Response) VisitDeleteInviteResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type GetLinkArtworkdefaultJSONResponse struct { +type DeleteInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetLinkArtworkdefaultJSONResponse) VisitGetLinkArtworkResponse(w http.ResponseWriter) error { +func (response DeleteInvitedefaultJSONResponse) VisitDeleteInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11916,17 +12031,17 @@ func (response GetLinkArtworkdefaultJSONResponse) VisitGetLinkArtworkResponse(w return err } -type GetCollectionRequestObject struct { - Id string `json:"id"` +type GetInviteRequestObject struct { + Code InviteCode `json:"code"` } -type GetCollectionResponseObject interface { - VisitGetCollectionResponse(w http.ResponseWriter) error +type GetInviteResponseObject interface { + VisitGetInviteResponse(w http.ResponseWriter) error } -type GetCollection200JSONResponse LinkCollection +type GetInvite200JSONResponse InviteInfo -func (response GetCollection200JSONResponse) VisitGetCollectionResponse(w http.ResponseWriter) error { +func (response GetInvite200JSONResponse) VisitGetInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11938,12 +12053,12 @@ func (response GetCollection200JSONResponse) VisitGetCollectionResponse(w http.R return err } -type GetCollectiondefaultJSONResponse struct { +type GetInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetCollectiondefaultJSONResponse) VisitGetCollectionResponse(w http.ResponseWriter) error { +func (response GetInvitedefaultJSONResponse) VisitGetInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11955,18 +12070,17 @@ func (response GetCollectiondefaultJSONResponse) VisitGetCollectionResponse(w ht return err } -type GetGenreRequestObject struct { - Id string `json:"id"` - Params GetGenreParams +type ListLinksRequestObject struct { + Params ListLinksParams } -type GetGenreResponseObject interface { - VisitGetGenreResponse(w http.ResponseWriter) error +type ListLinksResponseObject interface { + VisitListLinksResponse(w http.ResponseWriter) error } -type GetGenre200JSONResponse GenreDetail +type ListLinks200JSONResponse []ServiceLink -func (response GetGenre200JSONResponse) VisitGetGenreResponse(w http.ResponseWriter) error { +func (response ListLinks200JSONResponse) VisitListLinksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -11978,12 +12092,12 @@ func (response GetGenre200JSONResponse) VisitGetGenreResponse(w http.ResponseWri return err } -type GetGenredefaultJSONResponse struct { +type ListLinksdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGenredefaultJSONResponse) VisitGetGenreResponse(w http.ResponseWriter) error { +func (response ListLinksdefaultJSONResponse) VisitListLinksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -11995,35 +12109,34 @@ func (response GetGenredefaultJSONResponse) VisitGetGenreResponse(w http.Respons return err } -type ListPlaylistsRequestObject struct { - Id string `json:"id"` - Params ListPlaylistsParams +type CreateLinkRequestObject struct { + Body *CreateLinkJSONRequestBody } -type ListPlaylistsResponseObject interface { - VisitListPlaylistsResponse(w http.ResponseWriter) error +type CreateLinkResponseObject interface { + VisitCreateLinkResponse(w http.ResponseWriter) error } -type ListPlaylists200JSONResponse PlaylistList +type CreateLink201JSONResponse ServiceLink -func (response ListPlaylists200JSONResponse) VisitListPlaylistsResponse(w http.ResponseWriter) error { +func (response CreateLink201JSONResponse) VisitCreateLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type ListPlaylistsdefaultJSONResponse struct { +type CreateLinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListPlaylistsdefaultJSONResponse) VisitListPlaylistsResponse(w http.ResponseWriter) error { +func (response CreateLinkdefaultJSONResponse) VisitCreateLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12035,19 +12148,19 @@ func (response ListPlaylistsdefaultJSONResponse) VisitListPlaylistsResponse(w ht return err } -type GetPlaylistTracksRequestObject struct { - Id string `json:"id"` - PlaylistId string `json:"playlistId"` - Params GetPlaylistTracksParams +type BeginOAuthLinkRequestObject struct { + Body *BeginOAuthLinkJSONRequestBody } -type GetPlaylistTracksResponseObject interface { - VisitGetPlaylistTracksResponse(w http.ResponseWriter) error +type BeginOAuthLinkResponseObject interface { + VisitBeginOAuthLinkResponse(w http.ResponseWriter) error } -type GetPlaylistTracks200JSONResponse PlaylistTracks +type BeginOAuthLink200JSONResponse struct { + AuthUrl string `json:"authUrl"` +} -func (response GetPlaylistTracks200JSONResponse) VisitGetPlaylistTracksResponse(w http.ResponseWriter) error { +func (response BeginOAuthLink200JSONResponse) VisitBeginOAuthLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12059,12 +12172,12 @@ func (response GetPlaylistTracks200JSONResponse) VisitGetPlaylistTracksResponse( return err } -type GetPlaylistTracksdefaultJSONResponse struct { +type BeginOAuthLinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetPlaylistTracksdefaultJSONResponse) VisitGetPlaylistTracksResponse(w http.ResponseWriter) error { +func (response BeginOAuthLinkdefaultJSONResponse) VisitBeginOAuthLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12076,35 +12189,52 @@ func (response GetPlaylistTracksdefaultJSONResponse) VisitGetPlaylistTracksRespo return err } -type GetTrackLyricsRequestObject struct { - Id string `json:"id"` - TrackId string `json:"trackId"` +type CompleteOAuthLinkRequestObject struct { + Params CompleteOAuthLinkParams } -type GetTrackLyricsResponseObject interface { - VisitGetTrackLyricsResponse(w http.ResponseWriter) error +type CompleteOAuthLinkResponseObject interface { + VisitCompleteOAuthLinkResponse(w http.ResponseWriter) error } -type GetTrackLyrics200JSONResponse Lyrics +type CompleteOAuthLink303ResponseHeaders struct { + Location *string +} -func (response GetTrackLyrics200JSONResponse) VisitGetTrackLyricsResponse(w http.ResponseWriter) error { +type CompleteOAuthLink303Response struct { + Headers CompleteOAuthLink303ResponseHeaders +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err +func (response CompleteOAuthLink303Response) VisitCompleteOAuthLinkResponse(w http.ResponseWriter) error { + if response.Headers.Location != nil { + w.Header().Set("Location", fmt.Sprint(*response.Headers.Location)) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err + w.WriteHeader(303) + return nil } -type GetTrackLyricsdefaultJSONResponse struct { +type UnlinkRequestObject struct { + Id string `json:"id"` +} + +type UnlinkResponseObject interface { + VisitUnlinkResponse(w http.ResponseWriter) error +} + +type Unlink204Response struct { +} + +func (response Unlink204Response) VisitUnlinkResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type UnlinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetTrackLyricsdefaultJSONResponse) VisitGetTrackLyricsResponse(w http.ResponseWriter) error { +func (response UnlinkdefaultJSONResponse) VisitUnlinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12116,16 +12246,18 @@ func (response GetTrackLyricsdefaultJSONResponse) VisitGetTrackLyricsResponse(w return err } -type GetMeRequestObject struct { +type UpdateLinkRequestObject struct { + Id string `json:"id"` + Body *UpdateLinkJSONRequestBody } -type GetMeResponseObject interface { - VisitGetMeResponse(w http.ResponseWriter) error +type UpdateLinkResponseObject interface { + VisitUpdateLinkResponse(w http.ResponseWriter) error } -type GetMe200JSONResponse Me +type UpdateLink200JSONResponse ServiceLink -func (response GetMe200JSONResponse) VisitGetMeResponse(w http.ResponseWriter) error { +func (response UpdateLink200JSONResponse) VisitUpdateLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12137,12 +12269,12 @@ func (response GetMe200JSONResponse) VisitGetMeResponse(w http.ResponseWriter) e return err } -type GetMedefaultJSONResponse struct { +type UpdateLinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetMedefaultJSONResponse) VisitGetMeResponse(w http.ResponseWriter) error { +func (response UpdateLinkdefaultJSONResponse) VisitUpdateLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12154,17 +12286,18 @@ func (response GetMedefaultJSONResponse) VisitGetMeResponse(w http.ResponseWrite return err } -type UpdateMeRequestObject struct { - Body *UpdateMeJSONRequestBody +type RelinkRequestObject struct { + Id string `json:"id"` + Body *RelinkJSONRequestBody } -type UpdateMeResponseObject interface { - VisitUpdateMeResponse(w http.ResponseWriter) error +type RelinkResponseObject interface { + VisitRelinkResponse(w http.ResponseWriter) error } -type UpdateMe200JSONResponse Me +type Relink200JSONResponse ServiceLink -func (response UpdateMe200JSONResponse) VisitUpdateMeResponse(w http.ResponseWriter) error { +func (response Relink200JSONResponse) VisitRelinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12176,12 +12309,12 @@ func (response UpdateMe200JSONResponse) VisitUpdateMeResponse(w http.ResponseWri return err } -type UpdateMedefaultJSONResponse struct { +type RelinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateMedefaultJSONResponse) VisitUpdateMeResponse(w http.ResponseWriter) error { +func (response RelinkdefaultJSONResponse) VisitRelinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12193,18 +12326,18 @@ func (response UpdateMedefaultJSONResponse) VisitUpdateMeResponse(w http.Respons return err } -type UploadAvatarRequestObject struct { - ContentType string - Body io.Reader +type GetAlbumRequestObject struct { + Id string `json:"id"` + AlbumId string `json:"albumId"` } -type UploadAvatarResponseObject interface { - VisitUploadAvatarResponse(w http.ResponseWriter) error +type GetAlbumResponseObject interface { + VisitGetAlbumResponse(w http.ResponseWriter) error } -type UploadAvatar200JSONResponse Me +type GetAlbum200JSONResponse AlbumDetail -func (response UploadAvatar200JSONResponse) VisitUploadAvatarResponse(w http.ResponseWriter) error { +func (response GetAlbum200JSONResponse) VisitGetAlbumResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12216,12 +12349,12 @@ func (response UploadAvatar200JSONResponse) VisitUploadAvatarResponse(w http.Res return err } -type UploadAvatardefaultJSONResponse struct { +type GetAlbumdefaultJSONResponse struct { Body Error StatusCode int } -func (response UploadAvatardefaultJSONResponse) VisitUploadAvatarResponse(w http.ResponseWriter) error { +func (response GetAlbumdefaultJSONResponse) VisitGetAlbumResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12233,36 +12366,35 @@ func (response UploadAvatardefaultJSONResponse) VisitUploadAvatarResponse(w http return err } -type DeleteMeRequestObject struct { - Body *DeleteMeJSONRequestBody +type GetAlbumAboutRequestObject struct { + Id string `json:"id"` + AlbumId string `json:"albumId"` } -type DeleteMeResponseObject interface { - VisitDeleteMeResponse(w http.ResponseWriter) error +type GetAlbumAboutResponseObject interface { + VisitGetAlbumAboutResponse(w http.ResponseWriter) error } -type DeleteMe204ResponseHeaders struct { - SetCookie *string -} +type GetAlbumAbout200JSONResponse AlbumAbout -type DeleteMe204Response struct { - Headers DeleteMe204ResponseHeaders -} +func (response GetAlbumAbout200JSONResponse) VisitGetAlbumAboutResponse(w http.ResponseWriter) error { -func (response DeleteMe204Response) VisitDeleteMeResponse(w http.ResponseWriter) error { - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } - w.WriteHeader(204) - return nil + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type DeleteMedefaultJSONResponse struct { +type GetAlbumAboutdefaultJSONResponse struct { Body Error StatusCode int } -func (response DeleteMedefaultJSONResponse) VisitDeleteMeResponse(w http.ResponseWriter) error { +func (response GetAlbumAboutdefaultJSONResponse) VisitGetAlbumAboutResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12274,16 +12406,18 @@ func (response DeleteMedefaultJSONResponse) VisitDeleteMeResponse(w http.Respons return err } -type ListPasskeysRequestObject struct { +type GetArtistRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` } -type ListPasskeysResponseObject interface { - VisitListPasskeysResponse(w http.ResponseWriter) error +type GetArtistResponseObject interface { + VisitGetArtistResponse(w http.ResponseWriter) error } -type ListPasskeys200JSONResponse []Passkey +type GetArtist200JSONResponse ArtistDetail -func (response ListPasskeys200JSONResponse) VisitListPasskeysResponse(w http.ResponseWriter) error { +func (response GetArtist200JSONResponse) VisitGetArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12295,12 +12429,12 @@ func (response ListPasskeys200JSONResponse) VisitListPasskeysResponse(w http.Res return err } -type ListPasskeysdefaultJSONResponse struct { +type GetArtistdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListPasskeysdefaultJSONResponse) VisitListPasskeysResponse(w http.ResponseWriter) error { +func (response GetArtistdefaultJSONResponse) VisitGetArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12312,16 +12446,18 @@ func (response ListPasskeysdefaultJSONResponse) VisitListPasskeysResponse(w http return err } -type BeginAddPasskeyRequestObject struct { +type GetArtistAboutRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` } -type BeginAddPasskeyResponseObject interface { - VisitBeginAddPasskeyResponse(w http.ResponseWriter) error +type GetArtistAboutResponseObject interface { + VisitGetArtistAboutResponse(w http.ResponseWriter) error } -type BeginAddPasskey200JSONResponse struct{ CeremonyJSONResponse } +type GetArtistAbout200JSONResponse ArtistAbout -func (response BeginAddPasskey200JSONResponse) VisitBeginAddPasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistAbout200JSONResponse) VisitGetArtistAboutResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12333,12 +12469,12 @@ func (response BeginAddPasskey200JSONResponse) VisitBeginAddPasskeyResponse(w ht return err } -type BeginAddPasskeydefaultJSONResponse struct { +type GetArtistAboutdefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginAddPasskeydefaultJSONResponse) VisitBeginAddPasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistAboutdefaultJSONResponse) VisitGetArtistAboutResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12350,34 +12486,35 @@ func (response BeginAddPasskeydefaultJSONResponse) VisitBeginAddPasskeyResponse( return err } -type FinishAddPasskeyRequestObject struct { - Body *FinishAddPasskeyJSONRequestBody +type GetArtistElsewhereRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` } -type FinishAddPasskeyResponseObject interface { - VisitFinishAddPasskeyResponse(w http.ResponseWriter) error +type GetArtistElsewhereResponseObject interface { + VisitGetArtistElsewhereResponse(w http.ResponseWriter) error } -type FinishAddPasskey201JSONResponse Passkey +type GetArtistElsewhere200JSONResponse []ArtistElsewhere -func (response FinishAddPasskey201JSONResponse) VisitFinishAddPasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistElsewhere200JSONResponse) VisitGetArtistElsewhereResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type FinishAddPasskeydefaultJSONResponse struct { +type GetArtistElsewheredefaultJSONResponse struct { Body Error StatusCode int } -func (response FinishAddPasskeydefaultJSONResponse) VisitFinishAddPasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistElsewheredefaultJSONResponse) VisitGetArtistElsewhereResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12389,62 +12526,35 @@ func (response FinishAddPasskeydefaultJSONResponse) VisitFinishAddPasskeyRespons return err } -type DeletePasskeyRequestObject struct { - Id string `json:"id"` -} - -type DeletePasskeyResponseObject interface { - VisitDeletePasskeyResponse(w http.ResponseWriter) error -} - -type DeletePasskey204Response struct { +type GetArtistRelatedRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` } -func (response DeletePasskey204Response) VisitDeletePasskeyResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +type GetArtistRelatedResponseObject interface { + VisitGetArtistRelatedResponse(w http.ResponseWriter) error } -type DeletePasskeydefaultJSONResponse struct { - Body Error - StatusCode int -} +type GetArtistRelated200JSONResponse RelatedMusic -func (response DeletePasskeydefaultJSONResponse) VisitDeletePasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistRelated200JSONResponse) VisitGetArtistRelatedResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type RenamePasskeyRequestObject struct { - Id string `json:"id"` - Body *RenamePasskeyJSONRequestBody -} - -type RenamePasskeyResponseObject interface { - VisitRenamePasskeyResponse(w http.ResponseWriter) error -} - -type RenamePasskey204Response struct { -} - -func (response RenamePasskey204Response) VisitRenamePasskeyResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} - -type RenamePasskeydefaultJSONResponse struct { +type GetArtistRelateddefaultJSONResponse struct { Body Error StatusCode int } -func (response RenamePasskeydefaultJSONResponse) VisitRenamePasskeyResponse(w http.ResponseWriter) error { +func (response GetArtistRelateddefaultJSONResponse) VisitGetArtistRelatedResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12456,60 +12566,36 @@ func (response RenamePasskeydefaultJSONResponse) VisitRenamePasskeyResponse(w ht return err } -type DeletePasswordRequestObject struct { -} - -type DeletePasswordResponseObject interface { - VisitDeletePasswordResponse(w http.ResponseWriter) error -} - -type DeletePassword204Response struct { +type GetArtistShuffleRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` + Params GetArtistShuffleParams } -func (response DeletePassword204Response) VisitDeletePasswordResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +type GetArtistShuffleResponseObject interface { + VisitGetArtistShuffleResponse(w http.ResponseWriter) error } -type DeletePassworddefaultJSONResponse struct { - Body Error - StatusCode int -} +type GetArtistShuffle200JSONResponse []TrackResult -func (response DeletePassworddefaultJSONResponse) VisitDeletePasswordResponse(w http.ResponseWriter) error { +func (response GetArtistShuffle200JSONResponse) VisitGetArtistShuffleResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type SetPasswordRequestObject struct { - Body *SetPasswordJSONRequestBody -} - -type SetPasswordResponseObject interface { - VisitSetPasswordResponse(w http.ResponseWriter) error -} - -type SetPassword204Response struct { -} - -func (response SetPassword204Response) VisitSetPasswordResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} - -type SetPassworddefaultJSONResponse struct { +type GetArtistShuffledefaultJSONResponse struct { Body Error StatusCode int } -func (response SetPassworddefaultJSONResponse) VisitSetPasswordResponse(w http.ResponseWriter) error { +func (response GetArtistShuffledefaultJSONResponse) VisitGetArtistShuffleResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12521,16 +12607,18 @@ func (response SetPassworddefaultJSONResponse) VisitSetPasswordResponse(w http.R return err } -type BeginReauthRequestObject struct { +type GetArtistTracksRequestObject struct { + Id string `json:"id"` + ArtistId string `json:"artistId"` } -type BeginReauthResponseObject interface { - VisitBeginReauthResponse(w http.ResponseWriter) error +type GetArtistTracksResponseObject interface { + VisitGetArtistTracksResponse(w http.ResponseWriter) error } -type BeginReauth200JSONResponse struct{ CeremonyJSONResponse } +type GetArtistTracks200JSONResponse ArtistTracks -func (response BeginReauth200JSONResponse) VisitBeginReauthResponse(w http.ResponseWriter) error { +func (response GetArtistTracks200JSONResponse) VisitGetArtistTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12542,12 +12630,12 @@ func (response BeginReauth200JSONResponse) VisitBeginReauthResponse(w http.Respo return err } -type BeginReauthdefaultJSONResponse struct { +type GetArtistTracksdefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginReauthdefaultJSONResponse) VisitBeginReauthResponse(w http.ResponseWriter) error { +func (response GetArtistTracksdefaultJSONResponse) VisitGetArtistTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12559,27 +12647,42 @@ func (response BeginReauthdefaultJSONResponse) VisitBeginReauthResponse(w http.R return err } -type RevokeOtherSessionsRequestObject struct { +type GetLinkArtworkRequestObject struct { + Id string `json:"id"` + Params GetLinkArtworkParams } -type RevokeOtherSessionsResponseObject interface { - VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error +type GetLinkArtworkResponseObject interface { + VisitGetLinkArtworkResponse(w http.ResponseWriter) error } -type RevokeOtherSessions204Response struct { +type GetLinkArtwork200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 } -func (response RevokeOtherSessions204Response) VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response GetLinkArtwork200ImageResponse) VisitGetLinkArtworkResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err } -type RevokeOtherSessionsdefaultJSONResponse struct { +type GetLinkArtworkdefaultJSONResponse struct { Body Error StatusCode int } -func (response RevokeOtherSessionsdefaultJSONResponse) VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error { +func (response GetLinkArtworkdefaultJSONResponse) VisitGetLinkArtworkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12591,16 +12694,17 @@ func (response RevokeOtherSessionsdefaultJSONResponse) VisitRevokeOtherSessionsR return err } -type ListMySessionsRequestObject struct { +type GetCollectionRequestObject struct { + Id string `json:"id"` } -type ListMySessionsResponseObject interface { - VisitListMySessionsResponse(w http.ResponseWriter) error +type GetCollectionResponseObject interface { + VisitGetCollectionResponse(w http.ResponseWriter) error } -type ListMySessions200JSONResponse []SignedInSession +type GetCollection200JSONResponse LinkCollection -func (response ListMySessions200JSONResponse) VisitListMySessionsResponse(w http.ResponseWriter) error { +func (response GetCollection200JSONResponse) VisitGetCollectionResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12612,12 +12716,12 @@ func (response ListMySessions200JSONResponse) VisitListMySessionsResponse(w http return err } -type ListMySessionsdefaultJSONResponse struct { +type GetCollectiondefaultJSONResponse struct { Body Error StatusCode int } -func (response ListMySessionsdefaultJSONResponse) VisitListMySessionsResponse(w http.ResponseWriter) error { +func (response GetCollectiondefaultJSONResponse) VisitGetCollectionResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12629,28 +12733,35 @@ func (response ListMySessionsdefaultJSONResponse) VisitListMySessionsResponse(w return err } -type RevokeMySessionRequestObject struct { - Id string `json:"id"` +type GetGenreRequestObject struct { + Id string `json:"id"` + Params GetGenreParams } -type RevokeMySessionResponseObject interface { - VisitRevokeMySessionResponse(w http.ResponseWriter) error +type GetGenreResponseObject interface { + VisitGetGenreResponse(w http.ResponseWriter) error } -type RevokeMySession204Response struct { -} +type GetGenre200JSONResponse GenreDetail -func (response RevokeMySession204Response) VisitRevokeMySessionResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response GetGenre200JSONResponse) VisitGetGenreResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type RevokeMySessiondefaultJSONResponse struct { +type GetGenredefaultJSONResponse struct { Body Error StatusCode int } -func (response RevokeMySessiondefaultJSONResponse) VisitRevokeMySessionResponse(w http.ResponseWriter) error { +func (response GetGenredefaultJSONResponse) VisitGetGenreResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12662,17 +12773,18 @@ func (response RevokeMySessiondefaultJSONResponse) VisitRevokeMySessionResponse( return err } -type BeginPairingRequestObject struct { - Body *BeginPairingJSONRequestBody +type ListPlaylistsRequestObject struct { + Id string `json:"id"` + Params ListPlaylistsParams } -type BeginPairingResponseObject interface { - VisitBeginPairingResponse(w http.ResponseWriter) error +type ListPlaylistsResponseObject interface { + VisitListPlaylistsResponse(w http.ResponseWriter) error } -type BeginPairing200JSONResponse Pairing +type ListPlaylists200JSONResponse PlaylistList -func (response BeginPairing200JSONResponse) VisitBeginPairingResponse(w http.ResponseWriter) error { +func (response ListPlaylists200JSONResponse) VisitListPlaylistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12684,12 +12796,12 @@ func (response BeginPairing200JSONResponse) VisitBeginPairingResponse(w http.Res return err } -type BeginPairingdefaultJSONResponse struct { +type ListPlaylistsdefaultJSONResponse struct { Body Error StatusCode int } -func (response BeginPairingdefaultJSONResponse) VisitBeginPairingResponse(w http.ResponseWriter) error { +func (response ListPlaylistsdefaultJSONResponse) VisitListPlaylistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12701,17 +12813,19 @@ func (response BeginPairingdefaultJSONResponse) VisitBeginPairingResponse(w http return err } -type PollPairingRequestObject struct { - Id string `json:"id"` +type GetPlaylistTracksRequestObject struct { + Id string `json:"id"` + PlaylistId string `json:"playlistId"` + Params GetPlaylistTracksParams } -type PollPairingResponseObject interface { - VisitPollPairingResponse(w http.ResponseWriter) error +type GetPlaylistTracksResponseObject interface { + VisitGetPlaylistTracksResponse(w http.ResponseWriter) error } -type PollPairing200JSONResponse PairingStatus +type GetPlaylistTracks200JSONResponse PlaylistTracks -func (response PollPairing200JSONResponse) VisitPollPairingResponse(w http.ResponseWriter) error { +func (response GetPlaylistTracks200JSONResponse) VisitGetPlaylistTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12723,12 +12837,12 @@ func (response PollPairing200JSONResponse) VisitPollPairingResponse(w http.Respo return err } -type PollPairingdefaultJSONResponse struct { +type GetPlaylistTracksdefaultJSONResponse struct { Body Error StatusCode int } -func (response PollPairingdefaultJSONResponse) VisitPollPairingResponse(w http.ResponseWriter) error { +func (response GetPlaylistTracksdefaultJSONResponse) VisitGetPlaylistTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12740,16 +12854,18 @@ func (response PollPairingdefaultJSONResponse) VisitPollPairingResponse(w http.R return err } -type ListSavedPlaylistsRequestObject struct { +type GetTrackLyricsRequestObject struct { + Id string `json:"id"` + TrackId string `json:"trackId"` } -type ListSavedPlaylistsResponseObject interface { - VisitListSavedPlaylistsResponse(w http.ResponseWriter) error +type GetTrackLyricsResponseObject interface { + VisitGetTrackLyricsResponse(w http.ResponseWriter) error } -type ListSavedPlaylists200JSONResponse []SavedPlaylistSummary +type GetTrackLyrics200JSONResponse Lyrics -func (response ListSavedPlaylists200JSONResponse) VisitListSavedPlaylistsResponse(w http.ResponseWriter) error { +func (response GetTrackLyrics200JSONResponse) VisitGetTrackLyricsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12761,12 +12877,12 @@ func (response ListSavedPlaylists200JSONResponse) VisitListSavedPlaylistsRespons return err } -type ListSavedPlaylistsdefaultJSONResponse struct { +type GetTrackLyricsdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListSavedPlaylistsdefaultJSONResponse) VisitListSavedPlaylistsResponse(w http.ResponseWriter) error { +func (response GetTrackLyricsdefaultJSONResponse) VisitGetTrackLyricsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12778,34 +12894,33 @@ func (response ListSavedPlaylistsdefaultJSONResponse) VisitListSavedPlaylistsRes return err } -type CreateSavedPlaylistRequestObject struct { - Body *CreateSavedPlaylistJSONRequestBody +type GetMeRequestObject struct { } -type CreateSavedPlaylistResponseObject interface { - VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error +type GetMeResponseObject interface { + VisitGetMeResponse(w http.ResponseWriter) error } -type CreateSavedPlaylist201JSONResponse SavedPlaylist +type GetMe200JSONResponse Me -func (response CreateSavedPlaylist201JSONResponse) VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error { +func (response GetMe200JSONResponse) VisitGetMeResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateSavedPlaylistdefaultJSONResponse struct { +type GetMedefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateSavedPlaylistdefaultJSONResponse) VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error { +func (response GetMedefaultJSONResponse) VisitGetMeResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12817,28 +12932,34 @@ func (response CreateSavedPlaylistdefaultJSONResponse) VisitCreateSavedPlaylistR return err } -type DeleteSavedPlaylistRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` +type UpdateMeRequestObject struct { + Body *UpdateMeJSONRequestBody } -type DeleteSavedPlaylistResponseObject interface { - VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error +type UpdateMeResponseObject interface { + VisitUpdateMeResponse(w http.ResponseWriter) error } -type DeleteSavedPlaylist204Response struct { -} +type UpdateMe200JSONResponse Me -func (response DeleteSavedPlaylist204Response) VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response UpdateMe200JSONResponse) VisitUpdateMeResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type DeleteSavedPlaylistdefaultJSONResponse struct { +type UpdateMedefaultJSONResponse struct { Body Error StatusCode int } -func (response DeleteSavedPlaylistdefaultJSONResponse) VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error { +func (response UpdateMedefaultJSONResponse) VisitUpdateMeResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12850,17 +12971,18 @@ func (response DeleteSavedPlaylistdefaultJSONResponse) VisitDeleteSavedPlaylistR return err } -type GetSavedPlaylistRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` +type UploadAvatarRequestObject struct { + ContentType string + Body io.Reader } -type GetSavedPlaylistResponseObject interface { - VisitGetSavedPlaylistResponse(w http.ResponseWriter) error +type UploadAvatarResponseObject interface { + VisitUploadAvatarResponse(w http.ResponseWriter) error } -type GetSavedPlaylist200JSONResponse SavedPlaylist +type UploadAvatar200JSONResponse Me -func (response GetSavedPlaylist200JSONResponse) VisitGetSavedPlaylistResponse(w http.ResponseWriter) error { +func (response UploadAvatar200JSONResponse) VisitUploadAvatarResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12872,12 +12994,12 @@ func (response GetSavedPlaylist200JSONResponse) VisitGetSavedPlaylistResponse(w return err } -type GetSavedPlaylistdefaultJSONResponse struct { +type UploadAvatardefaultJSONResponse struct { Body Error StatusCode int } -func (response GetSavedPlaylistdefaultJSONResponse) VisitGetSavedPlaylistResponse(w http.ResponseWriter) error { +func (response UploadAvatardefaultJSONResponse) VisitUploadAvatarResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12889,35 +13011,36 @@ func (response GetSavedPlaylistdefaultJSONResponse) VisitGetSavedPlaylistRespons return err } -type UpdateSavedPlaylistRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` - Body *UpdateSavedPlaylistJSONRequestBody +type DeleteMeRequestObject struct { + Body *DeleteMeJSONRequestBody } -type UpdateSavedPlaylistResponseObject interface { - VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error +type DeleteMeResponseObject interface { + VisitDeleteMeResponse(w http.ResponseWriter) error } -type UpdateSavedPlaylist200JSONResponse SavedPlaylist +type DeleteMe204ResponseHeaders struct { + SetCookie *string +} -func (response UpdateSavedPlaylist200JSONResponse) VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error { +type DeleteMe204Response struct { + Headers DeleteMe204ResponseHeaders +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err +func (response DeleteMe204Response) VisitDeleteMeResponse(w http.ResponseWriter) error { + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err + w.WriteHeader(204) + return nil } -type UpdateSavedPlaylistdefaultJSONResponse struct { +type DeleteMedefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateSavedPlaylistdefaultJSONResponse) VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error { +func (response DeleteMedefaultJSONResponse) VisitDeleteMeResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12929,18 +13052,17 @@ func (response UpdateSavedPlaylistdefaultJSONResponse) VisitUpdateSavedPlaylistR return err } -type AddSavedPlaylistSongsRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` - Body *AddSavedPlaylistSongsJSONRequestBody +type SearchDiscoveryArtistsRequestObject struct { + Params SearchDiscoveryArtistsParams } -type AddSavedPlaylistSongsResponseObject interface { - VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error +type SearchDiscoveryArtistsResponseObject interface { + VisitSearchDiscoveryArtistsResponse(w http.ResponseWriter) error } -type AddSavedPlaylistSongs200JSONResponse SavedPlaylist +type SearchDiscoveryArtists200JSONResponse []DiscoveryArtist -func (response AddSavedPlaylistSongs200JSONResponse) VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error { +func (response SearchDiscoveryArtists200JSONResponse) VisitSearchDiscoveryArtistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12952,12 +13074,12 @@ func (response AddSavedPlaylistSongs200JSONResponse) VisitAddSavedPlaylistSongsR return err } -type AddSavedPlaylistSongsdefaultJSONResponse struct { +type SearchDiscoveryArtistsdefaultJSONResponse struct { Body Error StatusCode int } -func (response AddSavedPlaylistSongsdefaultJSONResponse) VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error { +func (response SearchDiscoveryArtistsdefaultJSONResponse) VisitSearchDiscoveryArtistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -12969,18 +13091,16 @@ func (response AddSavedPlaylistSongsdefaultJSONResponse) VisitAddSavedPlaylistSo return err } -type RemoveSavedPlaylistSongRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` - SongId PlaylistSongId `json:"songId"` +type ListDiscoveryBlocksRequestObject struct { } -type RemoveSavedPlaylistSongResponseObject interface { - VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error +type ListDiscoveryBlocksResponseObject interface { + VisitListDiscoveryBlocksResponse(w http.ResponseWriter) error } -type RemoveSavedPlaylistSong200JSONResponse SavedPlaylist +type ListDiscoveryBlocks200JSONResponse []DiscoveryBlock -func (response RemoveSavedPlaylistSong200JSONResponse) VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error { +func (response ListDiscoveryBlocks200JSONResponse) VisitListDiscoveryBlocksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -12992,12 +13112,12 @@ func (response RemoveSavedPlaylistSong200JSONResponse) VisitRemoveSavedPlaylistS return err } -type RemoveSavedPlaylistSongdefaultJSONResponse struct { +type ListDiscoveryBlocksdefaultJSONResponse struct { Body Error StatusCode int } -func (response RemoveSavedPlaylistSongdefaultJSONResponse) VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error { +func (response ListDiscoveryBlocksdefaultJSONResponse) VisitListDiscoveryBlocksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13009,43 +13129,34 @@ func (response RemoveSavedPlaylistSongdefaultJSONResponse) VisitRemoveSavedPlayl return err } -type GetSavedPlaylistSongArtworkRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` - SongId PlaylistSongId `json:"songId"` - Params GetSavedPlaylistSongArtworkParams +type BlockDiscoveryArtistRequestObject struct { + Body *BlockDiscoveryArtistJSONRequestBody } -type GetSavedPlaylistSongArtworkResponseObject interface { - VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error +type BlockDiscoveryArtistResponseObject interface { + VisitBlockDiscoveryArtistResponse(w http.ResponseWriter) error } -type GetSavedPlaylistSongArtwork200ImageResponse struct { - Body io.Reader - ContentType string - ContentLength int64 -} +type BlockDiscoveryArtist200JSONResponse DiscoveryBlock -func (response GetSavedPlaylistSongArtwork200ImageResponse) VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error { +func (response BlockDiscoveryArtist200JSONResponse) VisitBlockDiscoveryArtistResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() - } - _, err := io.Copy(w, response.Body) + _, err := buf.WriteTo(w) return err } -type GetSavedPlaylistSongArtworkdefaultJSONResponse struct { +type BlockDiscoveryArtistdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetSavedPlaylistSongArtworkdefaultJSONResponse) VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error { +func (response BlockDiscoveryArtistdefaultJSONResponse) VisitBlockDiscoveryArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13057,36 +13168,28 @@ func (response GetSavedPlaylistSongArtworkdefaultJSONResponse) VisitGetSavedPlay return err } -type MoveSavedPlaylistSongRequestObject struct { - PlaylistId PlaylistId `json:"playlistId"` - SongId PlaylistSongId `json:"songId"` - Body *MoveSavedPlaylistSongJSONRequestBody +type UnblockDiscoveryArtistRequestObject struct { + ArtistKey string `json:"artistKey"` } -type MoveSavedPlaylistSongResponseObject interface { - VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error +type UnblockDiscoveryArtistResponseObject interface { + VisitUnblockDiscoveryArtistResponse(w http.ResponseWriter) error } -type MoveSavedPlaylistSong200JSONResponse SavedPlaylist - -func (response MoveSavedPlaylistSong200JSONResponse) VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error { +type UnblockDiscoveryArtist204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response UnblockDiscoveryArtist204Response) VisitUnblockDiscoveryArtistResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type MoveSavedPlaylistSongdefaultJSONResponse struct { +type UnblockDiscoveryArtistdefaultJSONResponse struct { Body Error StatusCode int } -func (response MoveSavedPlaylistSongdefaultJSONResponse) VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error { +func (response UnblockDiscoveryArtistdefaultJSONResponse) VisitUnblockDiscoveryArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13098,33 +13201,28 @@ func (response MoveSavedPlaylistSongdefaultJSONResponse) VisitMoveSavedPlaylistS return err } -type ListProvidersRequestObject struct { +type PostDiscoveryFeedbackRequestObject struct { + Body *PostDiscoveryFeedbackJSONRequestBody } -type ListProvidersResponseObject interface { - VisitListProvidersResponse(w http.ResponseWriter) error +type PostDiscoveryFeedbackResponseObject interface { + VisitPostDiscoveryFeedbackResponse(w http.ResponseWriter) error } -type ListProviders200JSONResponse []ProviderInfo - -func (response ListProviders200JSONResponse) VisitListProvidersResponse(w http.ResponseWriter) error { +type PostDiscoveryFeedback204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response PostDiscoveryFeedback204Response) VisitPostDiscoveryFeedbackResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type ListProvidersdefaultJSONResponse struct { +type PostDiscoveryFeedbackdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListProvidersdefaultJSONResponse) VisitListProvidersResponse(w http.ResponseWriter) error { +func (response PostDiscoveryFeedbackdefaultJSONResponse) VisitPostDiscoveryFeedbackResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13136,34 +13234,43 @@ func (response ListProvidersdefaultJSONResponse) VisitListProvidersResponse(w ht return err } -type GetRandomTracksRequestObject struct { - Params GetRandomTracksParams +type GetDiscoveryImageRequestObject struct { + Kind string `json:"kind"` + ImageId string `json:"imageId"` + Params GetDiscoveryImageParams } -type GetRandomTracksResponseObject interface { - VisitGetRandomTracksResponse(w http.ResponseWriter) error +type GetDiscoveryImageResponseObject interface { + VisitGetDiscoveryImageResponse(w http.ResponseWriter) error } -type GetRandomTracks200JSONResponse TrackList +type GetDiscoveryImage200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} -func (response GetRandomTracks200JSONResponse) VisitGetRandomTracksResponse(w http.ResponseWriter) error { +func (response GetDiscoveryImage200ImageResponse) VisitGetDiscoveryImageResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - _, err := buf.WriteTo(w) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) return err } -type GetRandomTracksdefaultJSONResponse struct { +type GetDiscoveryImagedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRandomTracksdefaultJSONResponse) VisitGetRandomTracksResponse(w http.ResponseWriter) error { +func (response GetDiscoveryImagedefaultJSONResponse) VisitGetDiscoveryImageResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13175,16 +13282,16 @@ func (response GetRandomTracksdefaultJSONResponse) VisitGetRandomTracksResponse( return err } -type ListResetLinksRequestObject struct { +type GetDiscoveryLibraryRequestObject struct { } -type ListResetLinksResponseObject interface { - VisitListResetLinksResponse(w http.ResponseWriter) error +type GetDiscoveryLibraryResponseObject interface { + VisitGetDiscoveryLibraryResponse(w http.ResponseWriter) error } -type ListResetLinks200JSONResponse []ResetLink +type GetDiscoveryLibrary200JSONResponse DiscoveryLibrary -func (response ListResetLinks200JSONResponse) VisitListResetLinksResponse(w http.ResponseWriter) error { +func (response GetDiscoveryLibrary200JSONResponse) VisitGetDiscoveryLibraryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13196,12 +13303,12 @@ func (response ListResetLinks200JSONResponse) VisitListResetLinksResponse(w http return err } -type ListResetLinksdefaultJSONResponse struct { +type GetDiscoveryLibrarydefaultJSONResponse struct { Body Error StatusCode int } -func (response ListResetLinksdefaultJSONResponse) VisitListResetLinksResponse(w http.ResponseWriter) error { +func (response GetDiscoveryLibrarydefaultJSONResponse) VisitGetDiscoveryLibraryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13213,34 +13320,33 @@ func (response ListResetLinksdefaultJSONResponse) VisitListResetLinksResponse(w return err } -type GetResetLinkRequestObject struct { - Code ResetCode `json:"code"` +type RefreshDiscoveryLibraryRequestObject struct { } -type GetResetLinkResponseObject interface { - VisitGetResetLinkResponse(w http.ResponseWriter) error +type RefreshDiscoveryLibraryResponseObject interface { + VisitRefreshDiscoveryLibraryResponse(w http.ResponseWriter) error } -type GetResetLink200JSONResponse ResetLinkInfo +type RefreshDiscoveryLibrary202JSONResponse DiscoveryLibrary -func (response GetResetLink200JSONResponse) VisitGetResetLinkResponse(w http.ResponseWriter) error { +func (response RefreshDiscoveryLibrary202JSONResponse) VisitRefreshDiscoveryLibraryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(202) _, err := buf.WriteTo(w) return err } -type GetResetLinkdefaultJSONResponse struct { +type RefreshDiscoveryLibrarydefaultJSONResponse struct { Body Error StatusCode int } -func (response GetResetLinkdefaultJSONResponse) VisitGetResetLinkResponse(w http.ResponseWriter) error { +func (response RefreshDiscoveryLibrarydefaultJSONResponse) VisitRefreshDiscoveryLibraryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13252,77 +13358,63 @@ func (response GetResetLinkdefaultJSONResponse) VisitGetResetLinkResponse(w http return err } -type BeginResetPasskeyRequestObject struct { - Code ResetCode `json:"code"` +type GetDiscoveryPreviewRequestObject struct { + DeezerTrackId int64 `json:"deezerTrackId"` + Params GetDiscoveryPreviewParams } -type BeginResetPasskeyResponseObject interface { - VisitBeginResetPasskeyResponse(w http.ResponseWriter) error +type GetDiscoveryPreviewResponseObject interface { + VisitGetDiscoveryPreviewResponse(w http.ResponseWriter) error } -type BeginResetPasskey200JSONResponse struct{ CeremonyJSONResponse } +type GetDiscoveryPreview200AudioResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} -func (response BeginResetPasskey200JSONResponse) VisitBeginResetPasskeyResponse(w http.ResponseWriter) error { +func (response GetDiscoveryPreview200AudioResponse) VisitGetDiscoveryPreviewResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err -} - -type BeginResetPasskeydefaultJSONResponse struct { - Body Error - StatusCode int -} - -func (response BeginResetPasskeydefaultJSONResponse) VisitBeginResetPasskeyResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) - _, err := buf.WriteTo(w) + _, err := io.Copy(w, response.Body) return err } -type FinishResetPasskeyRequestObject struct { - Code ResetCode `json:"code"` - Body *FinishResetPasskeyJSONRequestBody -} - -type FinishResetPasskeyResponseObject interface { - VisitFinishResetPasskeyResponse(w http.ResponseWriter) error +type GetDiscoveryPreview206AudioResponse struct { + Body io.Reader + ContentType string + ContentLength int64 } -type FinishResetPasskey200JSONResponse struct{ SignedInJSONResponse } - -func (response FinishResetPasskey200JSONResponse) VisitFinishResetPasskeyResponse(w http.ResponseWriter) error { +func (response GetDiscoveryPreview206AudioResponse) VisitGetDiscoveryPreviewResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { - return err + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + w.WriteHeader(206) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() } - w.WriteHeader(200) - _, err := buf.WriteTo(w) + _, err := io.Copy(w, response.Body) return err } -type FinishResetPasskeydefaultJSONResponse struct { +type GetDiscoveryPreviewdefaultJSONResponse struct { Body Error StatusCode int } -func (response FinishResetPasskeydefaultJSONResponse) VisitFinishResetPasskeyResponse(w http.ResponseWriter) error { +func (response GetDiscoveryPreviewdefaultJSONResponse) VisitGetDiscoveryPreviewResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13334,38 +13426,33 @@ func (response FinishResetPasskeydefaultJSONResponse) VisitFinishResetPasskeyRes return err } -type ResetPasswordRequestObject struct { - Code ResetCode `json:"code"` - Body *ResetPasswordJSONRequestBody +type ListDiscoverySetsRequestObject struct { } -type ResetPasswordResponseObject interface { - VisitResetPasswordResponse(w http.ResponseWriter) error +type ListDiscoverySetsResponseObject interface { + VisitListDiscoverySetsResponse(w http.ResponseWriter) error } -type ResetPassword200JSONResponse struct{ SignedInJSONResponse } +type ListDiscoverySets200JSONResponse []DiscoverySetSummary -func (response ResetPassword200JSONResponse) VisitResetPasswordResponse(w http.ResponseWriter) error { +func (response ListDiscoverySets200JSONResponse) VisitListDiscoverySetsResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - if response.Headers.SetCookie != nil { - w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) - } w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type ResetPassworddefaultJSONResponse struct { +type ListDiscoverySetsdefaultJSONResponse struct { Body Error StatusCode int } -func (response ResetPassworddefaultJSONResponse) VisitResetPasswordResponse(w http.ResponseWriter) error { +func (response ListDiscoverySetsdefaultJSONResponse) VisitListDiscoverySetsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13377,34 +13464,34 @@ func (response ResetPassworddefaultJSONResponse) VisitResetPasswordResponse(w ht return err } -type GetRoomInviteRequestObject struct { - Code string `json:"code"` +type CreateDiscoverySetRequestObject struct { + Body *CreateDiscoverySetJSONRequestBody } -type GetRoomInviteResponseObject interface { - VisitGetRoomInviteResponse(w http.ResponseWriter) error +type CreateDiscoverySetResponseObject interface { + VisitCreateDiscoverySetResponse(w http.ResponseWriter) error } -type GetRoomInvite200JSONResponse RoomInvitePreview +type CreateDiscoverySet201JSONResponse DiscoverySet -func (response GetRoomInvite200JSONResponse) VisitGetRoomInviteResponse(w http.ResponseWriter) error { +func (response CreateDiscoverySet201JSONResponse) VisitCreateDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type GetRoomInvitedefaultJSONResponse struct { +type CreateDiscoverySetdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRoomInvitedefaultJSONResponse) VisitGetRoomInviteResponse(w http.ResponseWriter) error { +func (response CreateDiscoverySetdefaultJSONResponse) VisitCreateDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13416,34 +13503,28 @@ func (response GetRoomInvitedefaultJSONResponse) VisitGetRoomInviteResponse(w ht return err } -type UseRoomInviteRequestObject struct { - Code string `json:"code"` +type DeleteDiscoverySetRequestObject struct { + SetId DiscoverySetId `json:"setId"` } -type UseRoomInviteResponseObject interface { - VisitUseRoomInviteResponse(w http.ResponseWriter) error +type DeleteDiscoverySetResponseObject interface { + VisitDeleteDiscoverySetResponse(w http.ResponseWriter) error } -type UseRoomInvite200JSONResponse RoomInviteResult - -func (response UseRoomInvite200JSONResponse) VisitUseRoomInviteResponse(w http.ResponseWriter) error { +type DeleteDiscoverySet204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response DeleteDiscoverySet204Response) VisitDeleteDiscoverySetResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type UseRoomInvitedefaultJSONResponse struct { +type DeleteDiscoverySetdefaultJSONResponse struct { Body Error StatusCode int } -func (response UseRoomInvitedefaultJSONResponse) VisitUseRoomInviteResponse(w http.ResponseWriter) error { +func (response DeleteDiscoverySetdefaultJSONResponse) VisitDeleteDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13455,16 +13536,17 @@ func (response UseRoomInvitedefaultJSONResponse) VisitUseRoomInviteResponse(w ht return err } -type ListRoomsRequestObject struct { +type GetDiscoverySetRequestObject struct { + SetId DiscoverySetId `json:"setId"` } -type ListRoomsResponseObject interface { - VisitListRoomsResponse(w http.ResponseWriter) error +type GetDiscoverySetResponseObject interface { + VisitGetDiscoverySetResponse(w http.ResponseWriter) error } -type ListRooms200JSONResponse []Room +type GetDiscoverySet200JSONResponse DiscoverySet -func (response ListRooms200JSONResponse) VisitListRoomsResponse(w http.ResponseWriter) error { +func (response GetDiscoverySet200JSONResponse) VisitGetDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13476,12 +13558,12 @@ func (response ListRooms200JSONResponse) VisitListRoomsResponse(w http.ResponseW return err } -type ListRoomsdefaultJSONResponse struct { +type GetDiscoverySetdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListRoomsdefaultJSONResponse) VisitListRoomsResponse(w http.ResponseWriter) error { +func (response GetDiscoverySetdefaultJSONResponse) VisitGetDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13493,34 +13575,35 @@ func (response ListRoomsdefaultJSONResponse) VisitListRoomsResponse(w http.Respo return err } -type CreateRoomRequestObject struct { - Body *CreateRoomJSONRequestBody +type UpdateDiscoverySetRequestObject struct { + SetId DiscoverySetId `json:"setId"` + Body *UpdateDiscoverySetJSONRequestBody } -type CreateRoomResponseObject interface { - VisitCreateRoomResponse(w http.ResponseWriter) error +type UpdateDiscoverySetResponseObject interface { + VisitUpdateDiscoverySetResponse(w http.ResponseWriter) error } -type CreateRoom201JSONResponse Room +type UpdateDiscoverySet200JSONResponse DiscoverySet -func (response CreateRoom201JSONResponse) VisitCreateRoomResponse(w http.ResponseWriter) error { +func (response UpdateDiscoverySet200JSONResponse) VisitUpdateDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateRoomdefaultJSONResponse struct { +type UpdateDiscoverySetdefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateRoomdefaultJSONResponse) VisitCreateRoomResponse(w http.ResponseWriter) error { +func (response UpdateDiscoverySetdefaultJSONResponse) VisitUpdateDiscoverySetResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13532,28 +13615,35 @@ func (response CreateRoomdefaultJSONResponse) VisitCreateRoomResponse(w http.Res return err } -type DeleteRoomRequestObject struct { - RoomId RoomId `json:"roomId"` +type AddDiscoverySetArtistRequestObject struct { + SetId DiscoverySetId `json:"setId"` + Body *AddDiscoverySetArtistJSONRequestBody } -type DeleteRoomResponseObject interface { - VisitDeleteRoomResponse(w http.ResponseWriter) error +type AddDiscoverySetArtistResponseObject interface { + VisitAddDiscoverySetArtistResponse(w http.ResponseWriter) error } -type DeleteRoom204Response struct { -} +type AddDiscoverySetArtist200JSONResponse DiscoverySet -func (response DeleteRoom204Response) VisitDeleteRoomResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response AddDiscoverySetArtist200JSONResponse) VisitAddDiscoverySetArtistResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type DeleteRoomdefaultJSONResponse struct { +type AddDiscoverySetArtistdefaultJSONResponse struct { Body Error StatusCode int } -func (response DeleteRoomdefaultJSONResponse) VisitDeleteRoomResponse(w http.ResponseWriter) error { +func (response AddDiscoverySetArtistdefaultJSONResponse) VisitAddDiscoverySetArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13565,17 +13655,18 @@ func (response DeleteRoomdefaultJSONResponse) VisitDeleteRoomResponse(w http.Res return err } -type GetRoomRequestObject struct { - RoomId RoomId `json:"roomId"` +type RemoveDiscoverySetArtistRequestObject struct { + SetId DiscoverySetId `json:"setId"` + ArtistKey string `json:"artistKey"` } -type GetRoomResponseObject interface { - VisitGetRoomResponse(w http.ResponseWriter) error +type RemoveDiscoverySetArtistResponseObject interface { + VisitRemoveDiscoverySetArtistResponse(w http.ResponseWriter) error } -type GetRoom200JSONResponse Room +type RemoveDiscoverySetArtist200JSONResponse DiscoverySet -func (response GetRoom200JSONResponse) VisitGetRoomResponse(w http.ResponseWriter) error { +func (response RemoveDiscoverySetArtist200JSONResponse) VisitRemoveDiscoverySetArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13587,12 +13678,12 @@ func (response GetRoom200JSONResponse) VisitGetRoomResponse(w http.ResponseWrite return err } -type GetRoomdefaultJSONResponse struct { +type RemoveDiscoverySetArtistdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRoomdefaultJSONResponse) VisitGetRoomResponse(w http.ResponseWriter) error { +func (response RemoveDiscoverySetArtistdefaultJSONResponse) VisitRemoveDiscoverySetArtistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13604,18 +13695,18 @@ func (response GetRoomdefaultJSONResponse) VisitGetRoomResponse(w http.ResponseW return err } -type UpdateRoomRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *UpdateRoomJSONRequestBody +type GetDiscoveryFeedRequestObject struct { + SetId DiscoverySetId `json:"setId"` + Params GetDiscoveryFeedParams } -type UpdateRoomResponseObject interface { - VisitUpdateRoomResponse(w http.ResponseWriter) error +type GetDiscoveryFeedResponseObject interface { + VisitGetDiscoveryFeedResponse(w http.ResponseWriter) error } -type UpdateRoom200JSONResponse Room +type GetDiscoveryFeed200JSONResponse DiscoveryFeed -func (response UpdateRoom200JSONResponse) VisitUpdateRoomResponse(w http.ResponseWriter) error { +func (response GetDiscoveryFeed200JSONResponse) VisitGetDiscoveryFeedResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13627,12 +13718,12 @@ func (response UpdateRoom200JSONResponse) VisitUpdateRoomResponse(w http.Respons return err } -type UpdateRoomdefaultJSONResponse struct { +type GetDiscoveryFeeddefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateRoomdefaultJSONResponse) VisitUpdateRoomResponse(w http.ResponseWriter) error { +func (response GetDiscoveryFeeddefaultJSONResponse) VisitGetDiscoveryFeedResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13644,17 +13735,16 @@ func (response UpdateRoomdefaultJSONResponse) VisitUpdateRoomResponse(w http.Res return err } -type JoinRoomAsAdminRequestObject struct { - RoomId RoomId `json:"roomId"` +type ListPasskeysRequestObject struct { } -type JoinRoomAsAdminResponseObject interface { - VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error +type ListPasskeysResponseObject interface { + VisitListPasskeysResponse(w http.ResponseWriter) error } -type JoinRoomAsAdmin200JSONResponse Room +type ListPasskeys200JSONResponse []Passkey -func (response JoinRoomAsAdmin200JSONResponse) VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error { +func (response ListPasskeys200JSONResponse) VisitListPasskeysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13666,12 +13756,12 @@ func (response JoinRoomAsAdmin200JSONResponse) VisitJoinRoomAsAdminResponse(w ht return err } -type JoinRoomAsAdmindefaultJSONResponse struct { +type ListPasskeysdefaultJSONResponse struct { Body Error StatusCode int } -func (response JoinRoomAsAdmindefaultJSONResponse) VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error { +func (response ListPasskeysdefaultJSONResponse) VisitListPasskeysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13683,18 +13773,16 @@ func (response JoinRoomAsAdmindefaultJSONResponse) VisitJoinRoomAsAdminResponse( return err } -type GetRoomArtistPlaysRequestObject struct { - RoomId RoomId `json:"roomId"` - Params GetRoomArtistPlaysParams +type BeginAddPasskeyRequestObject struct { } -type GetRoomArtistPlaysResponseObject interface { - VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error +type BeginAddPasskeyResponseObject interface { + VisitBeginAddPasskeyResponse(w http.ResponseWriter) error } -type GetRoomArtistPlays200JSONResponse []TrackCount +type BeginAddPasskey200JSONResponse struct{ CeremonyJSONResponse } -func (response GetRoomArtistPlays200JSONResponse) VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error { +func (response BeginAddPasskey200JSONResponse) VisitBeginAddPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13706,12 +13794,12 @@ func (response GetRoomArtistPlays200JSONResponse) VisitGetRoomArtistPlaysRespons return err } -type GetRoomArtistPlaysdefaultJSONResponse struct { +type BeginAddPasskeydefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRoomArtistPlaysdefaultJSONResponse) VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error { +func (response BeginAddPasskeydefaultJSONResponse) VisitBeginAddPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13723,34 +13811,34 @@ func (response GetRoomArtistPlaysdefaultJSONResponse) VisitGetRoomArtistPlaysRes return err } -type ListDisplaysRequestObject struct { - RoomId RoomId `json:"roomId"` +type FinishAddPasskeyRequestObject struct { + Body *FinishAddPasskeyJSONRequestBody } -type ListDisplaysResponseObject interface { - VisitListDisplaysResponse(w http.ResponseWriter) error +type FinishAddPasskeyResponseObject interface { + VisitFinishAddPasskeyResponse(w http.ResponseWriter) error } -type ListDisplays200JSONResponse []Display +type FinishAddPasskey201JSONResponse Passkey -func (response ListDisplays200JSONResponse) VisitListDisplaysResponse(w http.ResponseWriter) error { +func (response FinishAddPasskey201JSONResponse) VisitFinishAddPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type ListDisplaysdefaultJSONResponse struct { +type FinishAddPasskeydefaultJSONResponse struct { Body Error StatusCode int } -func (response ListDisplaysdefaultJSONResponse) VisitListDisplaysResponse(w http.ResponseWriter) error { +func (response FinishAddPasskeydefaultJSONResponse) VisitFinishAddPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13762,35 +13850,28 @@ func (response ListDisplaysdefaultJSONResponse) VisitListDisplaysResponse(w http return err } -type PairDisplayRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *PairDisplayJSONRequestBody +type DeletePasskeyRequestObject struct { + Id string `json:"id"` } -type PairDisplayResponseObject interface { - VisitPairDisplayResponse(w http.ResponseWriter) error +type DeletePasskeyResponseObject interface { + VisitDeletePasskeyResponse(w http.ResponseWriter) error } -type PairDisplay201JSONResponse Display - -func (response PairDisplay201JSONResponse) VisitPairDisplayResponse(w http.ResponseWriter) error { +type DeletePasskey204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) - _, err := buf.WriteTo(w) - return err +func (response DeletePasskey204Response) VisitDeletePasskeyResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type PairDisplaydefaultJSONResponse struct { +type DeletePasskeydefaultJSONResponse struct { Body Error StatusCode int } -func (response PairDisplaydefaultJSONResponse) VisitPairDisplayResponse(w http.ResponseWriter) error { +func (response DeletePasskeydefaultJSONResponse) VisitDeletePasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13802,35 +13883,61 @@ func (response PairDisplaydefaultJSONResponse) VisitPairDisplayResponse(w http.R return err } -type LookupDisplayPairingRequestObject struct { - RoomId RoomId `json:"roomId"` - Code string `json:"code"` +type RenamePasskeyRequestObject struct { + Id string `json:"id"` + Body *RenamePasskeyJSONRequestBody } -type LookupDisplayPairingResponseObject interface { - VisitLookupDisplayPairingResponse(w http.ResponseWriter) error +type RenamePasskeyResponseObject interface { + VisitRenamePasskeyResponse(w http.ResponseWriter) error } -type LookupDisplayPairing200JSONResponse DisplayPairingInfo +type RenamePasskey204Response struct { +} -func (response LookupDisplayPairing200JSONResponse) VisitLookupDisplayPairingResponse(w http.ResponseWriter) error { +func (response RenamePasskey204Response) VisitRenamePasskeyResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type RenamePasskeydefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response RenamePasskeydefaultJSONResponse) VisitRenamePasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(response.StatusCode) _, err := buf.WriteTo(w) return err } -type LookupDisplayPairingdefaultJSONResponse struct { +type DeletePasswordRequestObject struct { +} + +type DeletePasswordResponseObject interface { + VisitDeletePasswordResponse(w http.ResponseWriter) error +} + +type DeletePassword204Response struct { +} + +func (response DeletePassword204Response) VisitDeletePasswordResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type DeletePassworddefaultJSONResponse struct { Body Error StatusCode int } -func (response LookupDisplayPairingdefaultJSONResponse) VisitLookupDisplayPairingResponse(w http.ResponseWriter) error { +func (response DeletePassworddefaultJSONResponse) VisitDeletePasswordResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13842,29 +13949,28 @@ func (response LookupDisplayPairingdefaultJSONResponse) VisitLookupDisplayPairin return err } -type UnpairDisplayRequestObject struct { - RoomId RoomId `json:"roomId"` - DisplayId string `json:"displayId"` +type SetPasswordRequestObject struct { + Body *SetPasswordJSONRequestBody } -type UnpairDisplayResponseObject interface { - VisitUnpairDisplayResponse(w http.ResponseWriter) error +type SetPasswordResponseObject interface { + VisitSetPasswordResponse(w http.ResponseWriter) error } -type UnpairDisplay204Response struct { +type SetPassword204Response struct { } -func (response UnpairDisplay204Response) VisitUnpairDisplayResponse(w http.ResponseWriter) error { +func (response SetPassword204Response) VisitSetPasswordResponse(w http.ResponseWriter) error { w.WriteHeader(204) return nil } -type UnpairDisplaydefaultJSONResponse struct { +type SetPassworddefaultJSONResponse struct { Body Error StatusCode int } -func (response UnpairDisplaydefaultJSONResponse) VisitUnpairDisplayResponse(w http.ResponseWriter) error { +func (response SetPassworddefaultJSONResponse) VisitSetPasswordResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13876,19 +13982,16 @@ func (response UnpairDisplaydefaultJSONResponse) VisitUnpairDisplayResponse(w ht return err } -type UpdateDisplayRequestObject struct { - RoomId RoomId `json:"roomId"` - DisplayId string `json:"displayId"` - Body *UpdateDisplayJSONRequestBody +type BeginReauthRequestObject struct { } -type UpdateDisplayResponseObject interface { - VisitUpdateDisplayResponse(w http.ResponseWriter) error +type BeginReauthResponseObject interface { + VisitBeginReauthResponse(w http.ResponseWriter) error } -type UpdateDisplay200JSONResponse Display +type BeginReauth200JSONResponse struct{ CeremonyJSONResponse } -func (response UpdateDisplay200JSONResponse) VisitUpdateDisplayResponse(w http.ResponseWriter) error { +func (response BeginReauth200JSONResponse) VisitBeginReauthResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13900,12 +14003,12 @@ func (response UpdateDisplay200JSONResponse) VisitUpdateDisplayResponse(w http.R return err } -type UpdateDisplaydefaultJSONResponse struct { +type BeginReauthdefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateDisplaydefaultJSONResponse) VisitUpdateDisplayResponse(w http.ResponseWriter) error { +func (response BeginReauthdefaultJSONResponse) VisitBeginReauthResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13917,41 +14020,27 @@ func (response UpdateDisplaydefaultJSONResponse) VisitUpdateDisplayResponse(w ht return err } -type GetGameClipRequestObject struct { - RoomId RoomId `json:"roomId"` - ClipId string `json:"clipId"` +type RevokeOtherSessionsRequestObject struct { } -type GetGameClipResponseObject interface { - VisitGetGameClipResponse(w http.ResponseWriter) error +type RevokeOtherSessionsResponseObject interface { + VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error } -type GetGameClip200AudiompegResponse struct { - Body io.Reader - ContentLength int64 +type RevokeOtherSessions204Response struct { } -func (response GetGameClip200AudiompegResponse) VisitGetGameClipResponse(w http.ResponseWriter) error { - - w.Header().Set("Content-Type", "audio/mpeg") - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(200) - - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() - } - _, err := io.Copy(w, response.Body) - return err +func (response RevokeOtherSessions204Response) VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type GetGameClipdefaultJSONResponse struct { +type RevokeOtherSessionsdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGameClipdefaultJSONResponse) VisitGetGameClipResponse(w http.ResponseWriter) error { +func (response RevokeOtherSessionsdefaultJSONResponse) VisitRevokeOtherSessionsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -13963,17 +14052,16 @@ func (response GetGameClipdefaultJSONResponse) VisitGetGameClipResponse(w http.R return err } -type GetQueueGamesRequestObject struct { - RoomId RoomId `json:"roomId"` +type ListMySessionsRequestObject struct { } -type GetQueueGamesResponseObject interface { - VisitGetQueueGamesResponse(w http.ResponseWriter) error +type ListMySessionsResponseObject interface { + VisitListMySessionsResponse(w http.ResponseWriter) error } -type GetQueueGames200JSONResponse QueueGames +type ListMySessions200JSONResponse []SignedInSession -func (response GetQueueGames200JSONResponse) VisitGetQueueGamesResponse(w http.ResponseWriter) error { +func (response ListMySessions200JSONResponse) VisitListMySessionsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -13985,12 +14073,12 @@ func (response GetQueueGames200JSONResponse) VisitGetQueueGamesResponse(w http.R return err } -type GetQueueGamesdefaultJSONResponse struct { +type ListMySessionsdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueGamesdefaultJSONResponse) VisitGetQueueGamesResponse(w http.ResponseWriter) error { +func (response ListMySessionsdefaultJSONResponse) VisitListMySessionsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14002,35 +14090,28 @@ func (response GetQueueGamesdefaultJSONResponse) VisitGetQueueGamesResponse(w ht return err } -type StartQueueGameRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *StartQueueGameJSONRequestBody +type RevokeMySessionRequestObject struct { + Id string `json:"id"` } -type StartQueueGameResponseObject interface { - VisitStartQueueGameResponse(w http.ResponseWriter) error +type RevokeMySessionResponseObject interface { + VisitRevokeMySessionResponse(w http.ResponseWriter) error } -type StartQueueGame201JSONResponse QueueGame - -func (response StartQueueGame201JSONResponse) VisitStartQueueGameResponse(w http.ResponseWriter) error { +type RevokeMySession204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) - _, err := buf.WriteTo(w) - return err +func (response RevokeMySession204Response) VisitRevokeMySessionResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type StartQueueGamedefaultJSONResponse struct { +type RevokeMySessiondefaultJSONResponse struct { Body Error StatusCode int } -func (response StartQueueGamedefaultJSONResponse) VisitStartQueueGameResponse(w http.ResponseWriter) error { +func (response RevokeMySessiondefaultJSONResponse) VisitRevokeMySessionResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14042,18 +14123,17 @@ func (response StartQueueGamedefaultJSONResponse) VisitStartQueueGameResponse(w return err } -type CloseQueueGameRequestObject struct { - RoomId RoomId `json:"roomId"` - GameId QueueGameId `json:"gameId"` +type BeginPairingRequestObject struct { + Body *BeginPairingJSONRequestBody } -type CloseQueueGameResponseObject interface { - VisitCloseQueueGameResponse(w http.ResponseWriter) error +type BeginPairingResponseObject interface { + VisitBeginPairingResponse(w http.ResponseWriter) error } -type CloseQueueGame200JSONResponse QueueGame +type BeginPairing200JSONResponse Pairing -func (response CloseQueueGame200JSONResponse) VisitCloseQueueGameResponse(w http.ResponseWriter) error { +func (response BeginPairing200JSONResponse) VisitBeginPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14065,12 +14145,12 @@ func (response CloseQueueGame200JSONResponse) VisitCloseQueueGameResponse(w http return err } -type CloseQueueGamedefaultJSONResponse struct { +type BeginPairingdefaultJSONResponse struct { Body Error StatusCode int } -func (response CloseQueueGamedefaultJSONResponse) VisitCloseQueueGameResponse(w http.ResponseWriter) error { +func (response BeginPairingdefaultJSONResponse) VisitBeginPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14082,19 +14162,17 @@ func (response CloseQueueGamedefaultJSONResponse) VisitCloseQueueGameResponse(w return err } -type EnterQueueGameRequestObject struct { - RoomId RoomId `json:"roomId"` - GameId QueueGameId `json:"gameId"` - Body *EnterQueueGameJSONRequestBody +type PollPairingRequestObject struct { + Id string `json:"id"` } -type EnterQueueGameResponseObject interface { - VisitEnterQueueGameResponse(w http.ResponseWriter) error +type PollPairingResponseObject interface { + VisitPollPairingResponse(w http.ResponseWriter) error } -type EnterQueueGame200JSONResponse QueueGame +type PollPairing200JSONResponse PairingStatus -func (response EnterQueueGame200JSONResponse) VisitEnterQueueGameResponse(w http.ResponseWriter) error { +func (response PollPairing200JSONResponse) VisitPollPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14106,12 +14184,12 @@ func (response EnterQueueGame200JSONResponse) VisitEnterQueueGameResponse(w http return err } -type EnterQueueGamedefaultJSONResponse struct { +type PollPairingdefaultJSONResponse struct { Body Error StatusCode int } -func (response EnterQueueGamedefaultJSONResponse) VisitEnterQueueGameResponse(w http.ResponseWriter) error { +func (response PollPairingdefaultJSONResponse) VisitPollPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14123,19 +14201,16 @@ func (response EnterQueueGamedefaultJSONResponse) VisitEnterQueueGameResponse(w return err } -type WithdrawQueueGameEntryRequestObject struct { - RoomId RoomId `json:"roomId"` - GameId QueueGameId `json:"gameId"` - ItemId string `json:"itemId"` +type ListSavedPlaylistsRequestObject struct { } -type WithdrawQueueGameEntryResponseObject interface { - VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error +type ListSavedPlaylistsResponseObject interface { + VisitListSavedPlaylistsResponse(w http.ResponseWriter) error } -type WithdrawQueueGameEntry200JSONResponse QueueGame +type ListSavedPlaylists200JSONResponse []SavedPlaylistSummary -func (response WithdrawQueueGameEntry200JSONResponse) VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error { +func (response ListSavedPlaylists200JSONResponse) VisitListSavedPlaylistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14147,12 +14222,12 @@ func (response WithdrawQueueGameEntry200JSONResponse) VisitWithdrawQueueGameEntr return err } -type WithdrawQueueGameEntrydefaultJSONResponse struct { +type ListSavedPlaylistsdefaultJSONResponse struct { Body Error StatusCode int } -func (response WithdrawQueueGameEntrydefaultJSONResponse) VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error { +func (response ListSavedPlaylistsdefaultJSONResponse) VisitListSavedPlaylistsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14164,35 +14239,34 @@ func (response WithdrawQueueGameEntrydefaultJSONResponse) VisitWithdrawQueueGame return err } -type HintQueueGameRequestObject struct { - RoomId RoomId `json:"roomId"` - GameId QueueGameId `json:"gameId"` +type CreateSavedPlaylistRequestObject struct { + Body *CreateSavedPlaylistJSONRequestBody } -type HintQueueGameResponseObject interface { - VisitHintQueueGameResponse(w http.ResponseWriter) error +type CreateSavedPlaylistResponseObject interface { + VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error } -type HintQueueGame200JSONResponse QueueGame +type CreateSavedPlaylist201JSONResponse SavedPlaylist -func (response HintQueueGame200JSONResponse) VisitHintQueueGameResponse(w http.ResponseWriter) error { +func (response CreateSavedPlaylist201JSONResponse) VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type HintQueueGamedefaultJSONResponse struct { +type CreateSavedPlaylistdefaultJSONResponse struct { Body Error StatusCode int } -func (response HintQueueGamedefaultJSONResponse) VisitHintQueueGameResponse(w http.ResponseWriter) error { +func (response CreateSavedPlaylistdefaultJSONResponse) VisitCreateSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14204,42 +14278,28 @@ func (response HintQueueGamedefaultJSONResponse) VisitHintQueueGameResponse(w ht return err } -type GetGameRoundRequestObject struct { - RoomId RoomId `json:"roomId"` -} - -type GetGameRoundResponseObject interface { - VisitGetGameRoundResponse(w http.ResponseWriter) error +type DeleteSavedPlaylistRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` } -type GetGameRound200JSONResponse GameRound - -func (response GetGameRound200JSONResponse) VisitGetGameRoundResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +type DeleteSavedPlaylistResponseObject interface { + VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error } -type GetGameRound204Response struct { +type DeleteSavedPlaylist204Response struct { } -func (response GetGameRound204Response) VisitGetGameRoundResponse(w http.ResponseWriter) error { +func (response DeleteSavedPlaylist204Response) VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error { w.WriteHeader(204) return nil } -type GetGameRounddefaultJSONResponse struct { +type DeleteSavedPlaylistdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGameRounddefaultJSONResponse) VisitGetGameRoundResponse(w http.ResponseWriter) error { +func (response DeleteSavedPlaylistdefaultJSONResponse) VisitDeleteSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14251,35 +14311,34 @@ func (response GetGameRounddefaultJSONResponse) VisitGetGameRoundResponse(w http return err } -type StartGameRoundRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *StartGameRoundJSONRequestBody +type GetSavedPlaylistRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` } -type StartGameRoundResponseObject interface { - VisitStartGameRoundResponse(w http.ResponseWriter) error +type GetSavedPlaylistResponseObject interface { + VisitGetSavedPlaylistResponse(w http.ResponseWriter) error } -type StartGameRound201JSONResponse GameRound +type GetSavedPlaylist200JSONResponse SavedPlaylist -func (response StartGameRound201JSONResponse) VisitStartGameRoundResponse(w http.ResponseWriter) error { +func (response GetSavedPlaylist200JSONResponse) VisitGetSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type StartGameRounddefaultJSONResponse struct { +type GetSavedPlaylistdefaultJSONResponse struct { Body Error StatusCode int } -func (response StartGameRounddefaultJSONResponse) VisitStartGameRoundResponse(w http.ResponseWriter) error { +func (response GetSavedPlaylistdefaultJSONResponse) VisitGetSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14291,19 +14350,18 @@ func (response StartGameRounddefaultJSONResponse) VisitStartGameRoundResponse(w return err } -type AnswerGameRoundRequestObject struct { - RoomId RoomId `json:"roomId"` - RoundId string `json:"roundId"` - Body *AnswerGameRoundJSONRequestBody +type UpdateSavedPlaylistRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` + Body *UpdateSavedPlaylistJSONRequestBody } -type AnswerGameRoundResponseObject interface { - VisitAnswerGameRoundResponse(w http.ResponseWriter) error +type UpdateSavedPlaylistResponseObject interface { + VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error } -type AnswerGameRound200JSONResponse GameAnswer +type UpdateSavedPlaylist200JSONResponse SavedPlaylist -func (response AnswerGameRound200JSONResponse) VisitAnswerGameRoundResponse(w http.ResponseWriter) error { +func (response UpdateSavedPlaylist200JSONResponse) VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14315,12 +14373,12 @@ func (response AnswerGameRound200JSONResponse) VisitAnswerGameRoundResponse(w ht return err } -type AnswerGameRounddefaultJSONResponse struct { +type UpdateSavedPlaylistdefaultJSONResponse struct { Body Error StatusCode int } -func (response AnswerGameRounddefaultJSONResponse) VisitAnswerGameRoundResponse(w http.ResponseWriter) error { +func (response UpdateSavedPlaylistdefaultJSONResponse) VisitUpdateSavedPlaylistResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14332,43 +14390,35 @@ func (response AnswerGameRounddefaultJSONResponse) VisitAnswerGameRoundResponse( return err } -type GetGameRoundArtworkRequestObject struct { - RoomId RoomId `json:"roomId"` - RoundId string `json:"roundId"` - Params GetGameRoundArtworkParams +type AddSavedPlaylistSongsRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` + Body *AddSavedPlaylistSongsJSONRequestBody } -type GetGameRoundArtworkResponseObject interface { - VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error +type AddSavedPlaylistSongsResponseObject interface { + VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error } -type GetGameRoundArtwork200ImageResponse struct { - Body io.Reader - ContentType string - ContentLength int64 -} +type AddSavedPlaylistSongs200JSONResponse SavedPlaylist -func (response GetGameRoundArtwork200ImageResponse) VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error { +func (response AddSavedPlaylistSongs200JSONResponse) VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() - } - _, err := io.Copy(w, response.Body) + _, err := buf.WriteTo(w) return err } -type GetGameRoundArtworkdefaultJSONResponse struct { +type AddSavedPlaylistSongsdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGameRoundArtworkdefaultJSONResponse) VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error { +func (response AddSavedPlaylistSongsdefaultJSONResponse) VisitAddSavedPlaylistSongsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14380,17 +14430,18 @@ func (response GetGameRoundArtworkdefaultJSONResponse) VisitGetGameRoundArtworkR return err } -type GetGameScoresRequestObject struct { - RoomId RoomId `json:"roomId"` +type RemoveSavedPlaylistSongRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` + SongId PlaylistSongId `json:"songId"` } -type GetGameScoresResponseObject interface { - VisitGetGameScoresResponse(w http.ResponseWriter) error +type RemoveSavedPlaylistSongResponseObject interface { + VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error } -type GetGameScores200JSONResponse GameScores +type RemoveSavedPlaylistSong200JSONResponse SavedPlaylist -func (response GetGameScores200JSONResponse) VisitGetGameScoresResponse(w http.ResponseWriter) error { +func (response RemoveSavedPlaylistSong200JSONResponse) VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14402,12 +14453,12 @@ func (response GetGameScores200JSONResponse) VisitGetGameScoresResponse(w http.R return err } -type GetGameScoresdefaultJSONResponse struct { +type RemoveSavedPlaylistSongdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGameScoresdefaultJSONResponse) VisitGetGameScoresResponse(w http.ResponseWriter) error { +func (response RemoveSavedPlaylistSongdefaultJSONResponse) VisitRemoveSavedPlaylistSongResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14419,28 +14470,43 @@ func (response GetGameScoresdefaultJSONResponse) VisitGetGameScoresResponse(w ht return err } -type RevokeGuestPassRequestObject struct { - RoomId RoomId `json:"roomId"` +type GetSavedPlaylistSongArtworkRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` + SongId PlaylistSongId `json:"songId"` + Params GetSavedPlaylistSongArtworkParams } -type RevokeGuestPassResponseObject interface { - VisitRevokeGuestPassResponse(w http.ResponseWriter) error +type GetSavedPlaylistSongArtworkResponseObject interface { + VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error } -type RevokeGuestPass204Response struct { +type GetSavedPlaylistSongArtwork200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 } -func (response RevokeGuestPass204Response) VisitRevokeGuestPassResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response GetSavedPlaylistSongArtwork200ImageResponse) VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err } -type RevokeGuestPassdefaultJSONResponse struct { +type GetSavedPlaylistSongArtworkdefaultJSONResponse struct { Body Error StatusCode int } -func (response RevokeGuestPassdefaultJSONResponse) VisitRevokeGuestPassResponse(w http.ResponseWriter) error { +func (response GetSavedPlaylistSongArtworkdefaultJSONResponse) VisitGetSavedPlaylistSongArtworkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14452,17 +14518,19 @@ func (response RevokeGuestPassdefaultJSONResponse) VisitRevokeGuestPassResponse( return err } -type GetGuestPassRequestObject struct { - RoomId RoomId `json:"roomId"` +type MoveSavedPlaylistSongRequestObject struct { + PlaylistId PlaylistId `json:"playlistId"` + SongId PlaylistSongId `json:"songId"` + Body *MoveSavedPlaylistSongJSONRequestBody } -type GetGuestPassResponseObject interface { - VisitGetGuestPassResponse(w http.ResponseWriter) error +type MoveSavedPlaylistSongResponseObject interface { + VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error } -type GetGuestPass200JSONResponse GuestPass +type MoveSavedPlaylistSong200JSONResponse SavedPlaylist -func (response GetGuestPass200JSONResponse) VisitGetGuestPassResponse(w http.ResponseWriter) error { +func (response MoveSavedPlaylistSong200JSONResponse) VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14474,12 +14542,12 @@ func (response GetGuestPass200JSONResponse) VisitGetGuestPassResponse(w http.Res return err } -type GetGuestPassdefaultJSONResponse struct { +type MoveSavedPlaylistSongdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetGuestPassdefaultJSONResponse) VisitGetGuestPassResponse(w http.ResponseWriter) error { +func (response MoveSavedPlaylistSongdefaultJSONResponse) VisitMoveSavedPlaylistSongResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14491,35 +14559,33 @@ func (response GetGuestPassdefaultJSONResponse) VisitGetGuestPassResponse(w http return err } -type CreateGuestPassRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *CreateGuestPassJSONRequestBody +type ListProvidersRequestObject struct { } -type CreateGuestPassResponseObject interface { - VisitCreateGuestPassResponse(w http.ResponseWriter) error +type ListProvidersResponseObject interface { + VisitListProvidersResponse(w http.ResponseWriter) error } -type CreateGuestPass201JSONResponse GuestPass +type ListProviders200JSONResponse []ProviderInfo -func (response CreateGuestPass201JSONResponse) VisitCreateGuestPassResponse(w http.ResponseWriter) error { +func (response ListProviders200JSONResponse) VisitListProvidersResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateGuestPassdefaultJSONResponse struct { +type ListProvidersdefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateGuestPassdefaultJSONResponse) VisitCreateGuestPassResponse(w http.ResponseWriter) error { +func (response ListProvidersdefaultJSONResponse) VisitListProvidersResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14531,17 +14597,17 @@ func (response CreateGuestPassdefaultJSONResponse) VisitCreateGuestPassResponse( return err } -type ListGuestsRequestObject struct { - RoomId RoomId `json:"roomId"` +type GetRandomTracksRequestObject struct { + Params GetRandomTracksParams } -type ListGuestsResponseObject interface { - VisitListGuestsResponse(w http.ResponseWriter) error +type GetRandomTracksResponseObject interface { + VisitGetRandomTracksResponse(w http.ResponseWriter) error } -type ListGuests200JSONResponse []Guest +type GetRandomTracks200JSONResponse TrackList -func (response ListGuests200JSONResponse) VisitListGuestsResponse(w http.ResponseWriter) error { +func (response GetRandomTracks200JSONResponse) VisitGetRandomTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14553,12 +14619,12 @@ func (response ListGuests200JSONResponse) VisitListGuestsResponse(w http.Respons return err } -type ListGuestsdefaultJSONResponse struct { +type GetRandomTracksdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListGuestsdefaultJSONResponse) VisitListGuestsResponse(w http.ResponseWriter) error { +func (response GetRandomTracksdefaultJSONResponse) VisitGetRandomTracksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14570,29 +14636,33 @@ func (response ListGuestsdefaultJSONResponse) VisitListGuestsResponse(w http.Res return err } -type KickGuestRequestObject struct { - RoomId RoomId `json:"roomId"` - UserId string `json:"userId"` +type ListResetLinksRequestObject struct { } -type KickGuestResponseObject interface { - VisitKickGuestResponse(w http.ResponseWriter) error +type ListResetLinksResponseObject interface { + VisitListResetLinksResponse(w http.ResponseWriter) error } -type KickGuest204Response struct { -} +type ListResetLinks200JSONResponse []ResetLink -func (response KickGuest204Response) VisitKickGuestResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response ListResetLinks200JSONResponse) VisitListResetLinksResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type KickGuestdefaultJSONResponse struct { +type ListResetLinksdefaultJSONResponse struct { Body Error StatusCode int } -func (response KickGuestdefaultJSONResponse) VisitKickGuestResponse(w http.ResponseWriter) error { +func (response ListResetLinksdefaultJSONResponse) VisitListResetLinksResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14604,18 +14674,17 @@ func (response KickGuestdefaultJSONResponse) VisitKickGuestResponse(w http.Respo return err } -type GetHistoryRequestObject struct { - RoomId RoomId `json:"roomId"` - Params GetHistoryParams +type GetResetLinkRequestObject struct { + Code ResetCode `json:"code"` } -type GetHistoryResponseObject interface { - VisitGetHistoryResponse(w http.ResponseWriter) error +type GetResetLinkResponseObject interface { + VisitGetResetLinkResponse(w http.ResponseWriter) error } -type GetHistory200JSONResponse []PlayedItem +type GetResetLink200JSONResponse ResetLinkInfo -func (response GetHistory200JSONResponse) VisitGetHistoryResponse(w http.ResponseWriter) error { +func (response GetResetLink200JSONResponse) VisitGetResetLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14627,12 +14696,12 @@ func (response GetHistory200JSONResponse) VisitGetHistoryResponse(w http.Respons return err } -type GetHistorydefaultJSONResponse struct { +type GetResetLinkdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetHistorydefaultJSONResponse) VisitGetHistoryResponse(w http.ResponseWriter) error { +func (response GetResetLinkdefaultJSONResponse) VisitGetResetLinkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14644,17 +14713,17 @@ func (response GetHistorydefaultJSONResponse) VisitGetHistoryResponse(w http.Res return err } -type ListRoomInvitesRequestObject struct { - RoomId RoomId `json:"roomId"` +type BeginResetPasskeyRequestObject struct { + Code ResetCode `json:"code"` } -type ListRoomInvitesResponseObject interface { - VisitListRoomInvitesResponse(w http.ResponseWriter) error +type BeginResetPasskeyResponseObject interface { + VisitBeginResetPasskeyResponse(w http.ResponseWriter) error } -type ListRoomInvites200JSONResponse []RoomInvite +type BeginResetPasskey200JSONResponse struct{ CeremonyJSONResponse } -func (response ListRoomInvites200JSONResponse) VisitListRoomInvitesResponse(w http.ResponseWriter) error { +func (response BeginResetPasskey200JSONResponse) VisitBeginResetPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14666,12 +14735,12 @@ func (response ListRoomInvites200JSONResponse) VisitListRoomInvitesResponse(w ht return err } -type ListRoomInvitesdefaultJSONResponse struct { +type BeginResetPasskeydefaultJSONResponse struct { Body Error StatusCode int } -func (response ListRoomInvitesdefaultJSONResponse) VisitListRoomInvitesResponse(w http.ResponseWriter) error { +func (response BeginResetPasskeydefaultJSONResponse) VisitBeginResetPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14683,35 +14752,38 @@ func (response ListRoomInvitesdefaultJSONResponse) VisitListRoomInvitesResponse( return err } -type CreateRoomInviteRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *CreateRoomInviteJSONRequestBody +type FinishResetPasskeyRequestObject struct { + Code ResetCode `json:"code"` + Body *FinishResetPasskeyJSONRequestBody } -type CreateRoomInviteResponseObject interface { - VisitCreateRoomInviteResponse(w http.ResponseWriter) error +type FinishResetPasskeyResponseObject interface { + VisitFinishResetPasskeyResponse(w http.ResponseWriter) error } -type CreateRoomInvite201JSONResponse RoomInvite +type FinishResetPasskey200JSONResponse struct{ SignedInJSONResponse } -func (response CreateRoomInvite201JSONResponse) VisitCreateRoomInviteResponse(w http.ResponseWriter) error { +func (response FinishResetPasskey200JSONResponse) VisitFinishResetPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateRoomInvitedefaultJSONResponse struct { +type FinishResetPasskeydefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateRoomInvitedefaultJSONResponse) VisitCreateRoomInviteResponse(w http.ResponseWriter) error { +func (response FinishResetPasskeydefaultJSONResponse) VisitFinishResetPasskeyResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14723,29 +14795,38 @@ func (response CreateRoomInvitedefaultJSONResponse) VisitCreateRoomInviteRespons return err } -type RevokeRoomInviteRequestObject struct { - RoomId RoomId `json:"roomId"` - Code string `json:"code"` +type ResetPasswordRequestObject struct { + Code ResetCode `json:"code"` + Body *ResetPasswordJSONRequestBody } -type RevokeRoomInviteResponseObject interface { - VisitRevokeRoomInviteResponse(w http.ResponseWriter) error +type ResetPasswordResponseObject interface { + VisitResetPasswordResponse(w http.ResponseWriter) error } -type RevokeRoomInvite204Response struct { -} +type ResetPassword200JSONResponse struct{ SignedInJSONResponse } -func (response RevokeRoomInvite204Response) VisitRevokeRoomInviteResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response ResetPassword200JSONResponse) VisitResetPasswordResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + if response.Headers.SetCookie != nil { + w.Header().Set("Set-Cookie", fmt.Sprint(*response.Headers.SetCookie)) + } + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type RevokeRoomInvitedefaultJSONResponse struct { +type ResetPassworddefaultJSONResponse struct { Body Error StatusCode int } -func (response RevokeRoomInvitedefaultJSONResponse) VisitRevokeRoomInviteResponse(w http.ResponseWriter) error { +func (response ResetPassworddefaultJSONResponse) VisitResetPasswordResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14757,17 +14838,17 @@ func (response RevokeRoomInvitedefaultJSONResponse) VisitRevokeRoomInviteRespons return err } -type ClearLaneRequestObject struct { - RoomId RoomId `json:"roomId"` +type GetRoomInviteRequestObject struct { + Code string `json:"code"` } -type ClearLaneResponseObject interface { - VisitClearLaneResponse(w http.ResponseWriter) error +type GetRoomInviteResponseObject interface { + VisitGetRoomInviteResponse(w http.ResponseWriter) error } -type ClearLane200JSONResponse ClearedLane +type GetRoomInvite200JSONResponse RoomInvitePreview -func (response ClearLane200JSONResponse) VisitClearLaneResponse(w http.ResponseWriter) error { +func (response GetRoomInvite200JSONResponse) VisitGetRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14779,12 +14860,12 @@ func (response ClearLane200JSONResponse) VisitClearLaneResponse(w http.ResponseW return err } -type ClearLanedefaultJSONResponse struct { +type GetRoomInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response ClearLanedefaultJSONResponse) VisitClearLaneResponse(w http.ResponseWriter) error { +func (response GetRoomInvitedefaultJSONResponse) VisitGetRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14796,17 +14877,17 @@ func (response ClearLanedefaultJSONResponse) VisitClearLaneResponse(w http.Respo return err } -type ListRoomMembersRequestObject struct { - RoomId RoomId `json:"roomId"` +type UseRoomInviteRequestObject struct { + Code string `json:"code"` } -type ListRoomMembersResponseObject interface { - VisitListRoomMembersResponse(w http.ResponseWriter) error +type UseRoomInviteResponseObject interface { + VisitUseRoomInviteResponse(w http.ResponseWriter) error } -type ListRoomMembers200JSONResponse []RoomMember +type UseRoomInvite200JSONResponse RoomInviteResult -func (response ListRoomMembers200JSONResponse) VisitListRoomMembersResponse(w http.ResponseWriter) error { +func (response UseRoomInvite200JSONResponse) VisitUseRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -14818,12 +14899,12 @@ func (response ListRoomMembers200JSONResponse) VisitListRoomMembersResponse(w ht return err } -type ListRoomMembersdefaultJSONResponse struct { +type UseRoomInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response ListRoomMembersdefaultJSONResponse) VisitListRoomMembersResponse(w http.ResponseWriter) error { +func (response UseRoomInvitedefaultJSONResponse) VisitUseRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14835,63 +14916,33 @@ func (response ListRoomMembersdefaultJSONResponse) VisitListRoomMembersResponse( return err } -type RemoveRoomMemberRequestObject struct { - RoomId RoomId `json:"roomId"` - UserId string `json:"userId"` -} - -type RemoveRoomMemberResponseObject interface { - VisitRemoveRoomMemberResponse(w http.ResponseWriter) error -} - -type RemoveRoomMember204Response struct { +type ListRoomsRequestObject struct { } -func (response RemoveRoomMember204Response) VisitRemoveRoomMemberResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +type ListRoomsResponseObject interface { + VisitListRoomsResponse(w http.ResponseWriter) error } -type RemoveRoomMemberdefaultJSONResponse struct { - Body Error - StatusCode int -} +type ListRooms200JSONResponse []Room -func (response RemoveRoomMemberdefaultJSONResponse) VisitRemoveRoomMemberResponse(w http.ResponseWriter) error { +func (response ListRooms200JSONResponse) VisitListRoomsResponse(w http.ResponseWriter) error { var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(response.StatusCode) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type AddRoomMemberRequestObject struct { - RoomId RoomId `json:"roomId"` - UserId string `json:"userId"` -} - -type AddRoomMemberResponseObject interface { - VisitAddRoomMemberResponse(w http.ResponseWriter) error -} - -type AddRoomMember204Response struct { -} - -func (response AddRoomMember204Response) VisitAddRoomMemberResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil -} - -type AddRoomMemberdefaultJSONResponse struct { +type ListRoomsdefaultJSONResponse struct { Body Error StatusCode int } -func (response AddRoomMemberdefaultJSONResponse) VisitAddRoomMemberResponse(w http.ResponseWriter) error { +func (response ListRoomsdefaultJSONResponse) VisitListRoomsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14903,35 +14954,34 @@ func (response AddRoomMemberdefaultJSONResponse) VisitAddRoomMemberResponse(w ht return err } -type ListNightsRequestObject struct { - RoomId RoomId `json:"roomId"` - Params ListNightsParams +type CreateRoomRequestObject struct { + Body *CreateRoomJSONRequestBody } -type ListNightsResponseObject interface { - VisitListNightsResponse(w http.ResponseWriter) error +type CreateRoomResponseObject interface { + VisitCreateRoomResponse(w http.ResponseWriter) error } -type ListNights200JSONResponse []Night +type CreateRoom201JSONResponse Room -func (response ListNights200JSONResponse) VisitListNightsResponse(w http.ResponseWriter) error { +func (response CreateRoom201JSONResponse) VisitCreateRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type ListNightsdefaultJSONResponse struct { +type CreateRoomdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListNightsdefaultJSONResponse) VisitListNightsResponse(w http.ResponseWriter) error { +func (response CreateRoomdefaultJSONResponse) VisitCreateRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14943,34 +14993,28 @@ func (response ListNightsdefaultJSONResponse) VisitListNightsResponse(w http.Res return err } -type EndNightRequestObject struct { +type DeleteRoomRequestObject struct { RoomId RoomId `json:"roomId"` } -type EndNightResponseObject interface { - VisitEndNightResponse(w http.ResponseWriter) error +type DeleteRoomResponseObject interface { + VisitDeleteRoomResponse(w http.ResponseWriter) error } -type EndNight201JSONResponse Night - -func (response EndNight201JSONResponse) VisitEndNightResponse(w http.ResponseWriter) error { +type DeleteRoom204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) - _, err := buf.WriteTo(w) - return err +func (response DeleteRoom204Response) VisitDeleteRoomResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type EndNightdefaultJSONResponse struct { +type DeleteRoomdefaultJSONResponse struct { Body Error StatusCode int } -func (response EndNightdefaultJSONResponse) VisitEndNightResponse(w http.ResponseWriter) error { +func (response DeleteRoomdefaultJSONResponse) VisitDeleteRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -14982,18 +15026,17 @@ func (response EndNightdefaultJSONResponse) VisitEndNightResponse(w http.Respons return err } -type TransferRoomRequestObject struct { +type GetRoomRequestObject struct { RoomId RoomId `json:"roomId"` - Body *TransferRoomJSONRequestBody } -type TransferRoomResponseObject interface { - VisitTransferRoomResponse(w http.ResponseWriter) error +type GetRoomResponseObject interface { + VisitGetRoomResponse(w http.ResponseWriter) error } -type TransferRoom200JSONResponse Room +type GetRoom200JSONResponse Room -func (response TransferRoom200JSONResponse) VisitTransferRoomResponse(w http.ResponseWriter) error { +func (response GetRoom200JSONResponse) VisitGetRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15005,12 +15048,12 @@ func (response TransferRoom200JSONResponse) VisitTransferRoomResponse(w http.Res return err } -type TransferRoomdefaultJSONResponse struct { +type GetRoomdefaultJSONResponse struct { Body Error StatusCode int } -func (response TransferRoomdefaultJSONResponse) VisitTransferRoomResponse(w http.ResponseWriter) error { +func (response GetRoomdefaultJSONResponse) VisitGetRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15022,17 +15065,18 @@ func (response TransferRoomdefaultJSONResponse) VisitTransferRoomResponse(w http return err } -type GetPlaybackRequestObject struct { +type UpdateRoomRequestObject struct { RoomId RoomId `json:"roomId"` + Body *UpdateRoomJSONRequestBody } -type GetPlaybackResponseObject interface { - VisitGetPlaybackResponse(w http.ResponseWriter) error +type UpdateRoomResponseObject interface { + VisitUpdateRoomResponse(w http.ResponseWriter) error } -type GetPlayback200JSONResponse NowPlaying +type UpdateRoom200JSONResponse Room -func (response GetPlayback200JSONResponse) VisitGetPlaybackResponse(w http.ResponseWriter) error { +func (response UpdateRoom200JSONResponse) VisitUpdateRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15044,12 +15088,12 @@ func (response GetPlayback200JSONResponse) VisitGetPlaybackResponse(w http.Respo return err } -type GetPlaybackdefaultJSONResponse struct { +type UpdateRoomdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetPlaybackdefaultJSONResponse) VisitGetPlaybackResponse(w http.ResponseWriter) error { +func (response UpdateRoomdefaultJSONResponse) VisitUpdateRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15061,18 +15105,17 @@ func (response GetPlaybackdefaultJSONResponse) VisitGetPlaybackResponse(w http.R return err } -type ControlPlaybackRequestObject struct { +type JoinRoomAsAdminRequestObject struct { RoomId RoomId `json:"roomId"` - Body *ControlPlaybackJSONRequestBody } -type ControlPlaybackResponseObject interface { - VisitControlPlaybackResponse(w http.ResponseWriter) error +type JoinRoomAsAdminResponseObject interface { + VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error } -type ControlPlayback200JSONResponse NowPlaying +type JoinRoomAsAdmin200JSONResponse Room -func (response ControlPlayback200JSONResponse) VisitControlPlaybackResponse(w http.ResponseWriter) error { +func (response JoinRoomAsAdmin200JSONResponse) VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15084,12 +15127,12 @@ func (response ControlPlayback200JSONResponse) VisitControlPlaybackResponse(w ht return err } -type ControlPlaybackdefaultJSONResponse struct { +type JoinRoomAsAdmindefaultJSONResponse struct { Body Error StatusCode int } -func (response ControlPlaybackdefaultJSONResponse) VisitControlPlaybackResponse(w http.ResponseWriter) error { +func (response JoinRoomAsAdmindefaultJSONResponse) VisitJoinRoomAsAdminResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15101,18 +15144,18 @@ func (response ControlPlaybackdefaultJSONResponse) VisitControlPlaybackResponse( return err } -type ReleasePlayerRequestObject struct { +type GetRoomArtistPlaysRequestObject struct { RoomId RoomId `json:"roomId"` - Params ReleasePlayerParams + Params GetRoomArtistPlaysParams } -type ReleasePlayerResponseObject interface { - VisitReleasePlayerResponse(w http.ResponseWriter) error +type GetRoomArtistPlaysResponseObject interface { + VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error } -type ReleasePlayer200JSONResponse NowPlaying +type GetRoomArtistPlays200JSONResponse []TrackCount -func (response ReleasePlayer200JSONResponse) VisitReleasePlayerResponse(w http.ResponseWriter) error { +func (response GetRoomArtistPlays200JSONResponse) VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15124,12 +15167,12 @@ func (response ReleasePlayer200JSONResponse) VisitReleasePlayerResponse(w http.R return err } -type ReleasePlayerdefaultJSONResponse struct { +type GetRoomArtistPlaysdefaultJSONResponse struct { Body Error StatusCode int } -func (response ReleasePlayerdefaultJSONResponse) VisitReleasePlayerResponse(w http.ResponseWriter) error { +func (response GetRoomArtistPlaysdefaultJSONResponse) VisitGetRoomArtistPlaysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15141,18 +15184,17 @@ func (response ReleasePlayerdefaultJSONResponse) VisitReleasePlayerResponse(w ht return err } -type ClaimPlayerRequestObject struct { +type ListDisplaysRequestObject struct { RoomId RoomId `json:"roomId"` - Body *ClaimPlayerJSONRequestBody } -type ClaimPlayerResponseObject interface { - VisitClaimPlayerResponse(w http.ResponseWriter) error +type ListDisplaysResponseObject interface { + VisitListDisplaysResponse(w http.ResponseWriter) error } -type ClaimPlayer200JSONResponse NowPlaying +type ListDisplays200JSONResponse []Display -func (response ClaimPlayer200JSONResponse) VisitClaimPlayerResponse(w http.ResponseWriter) error { +func (response ListDisplays200JSONResponse) VisitListDisplaysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15164,12 +15206,12 @@ func (response ClaimPlayer200JSONResponse) VisitClaimPlayerResponse(w http.Respo return err } -type ClaimPlayerdefaultJSONResponse struct { +type ListDisplaysdefaultJSONResponse struct { Body Error StatusCode int } -func (response ClaimPlayerdefaultJSONResponse) VisitClaimPlayerResponse(w http.ResponseWriter) error { +func (response ListDisplaysdefaultJSONResponse) VisitListDisplaysResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15181,35 +15223,35 @@ func (response ClaimPlayerdefaultJSONResponse) VisitClaimPlayerResponse(w http.R return err } -type ReportPlaybackRequestObject struct { +type PairDisplayRequestObject struct { RoomId RoomId `json:"roomId"` - Body *ReportPlaybackJSONRequestBody + Body *PairDisplayJSONRequestBody } -type ReportPlaybackResponseObject interface { - VisitReportPlaybackResponse(w http.ResponseWriter) error +type PairDisplayResponseObject interface { + VisitPairDisplayResponse(w http.ResponseWriter) error } -type ReportPlayback200JSONResponse NowPlaying +type PairDisplay201JSONResponse Display -func (response ReportPlayback200JSONResponse) VisitReportPlaybackResponse(w http.ResponseWriter) error { +func (response PairDisplay201JSONResponse) VisitPairDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type ReportPlaybackdefaultJSONResponse struct { +type PairDisplaydefaultJSONResponse struct { Body Error StatusCode int } -func (response ReportPlaybackdefaultJSONResponse) VisitReportPlaybackResponse(w http.ResponseWriter) error { +func (response PairDisplaydefaultJSONResponse) VisitPairDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15221,35 +15263,35 @@ func (response ReportPlaybackdefaultJSONResponse) VisitReportPlaybackResponse(w return err } -type SaveNightPlaylistRequestObject struct { +type LookupDisplayPairingRequestObject struct { RoomId RoomId `json:"roomId"` - Body *SaveNightPlaylistJSONRequestBody + Code string `json:"code"` } -type SaveNightPlaylistResponseObject interface { - VisitSaveNightPlaylistResponse(w http.ResponseWriter) error +type LookupDisplayPairingResponseObject interface { + VisitLookupDisplayPairingResponse(w http.ResponseWriter) error } -type SaveNightPlaylist201JSONResponse SavedPlaylist +type LookupDisplayPairing200JSONResponse DisplayPairingInfo -func (response SaveNightPlaylist201JSONResponse) VisitSaveNightPlaylistResponse(w http.ResponseWriter) error { +func (response LookupDisplayPairing200JSONResponse) VisitLookupDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type SaveNightPlaylistdefaultJSONResponse struct { +type LookupDisplayPairingdefaultJSONResponse struct { Body Error StatusCode int } -func (response SaveNightPlaylistdefaultJSONResponse) VisitSaveNightPlaylistResponse(w http.ResponseWriter) error { +func (response LookupDisplayPairingdefaultJSONResponse) VisitLookupDisplayPairingResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15261,34 +15303,29 @@ func (response SaveNightPlaylistdefaultJSONResponse) VisitSaveNightPlaylistRespo return err } -type GetQueueRequestObject struct { - RoomId RoomId `json:"roomId"` +type UnpairDisplayRequestObject struct { + RoomId RoomId `json:"roomId"` + DisplayId string `json:"displayId"` } -type GetQueueResponseObject interface { - VisitGetQueueResponse(w http.ResponseWriter) error +type UnpairDisplayResponseObject interface { + VisitUnpairDisplayResponse(w http.ResponseWriter) error } -type GetQueue200JSONResponse QueueSnapshot - -func (response GetQueue200JSONResponse) VisitGetQueueResponse(w http.ResponseWriter) error { +type UnpairDisplay204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response UnpairDisplay204Response) VisitUnpairDisplayResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type GetQueuedefaultJSONResponse struct { +type UnpairDisplaydefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueuedefaultJSONResponse) VisitGetQueueResponse(w http.ResponseWriter) error { +func (response UnpairDisplaydefaultJSONResponse) VisitUnpairDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15300,18 +15337,19 @@ func (response GetQueuedefaultJSONResponse) VisitGetQueueResponse(w http.Respons return err } -type AddToQueueRequestObject struct { - RoomId RoomId `json:"roomId"` - Body *AddToQueueJSONRequestBody +type UpdateDisplayRequestObject struct { + RoomId RoomId `json:"roomId"` + DisplayId string `json:"displayId"` + Body *UpdateDisplayJSONRequestBody } -type AddToQueueResponseObject interface { - VisitAddToQueueResponse(w http.ResponseWriter) error +type UpdateDisplayResponseObject interface { + VisitUpdateDisplayResponse(w http.ResponseWriter) error } -type AddToQueue200JSONResponse QueueSnapshot +type UpdateDisplay200JSONResponse Display -func (response AddToQueue200JSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { +func (response UpdateDisplay200JSONResponse) VisitUpdateDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15323,26 +15361,12 @@ func (response AddToQueue200JSONResponse) VisitAddToQueueResponse(w http.Respons return err } -type AddToQueue409JSONResponse AddToQueueConflict - -func (response AddToQueue409JSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { - - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(409) - _, err := buf.WriteTo(w) - return err -} - -type AddToQueuedefaultJSONResponse struct { +type UpdateDisplaydefaultJSONResponse struct { Body Error StatusCode int } -func (response AddToQueuedefaultJSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { +func (response UpdateDisplaydefaultJSONResponse) VisitUpdateDisplayResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15354,35 +15378,41 @@ func (response AddToQueuedefaultJSONResponse) VisitAddToQueueResponse(w http.Res return err } -type RestoreQueueItemsRequestObject struct { +type GetGameClipRequestObject struct { RoomId RoomId `json:"roomId"` - Body *RestoreQueueItemsJSONRequestBody + ClipId string `json:"clipId"` } -type RestoreQueueItemsResponseObject interface { - VisitRestoreQueueItemsResponse(w http.ResponseWriter) error +type GetGameClipResponseObject interface { + VisitGetGameClipResponse(w http.ResponseWriter) error } -type RestoreQueueItems200JSONResponse QueueSnapshot +type GetGameClip200AudiompegResponse struct { + Body io.Reader + ContentLength int64 +} -func (response RestoreQueueItems200JSONResponse) VisitRestoreQueueItemsResponse(w http.ResponseWriter) error { +func (response GetGameClip200AudiompegResponse) VisitGetGameClipResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + w.Header().Set("Content-Type", "audio/mpeg") + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - _, err := buf.WriteTo(w) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) return err } -type RestoreQueueItemsdefaultJSONResponse struct { +type GetGameClipdefaultJSONResponse struct { Body Error StatusCode int } -func (response RestoreQueueItemsdefaultJSONResponse) VisitRestoreQueueItemsResponse(w http.ResponseWriter) error { +func (response GetGameClipdefaultJSONResponse) VisitGetGameClipResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15394,18 +15424,17 @@ func (response RestoreQueueItemsdefaultJSONResponse) VisitRestoreQueueItemsRespo return err } -type RemoveQueueItemRequestObject struct { +type GetQueueGamesRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` } -type RemoveQueueItemResponseObject interface { - VisitRemoveQueueItemResponse(w http.ResponseWriter) error +type GetQueueGamesResponseObject interface { + VisitGetQueueGamesResponse(w http.ResponseWriter) error } -type RemoveQueueItem200JSONResponse QueueSnapshot +type GetQueueGames200JSONResponse QueueGames -func (response RemoveQueueItem200JSONResponse) VisitRemoveQueueItemResponse(w http.ResponseWriter) error { +func (response GetQueueGames200JSONResponse) VisitGetQueueGamesResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15417,12 +15446,12 @@ func (response RemoveQueueItem200JSONResponse) VisitRemoveQueueItemResponse(w ht return err } -type RemoveQueueItemdefaultJSONResponse struct { +type GetQueueGamesdefaultJSONResponse struct { Body Error StatusCode int } -func (response RemoveQueueItemdefaultJSONResponse) VisitRemoveQueueItemResponse(w http.ResponseWriter) error { +func (response GetQueueGamesdefaultJSONResponse) VisitGetQueueGamesResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15434,36 +15463,35 @@ func (response RemoveQueueItemdefaultJSONResponse) VisitRemoveQueueItemResponse( return err } -type MoveQueueItemRequestObject struct { +type StartQueueGameRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` - Body *MoveQueueItemJSONRequestBody + Body *StartQueueGameJSONRequestBody } -type MoveQueueItemResponseObject interface { - VisitMoveQueueItemResponse(w http.ResponseWriter) error +type StartQueueGameResponseObject interface { + VisitStartQueueGameResponse(w http.ResponseWriter) error } -type MoveQueueItem200JSONResponse QueueSnapshot +type StartQueueGame201JSONResponse QueueGame -func (response MoveQueueItem200JSONResponse) VisitMoveQueueItemResponse(w http.ResponseWriter) error { +func (response StartQueueGame201JSONResponse) VisitStartQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type MoveQueueItemdefaultJSONResponse struct { +type StartQueueGamedefaultJSONResponse struct { Body Error StatusCode int } -func (response MoveQueueItemdefaultJSONResponse) VisitMoveQueueItemResponse(w http.ResponseWriter) error { +func (response StartQueueGamedefaultJSONResponse) VisitStartQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15475,43 +15503,35 @@ func (response MoveQueueItemdefaultJSONResponse) VisitMoveQueueItemResponse(w ht return err } -type GetQueueItemArtworkRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` - Params GetQueueItemArtworkParams +type CloseQueueGameRequestObject struct { + RoomId RoomId `json:"roomId"` + GameId QueueGameId `json:"gameId"` } -type GetQueueItemArtworkResponseObject interface { - VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error +type CloseQueueGameResponseObject interface { + VisitCloseQueueGameResponse(w http.ResponseWriter) error } -type GetQueueItemArtwork200ImageResponse struct { - Body io.Reader - ContentType string - ContentLength int64 -} +type CloseQueueGame200JSONResponse QueueGame -func (response GetQueueItemArtwork200ImageResponse) VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error { +func (response CloseQueueGame200JSONResponse) VisitCloseQueueGameResponse(w http.ResponseWriter) error { - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() - } - _, err := io.Copy(w, response.Body) + _, err := buf.WriteTo(w) return err } -type GetQueueItemArtworkdefaultJSONResponse struct { +type CloseQueueGamedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemArtworkdefaultJSONResponse) VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error { +func (response CloseQueueGamedefaultJSONResponse) VisitCloseQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15523,18 +15543,19 @@ func (response GetQueueItemArtworkdefaultJSONResponse) VisitGetQueueItemArtworkR return err } -type GetQueueItemBeatMapRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` +type EnterQueueGameRequestObject struct { + RoomId RoomId `json:"roomId"` + GameId QueueGameId `json:"gameId"` + Body *EnterQueueGameJSONRequestBody } -type GetQueueItemBeatMapResponseObject interface { - VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error +type EnterQueueGameResponseObject interface { + VisitEnterQueueGameResponse(w http.ResponseWriter) error } -type GetQueueItemBeatMap200JSONResponse BeatMap +type EnterQueueGame200JSONResponse QueueGame -func (response GetQueueItemBeatMap200JSONResponse) VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error { +func (response EnterQueueGame200JSONResponse) VisitEnterQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15546,12 +15567,12 @@ func (response GetQueueItemBeatMap200JSONResponse) VisitGetQueueItemBeatMapRespo return err } -type GetQueueItemBeatMapdefaultJSONResponse struct { +type EnterQueueGamedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemBeatMapdefaultJSONResponse) VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error { +func (response EnterQueueGamedefaultJSONResponse) VisitEnterQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15563,18 +15584,19 @@ func (response GetQueueItemBeatMapdefaultJSONResponse) VisitGetQueueItemBeatMapR return err } -type UnheartSongRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` +type WithdrawQueueGameEntryRequestObject struct { + RoomId RoomId `json:"roomId"` + GameId QueueGameId `json:"gameId"` + ItemId string `json:"itemId"` } -type UnheartSongResponseObject interface { - VisitUnheartSongResponse(w http.ResponseWriter) error +type WithdrawQueueGameEntryResponseObject interface { + VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error } -type UnheartSong200JSONResponse Hearts +type WithdrawQueueGameEntry200JSONResponse QueueGame -func (response UnheartSong200JSONResponse) VisitUnheartSongResponse(w http.ResponseWriter) error { +func (response WithdrawQueueGameEntry200JSONResponse) VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15586,12 +15608,12 @@ func (response UnheartSong200JSONResponse) VisitUnheartSongResponse(w http.Respo return err } -type UnheartSongdefaultJSONResponse struct { +type WithdrawQueueGameEntrydefaultJSONResponse struct { Body Error StatusCode int } -func (response UnheartSongdefaultJSONResponse) VisitUnheartSongResponse(w http.ResponseWriter) error { +func (response WithdrawQueueGameEntrydefaultJSONResponse) VisitWithdrawQueueGameEntryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15603,18 +15625,18 @@ func (response UnheartSongdefaultJSONResponse) VisitUnheartSongResponse(w http.R return err } -type GetHeartsRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` -} - -type GetHeartsResponseObject interface { - VisitGetHeartsResponse(w http.ResponseWriter) error +type HintQueueGameRequestObject struct { + RoomId RoomId `json:"roomId"` + GameId QueueGameId `json:"gameId"` } -type GetHearts200JSONResponse Hearts +type HintQueueGameResponseObject interface { + VisitHintQueueGameResponse(w http.ResponseWriter) error +} -func (response GetHearts200JSONResponse) VisitGetHeartsResponse(w http.ResponseWriter) error { +type HintQueueGame200JSONResponse QueueGame + +func (response HintQueueGame200JSONResponse) VisitHintQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15626,12 +15648,12 @@ func (response GetHearts200JSONResponse) VisitGetHeartsResponse(w http.ResponseW return err } -type GetHeartsdefaultJSONResponse struct { +type HintQueueGamedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetHeartsdefaultJSONResponse) VisitGetHeartsResponse(w http.ResponseWriter) error { +func (response HintQueueGamedefaultJSONResponse) VisitHintQueueGameResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15643,18 +15665,17 @@ func (response GetHeartsdefaultJSONResponse) VisitGetHeartsResponse(w http.Respo return err } -type HeartSongRequestObject struct { +type GetGameRoundRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` } -type HeartSongResponseObject interface { - VisitHeartSongResponse(w http.ResponseWriter) error +type GetGameRoundResponseObject interface { + VisitGetGameRoundResponse(w http.ResponseWriter) error } -type HeartSong200JSONResponse Hearts +type GetGameRound200JSONResponse GameRound -func (response HeartSong200JSONResponse) VisitHeartSongResponse(w http.ResponseWriter) error { +func (response GetGameRound200JSONResponse) VisitGetGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15666,12 +15687,20 @@ func (response HeartSong200JSONResponse) VisitHeartSongResponse(w http.ResponseW return err } -type HeartSongdefaultJSONResponse struct { +type GetGameRound204Response struct { +} + +func (response GetGameRound204Response) VisitGetGameRoundResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type GetGameRounddefaultJSONResponse struct { Body Error StatusCode int } -func (response HeartSongdefaultJSONResponse) VisitHeartSongResponse(w http.ResponseWriter) error { +func (response GetGameRounddefaultJSONResponse) VisitGetGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15683,35 +15712,35 @@ func (response HeartSongdefaultJSONResponse) VisitHeartSongResponse(w http.Respo return err } -type GetQueueItemLinerNotesRequestObject struct { +type StartGameRoundRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` + Body *StartGameRoundJSONRequestBody } -type GetQueueItemLinerNotesResponseObject interface { - VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error +type StartGameRoundResponseObject interface { + VisitStartGameRoundResponse(w http.ResponseWriter) error } -type GetQueueItemLinerNotes200JSONResponse LinerNotes +type StartGameRound201JSONResponse GameRound -func (response GetQueueItemLinerNotes200JSONResponse) VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error { +func (response StartGameRound201JSONResponse) VisitStartGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type GetQueueItemLinerNotesdefaultJSONResponse struct { +type StartGameRounddefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemLinerNotesdefaultJSONResponse) VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error { +func (response StartGameRounddefaultJSONResponse) VisitStartGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15723,18 +15752,19 @@ func (response GetQueueItemLinerNotesdefaultJSONResponse) VisitGetQueueItemLiner return err } -type GetQueueItemLyricsRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` +type AnswerGameRoundRequestObject struct { + RoomId RoomId `json:"roomId"` + RoundId string `json:"roundId"` + Body *AnswerGameRoundJSONRequestBody } -type GetQueueItemLyricsResponseObject interface { - VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error +type AnswerGameRoundResponseObject interface { + VisitAnswerGameRoundResponse(w http.ResponseWriter) error } -type GetQueueItemLyrics200JSONResponse Lyrics +type AnswerGameRound200JSONResponse GameAnswer -func (response GetQueueItemLyrics200JSONResponse) VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error { +func (response AnswerGameRound200JSONResponse) VisitAnswerGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15746,12 +15776,12 @@ func (response GetQueueItemLyrics200JSONResponse) VisitGetQueueItemLyricsRespons return err } -type GetQueueItemLyricsdefaultJSONResponse struct { +type AnswerGameRounddefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemLyricsdefaultJSONResponse) VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error { +func (response AnswerGameRounddefaultJSONResponse) VisitAnswerGameRoundResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15763,35 +15793,43 @@ func (response GetQueueItemLyricsdefaultJSONResponse) VisitGetQueueItemLyricsRes return err } -type GetQueueItemPaletteRequestObject struct { - RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` +type GetGameRoundArtworkRequestObject struct { + RoomId RoomId `json:"roomId"` + RoundId string `json:"roundId"` + Params GetGameRoundArtworkParams } -type GetQueueItemPaletteResponseObject interface { - VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error +type GetGameRoundArtworkResponseObject interface { + VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error } -type GetQueueItemPalette200JSONResponse Palette +type GetGameRoundArtwork200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} -func (response GetQueueItemPalette200JSONResponse) VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error { +func (response GetGameRoundArtwork200ImageResponse) VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) - _, err := buf.WriteTo(w) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) return err } -type GetQueueItemPalettedefaultJSONResponse struct { +type GetGameRoundArtworkdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemPalettedefaultJSONResponse) VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error { +func (response GetGameRoundArtworkdefaultJSONResponse) VisitGetGameRoundArtworkResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15803,19 +15841,17 @@ func (response GetQueueItemPalettedefaultJSONResponse) VisitGetQueueItemPaletteR return err } -type GetQueueItemSimilarRequestObject struct { +type GetGameScoresRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` - Params GetQueueItemSimilarParams } -type GetQueueItemSimilarResponseObject interface { - VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error +type GetGameScoresResponseObject interface { + VisitGetGameScoresResponse(w http.ResponseWriter) error } -type GetQueueItemSimilar200JSONResponse TrackList +type GetGameScores200JSONResponse GameScores -func (response GetQueueItemSimilar200JSONResponse) VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error { +func (response GetGameScores200JSONResponse) VisitGetGameScoresResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15827,12 +15863,12 @@ func (response GetQueueItemSimilar200JSONResponse) VisitGetQueueItemSimilarRespo return err } -type GetQueueItemSimilardefaultJSONResponse struct { +type GetGameScoresdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetQueueItemSimilardefaultJSONResponse) VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error { +func (response GetGameScoresdefaultJSONResponse) VisitGetGameScoresResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15844,35 +15880,28 @@ func (response GetQueueItemSimilardefaultJSONResponse) VisitGetQueueItemSimilarR return err } -type SendReactionRequestObject struct { +type RevokeGuestPassRequestObject struct { RoomId RoomId `json:"roomId"` - Body *SendReactionJSONRequestBody } -type SendReactionResponseObject interface { - VisitSendReactionResponse(w http.ResponseWriter) error +type RevokeGuestPassResponseObject interface { + VisitRevokeGuestPassResponse(w http.ResponseWriter) error } -type SendReaction202JSONResponse Reaction - -func (response SendReaction202JSONResponse) VisitSendReactionResponse(w http.ResponseWriter) error { +type RevokeGuestPass204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(202) - _, err := buf.WriteTo(w) - return err +func (response RevokeGuestPass204Response) VisitRevokeGuestPassResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type SendReactiondefaultJSONResponse struct { +type RevokeGuestPassdefaultJSONResponse struct { Body Error StatusCode int } -func (response SendReactiondefaultJSONResponse) VisitSendReactionResponse(w http.ResponseWriter) error { +func (response RevokeGuestPassdefaultJSONResponse) VisitRevokeGuestPassResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15884,18 +15913,17 @@ func (response SendReactiondefaultJSONResponse) VisitSendReactionResponse(w http return err } -type GetRoomRecapRequestObject struct { +type GetGuestPassRequestObject struct { RoomId RoomId `json:"roomId"` - Params GetRoomRecapParams } -type GetRoomRecapResponseObject interface { - VisitGetRoomRecapResponse(w http.ResponseWriter) error +type GetGuestPassResponseObject interface { + VisitGetGuestPassResponse(w http.ResponseWriter) error } -type GetRoomRecap200JSONResponse Recap +type GetGuestPass200JSONResponse GuestPass -func (response GetRoomRecap200JSONResponse) VisitGetRoomRecapResponse(w http.ResponseWriter) error { +func (response GetGuestPass200JSONResponse) VisitGetGuestPassResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15907,12 +15935,12 @@ func (response GetRoomRecap200JSONResponse) VisitGetRoomRecapResponse(w http.Res return err } -type GetRoomRecapdefaultJSONResponse struct { +type GetGuestPassdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRoomRecapdefaultJSONResponse) VisitGetRoomRecapResponse(w http.ResponseWriter) error { +func (response GetGuestPassdefaultJSONResponse) VisitGetGuestPassResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15924,35 +15952,35 @@ func (response GetRoomRecapdefaultJSONResponse) VisitGetRoomRecapResponse(w http return err } -type ListSessionsRequestObject struct { +type CreateGuestPassRequestObject struct { RoomId RoomId `json:"roomId"` - Params ListSessionsParams + Body *CreateGuestPassJSONRequestBody } -type ListSessionsResponseObject interface { - VisitListSessionsResponse(w http.ResponseWriter) error +type CreateGuestPassResponseObject interface { + VisitCreateGuestPassResponse(w http.ResponseWriter) error } -type ListSessions200JSONResponse []ListeningSession +type CreateGuestPass201JSONResponse GuestPass -func (response ListSessions200JSONResponse) VisitListSessionsResponse(w http.ResponseWriter) error { +func (response CreateGuestPass201JSONResponse) VisitCreateGuestPassResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type ListSessionsdefaultJSONResponse struct { +type CreateGuestPassdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListSessionsdefaultJSONResponse) VisitListSessionsResponse(w http.ResponseWriter) error { +func (response CreateGuestPassdefaultJSONResponse) VisitCreateGuestPassResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -15964,18 +15992,17 @@ func (response ListSessionsdefaultJSONResponse) VisitListSessionsResponse(w http return err } -type GetRoomStatsRequestObject struct { +type ListGuestsRequestObject struct { RoomId RoomId `json:"roomId"` - Params GetRoomStatsParams } -type GetRoomStatsResponseObject interface { - VisitGetRoomStatsResponse(w http.ResponseWriter) error +type ListGuestsResponseObject interface { + VisitListGuestsResponse(w http.ResponseWriter) error } -type GetRoomStats200JSONResponse RoomStats +type ListGuests200JSONResponse []Guest -func (response GetRoomStats200JSONResponse) VisitGetRoomStatsResponse(w http.ResponseWriter) error { +func (response ListGuests200JSONResponse) VisitListGuestsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -15987,12 +16014,12 @@ func (response GetRoomStats200JSONResponse) VisitGetRoomStatsResponse(w http.Res return err } -type GetRoomStatsdefaultJSONResponse struct { +type ListGuestsdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetRoomStatsdefaultJSONResponse) VisitGetRoomStatsResponse(w http.ResponseWriter) error { +func (response ListGuestsdefaultJSONResponse) VisitListGuestsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16004,64 +16031,69 @@ func (response GetRoomStatsdefaultJSONResponse) VisitGetRoomStatsResponse(w http return err } -type StreamQueueItemRequestObject struct { +type KickGuestRequestObject struct { RoomId RoomId `json:"roomId"` - ItemId string `json:"itemId"` - Params StreamQueueItemParams + UserId string `json:"userId"` } -type StreamQueueItemResponseObject interface { - VisitStreamQueueItemResponse(w http.ResponseWriter) error +type KickGuestResponseObject interface { + VisitKickGuestResponse(w http.ResponseWriter) error } -type StreamQueueItem200AudioResponse struct { - Body io.Reader - ContentType string - ContentLength int64 +type KickGuest204Response struct { } -func (response StreamQueueItem200AudioResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { +func (response KickGuest204Response) VisitKickGuestResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(200) +type KickGuestdefaultJSONResponse struct { + Body Error + StatusCode int +} - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() +func (response KickGuestdefaultJSONResponse) VisitKickGuestResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err } - _, err := io.Copy(w, response.Body) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) return err } -type StreamQueueItem206AudioResponse struct { - Body io.Reader - ContentType string - ContentLength int64 +type GetHistoryRequestObject struct { + RoomId RoomId `json:"roomId"` + Params GetHistoryParams } -func (response StreamQueueItem206AudioResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { +type GetHistoryResponseObject interface { + VisitGetHistoryResponse(w http.ResponseWriter) error +} - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(206) +type GetHistory200JSONResponse []PlayedItem - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() +func (response GetHistory200JSONResponse) VisitGetHistoryResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } - _, err := io.Copy(w, response.Body) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) return err } -type StreamQueueItemdefaultJSONResponse struct { +type GetHistorydefaultJSONResponse struct { Body Error StatusCode int } -func (response StreamQueueItemdefaultJSONResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { +func (response GetHistorydefaultJSONResponse) VisitGetHistoryResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16073,18 +16105,17 @@ func (response StreamQueueItemdefaultJSONResponse) VisitStreamQueueItemResponse( return err } -type GetSuggestionsRequestObject struct { +type ListRoomInvitesRequestObject struct { RoomId RoomId `json:"roomId"` - Params GetSuggestionsParams } -type GetSuggestionsResponseObject interface { - VisitGetSuggestionsResponse(w http.ResponseWriter) error +type ListRoomInvitesResponseObject interface { + VisitListRoomInvitesResponse(w http.ResponseWriter) error } -type GetSuggestions200JSONResponse Suggestions +type ListRoomInvites200JSONResponse []RoomInvite -func (response GetSuggestions200JSONResponse) VisitGetSuggestionsResponse(w http.ResponseWriter) error { +func (response ListRoomInvites200JSONResponse) VisitListRoomInvitesResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -16096,12 +16127,12 @@ func (response GetSuggestions200JSONResponse) VisitGetSuggestionsResponse(w http return err } -type GetSuggestionsdefaultJSONResponse struct { +type ListRoomInvitesdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetSuggestionsdefaultJSONResponse) VisitGetSuggestionsResponse(w http.ResponseWriter) error { +func (response ListRoomInvitesdefaultJSONResponse) VisitListRoomInvitesResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16113,34 +16144,35 @@ func (response GetSuggestionsdefaultJSONResponse) VisitGetSuggestionsResponse(w return err } -type SearchRequestObject struct { - Params SearchParams +type CreateRoomInviteRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *CreateRoomInviteJSONRequestBody } -type SearchResponseObject interface { - VisitSearchResponse(w http.ResponseWriter) error +type CreateRoomInviteResponseObject interface { + VisitCreateRoomInviteResponse(w http.ResponseWriter) error } -type Search200JSONResponse SearchResults +type CreateRoomInvite201JSONResponse RoomInvite -func (response Search200JSONResponse) VisitSearchResponse(w http.ResponseWriter) error { +func (response CreateRoomInvite201JSONResponse) VisitCreateRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) + w.WriteHeader(201) _, err := buf.WriteTo(w) return err } -type SearchdefaultJSONResponse struct { +type CreateRoomInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response SearchdefaultJSONResponse) VisitSearchResponse(w http.ResponseWriter) error { +func (response CreateRoomInvitedefaultJSONResponse) VisitCreateRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16152,33 +16184,29 @@ func (response SearchdefaultJSONResponse) VisitSearchResponse(w http.ResponseWri return err } -type GetServerSettingsRequestObject struct { +type RevokeRoomInviteRequestObject struct { + RoomId RoomId `json:"roomId"` + Code string `json:"code"` } -type GetServerSettingsResponseObject interface { - VisitGetServerSettingsResponse(w http.ResponseWriter) error +type RevokeRoomInviteResponseObject interface { + VisitRevokeRoomInviteResponse(w http.ResponseWriter) error } -type GetServerSettings200JSONResponse ServerSettings - -func (response GetServerSettings200JSONResponse) VisitGetServerSettingsResponse(w http.ResponseWriter) error { +type RevokeRoomInvite204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response RevokeRoomInvite204Response) VisitRevokeRoomInviteResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type GetServerSettingsdefaultJSONResponse struct { +type RevokeRoomInvitedefaultJSONResponse struct { Body Error StatusCode int } -func (response GetServerSettingsdefaultJSONResponse) VisitGetServerSettingsResponse(w http.ResponseWriter) error { +func (response RevokeRoomInvitedefaultJSONResponse) VisitRevokeRoomInviteResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16190,17 +16218,17 @@ func (response GetServerSettingsdefaultJSONResponse) VisitGetServerSettingsRespo return err } -type UpdateServerSettingsRequestObject struct { - Body *UpdateServerSettingsJSONRequestBody +type ClearLaneRequestObject struct { + RoomId RoomId `json:"roomId"` } -type UpdateServerSettingsResponseObject interface { - VisitUpdateServerSettingsResponse(w http.ResponseWriter) error +type ClearLaneResponseObject interface { + VisitClearLaneResponse(w http.ResponseWriter) error } -type UpdateServerSettings200JSONResponse ServerSettings +type ClearLane200JSONResponse ClearedLane -func (response UpdateServerSettings200JSONResponse) VisitUpdateServerSettingsResponse(w http.ResponseWriter) error { +func (response ClearLane200JSONResponse) VisitClearLaneResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -16212,12 +16240,12 @@ func (response UpdateServerSettings200JSONResponse) VisitUpdateServerSettingsRes return err } -type UpdateServerSettingsdefaultJSONResponse struct { +type ClearLanedefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateServerSettingsdefaultJSONResponse) VisitUpdateServerSettingsResponse(w http.ResponseWriter) error { +func (response ClearLanedefaultJSONResponse) VisitClearLaneResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16229,16 +16257,17 @@ func (response UpdateServerSettingsdefaultJSONResponse) VisitUpdateServerSetting return err } -type ListUserAuditRequestObject struct { +type ListRoomMembersRequestObject struct { + RoomId RoomId `json:"roomId"` } -type ListUserAuditResponseObject interface { - VisitListUserAuditResponse(w http.ResponseWriter) error +type ListRoomMembersResponseObject interface { + VisitListRoomMembersResponse(w http.ResponseWriter) error } -type ListUserAudit200JSONResponse []UserAuditEntry +type ListRoomMembers200JSONResponse []RoomMember -func (response ListUserAudit200JSONResponse) VisitListUserAuditResponse(w http.ResponseWriter) error { +func (response ListRoomMembers200JSONResponse) VisitListRoomMembersResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -16250,12 +16279,12 @@ func (response ListUserAudit200JSONResponse) VisitListUserAuditResponse(w http.R return err } -type ListUserAuditdefaultJSONResponse struct { +type ListRoomMembersdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListUserAuditdefaultJSONResponse) VisitListUserAuditResponse(w http.ResponseWriter) error { +func (response ListRoomMembersdefaultJSONResponse) VisitListRoomMembersResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16267,33 +16296,29 @@ func (response ListUserAuditdefaultJSONResponse) VisitListUserAuditResponse(w ht return err } -type ListUsersRequestObject struct { +type RemoveRoomMemberRequestObject struct { + RoomId RoomId `json:"roomId"` + UserId string `json:"userId"` } -type ListUsersResponseObject interface { - VisitListUsersResponse(w http.ResponseWriter) error +type RemoveRoomMemberResponseObject interface { + VisitRemoveRoomMemberResponse(w http.ResponseWriter) error } -type ListUsers200JSONResponse []User - -func (response ListUsers200JSONResponse) VisitListUsersResponse(w http.ResponseWriter) error { +type RemoveRoomMember204Response struct { +} - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(response); err != nil { - return err - } - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(200) - _, err := buf.WriteTo(w) - return err +func (response RemoveRoomMember204Response) VisitRemoveRoomMemberResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil } -type ListUsersdefaultJSONResponse struct { +type RemoveRoomMemberdefaultJSONResponse struct { Body Error StatusCode int } -func (response ListUsersdefaultJSONResponse) VisitListUsersResponse(w http.ResponseWriter) error { +func (response RemoveRoomMemberdefaultJSONResponse) VisitRemoveRoomMemberResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16305,28 +16330,29 @@ func (response ListUsersdefaultJSONResponse) VisitListUsersResponse(w http.Respo return err } -type RemoveUserRequestObject struct { - Id string `json:"id"` +type AddRoomMemberRequestObject struct { + RoomId RoomId `json:"roomId"` + UserId string `json:"userId"` } -type RemoveUserResponseObject interface { - VisitRemoveUserResponse(w http.ResponseWriter) error +type AddRoomMemberResponseObject interface { + VisitAddRoomMemberResponse(w http.ResponseWriter) error } -type RemoveUser204Response struct { +type AddRoomMember204Response struct { } -func (response RemoveUser204Response) VisitRemoveUserResponse(w http.ResponseWriter) error { +func (response AddRoomMember204Response) VisitAddRoomMemberResponse(w http.ResponseWriter) error { w.WriteHeader(204) return nil } -type RemoveUserdefaultJSONResponse struct { +type AddRoomMemberdefaultJSONResponse struct { Body Error StatusCode int } -func (response RemoveUserdefaultJSONResponse) VisitRemoveUserResponse(w http.ResponseWriter) error { +func (response AddRoomMemberdefaultJSONResponse) VisitAddRoomMemberResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16338,18 +16364,18 @@ func (response RemoveUserdefaultJSONResponse) VisitRemoveUserResponse(w http.Res return err } -type UpdateUserRequestObject struct { - Id string `json:"id"` - Body *UpdateUserJSONRequestBody +type ListNightsRequestObject struct { + RoomId RoomId `json:"roomId"` + Params ListNightsParams } -type UpdateUserResponseObject interface { - VisitUpdateUserResponse(w http.ResponseWriter) error +type ListNightsResponseObject interface { + VisitListNightsResponse(w http.ResponseWriter) error } -type UpdateUser200JSONResponse User +type ListNights200JSONResponse []Night -func (response UpdateUser200JSONResponse) VisitUpdateUserResponse(w http.ResponseWriter) error { +func (response ListNights200JSONResponse) VisitListNightsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { @@ -16361,12 +16387,12 @@ func (response UpdateUser200JSONResponse) VisitUpdateUserResponse(w http.Respons return err } -type UpdateUserdefaultJSONResponse struct { +type ListNightsdefaultJSONResponse struct { Body Error StatusCode int } -func (response UpdateUserdefaultJSONResponse) VisitUpdateUserResponse(w http.ResponseWriter) error { +func (response ListNightsdefaultJSONResponse) VisitListNightsResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16378,41 +16404,34 @@ func (response UpdateUserdefaultJSONResponse) VisitUpdateUserResponse(w http.Res return err } -type GetUserAvatarRequestObject struct { - Id string `json:"id"` -} - -type GetUserAvatarResponseObject interface { - VisitGetUserAvatarResponse(w http.ResponseWriter) error +type EndNightRequestObject struct { + RoomId RoomId `json:"roomId"` } -type GetUserAvatar200ImageResponse struct { - Body io.Reader - ContentType string - ContentLength int64 +type EndNightResponseObject interface { + VisitEndNightResponse(w http.ResponseWriter) error } -func (response GetUserAvatar200ImageResponse) VisitGetUserAvatarResponse(w http.ResponseWriter) error { +type EndNight201JSONResponse Night - w.Header().Set("Content-Type", response.ContentType) - if response.ContentLength != 0 { - w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) - } - w.WriteHeader(200) +func (response EndNight201JSONResponse) VisitEndNightResponse(w http.ResponseWriter) error { - if closer, ok := response.Body.(io.ReadCloser); ok { - defer closer.Close() + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err } - _, err := io.Copy(w, response.Body) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(201) + _, err := buf.WriteTo(w) return err } -type GetUserAvatardefaultJSONResponse struct { +type EndNightdefaultJSONResponse struct { Body Error StatusCode int } -func (response GetUserAvatardefaultJSONResponse) VisitGetUserAvatarResponse(w http.ResponseWriter) error { +func (response EndNightdefaultJSONResponse) VisitEndNightResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16424,28 +16443,35 @@ func (response GetUserAvatardefaultJSONResponse) VisitGetUserAvatarResponse(w ht return err } -type RevokeResetLinkRequestObject struct { - Id string `json:"id"` +type TransferRoomRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *TransferRoomJSONRequestBody } -type RevokeResetLinkResponseObject interface { - VisitRevokeResetLinkResponse(w http.ResponseWriter) error +type TransferRoomResponseObject interface { + VisitTransferRoomResponse(w http.ResponseWriter) error } -type RevokeResetLink204Response struct { -} +type TransferRoom200JSONResponse Room -func (response RevokeResetLink204Response) VisitRevokeResetLinkResponse(w http.ResponseWriter) error { - w.WriteHeader(204) - return nil +func (response TransferRoom200JSONResponse) VisitTransferRoomResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err } -type RevokeResetLinkdefaultJSONResponse struct { +type TransferRoomdefaultJSONResponse struct { Body Error StatusCode int } -func (response RevokeResetLinkdefaultJSONResponse) VisitRevokeResetLinkResponse(w http.ResponseWriter) error { +func (response TransferRoomdefaultJSONResponse) VisitTransferRoomResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16457,35 +16483,34 @@ func (response RevokeResetLinkdefaultJSONResponse) VisitRevokeResetLinkResponse( return err } -type CreateResetLinkRequestObject struct { - Id string `json:"id"` - Body *CreateResetLinkJSONRequestBody +type GetPlaybackRequestObject struct { + RoomId RoomId `json:"roomId"` } -type CreateResetLinkResponseObject interface { - VisitCreateResetLinkResponse(w http.ResponseWriter) error +type GetPlaybackResponseObject interface { + VisitGetPlaybackResponse(w http.ResponseWriter) error } -type CreateResetLink201JSONResponse ResetLink +type GetPlayback200JSONResponse NowPlaying -func (response CreateResetLink201JSONResponse) VisitCreateResetLinkResponse(w http.ResponseWriter) error { +func (response GetPlayback200JSONResponse) VisitGetPlaybackResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response); err != nil { return err } w.Header().Set("Content-Type", "application/json") - w.WriteHeader(201) + w.WriteHeader(200) _, err := buf.WriteTo(w) return err } -type CreateResetLinkdefaultJSONResponse struct { +type GetPlaybackdefaultJSONResponse struct { Body Error StatusCode int } -func (response CreateResetLinkdefaultJSONResponse) VisitCreateResetLinkResponse(w http.ResponseWriter) error { +func (response GetPlaybackdefaultJSONResponse) VisitGetPlaybackResponse(w http.ResponseWriter) error { var buf bytes.Buffer if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { @@ -16497,260 +16522,1747 @@ func (response CreateResetLinkdefaultJSONResponse) VisitCreateResetLinkResponse( return err } -// StrictServerInterface represents all server handlers. -type StrictServerInterface interface { - // GetBackups Backups, their schedule, and any restore waiting for a restart (admin) - // (GET /admin/backups) - GetBackups(ctx context.Context, request GetBackupsRequestObject) (GetBackupsResponseObject, error) - // CreateBackup Back up the database now (admin) - // (POST /admin/backups) - CreateBackup(ctx context.Context, request CreateBackupRequestObject) (CreateBackupResponseObject, error) - // UpdateBackupSchedule Change when the database is backed up, and what's kept (admin) - // (PUT /admin/backups/schedule) - UpdateBackupSchedule(ctx context.Context, request UpdateBackupScheduleRequestObject) (UpdateBackupScheduleResponseObject, error) - // DeleteBackup Delete a backup (admin) - // (DELETE /admin/backups/{name}) - DeleteBackup(ctx context.Context, request DeleteBackupRequestObject) (DeleteBackupResponseObject, error) - // DownloadBackup Download a backup (admin) - // (GET /admin/backups/{name}) - DownloadBackup(ctx context.Context, request DownloadBackupRequestObject) (DownloadBackupResponseObject, error) - // ListAllLinks Every linked service on the server, and its health (admin) - // (GET /admin/links) - ListAllLinks(ctx context.Context, request ListAllLinksRequestObject) (ListAllLinksResponseObject, error) - // CancelRestore Don't restore a backup after all (admin) - // (DELETE /admin/restore) - CancelRestore(ctx context.Context, request CancelRestoreRequestObject) (CancelRestoreResponseObject, error) - // StageRestore Restore a backup when the server next restarts (admin) - // (PUT /admin/restore) - StageRestore(ctx context.Context, request StageRestoreRequestObject) (StageRestoreResponseObject, error) - // ListActiveRooms Every room, who's in it, and what it's playing through (admin) - // (GET /admin/rooms) - ListActiveRooms(ctx context.Context, request ListActiveRoomsRequestObject) (ListActiveRoomsResponseObject, error) - // GetRoomTaste What the DJ has learned of a room's taste (admin) - // (GET /admin/rooms/{roomId}/taste) - GetRoomTaste(ctx context.Context, request GetRoomTasteRequestObject) (GetRoomTasteResponseObject, error) - // GetServerInfo The server's version, uptime, database and backups (admin) - // (GET /admin/server) - GetServerInfo(ctx context.Context, request GetServerInfoRequestObject) (GetServerInfoResponseObject, error) - // ListAllSessions Everyone's signed-in devices (admin) - // (GET /admin/sessions) - ListAllSessions(ctx context.Context, request ListAllSessionsRequestObject) (ListAllSessionsResponseObject, error) - // RevokeSession Sign out anyone's device (admin) - // (DELETE /admin/sessions/{id}) - RevokeSession(ctx context.Context, request RevokeSessionRequestObject) (RevokeSessionResponseObject, error) - // Login Sign in with a username and password - // (POST /auth/login) - Login(ctx context.Context, request LoginRequestObject) (LoginResponseObject, error) - // Logout Sign out this session - // (POST /auth/logout) - Logout(ctx context.Context, request LogoutRequestObject) (LogoutResponseObject, error) - // BeginPasskeyLogin Start signing in with a passkey - // (POST /auth/passkey/begin) - BeginPasskeyLogin(ctx context.Context, request BeginPasskeyLoginRequestObject) (BeginPasskeyLoginResponseObject, error) - // FinishPasskeyLogin Finish signing in with a passkey - // (POST /auth/passkey/finish) - FinishPasskeyLogin(ctx context.Context, request FinishPasskeyLoginRequestObject) (FinishPasskeyLoginResponseObject, error) - // Signup Create an account with an invite and a password - // (POST /auth/signup) - Signup(ctx context.Context, request SignupRequestObject) (SignupResponseObject, error) - // BeginPasskeySignup Start creating an account with an invite and a passkey - // (POST /auth/signup/passkey/begin) - BeginPasskeySignup(ctx context.Context, request BeginPasskeySignupRequestObject) (BeginPasskeySignupResponseObject, error) - // FinishPasskeySignup Finish creating an account with a passkey - // (POST /auth/signup/passkey/finish) - FinishPasskeySignup(ctx context.Context, request FinishPasskeySignupRequestObject) (FinishPasskeySignupResponseObject, error) - // LeaveDisplay Unpair this display, from the display - // (DELETE /display) - LeaveDisplay(ctx context.Context, request LeaveDisplayRequestObject) (LeaveDisplayResponseObject, error) - // GetDisplay This display, and its room - // (GET /display) - GetDisplay(ctx context.Context, request GetDisplayRequestObject) (GetDisplayResponseObject, error) - // PollDisplayPairing Check whether this display has been paired - // (GET /display/pairing) - PollDisplayPairing(ctx context.Context, request PollDisplayPairingRequestObject) (PollDisplayPairingResponseObject, error) - // BeginDisplayPairing Start pairing this device as a display - // (POST /display/pairing) - BeginDisplayPairing(ctx context.Context, request BeginDisplayPairingRequestObject) (BeginDisplayPairingResponseObject, error) - // GetGuestInvite Check a guest pass before joining - // (GET /guest/{token}) - GetGuestInvite(ctx context.Context, request GetGuestInviteRequestObject) (GetGuestInviteResponseObject, error) - // JoinAsGuest Join a room as a guest - // (POST /guest/{token}) - JoinAsGuest(ctx context.Context, request JoinAsGuestRequestObject) (JoinAsGuestResponseObject, error) - // GetHealth Liveness and build info - // (GET /healthz) - GetHealth(ctx context.Context, request GetHealthRequestObject) (GetHealthResponseObject, error) - // ListInvites All invites (admin) - // (GET /invites) - ListInvites(ctx context.Context, request ListInvitesRequestObject) (ListInvitesResponseObject, error) - // CreateInvite Create an invite link (admin) - // (POST /invites) - CreateInvite(ctx context.Context, request CreateInviteRequestObject) (CreateInviteResponseObject, error) - // DeleteInvite Revoke an invite (admin) - // (DELETE /invites/{code}) - DeleteInvite(ctx context.Context, request DeleteInviteRequestObject) (DeleteInviteResponseObject, error) - // GetInvite Check an invite before signing up - // (GET /invites/{code}) - GetInvite(ctx context.Context, request GetInviteRequestObject) (GetInviteResponseObject, error) - // ListLinks Your linked service accounts - // (GET /links) - ListLinks(ctx context.Context, request ListLinksRequestObject) (ListLinksResponseObject, error) - // CreateLink Link an account with a form (credentials providers) - // (POST /links) - CreateLink(ctx context.Context, request CreateLinkRequestObject) (CreateLinkResponseObject, error) - // BeginOAuthLink Start linking (or re-linking) an OAuth2 provider - // (POST /links/oauth) - BeginOAuthLink(ctx context.Context, request BeginOAuthLinkRequestObject) (BeginOAuthLinkResponseObject, error) - // CompleteOAuthLink OAuth2 redirect target (browser navigation) - // (GET /links/oauth/callback) - CompleteOAuthLink(ctx context.Context, request CompleteOAuthLinkRequestObject) (CompleteOAuthLinkResponseObject, error) - // Unlink Unlink and delete the stored credentials - // (DELETE /links/{id}) - Unlink(ctx context.Context, request UnlinkRequestObject) (UnlinkResponseObject, error) - // UpdateLink Share a link with everyone, or stop sharing it - // (PATCH /links/{id}) - UpdateLink(ctx context.Context, request UpdateLinkRequestObject) (UpdateLinkResponseObject, error) - // Relink Re-link with new credentials (credentials providers) - // (PUT /links/{id}) - Relink(ctx context.Context, request RelinkRequestObject) (RelinkResponseObject, error) - // GetAlbum An album and its tracks, through one of your links or a shared one - // (GET /links/{id}/albums/{albumId}) - GetAlbum(ctx context.Context, request GetAlbumRequestObject) (GetAlbumResponseObject, error) - // GetAlbumAbout What's known about an album - // (GET /links/{id}/albums/{albumId}/about) - GetAlbumAbout(ctx context.Context, request GetAlbumAboutRequestObject) (GetAlbumAboutResponseObject, error) - // GetArtist An artist and their albums, through one of your links or a shared one - // (GET /links/{id}/artists/{artistId}) - GetArtist(ctx context.Context, request GetArtistRequestObject) (GetArtistResponseObject, error) - // GetArtistAbout What's known about an artist - // (GET /links/{id}/artists/{artistId}/about) - GetArtistAbout(ctx context.Context, request GetArtistAboutRequestObject) (GetArtistAboutResponseObject, error) - // GetArtistElsewhere The same artist on your other services - // (GET /links/{id}/artists/{artistId}/elsewhere) - GetArtistElsewhere(ctx context.Context, request GetArtistElsewhereRequestObject) (GetArtistElsewhereResponseObject, error) - // GetArtistRelated Artists like an artist, and songs by them - // (GET /links/{id}/artists/{artistId}/related) - GetArtistRelated(ctx context.Context, request GetArtistRelatedRequestObject) (GetArtistRelatedResponseObject, error) - // GetArtistShuffle Songs by an artist at random - // (GET /links/{id}/artists/{artistId}/shuffle) - GetArtistShuffle(ctx context.Context, request GetArtistShuffleRequestObject) (GetArtistShuffleResponseObject, error) - // GetArtistTracks An artist's top songs and appearances - // (GET /links/{id}/artists/{artistId}/tracks) - GetArtistTracks(ctx context.Context, request GetArtistTracksRequestObject) (GetArtistTracksResponseObject, error) - // GetLinkArtwork An image from one of your links or a shared one - // (GET /links/{id}/artwork) - GetLinkArtwork(ctx context.Context, request GetLinkArtworkRequestObject) (GetLinkArtworkResponseObject, error) - // GetCollection Shortcuts into the library of one of your links or a shared one - // (GET /links/{id}/collection) - GetCollection(ctx context.Context, request GetCollectionRequestObject) (GetCollectionResponseObject, error) - // GetGenre A genre's artists, and songs by them - // (GET /links/{id}/genre) - GetGenre(ctx context.Context, request GetGenreRequestObject) (GetGenreResponseObject, error) - // ListPlaylists The playlists of one of your links or a shared one - // (GET /links/{id}/playlists) - ListPlaylists(ctx context.Context, request ListPlaylistsRequestObject) (ListPlaylistsResponseObject, error) - // GetPlaylistTracks A page of a playlist's tracks, through one of your links or a shared one - // (GET /links/{id}/playlists/{playlistId}/tracks) - GetPlaylistTracks(ctx context.Context, request GetPlaylistTracksRequestObject) (GetPlaylistTracksResponseObject, error) - // GetTrackLyrics A track's lyrics, through one of your links or a shared one - // (GET /links/{id}/tracks/{trackId}/lyrics) - GetTrackLyrics(ctx context.Context, request GetTrackLyricsRequestObject) (GetTrackLyricsResponseObject, error) - // GetMe The signed-in user - // (GET /me) - GetMe(ctx context.Context, request GetMeRequestObject) (GetMeResponseObject, error) - // UpdateMe Update your profile - // (PATCH /me) - UpdateMe(ctx context.Context, request UpdateMeRequestObject) (UpdateMeResponseObject, error) - // UploadAvatar Upload a profile picture - // (PUT /me/avatar) - UploadAvatar(ctx context.Context, request UploadAvatarRequestObject) (UploadAvatarResponseObject, error) - // DeleteMe Delete your account - // (POST /me/delete) - DeleteMe(ctx context.Context, request DeleteMeRequestObject) (DeleteMeResponseObject, error) - // ListPasskeys Your passkeys - // (GET /me/passkeys) - ListPasskeys(ctx context.Context, request ListPasskeysRequestObject) (ListPasskeysResponseObject, error) - // BeginAddPasskey Start adding a passkey - // (POST /me/passkeys/begin) - BeginAddPasskey(ctx context.Context, request BeginAddPasskeyRequestObject) (BeginAddPasskeyResponseObject, error) - // FinishAddPasskey Finish adding a passkey - // (POST /me/passkeys/finish) - FinishAddPasskey(ctx context.Context, request FinishAddPasskeyRequestObject) (FinishAddPasskeyResponseObject, error) - // DeletePasskey Remove a passkey - // (DELETE /me/passkeys/{id}) - DeletePasskey(ctx context.Context, request DeletePasskeyRequestObject) (DeletePasskeyResponseObject, error) - // RenamePasskey Rename a passkey - // (PATCH /me/passkeys/{id}) - RenamePasskey(ctx context.Context, request RenamePasskeyRequestObject) (RenamePasskeyResponseObject, error) - // DeletePassword Remove your password (passkey-only sign-in) - // (DELETE /me/password) - DeletePassword(ctx context.Context, request DeletePasswordRequestObject) (DeletePasswordResponseObject, error) - // SetPassword Set or change your password - // (PUT /me/password) - SetPassword(ctx context.Context, request SetPasswordRequestObject) (SetPasswordResponseObject, error) - // BeginReauth Start confirming it's you with a passkey - // (POST /me/reauth/begin) - BeginReauth(ctx context.Context, request BeginReauthRequestObject) (BeginReauthResponseObject, error) - // RevokeOtherSessions Sign out everywhere else - // (DELETE /me/sessions) - RevokeOtherSessions(ctx context.Context, request RevokeOtherSessionsRequestObject) (RevokeOtherSessionsResponseObject, error) - // ListMySessions The devices you're signed in on - // (GET /me/sessions) - ListMySessions(ctx context.Context, request ListMySessionsRequestObject) (ListMySessionsResponseObject, error) - // RevokeMySession Sign out one device - // (DELETE /me/sessions/{id}) - RevokeMySession(ctx context.Context, request RevokeMySessionRequestObject) (RevokeMySessionResponseObject, error) - // BeginPairing Start linking (or re-linking) by device pairing - // (POST /pairings) - BeginPairing(ctx context.Context, request BeginPairingRequestObject) (BeginPairingResponseObject, error) - // PollPairing Whether a device pairing was approved - // (GET /pairings/{id}) - PollPairing(ctx context.Context, request PollPairingRequestObject) (PollPairingResponseObject, error) - // ListSavedPlaylists Your Syncphony playlists, and ones shared with your rooms - // (GET /playlists) - ListSavedPlaylists(ctx context.Context, request ListSavedPlaylistsRequestObject) (ListSavedPlaylistsResponseObject, error) - // CreateSavedPlaylist Make an empty playlist - // (POST /playlists) - CreateSavedPlaylist(ctx context.Context, request CreateSavedPlaylistRequestObject) (CreateSavedPlaylistResponseObject, error) - // DeleteSavedPlaylist Delete a playlist - // (DELETE /playlists/{playlistId}) - DeleteSavedPlaylist(ctx context.Context, request DeleteSavedPlaylistRequestObject) (DeleteSavedPlaylistResponseObject, error) - // GetSavedPlaylist A playlist and its songs - // (GET /playlists/{playlistId}) - GetSavedPlaylist(ctx context.Context, request GetSavedPlaylistRequestObject) (GetSavedPlaylistResponseObject, error) - // UpdateSavedPlaylist Rename a playlist, or share it with a room - // (PATCH /playlists/{playlistId}) - UpdateSavedPlaylist(ctx context.Context, request UpdateSavedPlaylistRequestObject) (UpdateSavedPlaylistResponseObject, error) - // AddSavedPlaylistSongs Add songs to the end of a playlist - // (POST /playlists/{playlistId}/songs) - AddSavedPlaylistSongs(ctx context.Context, request AddSavedPlaylistSongsRequestObject) (AddSavedPlaylistSongsResponseObject, error) - // RemoveSavedPlaylistSong Take a song out of a playlist - // (DELETE /playlists/{playlistId}/songs/{songId}) - RemoveSavedPlaylistSong(ctx context.Context, request RemoveSavedPlaylistSongRequestObject) (RemoveSavedPlaylistSongResponseObject, error) - // GetSavedPlaylistSongArtwork A playlist song's artwork - // (GET /playlists/{playlistId}/songs/{songId}/artwork) - GetSavedPlaylistSongArtwork(ctx context.Context, request GetSavedPlaylistSongArtworkRequestObject) (GetSavedPlaylistSongArtworkResponseObject, error) - // MoveSavedPlaylistSong Move a song within a playlist - // (PUT /playlists/{playlistId}/songs/{songId}/position) - MoveSavedPlaylistSong(ctx context.Context, request MoveSavedPlaylistSongRequestObject) (MoveSavedPlaylistSongResponseObject, error) - // ListProviders Services that can be linked - // (GET /providers) - ListProviders(ctx context.Context, request ListProvidersRequestObject) (ListProvidersResponseObject, error) - // GetRandomTracks Songs picked at random from services you can use - // (GET /random-tracks) - GetRandomTracks(ctx context.Context, request GetRandomTracksRequestObject) (GetRandomTracksResponseObject, error) - // ListResetLinks Reset links waiting to be used (admin) - // (GET /reset-links) - ListResetLinks(ctx context.Context, request ListResetLinksRequestObject) (ListResetLinksResponseObject, error) - // GetResetLink Check a reset link before using it - // (GET /reset-links/{code}) - GetResetLink(ctx context.Context, request GetResetLinkRequestObject) (GetResetLinkResponseObject, error) - // BeginResetPasskey Start adding a passkey with a reset link - // (POST /reset-links/{code}/passkey/begin) - BeginResetPasskey(ctx context.Context, request BeginResetPasskeyRequestObject) (BeginResetPasskeyResponseObject, error) - // FinishResetPasskey Finish adding a passkey with a reset link - // (POST /reset-links/{code}/passkey/finish) - FinishResetPasskey(ctx context.Context, request FinishResetPasskeyRequestObject) (FinishResetPasskeyResponseObject, error) +type ControlPlaybackRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *ControlPlaybackJSONRequestBody +} + +type ControlPlaybackResponseObject interface { + VisitControlPlaybackResponse(w http.ResponseWriter) error +} + +type ControlPlayback200JSONResponse NowPlaying + +func (response ControlPlayback200JSONResponse) VisitControlPlaybackResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ControlPlaybackdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ControlPlaybackdefaultJSONResponse) VisitControlPlaybackResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ReleasePlayerRequestObject struct { + RoomId RoomId `json:"roomId"` + Params ReleasePlayerParams +} + +type ReleasePlayerResponseObject interface { + VisitReleasePlayerResponse(w http.ResponseWriter) error +} + +type ReleasePlayer200JSONResponse NowPlaying + +func (response ReleasePlayer200JSONResponse) VisitReleasePlayerResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ReleasePlayerdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ReleasePlayerdefaultJSONResponse) VisitReleasePlayerResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ClaimPlayerRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *ClaimPlayerJSONRequestBody +} + +type ClaimPlayerResponseObject interface { + VisitClaimPlayerResponse(w http.ResponseWriter) error +} + +type ClaimPlayer200JSONResponse NowPlaying + +func (response ClaimPlayer200JSONResponse) VisitClaimPlayerResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ClaimPlayerdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ClaimPlayerdefaultJSONResponse) VisitClaimPlayerResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ReportPlaybackRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *ReportPlaybackJSONRequestBody +} + +type ReportPlaybackResponseObject interface { + VisitReportPlaybackResponse(w http.ResponseWriter) error +} + +type ReportPlayback200JSONResponse NowPlaying + +func (response ReportPlayback200JSONResponse) VisitReportPlaybackResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ReportPlaybackdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ReportPlaybackdefaultJSONResponse) VisitReportPlaybackResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type SaveNightPlaylistRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *SaveNightPlaylistJSONRequestBody +} + +type SaveNightPlaylistResponseObject interface { + VisitSaveNightPlaylistResponse(w http.ResponseWriter) error +} + +type SaveNightPlaylist201JSONResponse SavedPlaylist + +func (response SaveNightPlaylist201JSONResponse) VisitSaveNightPlaylistResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(201) + _, err := buf.WriteTo(w) + return err +} + +type SaveNightPlaylistdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response SaveNightPlaylistdefaultJSONResponse) VisitSaveNightPlaylistResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueRequestObject struct { + RoomId RoomId `json:"roomId"` +} + +type GetQueueResponseObject interface { + VisitGetQueueResponse(w http.ResponseWriter) error +} + +type GetQueue200JSONResponse QueueSnapshot + +func (response GetQueue200JSONResponse) VisitGetQueueResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueuedefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueuedefaultJSONResponse) VisitGetQueueResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type AddToQueueRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *AddToQueueJSONRequestBody +} + +type AddToQueueResponseObject interface { + VisitAddToQueueResponse(w http.ResponseWriter) error +} + +type AddToQueue200JSONResponse QueueSnapshot + +func (response AddToQueue200JSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type AddToQueue409JSONResponse AddToQueueConflict + +func (response AddToQueue409JSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(409) + _, err := buf.WriteTo(w) + return err +} + +type AddToQueuedefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response AddToQueuedefaultJSONResponse) VisitAddToQueueResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type RestoreQueueItemsRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *RestoreQueueItemsJSONRequestBody +} + +type RestoreQueueItemsResponseObject interface { + VisitRestoreQueueItemsResponse(w http.ResponseWriter) error +} + +type RestoreQueueItems200JSONResponse QueueSnapshot + +func (response RestoreQueueItems200JSONResponse) VisitRestoreQueueItemsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type RestoreQueueItemsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response RestoreQueueItemsdefaultJSONResponse) VisitRestoreQueueItemsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type RemoveQueueItemRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type RemoveQueueItemResponseObject interface { + VisitRemoveQueueItemResponse(w http.ResponseWriter) error +} + +type RemoveQueueItem200JSONResponse QueueSnapshot + +func (response RemoveQueueItem200JSONResponse) VisitRemoveQueueItemResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type RemoveQueueItemdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response RemoveQueueItemdefaultJSONResponse) VisitRemoveQueueItemResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type MoveQueueItemRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` + Body *MoveQueueItemJSONRequestBody +} + +type MoveQueueItemResponseObject interface { + VisitMoveQueueItemResponse(w http.ResponseWriter) error +} + +type MoveQueueItem200JSONResponse QueueSnapshot + +func (response MoveQueueItem200JSONResponse) VisitMoveQueueItemResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type MoveQueueItemdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response MoveQueueItemdefaultJSONResponse) VisitMoveQueueItemResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemArtworkRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` + Params GetQueueItemArtworkParams +} + +type GetQueueItemArtworkResponseObject interface { + VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error +} + +type GetQueueItemArtwork200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} + +func (response GetQueueItemArtwork200ImageResponse) VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err +} + +type GetQueueItemArtworkdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemArtworkdefaultJSONResponse) VisitGetQueueItemArtworkResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemBeatMapRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type GetQueueItemBeatMapResponseObject interface { + VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error +} + +type GetQueueItemBeatMap200JSONResponse BeatMap + +func (response GetQueueItemBeatMap200JSONResponse) VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemBeatMapdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemBeatMapdefaultJSONResponse) VisitGetQueueItemBeatMapResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type UnheartSongRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type UnheartSongResponseObject interface { + VisitUnheartSongResponse(w http.ResponseWriter) error +} + +type UnheartSong200JSONResponse Hearts + +func (response UnheartSong200JSONResponse) VisitUnheartSongResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type UnheartSongdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response UnheartSongdefaultJSONResponse) VisitUnheartSongResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetHeartsRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type GetHeartsResponseObject interface { + VisitGetHeartsResponse(w http.ResponseWriter) error +} + +type GetHearts200JSONResponse Hearts + +func (response GetHearts200JSONResponse) VisitGetHeartsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetHeartsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetHeartsdefaultJSONResponse) VisitGetHeartsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type HeartSongRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type HeartSongResponseObject interface { + VisitHeartSongResponse(w http.ResponseWriter) error +} + +type HeartSong200JSONResponse Hearts + +func (response HeartSong200JSONResponse) VisitHeartSongResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type HeartSongdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response HeartSongdefaultJSONResponse) VisitHeartSongResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemLinerNotesRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type GetQueueItemLinerNotesResponseObject interface { + VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error +} + +type GetQueueItemLinerNotes200JSONResponse LinerNotes + +func (response GetQueueItemLinerNotes200JSONResponse) VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemLinerNotesdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemLinerNotesdefaultJSONResponse) VisitGetQueueItemLinerNotesResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemLyricsRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type GetQueueItemLyricsResponseObject interface { + VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error +} + +type GetQueueItemLyrics200JSONResponse Lyrics + +func (response GetQueueItemLyrics200JSONResponse) VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemLyricsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemLyricsdefaultJSONResponse) VisitGetQueueItemLyricsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemPaletteRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` +} + +type GetQueueItemPaletteResponseObject interface { + VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error +} + +type GetQueueItemPalette200JSONResponse Palette + +func (response GetQueueItemPalette200JSONResponse) VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemPalettedefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemPalettedefaultJSONResponse) VisitGetQueueItemPaletteResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemSimilarRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` + Params GetQueueItemSimilarParams +} + +type GetQueueItemSimilarResponseObject interface { + VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error +} + +type GetQueueItemSimilar200JSONResponse TrackList + +func (response GetQueueItemSimilar200JSONResponse) VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetQueueItemSimilardefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetQueueItemSimilardefaultJSONResponse) VisitGetQueueItemSimilarResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type SendReactionRequestObject struct { + RoomId RoomId `json:"roomId"` + Body *SendReactionJSONRequestBody +} + +type SendReactionResponseObject interface { + VisitSendReactionResponse(w http.ResponseWriter) error +} + +type SendReaction202JSONResponse Reaction + +func (response SendReaction202JSONResponse) VisitSendReactionResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(202) + _, err := buf.WriteTo(w) + return err +} + +type SendReactiondefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response SendReactiondefaultJSONResponse) VisitSendReactionResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetRoomRecapRequestObject struct { + RoomId RoomId `json:"roomId"` + Params GetRoomRecapParams +} + +type GetRoomRecapResponseObject interface { + VisitGetRoomRecapResponse(w http.ResponseWriter) error +} + +type GetRoomRecap200JSONResponse Recap + +func (response GetRoomRecap200JSONResponse) VisitGetRoomRecapResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetRoomRecapdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetRoomRecapdefaultJSONResponse) VisitGetRoomRecapResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ListSessionsRequestObject struct { + RoomId RoomId `json:"roomId"` + Params ListSessionsParams +} + +type ListSessionsResponseObject interface { + VisitListSessionsResponse(w http.ResponseWriter) error +} + +type ListSessions200JSONResponse []ListeningSession + +func (response ListSessions200JSONResponse) VisitListSessionsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ListSessionsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ListSessionsdefaultJSONResponse) VisitListSessionsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetRoomStatsRequestObject struct { + RoomId RoomId `json:"roomId"` + Params GetRoomStatsParams +} + +type GetRoomStatsResponseObject interface { + VisitGetRoomStatsResponse(w http.ResponseWriter) error +} + +type GetRoomStats200JSONResponse RoomStats + +func (response GetRoomStats200JSONResponse) VisitGetRoomStatsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetRoomStatsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetRoomStatsdefaultJSONResponse) VisitGetRoomStatsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type StreamQueueItemRequestObject struct { + RoomId RoomId `json:"roomId"` + ItemId string `json:"itemId"` + Params StreamQueueItemParams +} + +type StreamQueueItemResponseObject interface { + VisitStreamQueueItemResponse(w http.ResponseWriter) error +} + +type StreamQueueItem200AudioResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} + +func (response StreamQueueItem200AudioResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err +} + +type StreamQueueItem206AudioResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} + +func (response StreamQueueItem206AudioResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(206) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err +} + +type StreamQueueItemdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response StreamQueueItemdefaultJSONResponse) VisitStreamQueueItemResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetSuggestionsRequestObject struct { + RoomId RoomId `json:"roomId"` + Params GetSuggestionsParams +} + +type GetSuggestionsResponseObject interface { + VisitGetSuggestionsResponse(w http.ResponseWriter) error +} + +type GetSuggestions200JSONResponse Suggestions + +func (response GetSuggestions200JSONResponse) VisitGetSuggestionsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetSuggestionsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetSuggestionsdefaultJSONResponse) VisitGetSuggestionsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type SearchRequestObject struct { + Params SearchParams +} + +type SearchResponseObject interface { + VisitSearchResponse(w http.ResponseWriter) error +} + +type Search200JSONResponse SearchResults + +func (response Search200JSONResponse) VisitSearchResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type SearchdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response SearchdefaultJSONResponse) VisitSearchResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetServerSettingsRequestObject struct { +} + +type GetServerSettingsResponseObject interface { + VisitGetServerSettingsResponse(w http.ResponseWriter) error +} + +type GetServerSettings200JSONResponse ServerSettings + +func (response GetServerSettings200JSONResponse) VisitGetServerSettingsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type GetServerSettingsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetServerSettingsdefaultJSONResponse) VisitGetServerSettingsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type UpdateServerSettingsRequestObject struct { + Body *UpdateServerSettingsJSONRequestBody +} + +type UpdateServerSettingsResponseObject interface { + VisitUpdateServerSettingsResponse(w http.ResponseWriter) error +} + +type UpdateServerSettings200JSONResponse ServerSettings + +func (response UpdateServerSettings200JSONResponse) VisitUpdateServerSettingsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type UpdateServerSettingsdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response UpdateServerSettingsdefaultJSONResponse) VisitUpdateServerSettingsResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ListUserAuditRequestObject struct { +} + +type ListUserAuditResponseObject interface { + VisitListUserAuditResponse(w http.ResponseWriter) error +} + +type ListUserAudit200JSONResponse []UserAuditEntry + +func (response ListUserAudit200JSONResponse) VisitListUserAuditResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ListUserAuditdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ListUserAuditdefaultJSONResponse) VisitListUserAuditResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type ListUsersRequestObject struct { +} + +type ListUsersResponseObject interface { + VisitListUsersResponse(w http.ResponseWriter) error +} + +type ListUsers200JSONResponse []User + +func (response ListUsers200JSONResponse) VisitListUsersResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type ListUsersdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response ListUsersdefaultJSONResponse) VisitListUsersResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type RemoveUserRequestObject struct { + Id string `json:"id"` +} + +type RemoveUserResponseObject interface { + VisitRemoveUserResponse(w http.ResponseWriter) error +} + +type RemoveUser204Response struct { +} + +func (response RemoveUser204Response) VisitRemoveUserResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type RemoveUserdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response RemoveUserdefaultJSONResponse) VisitRemoveUserResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type UpdateUserRequestObject struct { + Id string `json:"id"` + Body *UpdateUserJSONRequestBody +} + +type UpdateUserResponseObject interface { + VisitUpdateUserResponse(w http.ResponseWriter) error +} + +type UpdateUser200JSONResponse User + +func (response UpdateUser200JSONResponse) VisitUpdateUserResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + _, err := buf.WriteTo(w) + return err +} + +type UpdateUserdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response UpdateUserdefaultJSONResponse) VisitUpdateUserResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type GetUserAvatarRequestObject struct { + Id string `json:"id"` +} + +type GetUserAvatarResponseObject interface { + VisitGetUserAvatarResponse(w http.ResponseWriter) error +} + +type GetUserAvatar200ImageResponse struct { + Body io.Reader + ContentType string + ContentLength int64 +} + +func (response GetUserAvatar200ImageResponse) VisitGetUserAvatarResponse(w http.ResponseWriter) error { + + w.Header().Set("Content-Type", response.ContentType) + if response.ContentLength != 0 { + w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength)) + } + w.WriteHeader(200) + + if closer, ok := response.Body.(io.ReadCloser); ok { + defer closer.Close() + } + _, err := io.Copy(w, response.Body) + return err +} + +type GetUserAvatardefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response GetUserAvatardefaultJSONResponse) VisitGetUserAvatarResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type RevokeResetLinkRequestObject struct { + Id string `json:"id"` +} + +type RevokeResetLinkResponseObject interface { + VisitRevokeResetLinkResponse(w http.ResponseWriter) error +} + +type RevokeResetLink204Response struct { +} + +func (response RevokeResetLink204Response) VisitRevokeResetLinkResponse(w http.ResponseWriter) error { + w.WriteHeader(204) + return nil +} + +type RevokeResetLinkdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response RevokeResetLinkdefaultJSONResponse) VisitRevokeResetLinkResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +type CreateResetLinkRequestObject struct { + Id string `json:"id"` + Body *CreateResetLinkJSONRequestBody +} + +type CreateResetLinkResponseObject interface { + VisitCreateResetLinkResponse(w http.ResponseWriter) error +} + +type CreateResetLink201JSONResponse ResetLink + +func (response CreateResetLink201JSONResponse) VisitCreateResetLinkResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(201) + _, err := buf.WriteTo(w) + return err +} + +type CreateResetLinkdefaultJSONResponse struct { + Body Error + StatusCode int +} + +func (response CreateResetLinkdefaultJSONResponse) VisitCreateResetLinkResponse(w http.ResponseWriter) error { + + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(response.Body); err != nil { + return err + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(response.StatusCode) + _, err := buf.WriteTo(w) + return err +} + +// StrictServerInterface represents all server handlers. +type StrictServerInterface interface { + // GetBackups Backups, their schedule, and any restore waiting for a restart (admin) + // (GET /admin/backups) + GetBackups(ctx context.Context, request GetBackupsRequestObject) (GetBackupsResponseObject, error) + // CreateBackup Back up the database now (admin) + // (POST /admin/backups) + CreateBackup(ctx context.Context, request CreateBackupRequestObject) (CreateBackupResponseObject, error) + // UpdateBackupSchedule Change when the database is backed up, and what's kept (admin) + // (PUT /admin/backups/schedule) + UpdateBackupSchedule(ctx context.Context, request UpdateBackupScheduleRequestObject) (UpdateBackupScheduleResponseObject, error) + // DeleteBackup Delete a backup (admin) + // (DELETE /admin/backups/{name}) + DeleteBackup(ctx context.Context, request DeleteBackupRequestObject) (DeleteBackupResponseObject, error) + // DownloadBackup Download a backup (admin) + // (GET /admin/backups/{name}) + DownloadBackup(ctx context.Context, request DownloadBackupRequestObject) (DownloadBackupResponseObject, error) + // ListAllLinks Every linked service on the server, and its health (admin) + // (GET /admin/links) + ListAllLinks(ctx context.Context, request ListAllLinksRequestObject) (ListAllLinksResponseObject, error) + // CancelRestore Don't restore a backup after all (admin) + // (DELETE /admin/restore) + CancelRestore(ctx context.Context, request CancelRestoreRequestObject) (CancelRestoreResponseObject, error) + // StageRestore Restore a backup when the server next restarts (admin) + // (PUT /admin/restore) + StageRestore(ctx context.Context, request StageRestoreRequestObject) (StageRestoreResponseObject, error) + // ListActiveRooms Every room, who's in it, and what it's playing through (admin) + // (GET /admin/rooms) + ListActiveRooms(ctx context.Context, request ListActiveRoomsRequestObject) (ListActiveRoomsResponseObject, error) + // GetRoomTaste What the DJ has learned of a room's taste (admin) + // (GET /admin/rooms/{roomId}/taste) + GetRoomTaste(ctx context.Context, request GetRoomTasteRequestObject) (GetRoomTasteResponseObject, error) + // GetServerInfo The server's version, uptime, database and backups (admin) + // (GET /admin/server) + GetServerInfo(ctx context.Context, request GetServerInfoRequestObject) (GetServerInfoResponseObject, error) + // ListAllSessions Everyone's signed-in devices (admin) + // (GET /admin/sessions) + ListAllSessions(ctx context.Context, request ListAllSessionsRequestObject) (ListAllSessionsResponseObject, error) + // RevokeSession Sign out anyone's device (admin) + // (DELETE /admin/sessions/{id}) + RevokeSession(ctx context.Context, request RevokeSessionRequestObject) (RevokeSessionResponseObject, error) + // Login Sign in with a username and password + // (POST /auth/login) + Login(ctx context.Context, request LoginRequestObject) (LoginResponseObject, error) + // Logout Sign out this session + // (POST /auth/logout) + Logout(ctx context.Context, request LogoutRequestObject) (LogoutResponseObject, error) + // BeginPasskeyLogin Start signing in with a passkey + // (POST /auth/passkey/begin) + BeginPasskeyLogin(ctx context.Context, request BeginPasskeyLoginRequestObject) (BeginPasskeyLoginResponseObject, error) + // FinishPasskeyLogin Finish signing in with a passkey + // (POST /auth/passkey/finish) + FinishPasskeyLogin(ctx context.Context, request FinishPasskeyLoginRequestObject) (FinishPasskeyLoginResponseObject, error) + // Signup Create an account with an invite and a password + // (POST /auth/signup) + Signup(ctx context.Context, request SignupRequestObject) (SignupResponseObject, error) + // BeginPasskeySignup Start creating an account with an invite and a passkey + // (POST /auth/signup/passkey/begin) + BeginPasskeySignup(ctx context.Context, request BeginPasskeySignupRequestObject) (BeginPasskeySignupResponseObject, error) + // FinishPasskeySignup Finish creating an account with a passkey + // (POST /auth/signup/passkey/finish) + FinishPasskeySignup(ctx context.Context, request FinishPasskeySignupRequestObject) (FinishPasskeySignupResponseObject, error) + // LeaveDisplay Unpair this display, from the display + // (DELETE /display) + LeaveDisplay(ctx context.Context, request LeaveDisplayRequestObject) (LeaveDisplayResponseObject, error) + // GetDisplay This display, and its room + // (GET /display) + GetDisplay(ctx context.Context, request GetDisplayRequestObject) (GetDisplayResponseObject, error) + // PollDisplayPairing Check whether this display has been paired + // (GET /display/pairing) + PollDisplayPairing(ctx context.Context, request PollDisplayPairingRequestObject) (PollDisplayPairingResponseObject, error) + // BeginDisplayPairing Start pairing this device as a display + // (POST /display/pairing) + BeginDisplayPairing(ctx context.Context, request BeginDisplayPairingRequestObject) (BeginDisplayPairingResponseObject, error) + // GetGuestInvite Check a guest pass before joining + // (GET /guest/{token}) + GetGuestInvite(ctx context.Context, request GetGuestInviteRequestObject) (GetGuestInviteResponseObject, error) + // JoinAsGuest Join a room as a guest + // (POST /guest/{token}) + JoinAsGuest(ctx context.Context, request JoinAsGuestRequestObject) (JoinAsGuestResponseObject, error) + // GetHealth Liveness and build info + // (GET /healthz) + GetHealth(ctx context.Context, request GetHealthRequestObject) (GetHealthResponseObject, error) + // ListInvites All invites (admin) + // (GET /invites) + ListInvites(ctx context.Context, request ListInvitesRequestObject) (ListInvitesResponseObject, error) + // CreateInvite Create an invite link (admin) + // (POST /invites) + CreateInvite(ctx context.Context, request CreateInviteRequestObject) (CreateInviteResponseObject, error) + // DeleteInvite Revoke an invite (admin) + // (DELETE /invites/{code}) + DeleteInvite(ctx context.Context, request DeleteInviteRequestObject) (DeleteInviteResponseObject, error) + // GetInvite Check an invite before signing up + // (GET /invites/{code}) + GetInvite(ctx context.Context, request GetInviteRequestObject) (GetInviteResponseObject, error) + // ListLinks Your linked service accounts + // (GET /links) + ListLinks(ctx context.Context, request ListLinksRequestObject) (ListLinksResponseObject, error) + // CreateLink Link an account with a form (credentials providers) + // (POST /links) + CreateLink(ctx context.Context, request CreateLinkRequestObject) (CreateLinkResponseObject, error) + // BeginOAuthLink Start linking (or re-linking) an OAuth2 provider + // (POST /links/oauth) + BeginOAuthLink(ctx context.Context, request BeginOAuthLinkRequestObject) (BeginOAuthLinkResponseObject, error) + // CompleteOAuthLink OAuth2 redirect target (browser navigation) + // (GET /links/oauth/callback) + CompleteOAuthLink(ctx context.Context, request CompleteOAuthLinkRequestObject) (CompleteOAuthLinkResponseObject, error) + // Unlink Unlink and delete the stored credentials + // (DELETE /links/{id}) + Unlink(ctx context.Context, request UnlinkRequestObject) (UnlinkResponseObject, error) + // UpdateLink Share a link with everyone, or stop sharing it + // (PATCH /links/{id}) + UpdateLink(ctx context.Context, request UpdateLinkRequestObject) (UpdateLinkResponseObject, error) + // Relink Re-link with new credentials (credentials providers) + // (PUT /links/{id}) + Relink(ctx context.Context, request RelinkRequestObject) (RelinkResponseObject, error) + // GetAlbum An album and its tracks, through one of your links or a shared one + // (GET /links/{id}/albums/{albumId}) + GetAlbum(ctx context.Context, request GetAlbumRequestObject) (GetAlbumResponseObject, error) + // GetAlbumAbout What's known about an album + // (GET /links/{id}/albums/{albumId}/about) + GetAlbumAbout(ctx context.Context, request GetAlbumAboutRequestObject) (GetAlbumAboutResponseObject, error) + // GetArtist An artist and their albums, through one of your links or a shared one + // (GET /links/{id}/artists/{artistId}) + GetArtist(ctx context.Context, request GetArtistRequestObject) (GetArtistResponseObject, error) + // GetArtistAbout What's known about an artist + // (GET /links/{id}/artists/{artistId}/about) + GetArtistAbout(ctx context.Context, request GetArtistAboutRequestObject) (GetArtistAboutResponseObject, error) + // GetArtistElsewhere The same artist on your other services + // (GET /links/{id}/artists/{artistId}/elsewhere) + GetArtistElsewhere(ctx context.Context, request GetArtistElsewhereRequestObject) (GetArtistElsewhereResponseObject, error) + // GetArtistRelated Artists like an artist, and songs by them + // (GET /links/{id}/artists/{artistId}/related) + GetArtistRelated(ctx context.Context, request GetArtistRelatedRequestObject) (GetArtistRelatedResponseObject, error) + // GetArtistShuffle Songs by an artist at random + // (GET /links/{id}/artists/{artistId}/shuffle) + GetArtistShuffle(ctx context.Context, request GetArtistShuffleRequestObject) (GetArtistShuffleResponseObject, error) + // GetArtistTracks An artist's top songs and appearances + // (GET /links/{id}/artists/{artistId}/tracks) + GetArtistTracks(ctx context.Context, request GetArtistTracksRequestObject) (GetArtistTracksResponseObject, error) + // GetLinkArtwork An image from one of your links or a shared one + // (GET /links/{id}/artwork) + GetLinkArtwork(ctx context.Context, request GetLinkArtworkRequestObject) (GetLinkArtworkResponseObject, error) + // GetCollection Shortcuts into the library of one of your links or a shared one + // (GET /links/{id}/collection) + GetCollection(ctx context.Context, request GetCollectionRequestObject) (GetCollectionResponseObject, error) + // GetGenre A genre's artists, and songs by them + // (GET /links/{id}/genre) + GetGenre(ctx context.Context, request GetGenreRequestObject) (GetGenreResponseObject, error) + // ListPlaylists The playlists of one of your links or a shared one + // (GET /links/{id}/playlists) + ListPlaylists(ctx context.Context, request ListPlaylistsRequestObject) (ListPlaylistsResponseObject, error) + // GetPlaylistTracks A page of a playlist's tracks, through one of your links or a shared one + // (GET /links/{id}/playlists/{playlistId}/tracks) + GetPlaylistTracks(ctx context.Context, request GetPlaylistTracksRequestObject) (GetPlaylistTracksResponseObject, error) + // GetTrackLyrics A track's lyrics, through one of your links or a shared one + // (GET /links/{id}/tracks/{trackId}/lyrics) + GetTrackLyrics(ctx context.Context, request GetTrackLyricsRequestObject) (GetTrackLyricsResponseObject, error) + // GetMe The signed-in user + // (GET /me) + GetMe(ctx context.Context, request GetMeRequestObject) (GetMeResponseObject, error) + // UpdateMe Update your profile + // (PATCH /me) + UpdateMe(ctx context.Context, request UpdateMeRequestObject) (UpdateMeResponseObject, error) + // UploadAvatar Upload a profile picture + // (PUT /me/avatar) + UploadAvatar(ctx context.Context, request UploadAvatarRequestObject) (UploadAvatarResponseObject, error) + // DeleteMe Delete your account + // (POST /me/delete) + DeleteMe(ctx context.Context, request DeleteMeRequestObject) (DeleteMeResponseObject, error) + // SearchDiscoveryArtists Find artists to seed a set with + // (GET /me/discover/artists) + SearchDiscoveryArtists(ctx context.Context, request SearchDiscoveryArtistsRequestObject) (SearchDiscoveryArtistsResponseObject, error) + // ListDiscoveryBlocks Artists you said aren't for you + // (GET /me/discover/blocks) + ListDiscoveryBlocks(ctx context.Context, request ListDiscoveryBlocksRequestObject) (ListDiscoveryBlocksResponseObject, error) + // BlockDiscoveryArtist Not for me + // (POST /me/discover/blocks) + BlockDiscoveryArtist(ctx context.Context, request BlockDiscoveryArtistRequestObject) (BlockDiscoveryArtistResponseObject, error) + // UnblockDiscoveryArtist Let a blocked artist back into your feeds + // (DELETE /me/discover/blocks/{artistKey}) + UnblockDiscoveryArtist(ctx context.Context, request UnblockDiscoveryArtistRequestObject) (UnblockDiscoveryArtistResponseObject, error) + // PostDiscoveryFeedback Thumbs up or down on a song + // (POST /me/discover/feedback) + PostDiscoveryFeedback(ctx context.Context, request PostDiscoveryFeedbackRequestObject) (PostDiscoveryFeedbackResponseObject, error) + // GetDiscoveryImage A cover or artist picture from Deezer, through the server + // (GET /me/discover/images/{kind}/{imageId}) + GetDiscoveryImage(ctx context.Context, request GetDiscoveryImageRequestObject) (GetDiscoveryImageResponseObject, error) + // GetDiscoveryLibrary How far your library is indexed + // (GET /me/discover/library) + GetDiscoveryLibrary(ctx context.Context, request GetDiscoveryLibraryRequestObject) (GetDiscoveryLibraryResponseObject, error) + // RefreshDiscoveryLibrary Index your library again now + // (POST /me/discover/library) + RefreshDiscoveryLibrary(ctx context.Context, request RefreshDiscoveryLibraryRequestObject) (RefreshDiscoveryLibraryResponseObject, error) + // GetDiscoveryPreview A song's 30-second preview + // (GET /me/discover/preview/{deezerTrackId}) + GetDiscoveryPreview(ctx context.Context, request GetDiscoveryPreviewRequestObject) (GetDiscoveryPreviewResponseObject, error) + // ListDiscoverySets Your discovery sets + // (GET /me/discover/sets) + ListDiscoverySets(ctx context.Context, request ListDiscoverySetsRequestObject) (ListDiscoverySetsResponseObject, error) + // CreateDiscoverySet Make a discovery set + // (POST /me/discover/sets) + CreateDiscoverySet(ctx context.Context, request CreateDiscoverySetRequestObject) (CreateDiscoverySetResponseObject, error) + // DeleteDiscoverySet Delete a discovery set + // (DELETE /me/discover/sets/{setId}) + DeleteDiscoverySet(ctx context.Context, request DeleteDiscoverySetRequestObject) (DeleteDiscoverySetResponseObject, error) + // GetDiscoverySet A discovery set and its artists + // (GET /me/discover/sets/{setId}) + GetDiscoverySet(ctx context.Context, request GetDiscoverySetRequestObject) (GetDiscoverySetResponseObject, error) + // UpdateDiscoverySet Rename a set, or change how far it explores and which feeds it shows + // (PATCH /me/discover/sets/{setId}) + UpdateDiscoverySet(ctx context.Context, request UpdateDiscoverySetRequestObject) (UpdateDiscoverySetResponseObject, error) + // AddDiscoverySetArtist Add a seed artist to a set + // (POST /me/discover/sets/{setId}/artists) + AddDiscoverySetArtist(ctx context.Context, request AddDiscoverySetArtistRequestObject) (AddDiscoverySetArtistResponseObject, error) + // RemoveDiscoverySetArtist Take a seed artist out of a set + // (DELETE /me/discover/sets/{setId}/artists/{artistKey}) + RemoveDiscoverySetArtist(ctx context.Context, request RemoveDiscoverySetArtistRequestObject) (RemoveDiscoverySetArtistResponseObject, error) + // GetDiscoveryFeed A page of a set's feed + // (GET /me/discover/sets/{setId}/feed) + GetDiscoveryFeed(ctx context.Context, request GetDiscoveryFeedRequestObject) (GetDiscoveryFeedResponseObject, error) + // ListPasskeys Your passkeys + // (GET /me/passkeys) + ListPasskeys(ctx context.Context, request ListPasskeysRequestObject) (ListPasskeysResponseObject, error) + // BeginAddPasskey Start adding a passkey + // (POST /me/passkeys/begin) + BeginAddPasskey(ctx context.Context, request BeginAddPasskeyRequestObject) (BeginAddPasskeyResponseObject, error) + // FinishAddPasskey Finish adding a passkey + // (POST /me/passkeys/finish) + FinishAddPasskey(ctx context.Context, request FinishAddPasskeyRequestObject) (FinishAddPasskeyResponseObject, error) + // DeletePasskey Remove a passkey + // (DELETE /me/passkeys/{id}) + DeletePasskey(ctx context.Context, request DeletePasskeyRequestObject) (DeletePasskeyResponseObject, error) + // RenamePasskey Rename a passkey + // (PATCH /me/passkeys/{id}) + RenamePasskey(ctx context.Context, request RenamePasskeyRequestObject) (RenamePasskeyResponseObject, error) + // DeletePassword Remove your password (passkey-only sign-in) + // (DELETE /me/password) + DeletePassword(ctx context.Context, request DeletePasswordRequestObject) (DeletePasswordResponseObject, error) + // SetPassword Set or change your password + // (PUT /me/password) + SetPassword(ctx context.Context, request SetPasswordRequestObject) (SetPasswordResponseObject, error) + // BeginReauth Start confirming it's you with a passkey + // (POST /me/reauth/begin) + BeginReauth(ctx context.Context, request BeginReauthRequestObject) (BeginReauthResponseObject, error) + // RevokeOtherSessions Sign out everywhere else + // (DELETE /me/sessions) + RevokeOtherSessions(ctx context.Context, request RevokeOtherSessionsRequestObject) (RevokeOtherSessionsResponseObject, error) + // ListMySessions The devices you're signed in on + // (GET /me/sessions) + ListMySessions(ctx context.Context, request ListMySessionsRequestObject) (ListMySessionsResponseObject, error) + // RevokeMySession Sign out one device + // (DELETE /me/sessions/{id}) + RevokeMySession(ctx context.Context, request RevokeMySessionRequestObject) (RevokeMySessionResponseObject, error) + // BeginPairing Start linking (or re-linking) by device pairing + // (POST /pairings) + BeginPairing(ctx context.Context, request BeginPairingRequestObject) (BeginPairingResponseObject, error) + // PollPairing Whether a device pairing was approved + // (GET /pairings/{id}) + PollPairing(ctx context.Context, request PollPairingRequestObject) (PollPairingResponseObject, error) + // ListSavedPlaylists Your Syncphony playlists, and ones shared with your rooms + // (GET /playlists) + ListSavedPlaylists(ctx context.Context, request ListSavedPlaylistsRequestObject) (ListSavedPlaylistsResponseObject, error) + // CreateSavedPlaylist Make an empty playlist + // (POST /playlists) + CreateSavedPlaylist(ctx context.Context, request CreateSavedPlaylistRequestObject) (CreateSavedPlaylistResponseObject, error) + // DeleteSavedPlaylist Delete a playlist + // (DELETE /playlists/{playlistId}) + DeleteSavedPlaylist(ctx context.Context, request DeleteSavedPlaylistRequestObject) (DeleteSavedPlaylistResponseObject, error) + // GetSavedPlaylist A playlist and its songs + // (GET /playlists/{playlistId}) + GetSavedPlaylist(ctx context.Context, request GetSavedPlaylistRequestObject) (GetSavedPlaylistResponseObject, error) + // UpdateSavedPlaylist Rename a playlist, or share it with a room + // (PATCH /playlists/{playlistId}) + UpdateSavedPlaylist(ctx context.Context, request UpdateSavedPlaylistRequestObject) (UpdateSavedPlaylistResponseObject, error) + // AddSavedPlaylistSongs Add songs to the end of a playlist + // (POST /playlists/{playlistId}/songs) + AddSavedPlaylistSongs(ctx context.Context, request AddSavedPlaylistSongsRequestObject) (AddSavedPlaylistSongsResponseObject, error) + // RemoveSavedPlaylistSong Take a song out of a playlist + // (DELETE /playlists/{playlistId}/songs/{songId}) + RemoveSavedPlaylistSong(ctx context.Context, request RemoveSavedPlaylistSongRequestObject) (RemoveSavedPlaylistSongResponseObject, error) + // GetSavedPlaylistSongArtwork A playlist song's artwork + // (GET /playlists/{playlistId}/songs/{songId}/artwork) + GetSavedPlaylistSongArtwork(ctx context.Context, request GetSavedPlaylistSongArtworkRequestObject) (GetSavedPlaylistSongArtworkResponseObject, error) + // MoveSavedPlaylistSong Move a song within a playlist + // (PUT /playlists/{playlistId}/songs/{songId}/position) + MoveSavedPlaylistSong(ctx context.Context, request MoveSavedPlaylistSongRequestObject) (MoveSavedPlaylistSongResponseObject, error) + // ListProviders Services that can be linked + // (GET /providers) + ListProviders(ctx context.Context, request ListProvidersRequestObject) (ListProvidersResponseObject, error) + // GetRandomTracks Songs picked at random from services you can use + // (GET /random-tracks) + GetRandomTracks(ctx context.Context, request GetRandomTracksRequestObject) (GetRandomTracksResponseObject, error) + // ListResetLinks Reset links waiting to be used (admin) + // (GET /reset-links) + ListResetLinks(ctx context.Context, request ListResetLinksRequestObject) (ListResetLinksResponseObject, error) + // GetResetLink Check a reset link before using it + // (GET /reset-links/{code}) + GetResetLink(ctx context.Context, request GetResetLinkRequestObject) (GetResetLinkResponseObject, error) + // BeginResetPasskey Start adding a passkey with a reset link + // (POST /reset-links/{code}/passkey/begin) + BeginResetPasskey(ctx context.Context, request BeginResetPasskeyRequestObject) (BeginResetPasskeyResponseObject, error) + // FinishResetPasskey Finish adding a passkey with a reset link + // (POST /reset-links/{code}/passkey/finish) + FinishResetPasskey(ctx context.Context, request FinishResetPasskeyRequestObject) (FinishResetPasskeyResponseObject, error) // ResetPassword Set a new password with a reset link // (POST /reset-links/{code}/password) ResetPassword(ctx context.Context, request ResetPasswordRequestObject) (ResetPasswordResponseObject, error) @@ -16990,62 +18502,482 @@ type StrictServerInterface interface { CreateResetLink(ctx context.Context, request CreateResetLinkRequestObject) (CreateResetLinkResponseObject, error) } -type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error) -type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc +type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error) +type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc + +type StrictHTTPServerOptions struct { + RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) + ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) +} + +func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { + return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{ + RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + }, + ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusInternalServerError) + }, + }} +} + +func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface { + if options.RequestErrorHandlerFunc == nil { + options.RequestErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusBadRequest) + } + } + if options.ResponseErrorHandlerFunc == nil { + options.ResponseErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + return &strictHandler{ssi: ssi, middlewares: middlewares, options: options} +} + +type strictHandler struct { + ssi StrictServerInterface + middlewares []StrictMiddlewareFunc + options StrictHTTPServerOptions +} + +// GetBackups operation middleware +func (sh *strictHandler) GetBackups(w http.ResponseWriter, r *http.Request) { + var request GetBackupsRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetBackups(ctx, request.(GetBackupsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetBackups") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetBackupsResponseObject); ok { + if err := validResponse.VisitGetBackupsResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// CreateBackup operation middleware +func (sh *strictHandler) CreateBackup(w http.ResponseWriter, r *http.Request) { + var request CreateBackupRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.CreateBackup(ctx, request.(CreateBackupRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CreateBackup") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(CreateBackupResponseObject); ok { + if err := validResponse.VisitCreateBackupResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// UpdateBackupSchedule operation middleware +func (sh *strictHandler) UpdateBackupSchedule(w http.ResponseWriter, r *http.Request) { + var request UpdateBackupScheduleRequestObject + + var body UpdateBackupScheduleJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.UpdateBackupSchedule(ctx, request.(UpdateBackupScheduleRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "UpdateBackupSchedule") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(UpdateBackupScheduleResponseObject); ok { + if err := validResponse.VisitUpdateBackupScheduleResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// DeleteBackup operation middleware +func (sh *strictHandler) DeleteBackup(w http.ResponseWriter, r *http.Request, name string) { + var request DeleteBackupRequestObject + + request.Name = name + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.DeleteBackup(ctx, request.(DeleteBackupRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "DeleteBackup") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(DeleteBackupResponseObject); ok { + if err := validResponse.VisitDeleteBackupResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// DownloadBackup operation middleware +func (sh *strictHandler) DownloadBackup(w http.ResponseWriter, r *http.Request, name string) { + var request DownloadBackupRequestObject + + request.Name = name + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.DownloadBackup(ctx, request.(DownloadBackupRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "DownloadBackup") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(DownloadBackupResponseObject); ok { + if err := validResponse.VisitDownloadBackupResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// ListAllLinks operation middleware +func (sh *strictHandler) ListAllLinks(w http.ResponseWriter, r *http.Request) { + var request ListAllLinksRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ListAllLinks(ctx, request.(ListAllLinksRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ListAllLinks") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ListAllLinksResponseObject); ok { + if err := validResponse.VisitListAllLinksResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// CancelRestore operation middleware +func (sh *strictHandler) CancelRestore(w http.ResponseWriter, r *http.Request) { + var request CancelRestoreRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.CancelRestore(ctx, request.(CancelRestoreRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "CancelRestore") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(CancelRestoreResponseObject); ok { + if err := validResponse.VisitCancelRestoreResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// StageRestore operation middleware +func (sh *strictHandler) StageRestore(w http.ResponseWriter, r *http.Request) { + var request StageRestoreRequestObject + + var body StageRestoreJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.StageRestore(ctx, request.(StageRestoreRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "StageRestore") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(StageRestoreResponseObject); ok { + if err := validResponse.VisitStageRestoreResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// ListActiveRooms operation middleware +func (sh *strictHandler) ListActiveRooms(w http.ResponseWriter, r *http.Request) { + var request ListActiveRoomsRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ListActiveRooms(ctx, request.(ListActiveRoomsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ListActiveRooms") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ListActiveRoomsResponseObject); ok { + if err := validResponse.VisitListActiveRoomsResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// GetRoomTaste operation middleware +func (sh *strictHandler) GetRoomTaste(w http.ResponseWriter, r *http.Request, roomId RoomId) { + var request GetRoomTasteRequestObject + + request.RoomId = roomId + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetRoomTaste(ctx, request.(GetRoomTasteRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetRoomTaste") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetRoomTasteResponseObject); ok { + if err := validResponse.VisitGetRoomTasteResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// GetServerInfo operation middleware +func (sh *strictHandler) GetServerInfo(w http.ResponseWriter, r *http.Request) { + var request GetServerInfoRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetServerInfo(ctx, request.(GetServerInfoRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetServerInfo") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetServerInfoResponseObject); ok { + if err := validResponse.VisitGetServerInfoResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// ListAllSessions operation middleware +func (sh *strictHandler) ListAllSessions(w http.ResponseWriter, r *http.Request) { + var request ListAllSessionsRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ListAllSessions(ctx, request.(ListAllSessionsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ListAllSessions") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ListAllSessionsResponseObject); ok { + if err := validResponse.VisitListAllSessionsResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// RevokeSession operation middleware +func (sh *strictHandler) RevokeSession(w http.ResponseWriter, r *http.Request, id string) { + var request RevokeSessionRequestObject + + request.Id = id + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.RevokeSession(ctx, request.(RevokeSessionRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "RevokeSession") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(RevokeSessionResponseObject); ok { + if err := validResponse.VisitRevokeSessionResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// Login operation middleware +func (sh *strictHandler) Login(w http.ResponseWriter, r *http.Request) { + var request LoginRequestObject + + var body LoginJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.Login(ctx, request.(LoginRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "Login") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(LoginResponseObject); ok { + if err := validResponse.VisitLoginResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// Logout operation middleware +func (sh *strictHandler) Logout(w http.ResponseWriter, r *http.Request) { + var request LogoutRequestObject -type StrictHTTPServerOptions struct { - RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) - ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error) -} + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.Logout(ctx, request.(LogoutRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "Logout") + } -func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface { - return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{ - RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) - }, - ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusInternalServerError) - }, - }} -} + response, err := handler(r.Context(), w, r, request) -func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface { - if options.RequestErrorHandlerFunc == nil { - options.RequestErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusBadRequest) + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(LogoutResponseObject); ok { + if err := validResponse.VisitLogoutResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) } - if options.ResponseErrorHandlerFunc == nil { - options.ResponseErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) { - http.Error(w, err.Error(), http.StatusInternalServerError) +} + +// BeginPasskeyLogin operation middleware +func (sh *strictHandler) BeginPasskeyLogin(w http.ResponseWriter, r *http.Request) { + var request BeginPasskeyLoginRequestObject + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.BeginPasskeyLogin(ctx, request.(BeginPasskeyLoginRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "BeginPasskeyLogin") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(BeginPasskeyLoginResponseObject); ok { + if err := validResponse.VisitBeginPasskeyLoginResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) } - return &strictHandler{ssi: ssi, middlewares: middlewares, options: options} } -type strictHandler struct { - ssi StrictServerInterface - middlewares []StrictMiddlewareFunc - options StrictHTTPServerOptions -} +// FinishPasskeyLogin operation middleware +func (sh *strictHandler) FinishPasskeyLogin(w http.ResponseWriter, r *http.Request) { + var request FinishPasskeyLoginRequestObject -// GetBackups operation middleware -func (sh *strictHandler) GetBackups(w http.ResponseWriter, r *http.Request) { - var request GetBackupsRequestObject + var body FinishPasskeyLoginJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetBackups(ctx, request.(GetBackupsRequestObject)) + return sh.ssi.FinishPasskeyLogin(ctx, request.(FinishPasskeyLoginRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetBackups") + handler = middleware(handler, "FinishPasskeyLogin") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetBackupsResponseObject); ok { - if err := validResponse.VisitGetBackupsResponse(w); err != nil { + } else if validResponse, ok := response.(FinishPasskeyLoginResponseObject); ok { + if err := validResponse.VisitFinishPasskeyLoginResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17053,23 +18985,30 @@ func (sh *strictHandler) GetBackups(w http.ResponseWriter, r *http.Request) { } } -// CreateBackup operation middleware -func (sh *strictHandler) CreateBackup(w http.ResponseWriter, r *http.Request) { - var request CreateBackupRequestObject +// Signup operation middleware +func (sh *strictHandler) Signup(w http.ResponseWriter, r *http.Request) { + var request SignupRequestObject + + var body SignupJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.CreateBackup(ctx, request.(CreateBackupRequestObject)) + return sh.ssi.Signup(ctx, request.(SignupRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "CreateBackup") + handler = middleware(handler, "Signup") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(CreateBackupResponseObject); ok { - if err := validResponse.VisitCreateBackupResponse(w); err != nil { + } else if validResponse, ok := response.(SignupResponseObject); ok { + if err := validResponse.VisitSignupResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17077,11 +19016,11 @@ func (sh *strictHandler) CreateBackup(w http.ResponseWriter, r *http.Request) { } } -// UpdateBackupSchedule operation middleware -func (sh *strictHandler) UpdateBackupSchedule(w http.ResponseWriter, r *http.Request) { - var request UpdateBackupScheduleRequestObject +// BeginPasskeySignup operation middleware +func (sh *strictHandler) BeginPasskeySignup(w http.ResponseWriter, r *http.Request) { + var request BeginPasskeySignupRequestObject - var body UpdateBackupScheduleJSONRequestBody + var body BeginPasskeySignupJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) return @@ -17089,18 +19028,18 @@ func (sh *strictHandler) UpdateBackupSchedule(w http.ResponseWriter, r *http.Req request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.UpdateBackupSchedule(ctx, request.(UpdateBackupScheduleRequestObject)) + return sh.ssi.BeginPasskeySignup(ctx, request.(BeginPasskeySignupRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "UpdateBackupSchedule") + handler = middleware(handler, "BeginPasskeySignup") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UpdateBackupScheduleResponseObject); ok { - if err := validResponse.VisitUpdateBackupScheduleResponse(w); err != nil { + } else if validResponse, ok := response.(BeginPasskeySignupResponseObject); ok { + if err := validResponse.VisitBeginPasskeySignupResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17108,25 +19047,30 @@ func (sh *strictHandler) UpdateBackupSchedule(w http.ResponseWriter, r *http.Req } } -// DeleteBackup operation middleware -func (sh *strictHandler) DeleteBackup(w http.ResponseWriter, r *http.Request, name string) { - var request DeleteBackupRequestObject +// FinishPasskeySignup operation middleware +func (sh *strictHandler) FinishPasskeySignup(w http.ResponseWriter, r *http.Request) { + var request FinishPasskeySignupRequestObject - request.Name = name + var body FinishPasskeySignupJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.DeleteBackup(ctx, request.(DeleteBackupRequestObject)) + return sh.ssi.FinishPasskeySignup(ctx, request.(FinishPasskeySignupRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "DeleteBackup") + handler = middleware(handler, "FinishPasskeySignup") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(DeleteBackupResponseObject); ok { - if err := validResponse.VisitDeleteBackupResponse(w); err != nil { + } else if validResponse, ok := response.(FinishPasskeySignupResponseObject); ok { + if err := validResponse.VisitFinishPasskeySignupResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17134,25 +19078,23 @@ func (sh *strictHandler) DeleteBackup(w http.ResponseWriter, r *http.Request, na } } -// DownloadBackup operation middleware -func (sh *strictHandler) DownloadBackup(w http.ResponseWriter, r *http.Request, name string) { - var request DownloadBackupRequestObject - - request.Name = name +// LeaveDisplay operation middleware +func (sh *strictHandler) LeaveDisplay(w http.ResponseWriter, r *http.Request) { + var request LeaveDisplayRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.DownloadBackup(ctx, request.(DownloadBackupRequestObject)) + return sh.ssi.LeaveDisplay(ctx, request.(LeaveDisplayRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "DownloadBackup") + handler = middleware(handler, "LeaveDisplay") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(DownloadBackupResponseObject); ok { - if err := validResponse.VisitDownloadBackupResponse(w); err != nil { + } else if validResponse, ok := response.(LeaveDisplayResponseObject); ok { + if err := validResponse.VisitLeaveDisplayResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17160,23 +19102,23 @@ func (sh *strictHandler) DownloadBackup(w http.ResponseWriter, r *http.Request, } } -// ListAllLinks operation middleware -func (sh *strictHandler) ListAllLinks(w http.ResponseWriter, r *http.Request) { - var request ListAllLinksRequestObject +// GetDisplay operation middleware +func (sh *strictHandler) GetDisplay(w http.ResponseWriter, r *http.Request) { + var request GetDisplayRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListAllLinks(ctx, request.(ListAllLinksRequestObject)) + return sh.ssi.GetDisplay(ctx, request.(GetDisplayRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListAllLinks") + handler = middleware(handler, "GetDisplay") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListAllLinksResponseObject); ok { - if err := validResponse.VisitListAllLinksResponse(w); err != nil { + } else if validResponse, ok := response.(GetDisplayResponseObject); ok { + if err := validResponse.VisitGetDisplayResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17184,23 +19126,23 @@ func (sh *strictHandler) ListAllLinks(w http.ResponseWriter, r *http.Request) { } } -// CancelRestore operation middleware -func (sh *strictHandler) CancelRestore(w http.ResponseWriter, r *http.Request) { - var request CancelRestoreRequestObject +// PollDisplayPairing operation middleware +func (sh *strictHandler) PollDisplayPairing(w http.ResponseWriter, r *http.Request) { + var request PollDisplayPairingRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.CancelRestore(ctx, request.(CancelRestoreRequestObject)) + return sh.ssi.PollDisplayPairing(ctx, request.(PollDisplayPairingRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "CancelRestore") + handler = middleware(handler, "PollDisplayPairing") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(CancelRestoreResponseObject); ok { - if err := validResponse.VisitCancelRestoreResponse(w); err != nil { + } else if validResponse, ok := response.(PollDisplayPairingResponseObject); ok { + if err := validResponse.VisitPollDisplayPairingResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17208,30 +19150,33 @@ func (sh *strictHandler) CancelRestore(w http.ResponseWriter, r *http.Request) { } } -// StageRestore operation middleware -func (sh *strictHandler) StageRestore(w http.ResponseWriter, r *http.Request) { - var request StageRestoreRequestObject +// BeginDisplayPairing operation middleware +func (sh *strictHandler) BeginDisplayPairing(w http.ResponseWriter, r *http.Request) { + var request BeginDisplayPairingRequestObject - var body StageRestoreJSONRequestBody + var body BeginDisplayPairingJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return + if !errors.Is(err, io.EOF) { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + } else { + request.Body = &body } - request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.StageRestore(ctx, request.(StageRestoreRequestObject)) + return sh.ssi.BeginDisplayPairing(ctx, request.(BeginDisplayPairingRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "StageRestore") + handler = middleware(handler, "BeginDisplayPairing") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(StageRestoreResponseObject); ok { - if err := validResponse.VisitStageRestoreResponse(w); err != nil { + } else if validResponse, ok := response.(BeginDisplayPairingResponseObject); ok { + if err := validResponse.VisitBeginDisplayPairingResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17239,23 +19184,58 @@ func (sh *strictHandler) StageRestore(w http.ResponseWriter, r *http.Request) { } } -// ListActiveRooms operation middleware -func (sh *strictHandler) ListActiveRooms(w http.ResponseWriter, r *http.Request) { - var request ListActiveRoomsRequestObject +// GetGuestInvite operation middleware +func (sh *strictHandler) GetGuestInvite(w http.ResponseWriter, r *http.Request, token string) { + var request GetGuestInviteRequestObject + + request.Token = token + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.GetGuestInvite(ctx, request.(GetGuestInviteRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "GetGuestInvite") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(GetGuestInviteResponseObject); ok { + if err := validResponse.VisitGetGuestInviteResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + +// JoinAsGuest operation middleware +func (sh *strictHandler) JoinAsGuest(w http.ResponseWriter, r *http.Request, token string) { + var request JoinAsGuestRequestObject + + request.Token = token + + var body JoinAsGuestJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListActiveRooms(ctx, request.(ListActiveRoomsRequestObject)) + return sh.ssi.JoinAsGuest(ctx, request.(JoinAsGuestRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListActiveRooms") + handler = middleware(handler, "JoinAsGuest") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListActiveRoomsResponseObject); ok { - if err := validResponse.VisitListActiveRoomsResponse(w); err != nil { + } else if validResponse, ok := response.(JoinAsGuestResponseObject); ok { + if err := validResponse.VisitJoinAsGuestResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17263,25 +19243,23 @@ func (sh *strictHandler) ListActiveRooms(w http.ResponseWriter, r *http.Request) } } -// GetRoomTaste operation middleware -func (sh *strictHandler) GetRoomTaste(w http.ResponseWriter, r *http.Request, roomId RoomId) { - var request GetRoomTasteRequestObject - - request.RoomId = roomId +// GetHealth operation middleware +func (sh *strictHandler) GetHealth(w http.ResponseWriter, r *http.Request) { + var request GetHealthRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetRoomTaste(ctx, request.(GetRoomTasteRequestObject)) + return sh.ssi.GetHealth(ctx, request.(GetHealthRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetRoomTaste") + handler = middleware(handler, "GetHealth") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetRoomTasteResponseObject); ok { - if err := validResponse.VisitGetRoomTasteResponse(w); err != nil { + } else if validResponse, ok := response.(GetHealthResponseObject); ok { + if err := validResponse.VisitGetHealthResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17289,23 +19267,23 @@ func (sh *strictHandler) GetRoomTaste(w http.ResponseWriter, r *http.Request, ro } } -// GetServerInfo operation middleware -func (sh *strictHandler) GetServerInfo(w http.ResponseWriter, r *http.Request) { - var request GetServerInfoRequestObject +// ListInvites operation middleware +func (sh *strictHandler) ListInvites(w http.ResponseWriter, r *http.Request) { + var request ListInvitesRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetServerInfo(ctx, request.(GetServerInfoRequestObject)) + return sh.ssi.ListInvites(ctx, request.(ListInvitesRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetServerInfo") + handler = middleware(handler, "ListInvites") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetServerInfoResponseObject); ok { - if err := validResponse.VisitGetServerInfoResponse(w); err != nil { + } else if validResponse, ok := response.(ListInvitesResponseObject); ok { + if err := validResponse.VisitListInvitesResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17313,23 +19291,30 @@ func (sh *strictHandler) GetServerInfo(w http.ResponseWriter, r *http.Request) { } } -// ListAllSessions operation middleware -func (sh *strictHandler) ListAllSessions(w http.ResponseWriter, r *http.Request) { - var request ListAllSessionsRequestObject +// CreateInvite operation middleware +func (sh *strictHandler) CreateInvite(w http.ResponseWriter, r *http.Request) { + var request CreateInviteRequestObject + + var body CreateInviteJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListAllSessions(ctx, request.(ListAllSessionsRequestObject)) + return sh.ssi.CreateInvite(ctx, request.(CreateInviteRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListAllSessions") + handler = middleware(handler, "CreateInvite") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListAllSessionsResponseObject); ok { - if err := validResponse.VisitListAllSessionsResponse(w); err != nil { + } else if validResponse, ok := response.(CreateInviteResponseObject); ok { + if err := validResponse.VisitCreateInviteResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17337,25 +19322,25 @@ func (sh *strictHandler) ListAllSessions(w http.ResponseWriter, r *http.Request) } } -// RevokeSession operation middleware -func (sh *strictHandler) RevokeSession(w http.ResponseWriter, r *http.Request, id string) { - var request RevokeSessionRequestObject +// DeleteInvite operation middleware +func (sh *strictHandler) DeleteInvite(w http.ResponseWriter, r *http.Request, code InviteCode) { + var request DeleteInviteRequestObject - request.Id = id + request.Code = code handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.RevokeSession(ctx, request.(RevokeSessionRequestObject)) + return sh.ssi.DeleteInvite(ctx, request.(DeleteInviteRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "RevokeSession") + handler = middleware(handler, "DeleteInvite") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(RevokeSessionResponseObject); ok { - if err := validResponse.VisitRevokeSessionResponse(w); err != nil { + } else if validResponse, ok := response.(DeleteInviteResponseObject); ok { + if err := validResponse.VisitDeleteInviteResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17363,30 +19348,25 @@ func (sh *strictHandler) RevokeSession(w http.ResponseWriter, r *http.Request, i } } -// Login operation middleware -func (sh *strictHandler) Login(w http.ResponseWriter, r *http.Request) { - var request LoginRequestObject +// GetInvite operation middleware +func (sh *strictHandler) GetInvite(w http.ResponseWriter, r *http.Request, code InviteCode) { + var request GetInviteRequestObject - var body LoginJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Code = code handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.Login(ctx, request.(LoginRequestObject)) + return sh.ssi.GetInvite(ctx, request.(GetInviteRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "Login") + handler = middleware(handler, "GetInvite") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(LoginResponseObject); ok { - if err := validResponse.VisitLoginResponse(w); err != nil { + } else if validResponse, ok := response.(GetInviteResponseObject); ok { + if err := validResponse.VisitGetInviteResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17394,23 +19374,25 @@ func (sh *strictHandler) Login(w http.ResponseWriter, r *http.Request) { } } -// Logout operation middleware -func (sh *strictHandler) Logout(w http.ResponseWriter, r *http.Request) { - var request LogoutRequestObject +// ListLinks operation middleware +func (sh *strictHandler) ListLinks(w http.ResponseWriter, r *http.Request, params ListLinksParams) { + var request ListLinksRequestObject + + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.Logout(ctx, request.(LogoutRequestObject)) + return sh.ssi.ListLinks(ctx, request.(ListLinksRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "Logout") + handler = middleware(handler, "ListLinks") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(LogoutResponseObject); ok { - if err := validResponse.VisitLogoutResponse(w); err != nil { + } else if validResponse, ok := response.(ListLinksResponseObject); ok { + if err := validResponse.VisitListLinksResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17418,23 +19400,30 @@ func (sh *strictHandler) Logout(w http.ResponseWriter, r *http.Request) { } } -// BeginPasskeyLogin operation middleware -func (sh *strictHandler) BeginPasskeyLogin(w http.ResponseWriter, r *http.Request) { - var request BeginPasskeyLoginRequestObject +// CreateLink operation middleware +func (sh *strictHandler) CreateLink(w http.ResponseWriter, r *http.Request) { + var request CreateLinkRequestObject + + var body CreateLinkJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.BeginPasskeyLogin(ctx, request.(BeginPasskeyLoginRequestObject)) + return sh.ssi.CreateLink(ctx, request.(CreateLinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "BeginPasskeyLogin") + handler = middleware(handler, "CreateLink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(BeginPasskeyLoginResponseObject); ok { - if err := validResponse.VisitBeginPasskeyLoginResponse(w); err != nil { + } else if validResponse, ok := response.(CreateLinkResponseObject); ok { + if err := validResponse.VisitCreateLinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17442,11 +19431,11 @@ func (sh *strictHandler) BeginPasskeyLogin(w http.ResponseWriter, r *http.Reques } } -// FinishPasskeyLogin operation middleware -func (sh *strictHandler) FinishPasskeyLogin(w http.ResponseWriter, r *http.Request) { - var request FinishPasskeyLoginRequestObject +// BeginOAuthLink operation middleware +func (sh *strictHandler) BeginOAuthLink(w http.ResponseWriter, r *http.Request) { + var request BeginOAuthLinkRequestObject - var body FinishPasskeyLoginJSONRequestBody + var body BeginOAuthLinkJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) return @@ -17454,18 +19443,18 @@ func (sh *strictHandler) FinishPasskeyLogin(w http.ResponseWriter, r *http.Reque request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.FinishPasskeyLogin(ctx, request.(FinishPasskeyLoginRequestObject)) + return sh.ssi.BeginOAuthLink(ctx, request.(BeginOAuthLinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "FinishPasskeyLogin") + handler = middleware(handler, "BeginOAuthLink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(FinishPasskeyLoginResponseObject); ok { - if err := validResponse.VisitFinishPasskeyLoginResponse(w); err != nil { + } else if validResponse, ok := response.(BeginOAuthLinkResponseObject); ok { + if err := validResponse.VisitBeginOAuthLinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17473,30 +19462,25 @@ func (sh *strictHandler) FinishPasskeyLogin(w http.ResponseWriter, r *http.Reque } } -// Signup operation middleware -func (sh *strictHandler) Signup(w http.ResponseWriter, r *http.Request) { - var request SignupRequestObject +// CompleteOAuthLink operation middleware +func (sh *strictHandler) CompleteOAuthLink(w http.ResponseWriter, r *http.Request, params CompleteOAuthLinkParams) { + var request CompleteOAuthLinkRequestObject - var body SignupJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.Signup(ctx, request.(SignupRequestObject)) + return sh.ssi.CompleteOAuthLink(ctx, request.(CompleteOAuthLinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "Signup") + handler = middleware(handler, "CompleteOAuthLink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(SignupResponseObject); ok { - if err := validResponse.VisitSignupResponse(w); err != nil { + } else if validResponse, ok := response.(CompleteOAuthLinkResponseObject); ok { + if err := validResponse.VisitCompleteOAuthLinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17504,30 +19488,25 @@ func (sh *strictHandler) Signup(w http.ResponseWriter, r *http.Request) { } } -// BeginPasskeySignup operation middleware -func (sh *strictHandler) BeginPasskeySignup(w http.ResponseWriter, r *http.Request) { - var request BeginPasskeySignupRequestObject +// Unlink operation middleware +func (sh *strictHandler) Unlink(w http.ResponseWriter, r *http.Request, id string) { + var request UnlinkRequestObject - var body BeginPasskeySignupJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Id = id handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.BeginPasskeySignup(ctx, request.(BeginPasskeySignupRequestObject)) + return sh.ssi.Unlink(ctx, request.(UnlinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "BeginPasskeySignup") + handler = middleware(handler, "Unlink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(BeginPasskeySignupResponseObject); ok { - if err := validResponse.VisitBeginPasskeySignupResponse(w); err != nil { + } else if validResponse, ok := response.(UnlinkResponseObject); ok { + if err := validResponse.VisitUnlinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17535,11 +19514,13 @@ func (sh *strictHandler) BeginPasskeySignup(w http.ResponseWriter, r *http.Reque } } -// FinishPasskeySignup operation middleware -func (sh *strictHandler) FinishPasskeySignup(w http.ResponseWriter, r *http.Request) { - var request FinishPasskeySignupRequestObject +// UpdateLink operation middleware +func (sh *strictHandler) UpdateLink(w http.ResponseWriter, r *http.Request, id string) { + var request UpdateLinkRequestObject - var body FinishPasskeySignupJSONRequestBody + request.Id = id + + var body UpdateLinkJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) return @@ -17547,18 +19528,18 @@ func (sh *strictHandler) FinishPasskeySignup(w http.ResponseWriter, r *http.Requ request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.FinishPasskeySignup(ctx, request.(FinishPasskeySignupRequestObject)) + return sh.ssi.UpdateLink(ctx, request.(UpdateLinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "FinishPasskeySignup") + handler = middleware(handler, "UpdateLink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(FinishPasskeySignupResponseObject); ok { - if err := validResponse.VisitFinishPasskeySignupResponse(w); err != nil { + } else if validResponse, ok := response.(UpdateLinkResponseObject); ok { + if err := validResponse.VisitUpdateLinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17566,23 +19547,32 @@ func (sh *strictHandler) FinishPasskeySignup(w http.ResponseWriter, r *http.Requ } } -// LeaveDisplay operation middleware -func (sh *strictHandler) LeaveDisplay(w http.ResponseWriter, r *http.Request) { - var request LeaveDisplayRequestObject +// Relink operation middleware +func (sh *strictHandler) Relink(w http.ResponseWriter, r *http.Request, id string) { + var request RelinkRequestObject + + request.Id = id + + var body RelinkJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.LeaveDisplay(ctx, request.(LeaveDisplayRequestObject)) + return sh.ssi.Relink(ctx, request.(RelinkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "LeaveDisplay") + handler = middleware(handler, "Relink") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(LeaveDisplayResponseObject); ok { - if err := validResponse.VisitLeaveDisplayResponse(w); err != nil { + } else if validResponse, ok := response.(RelinkResponseObject); ok { + if err := validResponse.VisitRelinkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17590,23 +19580,26 @@ func (sh *strictHandler) LeaveDisplay(w http.ResponseWriter, r *http.Request) { } } -// GetDisplay operation middleware -func (sh *strictHandler) GetDisplay(w http.ResponseWriter, r *http.Request) { - var request GetDisplayRequestObject +// GetAlbum operation middleware +func (sh *strictHandler) GetAlbum(w http.ResponseWriter, r *http.Request, id string, albumId string) { + var request GetAlbumRequestObject + + request.Id = id + request.AlbumId = albumId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetDisplay(ctx, request.(GetDisplayRequestObject)) + return sh.ssi.GetAlbum(ctx, request.(GetAlbumRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetDisplay") + handler = middleware(handler, "GetAlbum") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetDisplayResponseObject); ok { - if err := validResponse.VisitGetDisplayResponse(w); err != nil { + } else if validResponse, ok := response.(GetAlbumResponseObject); ok { + if err := validResponse.VisitGetAlbumResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17614,23 +19607,26 @@ func (sh *strictHandler) GetDisplay(w http.ResponseWriter, r *http.Request) { } } -// PollDisplayPairing operation middleware -func (sh *strictHandler) PollDisplayPairing(w http.ResponseWriter, r *http.Request) { - var request PollDisplayPairingRequestObject +// GetAlbumAbout operation middleware +func (sh *strictHandler) GetAlbumAbout(w http.ResponseWriter, r *http.Request, id string, albumId string) { + var request GetAlbumAboutRequestObject + + request.Id = id + request.AlbumId = albumId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.PollDisplayPairing(ctx, request.(PollDisplayPairingRequestObject)) + return sh.ssi.GetAlbumAbout(ctx, request.(GetAlbumAboutRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "PollDisplayPairing") + handler = middleware(handler, "GetAlbumAbout") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(PollDisplayPairingResponseObject); ok { - if err := validResponse.VisitPollDisplayPairingResponse(w); err != nil { + } else if validResponse, ok := response.(GetAlbumAboutResponseObject); ok { + if err := validResponse.VisitGetAlbumAboutResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17638,33 +19634,26 @@ func (sh *strictHandler) PollDisplayPairing(w http.ResponseWriter, r *http.Reque } } -// BeginDisplayPairing operation middleware -func (sh *strictHandler) BeginDisplayPairing(w http.ResponseWriter, r *http.Request) { - var request BeginDisplayPairingRequestObject +// GetArtist operation middleware +func (sh *strictHandler) GetArtist(w http.ResponseWriter, r *http.Request, id string, artistId string) { + var request GetArtistRequestObject - var body BeginDisplayPairingJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - if !errors.Is(err, io.EOF) { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - } else { - request.Body = &body - } + request.Id = id + request.ArtistId = artistId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.BeginDisplayPairing(ctx, request.(BeginDisplayPairingRequestObject)) + return sh.ssi.GetArtist(ctx, request.(GetArtistRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "BeginDisplayPairing") + handler = middleware(handler, "GetArtist") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(BeginDisplayPairingResponseObject); ok { - if err := validResponse.VisitBeginDisplayPairingResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistResponseObject); ok { + if err := validResponse.VisitGetArtistResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17672,25 +19661,26 @@ func (sh *strictHandler) BeginDisplayPairing(w http.ResponseWriter, r *http.Requ } } -// GetGuestInvite operation middleware -func (sh *strictHandler) GetGuestInvite(w http.ResponseWriter, r *http.Request, token string) { - var request GetGuestInviteRequestObject +// GetArtistAbout operation middleware +func (sh *strictHandler) GetArtistAbout(w http.ResponseWriter, r *http.Request, id string, artistId string) { + var request GetArtistAboutRequestObject - request.Token = token + request.Id = id + request.ArtistId = artistId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetGuestInvite(ctx, request.(GetGuestInviteRequestObject)) + return sh.ssi.GetArtistAbout(ctx, request.(GetArtistAboutRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetGuestInvite") + handler = middleware(handler, "GetArtistAbout") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetGuestInviteResponseObject); ok { - if err := validResponse.VisitGetGuestInviteResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistAboutResponseObject); ok { + if err := validResponse.VisitGetArtistAboutResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17698,32 +19688,26 @@ func (sh *strictHandler) GetGuestInvite(w http.ResponseWriter, r *http.Request, } } -// JoinAsGuest operation middleware -func (sh *strictHandler) JoinAsGuest(w http.ResponseWriter, r *http.Request, token string) { - var request JoinAsGuestRequestObject - - request.Token = token +// GetArtistElsewhere operation middleware +func (sh *strictHandler) GetArtistElsewhere(w http.ResponseWriter, r *http.Request, id string, artistId string) { + var request GetArtistElsewhereRequestObject - var body JoinAsGuestJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Id = id + request.ArtistId = artistId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.JoinAsGuest(ctx, request.(JoinAsGuestRequestObject)) + return sh.ssi.GetArtistElsewhere(ctx, request.(GetArtistElsewhereRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "JoinAsGuest") + handler = middleware(handler, "GetArtistElsewhere") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(JoinAsGuestResponseObject); ok { - if err := validResponse.VisitJoinAsGuestResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistElsewhereResponseObject); ok { + if err := validResponse.VisitGetArtistElsewhereResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17731,23 +19715,26 @@ func (sh *strictHandler) JoinAsGuest(w http.ResponseWriter, r *http.Request, tok } } -// GetHealth operation middleware -func (sh *strictHandler) GetHealth(w http.ResponseWriter, r *http.Request) { - var request GetHealthRequestObject +// GetArtistRelated operation middleware +func (sh *strictHandler) GetArtistRelated(w http.ResponseWriter, r *http.Request, id string, artistId string) { + var request GetArtistRelatedRequestObject + + request.Id = id + request.ArtistId = artistId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetHealth(ctx, request.(GetHealthRequestObject)) + return sh.ssi.GetArtistRelated(ctx, request.(GetArtistRelatedRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetHealth") + handler = middleware(handler, "GetArtistRelated") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetHealthResponseObject); ok { - if err := validResponse.VisitGetHealthResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistRelatedResponseObject); ok { + if err := validResponse.VisitGetArtistRelatedResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17755,23 +19742,27 @@ func (sh *strictHandler) GetHealth(w http.ResponseWriter, r *http.Request) { } } -// ListInvites operation middleware -func (sh *strictHandler) ListInvites(w http.ResponseWriter, r *http.Request) { - var request ListInvitesRequestObject +// GetArtistShuffle operation middleware +func (sh *strictHandler) GetArtistShuffle(w http.ResponseWriter, r *http.Request, id string, artistId string, params GetArtistShuffleParams) { + var request GetArtistShuffleRequestObject + + request.Id = id + request.ArtistId = artistId + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListInvites(ctx, request.(ListInvitesRequestObject)) + return sh.ssi.GetArtistShuffle(ctx, request.(GetArtistShuffleRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListInvites") + handler = middleware(handler, "GetArtistShuffle") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListInvitesResponseObject); ok { - if err := validResponse.VisitListInvitesResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistShuffleResponseObject); ok { + if err := validResponse.VisitGetArtistShuffleResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17779,30 +19770,26 @@ func (sh *strictHandler) ListInvites(w http.ResponseWriter, r *http.Request) { } } -// CreateInvite operation middleware -func (sh *strictHandler) CreateInvite(w http.ResponseWriter, r *http.Request) { - var request CreateInviteRequestObject +// GetArtistTracks operation middleware +func (sh *strictHandler) GetArtistTracks(w http.ResponseWriter, r *http.Request, id string, artistId string) { + var request GetArtistTracksRequestObject - var body CreateInviteJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Id = id + request.ArtistId = artistId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.CreateInvite(ctx, request.(CreateInviteRequestObject)) + return sh.ssi.GetArtistTracks(ctx, request.(GetArtistTracksRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "CreateInvite") + handler = middleware(handler, "GetArtistTracks") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(CreateInviteResponseObject); ok { - if err := validResponse.VisitCreateInviteResponse(w); err != nil { + } else if validResponse, ok := response.(GetArtistTracksResponseObject); ok { + if err := validResponse.VisitGetArtistTracksResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17810,25 +19797,26 @@ func (sh *strictHandler) CreateInvite(w http.ResponseWriter, r *http.Request) { } } -// DeleteInvite operation middleware -func (sh *strictHandler) DeleteInvite(w http.ResponseWriter, r *http.Request, code InviteCode) { - var request DeleteInviteRequestObject +// GetLinkArtwork operation middleware +func (sh *strictHandler) GetLinkArtwork(w http.ResponseWriter, r *http.Request, id string, params GetLinkArtworkParams) { + var request GetLinkArtworkRequestObject - request.Code = code + request.Id = id + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.DeleteInvite(ctx, request.(DeleteInviteRequestObject)) + return sh.ssi.GetLinkArtwork(ctx, request.(GetLinkArtworkRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "DeleteInvite") + handler = middleware(handler, "GetLinkArtwork") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(DeleteInviteResponseObject); ok { - if err := validResponse.VisitDeleteInviteResponse(w); err != nil { + } else if validResponse, ok := response.(GetLinkArtworkResponseObject); ok { + if err := validResponse.VisitGetLinkArtworkResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17836,25 +19824,25 @@ func (sh *strictHandler) DeleteInvite(w http.ResponseWriter, r *http.Request, co } } -// GetInvite operation middleware -func (sh *strictHandler) GetInvite(w http.ResponseWriter, r *http.Request, code InviteCode) { - var request GetInviteRequestObject +// GetCollection operation middleware +func (sh *strictHandler) GetCollection(w http.ResponseWriter, r *http.Request, id string) { + var request GetCollectionRequestObject - request.Code = code + request.Id = id handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetInvite(ctx, request.(GetInviteRequestObject)) + return sh.ssi.GetCollection(ctx, request.(GetCollectionRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetInvite") + handler = middleware(handler, "GetCollection") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetInviteResponseObject); ok { - if err := validResponse.VisitGetInviteResponse(w); err != nil { + } else if validResponse, ok := response.(GetCollectionResponseObject); ok { + if err := validResponse.VisitGetCollectionResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17862,25 +19850,26 @@ func (sh *strictHandler) GetInvite(w http.ResponseWriter, r *http.Request, code } } -// ListLinks operation middleware -func (sh *strictHandler) ListLinks(w http.ResponseWriter, r *http.Request, params ListLinksParams) { - var request ListLinksRequestObject +// GetGenre operation middleware +func (sh *strictHandler) GetGenre(w http.ResponseWriter, r *http.Request, id string, params GetGenreParams) { + var request GetGenreRequestObject + request.Id = id request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListLinks(ctx, request.(ListLinksRequestObject)) + return sh.ssi.GetGenre(ctx, request.(GetGenreRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListLinks") + handler = middleware(handler, "GetGenre") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListLinksResponseObject); ok { - if err := validResponse.VisitListLinksResponse(w); err != nil { + } else if validResponse, ok := response.(GetGenreResponseObject); ok { + if err := validResponse.VisitGetGenreResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17888,30 +19877,26 @@ func (sh *strictHandler) ListLinks(w http.ResponseWriter, r *http.Request, param } } -// CreateLink operation middleware -func (sh *strictHandler) CreateLink(w http.ResponseWriter, r *http.Request) { - var request CreateLinkRequestObject +// ListPlaylists operation middleware +func (sh *strictHandler) ListPlaylists(w http.ResponseWriter, r *http.Request, id string, params ListPlaylistsParams) { + var request ListPlaylistsRequestObject - var body CreateLinkJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Id = id + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.CreateLink(ctx, request.(CreateLinkRequestObject)) + return sh.ssi.ListPlaylists(ctx, request.(ListPlaylistsRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "CreateLink") + handler = middleware(handler, "ListPlaylists") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(CreateLinkResponseObject); ok { - if err := validResponse.VisitCreateLinkResponse(w); err != nil { + } else if validResponse, ok := response.(ListPlaylistsResponseObject); ok { + if err := validResponse.VisitListPlaylistsResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17919,30 +19904,27 @@ func (sh *strictHandler) CreateLink(w http.ResponseWriter, r *http.Request) { } } -// BeginOAuthLink operation middleware -func (sh *strictHandler) BeginOAuthLink(w http.ResponseWriter, r *http.Request) { - var request BeginOAuthLinkRequestObject +// GetPlaylistTracks operation middleware +func (sh *strictHandler) GetPlaylistTracks(w http.ResponseWriter, r *http.Request, id string, playlistId string, params GetPlaylistTracksParams) { + var request GetPlaylistTracksRequestObject - var body BeginOAuthLinkJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Id = id + request.PlaylistId = playlistId + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.BeginOAuthLink(ctx, request.(BeginOAuthLinkRequestObject)) + return sh.ssi.GetPlaylistTracks(ctx, request.(GetPlaylistTracksRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "BeginOAuthLink") + handler = middleware(handler, "GetPlaylistTracks") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(BeginOAuthLinkResponseObject); ok { - if err := validResponse.VisitBeginOAuthLinkResponse(w); err != nil { + } else if validResponse, ok := response.(GetPlaylistTracksResponseObject); ok { + if err := validResponse.VisitGetPlaylistTracksResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17950,25 +19932,26 @@ func (sh *strictHandler) BeginOAuthLink(w http.ResponseWriter, r *http.Request) } } -// CompleteOAuthLink operation middleware -func (sh *strictHandler) CompleteOAuthLink(w http.ResponseWriter, r *http.Request, params CompleteOAuthLinkParams) { - var request CompleteOAuthLinkRequestObject +// GetTrackLyrics operation middleware +func (sh *strictHandler) GetTrackLyrics(w http.ResponseWriter, r *http.Request, id string, trackId string) { + var request GetTrackLyricsRequestObject - request.Params = params + request.Id = id + request.TrackId = trackId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.CompleteOAuthLink(ctx, request.(CompleteOAuthLinkRequestObject)) + return sh.ssi.GetTrackLyrics(ctx, request.(GetTrackLyricsRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "CompleteOAuthLink") + handler = middleware(handler, "GetTrackLyrics") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(CompleteOAuthLinkResponseObject); ok { - if err := validResponse.VisitCompleteOAuthLinkResponse(w); err != nil { + } else if validResponse, ok := response.(GetTrackLyricsResponseObject); ok { + if err := validResponse.VisitGetTrackLyricsResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -17976,25 +19959,23 @@ func (sh *strictHandler) CompleteOAuthLink(w http.ResponseWriter, r *http.Reques } } -// Unlink operation middleware -func (sh *strictHandler) Unlink(w http.ResponseWriter, r *http.Request, id string) { - var request UnlinkRequestObject - - request.Id = id +// GetMe operation middleware +func (sh *strictHandler) GetMe(w http.ResponseWriter, r *http.Request) { + var request GetMeRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.Unlink(ctx, request.(UnlinkRequestObject)) + return sh.ssi.GetMe(ctx, request.(GetMeRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "Unlink") + handler = middleware(handler, "GetMe") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UnlinkResponseObject); ok { - if err := validResponse.VisitUnlinkResponse(w); err != nil { + } else if validResponse, ok := response.(GetMeResponseObject); ok { + if err := validResponse.VisitGetMeResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18002,13 +19983,11 @@ func (sh *strictHandler) Unlink(w http.ResponseWriter, r *http.Request, id strin } } -// UpdateLink operation middleware -func (sh *strictHandler) UpdateLink(w http.ResponseWriter, r *http.Request, id string) { - var request UpdateLinkRequestObject - - request.Id = id +// UpdateMe operation middleware +func (sh *strictHandler) UpdateMe(w http.ResponseWriter, r *http.Request) { + var request UpdateMeRequestObject - var body UpdateLinkJSONRequestBody + var body UpdateMeJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) return @@ -18016,18 +19995,18 @@ func (sh *strictHandler) UpdateLink(w http.ResponseWriter, r *http.Request, id s request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.UpdateLink(ctx, request.(UpdateLinkRequestObject)) + return sh.ssi.UpdateMe(ctx, request.(UpdateMeRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "UpdateLink") + handler = middleware(handler, "UpdateMe") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UpdateLinkResponseObject); ok { - if err := validResponse.VisitUpdateLinkResponse(w); err != nil { + } else if validResponse, ok := response.(UpdateMeResponseObject); ok { + if err := validResponse.VisitUpdateMeResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18035,32 +20014,27 @@ func (sh *strictHandler) UpdateLink(w http.ResponseWriter, r *http.Request, id s } } -// Relink operation middleware -func (sh *strictHandler) Relink(w http.ResponseWriter, r *http.Request, id string) { - var request RelinkRequestObject +// UploadAvatar operation middleware +func (sh *strictHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) { + var request UploadAvatarRequestObject - request.Id = id + request.ContentType = r.Header.Get("Content-Type") - var body RelinkJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.Body = r.Body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.Relink(ctx, request.(RelinkRequestObject)) + return sh.ssi.UploadAvatar(ctx, request.(UploadAvatarRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "Relink") + handler = middleware(handler, "UploadAvatar") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(RelinkResponseObject); ok { - if err := validResponse.VisitRelinkResponse(w); err != nil { + } else if validResponse, ok := response.(UploadAvatarResponseObject); ok { + if err := validResponse.VisitUploadAvatarResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18068,26 +20042,30 @@ func (sh *strictHandler) Relink(w http.ResponseWriter, r *http.Request, id strin } } -// GetAlbum operation middleware -func (sh *strictHandler) GetAlbum(w http.ResponseWriter, r *http.Request, id string, albumId string) { - var request GetAlbumRequestObject +// DeleteMe operation middleware +func (sh *strictHandler) DeleteMe(w http.ResponseWriter, r *http.Request) { + var request DeleteMeRequestObject - request.Id = id - request.AlbumId = albumId + var body DeleteMeJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetAlbum(ctx, request.(GetAlbumRequestObject)) + return sh.ssi.DeleteMe(ctx, request.(DeleteMeRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetAlbum") + handler = middleware(handler, "DeleteMe") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetAlbumResponseObject); ok { - if err := validResponse.VisitGetAlbumResponse(w); err != nil { + } else if validResponse, ok := response.(DeleteMeResponseObject); ok { + if err := validResponse.VisitDeleteMeResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18095,26 +20073,25 @@ func (sh *strictHandler) GetAlbum(w http.ResponseWriter, r *http.Request, id str } } -// GetAlbumAbout operation middleware -func (sh *strictHandler) GetAlbumAbout(w http.ResponseWriter, r *http.Request, id string, albumId string) { - var request GetAlbumAboutRequestObject +// SearchDiscoveryArtists operation middleware +func (sh *strictHandler) SearchDiscoveryArtists(w http.ResponseWriter, r *http.Request, params SearchDiscoveryArtistsParams) { + var request SearchDiscoveryArtistsRequestObject - request.Id = id - request.AlbumId = albumId + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetAlbumAbout(ctx, request.(GetAlbumAboutRequestObject)) + return sh.ssi.SearchDiscoveryArtists(ctx, request.(SearchDiscoveryArtistsRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetAlbumAbout") + handler = middleware(handler, "SearchDiscoveryArtists") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetAlbumAboutResponseObject); ok { - if err := validResponse.VisitGetAlbumAboutResponse(w); err != nil { + } else if validResponse, ok := response.(SearchDiscoveryArtistsResponseObject); ok { + if err := validResponse.VisitSearchDiscoveryArtistsResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18122,26 +20099,23 @@ func (sh *strictHandler) GetAlbumAbout(w http.ResponseWriter, r *http.Request, i } } -// GetArtist operation middleware -func (sh *strictHandler) GetArtist(w http.ResponseWriter, r *http.Request, id string, artistId string) { - var request GetArtistRequestObject - - request.Id = id - request.ArtistId = artistId +// ListDiscoveryBlocks operation middleware +func (sh *strictHandler) ListDiscoveryBlocks(w http.ResponseWriter, r *http.Request) { + var request ListDiscoveryBlocksRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtist(ctx, request.(GetArtistRequestObject)) + return sh.ssi.ListDiscoveryBlocks(ctx, request.(ListDiscoveryBlocksRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtist") + handler = middleware(handler, "ListDiscoveryBlocks") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistResponseObject); ok { - if err := validResponse.VisitGetArtistResponse(w); err != nil { + } else if validResponse, ok := response.(ListDiscoveryBlocksResponseObject); ok { + if err := validResponse.VisitListDiscoveryBlocksResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18149,26 +20123,30 @@ func (sh *strictHandler) GetArtist(w http.ResponseWriter, r *http.Request, id st } } -// GetArtistAbout operation middleware -func (sh *strictHandler) GetArtistAbout(w http.ResponseWriter, r *http.Request, id string, artistId string) { - var request GetArtistAboutRequestObject +// BlockDiscoveryArtist operation middleware +func (sh *strictHandler) BlockDiscoveryArtist(w http.ResponseWriter, r *http.Request) { + var request BlockDiscoveryArtistRequestObject - request.Id = id - request.ArtistId = artistId + var body BlockDiscoveryArtistJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtistAbout(ctx, request.(GetArtistAboutRequestObject)) + return sh.ssi.BlockDiscoveryArtist(ctx, request.(BlockDiscoveryArtistRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtistAbout") + handler = middleware(handler, "BlockDiscoveryArtist") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistAboutResponseObject); ok { - if err := validResponse.VisitGetArtistAboutResponse(w); err != nil { + } else if validResponse, ok := response.(BlockDiscoveryArtistResponseObject); ok { + if err := validResponse.VisitBlockDiscoveryArtistResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18176,26 +20154,25 @@ func (sh *strictHandler) GetArtistAbout(w http.ResponseWriter, r *http.Request, } } -// GetArtistElsewhere operation middleware -func (sh *strictHandler) GetArtistElsewhere(w http.ResponseWriter, r *http.Request, id string, artistId string) { - var request GetArtistElsewhereRequestObject +// UnblockDiscoveryArtist operation middleware +func (sh *strictHandler) UnblockDiscoveryArtist(w http.ResponseWriter, r *http.Request, artistKey string) { + var request UnblockDiscoveryArtistRequestObject - request.Id = id - request.ArtistId = artistId + request.ArtistKey = artistKey handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtistElsewhere(ctx, request.(GetArtistElsewhereRequestObject)) + return sh.ssi.UnblockDiscoveryArtist(ctx, request.(UnblockDiscoveryArtistRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtistElsewhere") + handler = middleware(handler, "UnblockDiscoveryArtist") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistElsewhereResponseObject); ok { - if err := validResponse.VisitGetArtistElsewhereResponse(w); err != nil { + } else if validResponse, ok := response.(UnblockDiscoveryArtistResponseObject); ok { + if err := validResponse.VisitUnblockDiscoveryArtistResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18203,26 +20180,30 @@ func (sh *strictHandler) GetArtistElsewhere(w http.ResponseWriter, r *http.Reque } } -// GetArtistRelated operation middleware -func (sh *strictHandler) GetArtistRelated(w http.ResponseWriter, r *http.Request, id string, artistId string) { - var request GetArtistRelatedRequestObject +// PostDiscoveryFeedback operation middleware +func (sh *strictHandler) PostDiscoveryFeedback(w http.ResponseWriter, r *http.Request) { + var request PostDiscoveryFeedbackRequestObject - request.Id = id - request.ArtistId = artistId + var body PostDiscoveryFeedbackJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtistRelated(ctx, request.(GetArtistRelatedRequestObject)) + return sh.ssi.PostDiscoveryFeedback(ctx, request.(PostDiscoveryFeedbackRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtistRelated") + handler = middleware(handler, "PostDiscoveryFeedback") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistRelatedResponseObject); ok { - if err := validResponse.VisitGetArtistRelatedResponse(w); err != nil { + } else if validResponse, ok := response.(PostDiscoveryFeedbackResponseObject); ok { + if err := validResponse.VisitPostDiscoveryFeedbackResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18230,27 +20211,27 @@ func (sh *strictHandler) GetArtistRelated(w http.ResponseWriter, r *http.Request } } -// GetArtistShuffle operation middleware -func (sh *strictHandler) GetArtistShuffle(w http.ResponseWriter, r *http.Request, id string, artistId string, params GetArtistShuffleParams) { - var request GetArtistShuffleRequestObject +// GetDiscoveryImage operation middleware +func (sh *strictHandler) GetDiscoveryImage(w http.ResponseWriter, r *http.Request, kind string, imageId string, params GetDiscoveryImageParams) { + var request GetDiscoveryImageRequestObject - request.Id = id - request.ArtistId = artistId + request.Kind = kind + request.ImageId = imageId request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtistShuffle(ctx, request.(GetArtistShuffleRequestObject)) + return sh.ssi.GetDiscoveryImage(ctx, request.(GetDiscoveryImageRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtistShuffle") + handler = middleware(handler, "GetDiscoveryImage") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistShuffleResponseObject); ok { - if err := validResponse.VisitGetArtistShuffleResponse(w); err != nil { + } else if validResponse, ok := response.(GetDiscoveryImageResponseObject); ok { + if err := validResponse.VisitGetDiscoveryImageResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18258,26 +20239,23 @@ func (sh *strictHandler) GetArtistShuffle(w http.ResponseWriter, r *http.Request } } -// GetArtistTracks operation middleware -func (sh *strictHandler) GetArtistTracks(w http.ResponseWriter, r *http.Request, id string, artistId string) { - var request GetArtistTracksRequestObject - - request.Id = id - request.ArtistId = artistId +// GetDiscoveryLibrary operation middleware +func (sh *strictHandler) GetDiscoveryLibrary(w http.ResponseWriter, r *http.Request) { + var request GetDiscoveryLibraryRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetArtistTracks(ctx, request.(GetArtistTracksRequestObject)) + return sh.ssi.GetDiscoveryLibrary(ctx, request.(GetDiscoveryLibraryRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetArtistTracks") + handler = middleware(handler, "GetDiscoveryLibrary") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetArtistTracksResponseObject); ok { - if err := validResponse.VisitGetArtistTracksResponse(w); err != nil { + } else if validResponse, ok := response.(GetDiscoveryLibraryResponseObject); ok { + if err := validResponse.VisitGetDiscoveryLibraryResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18285,26 +20263,23 @@ func (sh *strictHandler) GetArtistTracks(w http.ResponseWriter, r *http.Request, } } -// GetLinkArtwork operation middleware -func (sh *strictHandler) GetLinkArtwork(w http.ResponseWriter, r *http.Request, id string, params GetLinkArtworkParams) { - var request GetLinkArtworkRequestObject - - request.Id = id - request.Params = params +// RefreshDiscoveryLibrary operation middleware +func (sh *strictHandler) RefreshDiscoveryLibrary(w http.ResponseWriter, r *http.Request) { + var request RefreshDiscoveryLibraryRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetLinkArtwork(ctx, request.(GetLinkArtworkRequestObject)) + return sh.ssi.RefreshDiscoveryLibrary(ctx, request.(RefreshDiscoveryLibraryRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetLinkArtwork") + handler = middleware(handler, "RefreshDiscoveryLibrary") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetLinkArtworkResponseObject); ok { - if err := validResponse.VisitGetLinkArtworkResponse(w); err != nil { + } else if validResponse, ok := response.(RefreshDiscoveryLibraryResponseObject); ok { + if err := validResponse.VisitRefreshDiscoveryLibraryResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18312,25 +20287,26 @@ func (sh *strictHandler) GetLinkArtwork(w http.ResponseWriter, r *http.Request, } } -// GetCollection operation middleware -func (sh *strictHandler) GetCollection(w http.ResponseWriter, r *http.Request, id string) { - var request GetCollectionRequestObject +// GetDiscoveryPreview operation middleware +func (sh *strictHandler) GetDiscoveryPreview(w http.ResponseWriter, r *http.Request, deezerTrackId int64, params GetDiscoveryPreviewParams) { + var request GetDiscoveryPreviewRequestObject - request.Id = id + request.DeezerTrackId = deezerTrackId + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetCollection(ctx, request.(GetCollectionRequestObject)) + return sh.ssi.GetDiscoveryPreview(ctx, request.(GetDiscoveryPreviewRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetCollection") + handler = middleware(handler, "GetDiscoveryPreview") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetCollectionResponseObject); ok { - if err := validResponse.VisitGetCollectionResponse(w); err != nil { + } else if validResponse, ok := response.(GetDiscoveryPreviewResponseObject); ok { + if err := validResponse.VisitGetDiscoveryPreviewResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18338,26 +20314,23 @@ func (sh *strictHandler) GetCollection(w http.ResponseWriter, r *http.Request, i } } -// GetGenre operation middleware -func (sh *strictHandler) GetGenre(w http.ResponseWriter, r *http.Request, id string, params GetGenreParams) { - var request GetGenreRequestObject - - request.Id = id - request.Params = params +// ListDiscoverySets operation middleware +func (sh *strictHandler) ListDiscoverySets(w http.ResponseWriter, r *http.Request) { + var request ListDiscoverySetsRequestObject handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetGenre(ctx, request.(GetGenreRequestObject)) + return sh.ssi.ListDiscoverySets(ctx, request.(ListDiscoverySetsRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetGenre") + handler = middleware(handler, "ListDiscoverySets") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetGenreResponseObject); ok { - if err := validResponse.VisitGetGenreResponse(w); err != nil { + } else if validResponse, ok := response.(ListDiscoverySetsResponseObject); ok { + if err := validResponse.VisitListDiscoverySetsResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18365,26 +20338,30 @@ func (sh *strictHandler) GetGenre(w http.ResponseWriter, r *http.Request, id str } } -// ListPlaylists operation middleware -func (sh *strictHandler) ListPlaylists(w http.ResponseWriter, r *http.Request, id string, params ListPlaylistsParams) { - var request ListPlaylistsRequestObject +// CreateDiscoverySet operation middleware +func (sh *strictHandler) CreateDiscoverySet(w http.ResponseWriter, r *http.Request) { + var request CreateDiscoverySetRequestObject - request.Id = id - request.Params = params + var body CreateDiscoverySetJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.ListPlaylists(ctx, request.(ListPlaylistsRequestObject)) + return sh.ssi.CreateDiscoverySet(ctx, request.(CreateDiscoverySetRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "ListPlaylists") + handler = middleware(handler, "CreateDiscoverySet") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(ListPlaylistsResponseObject); ok { - if err := validResponse.VisitListPlaylistsResponse(w); err != nil { + } else if validResponse, ok := response.(CreateDiscoverySetResponseObject); ok { + if err := validResponse.VisitCreateDiscoverySetResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18392,27 +20369,25 @@ func (sh *strictHandler) ListPlaylists(w http.ResponseWriter, r *http.Request, i } } -// GetPlaylistTracks operation middleware -func (sh *strictHandler) GetPlaylistTracks(w http.ResponseWriter, r *http.Request, id string, playlistId string, params GetPlaylistTracksParams) { - var request GetPlaylistTracksRequestObject +// DeleteDiscoverySet operation middleware +func (sh *strictHandler) DeleteDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) { + var request DeleteDiscoverySetRequestObject - request.Id = id - request.PlaylistId = playlistId - request.Params = params + request.SetId = setId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetPlaylistTracks(ctx, request.(GetPlaylistTracksRequestObject)) + return sh.ssi.DeleteDiscoverySet(ctx, request.(DeleteDiscoverySetRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetPlaylistTracks") + handler = middleware(handler, "DeleteDiscoverySet") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetPlaylistTracksResponseObject); ok { - if err := validResponse.VisitGetPlaylistTracksResponse(w); err != nil { + } else if validResponse, ok := response.(DeleteDiscoverySetResponseObject); ok { + if err := validResponse.VisitDeleteDiscoverySetResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18420,26 +20395,25 @@ func (sh *strictHandler) GetPlaylistTracks(w http.ResponseWriter, r *http.Reques } } -// GetTrackLyrics operation middleware -func (sh *strictHandler) GetTrackLyrics(w http.ResponseWriter, r *http.Request, id string, trackId string) { - var request GetTrackLyricsRequestObject +// GetDiscoverySet operation middleware +func (sh *strictHandler) GetDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) { + var request GetDiscoverySetRequestObject - request.Id = id - request.TrackId = trackId + request.SetId = setId handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetTrackLyrics(ctx, request.(GetTrackLyricsRequestObject)) + return sh.ssi.GetDiscoverySet(ctx, request.(GetDiscoverySetRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetTrackLyrics") + handler = middleware(handler, "GetDiscoverySet") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetTrackLyricsResponseObject); ok { - if err := validResponse.VisitGetTrackLyricsResponse(w); err != nil { + } else if validResponse, ok := response.(GetDiscoverySetResponseObject); ok { + if err := validResponse.VisitGetDiscoverySetResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18447,23 +20421,32 @@ func (sh *strictHandler) GetTrackLyrics(w http.ResponseWriter, r *http.Request, } } -// GetMe operation middleware -func (sh *strictHandler) GetMe(w http.ResponseWriter, r *http.Request) { - var request GetMeRequestObject +// UpdateDiscoverySet operation middleware +func (sh *strictHandler) UpdateDiscoverySet(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) { + var request UpdateDiscoverySetRequestObject + + request.SetId = setId + + var body UpdateDiscoverySetJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.GetMe(ctx, request.(GetMeRequestObject)) + return sh.ssi.UpdateDiscoverySet(ctx, request.(UpdateDiscoverySetRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "GetMe") + handler = middleware(handler, "UpdateDiscoverySet") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(GetMeResponseObject); ok { - if err := validResponse.VisitGetMeResponse(w); err != nil { + } else if validResponse, ok := response.(UpdateDiscoverySetResponseObject); ok { + if err := validResponse.VisitUpdateDiscoverySetResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18471,11 +20454,13 @@ func (sh *strictHandler) GetMe(w http.ResponseWriter, r *http.Request) { } } -// UpdateMe operation middleware -func (sh *strictHandler) UpdateMe(w http.ResponseWriter, r *http.Request) { - var request UpdateMeRequestObject +// AddDiscoverySetArtist operation middleware +func (sh *strictHandler) AddDiscoverySetArtist(w http.ResponseWriter, r *http.Request, setId DiscoverySetId) { + var request AddDiscoverySetArtistRequestObject - var body UpdateMeJSONRequestBody + request.SetId = setId + + var body AddDiscoverySetArtistJSONRequestBody if err := json.NewDecoder(r.Body).Decode(&body); err != nil { sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) return @@ -18483,18 +20468,18 @@ func (sh *strictHandler) UpdateMe(w http.ResponseWriter, r *http.Request) { request.Body = &body handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.UpdateMe(ctx, request.(UpdateMeRequestObject)) + return sh.ssi.AddDiscoverySetArtist(ctx, request.(AddDiscoverySetArtistRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "UpdateMe") + handler = middleware(handler, "AddDiscoverySetArtist") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UpdateMeResponseObject); ok { - if err := validResponse.VisitUpdateMeResponse(w); err != nil { + } else if validResponse, ok := response.(AddDiscoverySetArtistResponseObject); ok { + if err := validResponse.VisitAddDiscoverySetArtistResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18502,27 +20487,26 @@ func (sh *strictHandler) UpdateMe(w http.ResponseWriter, r *http.Request) { } } -// UploadAvatar operation middleware -func (sh *strictHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) { - var request UploadAvatarRequestObject - - request.ContentType = r.Header.Get("Content-Type") +// RemoveDiscoverySetArtist operation middleware +func (sh *strictHandler) RemoveDiscoverySetArtist(w http.ResponseWriter, r *http.Request, setId DiscoverySetId, artistKey string) { + var request RemoveDiscoverySetArtistRequestObject - request.Body = r.Body + request.SetId = setId + request.ArtistKey = artistKey handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.UploadAvatar(ctx, request.(UploadAvatarRequestObject)) + return sh.ssi.RemoveDiscoverySetArtist(ctx, request.(RemoveDiscoverySetArtistRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "UploadAvatar") + handler = middleware(handler, "RemoveDiscoverySetArtist") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(UploadAvatarResponseObject); ok { - if err := validResponse.VisitUploadAvatarResponse(w); err != nil { + } else if validResponse, ok := response.(RemoveDiscoverySetArtistResponseObject); ok { + if err := validResponse.VisitRemoveDiscoverySetArtistResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { @@ -18530,30 +20514,26 @@ func (sh *strictHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) { } } -// DeleteMe operation middleware -func (sh *strictHandler) DeleteMe(w http.ResponseWriter, r *http.Request) { - var request DeleteMeRequestObject +// GetDiscoveryFeed operation middleware +func (sh *strictHandler) GetDiscoveryFeed(w http.ResponseWriter, r *http.Request, setId DiscoverySetId, params GetDiscoveryFeedParams) { + var request GetDiscoveryFeedRequestObject - var body DeleteMeJSONRequestBody - if err := json.NewDecoder(r.Body).Decode(&body); err != nil { - sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) - return - } - request.Body = &body + request.SetId = setId + request.Params = params handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { - return sh.ssi.DeleteMe(ctx, request.(DeleteMeRequestObject)) + return sh.ssi.GetDiscoveryFeed(ctx, request.(GetDiscoveryFeedRequestObject)) } for _, middleware := range sh.middlewares { - handler = middleware(handler, "DeleteMe") + handler = middleware(handler, "GetDiscoveryFeed") } response, err := handler(r.Context(), w, r, request) if err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) - } else if validResponse, ok := response.(DeleteMeResponseObject); ok { - if err := validResponse.VisitDeleteMeResponse(w); err != nil { + } else if validResponse, ok := response.(GetDiscoveryFeedResponseObject); ok { + if err := validResponse.VisitGetDiscoveryFeedResponse(w); err != nil { sh.options.ResponseErrorHandlerFunc(w, r, err) } } else if response != nil { diff --git a/server/internal/httpapi/discover.go b/server/internal/httpapi/discover.go new file mode 100644 index 0000000..d31cf19 --- /dev/null +++ b/server/internal/httpapi/discover.go @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package httpapi + +import ( + "bytes" + "context" + "io" + "net/http" + + "github.com/madeofpendletonwool/syncphony/server/internal/discover" + "github.com/madeofpendletonwool/syncphony/server/internal/library" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// Personal discovery (ADR 0017). Every call is the signed-in member's own; +// guests have no discovery. + +func toDiscoverySet(set discover.Set) DiscoverySet { + out := DiscoverySet{ + Id: set.ID, Name: set.Name, Explore: int(set.Explore), Mode: DiscoveryMode(set.Mode), + Artists: make([]DiscoverySetArtist, len(set.Artists)), CreatedAt: set.CreatedAt, UpdatedAt: set.UpdatedAt, + } + for i, a := range set.Artists { + out.Artists[i] = DiscoverySetArtist{ + Key: a.ArtistKey, Name: a.Name, Mbid: nonEmpty(a.Mbid.String), AddedFrom: DiscoverySetArtistAddedFrom(a.AddedFrom), AddedAt: a.AddedAt, + } + } + return out +} + +func toDiscoveryLibrary(st library.Status) DiscoveryLibrary { + return DiscoveryLibrary{Links: st.Links, Songs: st.Songs, Building: st.Building, BuiltAt: timePtr(st.BuiltAt, !st.BuiltAt.IsZero())} +} + +func toDiscoveryBlock(b store.DiscoveryBlock) DiscoveryBlock { + return DiscoveryBlock{Key: b.ArtistKey, Name: b.Name, CreatedAt: b.CreatedAt} +} + +func toSeeds(in []DiscoverySeed) []discover.Seed { + out := make([]discover.Seed, len(in)) + for i, a := range in { + out[i] = discover.Seed{Name: a.Name, MBID: deref(a.Mbid)} + } + return out +} + +// ListDiscoverySets lists the caller's sets. +func (s *Server) ListDiscoverySets(ctx context.Context, _ ListDiscoverySetsRequestObject) (ListDiscoverySetsResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + sets, err := s.Discover.Sets(ctx, u.ID) + if err != nil { + return nil, err + } + out := make(ListDiscoverySets200JSONResponse, len(sets)) + for i, set := range sets { + out[i] = DiscoverySetSummary{ + Id: set.ID, Name: set.Name, Explore: int(set.Explore), Mode: DiscoveryMode(set.Mode), ArtistCount: int(set.Artists), + CreatedAt: set.CreatedAt, UpdatedAt: set.UpdatedAt, + } + } + return out, nil +} + +// CreateDiscoverySet makes a set. +func (s *Server) CreateDiscoverySet(ctx context.Context, req CreateDiscoverySetRequestObject) (CreateDiscoverySetResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + var seeds []discover.Seed + if req.Body.Artists != nil { + seeds = toSeeds(*req.Body.Artists) + } + set, err := s.Discover.Create(ctx, u.ID, req.Body.Name, seeds) + if err != nil { + return nil, err + } + return CreateDiscoverySet201JSONResponse(toDiscoverySet(set)), nil +} + +// GetDiscoverySet returns one of the caller's sets. +func (s *Server) GetDiscoverySet(ctx context.Context, req GetDiscoverySetRequestObject) (GetDiscoverySetResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + set, err := s.Discover.Get(ctx, u.ID, req.SetId) + if err != nil { + return nil, err + } + return GetDiscoverySet200JSONResponse(toDiscoverySet(set)), nil +} + +// UpdateDiscoverySet renames a set or changes its explore or mode. +func (s *Server) UpdateDiscoverySet(ctx context.Context, req UpdateDiscoverySetRequestObject) (UpdateDiscoverySetResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + c := discover.Changes{Name: req.Body.Name, Explore: req.Body.Explore} + if req.Body.Mode != nil { + c.Mode = ptr(string(*req.Body.Mode)) + } + set, err := s.Discover.Update(ctx, u.ID, req.SetId, c) + if err != nil { + return nil, err + } + return UpdateDiscoverySet200JSONResponse(toDiscoverySet(set)), nil +} + +// DeleteDiscoverySet deletes a set. +func (s *Server) DeleteDiscoverySet(ctx context.Context, req DeleteDiscoverySetRequestObject) (DeleteDiscoverySetResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + if err := s.Discover.Delete(ctx, u.ID, req.SetId); err != nil { + return nil, err + } + return DeleteDiscoverySet204Response{}, nil +} + +// AddDiscoverySetArtist adds a seed artist to a set. +func (s *Server) AddDiscoverySetArtist(ctx context.Context, req AddDiscoverySetArtistRequestObject) (AddDiscoverySetArtistResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + set, err := s.Discover.AddArtist(ctx, u.ID, req.SetId, discover.Seed{Name: req.Body.Name, MBID: deref(req.Body.Mbid)}) + if err != nil { + return nil, err + } + return AddDiscoverySetArtist200JSONResponse(toDiscoverySet(set)), nil +} + +// RemoveDiscoverySetArtist takes a seed artist out of a set. +func (s *Server) RemoveDiscoverySetArtist(ctx context.Context, req RemoveDiscoverySetArtistRequestObject) (RemoveDiscoverySetArtistResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + set, err := s.Discover.RemoveArtist(ctx, u.ID, req.SetId, req.ArtistKey) + if err != nil { + return nil, err + } + return RemoveDiscoverySetArtist200JSONResponse(toDiscoverySet(set)), nil +} + +// GetDiscoveryFeed returns a page of a set's feed. +func (s *Server) GetDiscoveryFeed(ctx context.Context, req GetDiscoveryFeedRequestObject) (GetDiscoveryFeedResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + f, err := s.Discover.Feed(ctx, u.ID, req.SetId, deref(req.Params.Cursor), req.Params.Refresh != nil && *req.Params.Refresh) + if err != nil { + return nil, err + } + out := DiscoveryFeed{Items: make([]DiscoveryItem, len(f.Items)), Next: nonEmpty(f.Next), Library: toDiscoveryLibrary(f.Library), NoGraph: f.NoGraph} + for i, it := range f.Items { + out.Items[i] = DiscoveryItem{ + Key: it.Key, Title: it.Title, Artist: it.Artist, Album: nonEmpty(it.Album), Mbid: nonEmpty(it.MBID), Isrc: nonEmpty(it.ISRC), + DeezerId: nonZero(it.DeezerID), Cover: nonEmpty(it.Cover), Because: it.Because, Seed: it.Seed, + } + if out.Items[i].Because == nil { + out.Items[i].Because = []string{} + } + } + return GetDiscoveryFeed200JSONResponse(out), nil +} + +// PostDiscoveryFeedback records a thumb on a song. +func (s *Server) PostDiscoveryFeedback(ctx context.Context, req PostDiscoveryFeedbackRequestObject) (PostDiscoveryFeedbackResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + b := req.Body + song := discover.Song{Title: b.Title, Artist: b.Artist, MBID: deref(b.Mbid), ISRC: deref(b.Isrc)} + if b.DeezerId != nil { + song.DeezerID = *b.DeezerId + } + if err := s.Discover.Thumb(ctx, u.ID, deref(b.SetId), string(b.Kind), song); err != nil { + return nil, err + } + return PostDiscoveryFeedback204Response{}, nil +} + +// ListDiscoveryBlocks lists the artists the caller blocked. +func (s *Server) ListDiscoveryBlocks(ctx context.Context, _ ListDiscoveryBlocksRequestObject) (ListDiscoveryBlocksResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + bs, err := s.Discover.Blocks(ctx, u.ID) + if err != nil { + return nil, err + } + out := make(ListDiscoveryBlocks200JSONResponse, len(bs)) + for i, b := range bs { + out[i] = toDiscoveryBlock(b) + } + return out, nil +} + +// BlockDiscoveryArtist keeps an artist out of the caller's feeds. +func (s *Server) BlockDiscoveryArtist(ctx context.Context, req BlockDiscoveryArtistRequestObject) (BlockDiscoveryArtistResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + b, err := s.Discover.Block(ctx, u.ID, req.Body.Name) + if err != nil { + return nil, err + } + return BlockDiscoveryArtist200JSONResponse(toDiscoveryBlock(b)), nil +} + +// UnblockDiscoveryArtist lets a blocked artist back in. +func (s *Server) UnblockDiscoveryArtist(ctx context.Context, req UnblockDiscoveryArtistRequestObject) (UnblockDiscoveryArtistResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + if err := s.Discover.Unblock(ctx, u.ID, req.ArtistKey); err != nil { + return nil, err + } + return UnblockDiscoveryArtist204Response{}, nil +} + +// SearchDiscoveryArtists finds artists to seed a set with. +func (s *Server) SearchDiscoveryArtists(ctx context.Context, req SearchDiscoveryArtistsRequestObject) (SearchDiscoveryArtistsResponseObject, error) { + if _, err := member(ctx); err != nil { + return nil, err + } + found, err := s.Discover.SearchArtists(ctx, req.Params.Q) + if err != nil { + return nil, err + } + out := make(SearchDiscoveryArtists200JSONResponse, len(found)) + for i, a := range found { + out[i] = DiscoveryArtist{Name: a.Name, Fans: nonZero(a.Fans), Picture: nonEmpty(a.Picture)} + } + return out, nil +} + +// GetDiscoveryLibrary reports how far the caller's library is indexed, +// and starts indexing it if it never was. +func (s *Server) GetDiscoveryLibrary(ctx context.Context, _ GetDiscoveryLibraryRequestObject) (GetDiscoveryLibraryResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + st, err := s.Discover.LibraryStatus(ctx, u.ID) + if err != nil { + return nil, err + } + return GetDiscoveryLibrary200JSONResponse(toDiscoveryLibrary(st)), nil +} + +// RefreshDiscoveryLibrary indexes the caller's library again, in the +// background. +func (s *Server) RefreshDiscoveryLibrary(ctx context.Context, _ RefreshDiscoveryLibraryRequestObject) (RefreshDiscoveryLibraryResponseObject, error) { + u, err := member(ctx) + if err != nil { + return nil, err + } + if s.Library != nil { + if err := s.Library.Refresh(ctx, u.ID); err != nil { + return nil, err + } + } + st, err := s.Discover.LibraryStatus(ctx, u.ID) + if err != nil { + return nil, err + } + st.Building = st.Building || s.Library != nil + return RefreshDiscoveryLibrary202JSONResponse(toDiscoveryLibrary(st)), nil +} + +// GetDiscoveryPreview streams a song's 30-second preview from Deezer. +func (s *Server) GetDiscoveryPreview(ctx context.Context, req GetDiscoveryPreviewRequestObject) (GetDiscoveryPreviewResponseObject, error) { + if _, err := member(ctx); err != nil { + return nil, err + } + if s.Deezer == nil { + return nil, provider.ErrNotFound + } + var r *provider.ByteRange + if req.Params.Range != nil { + r = parseRange(*req.Params.Range) + } + a, err := s.Deezer.OpenPreview(ctx, req.DeezerTrackId, r) + if err != nil { + return nil, err + } + return previewResponse{streamResponse{a}}, nil +} + +// previewResponse writes a preview as streamResponse writes a song. +type previewResponse struct{ streamResponse } + +func (r previewResponse) VisitGetDiscoveryPreviewResponse(w http.ResponseWriter) error { + return r.VisitStreamQueueItemResponse(w) +} + +// GetDiscoveryImage loads a cover or artist picture from Deezer. +func (s *Server) GetDiscoveryImage(ctx context.Context, req GetDiscoveryImageRequestObject) (GetDiscoveryImageResponseObject, error) { + if _, err := member(ctx); err != nil { + return nil, err + } + if s.Deezer == nil { + return nil, provider.ErrNotFound + } + size := 250 + if req.Params.Size != nil { + size = *req.Params.Size + } + img, ct, err := s.Deezer.Image(ctx, req.Kind, req.ImageId, size) + if err != nil { + return nil, err + } + return artworkResponse{body: io.NopCloser(bytes.NewReader(img)), ct: ct}, nil +} + +func (r artworkResponse) VisitGetDiscoveryImageResponse(w http.ResponseWriter) error { + return r.write(w) +} diff --git a/server/internal/httpapi/discover_test.go b/server/internal/httpapi/discover_test.go new file mode 100644 index 0000000..653d4c9 --- /dev/null +++ b/server/internal/httpapi/discover_test.go @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package httpapi_test + +import ( + "bytes" + "context" + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/httpapi" + "github.com/madeofpendletonwool/syncphony/server/internal/musicgraph" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" +) + +// discoverGraph knows Hum, who's like Failure and Shiner. +type discoverGraph struct{} + +func (discoverGraph) CachedArtist(_ context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, bool, error) { + songs := func(name string, id int64) []musicgraph.Song { + var out []musicgraph.Song + for i := range 3 { + out = append(out, musicgraph.Song{SongRef: musicgraph.SongRef{ + Title: fmt.Sprintf("%s %d", name, i+1), Artist: musicgraph.ArtistRef{Name: name}, DeezerID: id + int64(i), + }, Score: 1}) + } + return out + } + switch a.Name { + case "Hum": + return musicgraph.Artist{Ref: a, Similar: []musicgraph.Similar{ + {Artist: musicgraph.ArtistRef{Name: "Failure"}, Score: 0.8}, {Artist: musicgraph.ArtistRef{Name: "Shiner"}, Score: 0.5}, + }, Top: songs("Hum", 10)}, true, nil + case "Failure", "Shiner": + return musicgraph.Artist{Ref: a, Top: songs(a.Name, int64(len(a.Name))*100)}, true, nil + } + return musicgraph.Artist{}, true, provider.ErrNotFound +} + +func (g discoverGraph) Artist(ctx context.Context, a musicgraph.ArtistRef) (musicgraph.Artist, error) { + out, _, err := g.CachedArtist(ctx, a) + return out, err +} + +func (discoverGraph) WarmArtist(...musicgraph.ArtistRef) {} + +func TestDiscover(t *testing.T) { + e := newEnv(t) + alice := e.admin() + bob := e.member(alice, "bob") + e.api.Discover.Graph = discoverGraph{} + audio := bytes.Repeat([]byte("mp3!"), 100) + var dzURL string + dz := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/track/800": + fmt.Fprintf(w, `{"id":800,"title":"Failure 1","preview":"%s/preview.mp3?exp=1","artist":{"name":"Failure"}}`, dzURL) + case "/preview.mp3": + w.Header().Set("Content-Type", "audio/mpeg") + http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(audio)) + default: + fmt.Fprint(w, `{"error":{"code":800,"message":"no data"}}`) + } + })) + t.Cleanup(dz.Close) + dzURL = dz.URL + e.api.Deezer = musicgraph.NewDeezer(musicgraph.DeezerOptions{BaseURL: dz.URL, Interval: -1}) + + var set httpapi.DiscoverySet + alice.want(http.StatusCreated, "POST", "/me/discover/sets", httpapi.CreateDiscoverySetRequest{ + Name: "90s alt", Artists: &[]httpapi.DiscoverySeed{{Name: "Hum"}}, + }).decode(t, &set) + if len(set.Artists) != 1 || set.Explore != 40 || set.Mode != httpapi.DiscoveryModeBoth { + t.Fatalf("set: %+v", set) + } + base := "/me/discover/sets/" + set.Id + alice.want(http.StatusOK, "POST", base+"/artists", httpapi.DiscoverySeed{Name: "Nobody Knows"}).decode(t, &set) + alice.want(http.StatusOK, "DELETE", base+"/artists/"+url.PathEscape(set.Artists[1].Key), nil).decode(t, &set) + if len(set.Artists) != 1 { + t.Fatalf("artists: %+v", set.Artists) + } + mode := httpapi.DiscoveryModeDeep + alice.want(http.StatusOK, "PATCH", base, httpapi.UpdateDiscoverySetRequest{Mode: &mode, Explore: ptr(70)}).decode(t, &set) + if set.Mode != httpapi.DiscoveryModeDeep || set.Explore != 70 { + t.Fatalf("updated: %+v", set) + } + if r := alice.do("PATCH", base, httpapi.UpdateDiscoverySetRequest{Explore: ptr(101)}); r.status != http.StatusBadRequest { + t.Errorf("explore 101: %d %s", r.status, r.body) + } + + // The feed: Failure's songs lead, each saying why. + var feed httpapi.DiscoveryFeed + alice.want(http.StatusOK, "GET", base+"/feed", nil).decode(t, &feed) + if len(feed.Items) == 0 || feed.Items[0].Artist != "Failure" || len(feed.Items[0].Because) != 1 || feed.Items[0].Because[0] != "Hum" || feed.NoGraph { + t.Fatalf("feed: %+v", feed) + } + first := feed.Items[0] + alice.want(http.StatusNoContent, "POST", "/me/discover/feedback", httpapi.DiscoveryFeedbackRequest{ + Kind: httpapi.DiscoveryFeedbackRequestKindDown, SetId: &set.Id, Title: first.Title, Artist: first.Artist, + }) + alice.want(http.StatusOK, "GET", base+"/feed", nil).decode(t, &feed) + for _, it := range feed.Items { + if it.Key == first.Key { + t.Fatal("still there after a thumbs-down") + } + } + var block httpapi.DiscoveryBlock + alice.want(http.StatusOK, "POST", "/me/discover/blocks", httpapi.BlockDiscoveryArtistRequest{Name: "Shiner"}).decode(t, &block) + alice.want(http.StatusOK, "GET", base+"/feed", nil).decode(t, &feed) + for _, it := range feed.Items { + if it.Artist == "Shiner" { + t.Fatal("a blocked artist") + } + } + alice.want(http.StatusNoContent, "DELETE", "/me/discover/blocks/"+url.PathEscape(block.Key), nil) + + // The preview plays through the server, a range at a time. + r := alice.do("GET", "/me/discover/preview/800", nil, "Range", "bytes=100-") + if r.status != http.StatusPartialContent || len(r.body) != len(audio)-100 || r.header.Get("Content-Type") != "audio/mpeg" { + t.Errorf("preview: %d, %d bytes, %s", r.status, len(r.body), r.header.Get("Content-Type")) + } + if r := alice.do("GET", "/me/discover/preview/801", nil); r.status != http.StatusNotFound { + t.Errorf("a song with no preview: %d", r.status) + } + + var found []httpapi.DiscoveryArtist + alice.want(http.StatusOK, "GET", "/me/discover/artists?q=Duster", nil).decode(t, &found) + if len(found) != 1 || found[0].Name != "Duster" { + t.Errorf("artist search: %+v", found) + } + var lib httpapi.DiscoveryLibrary + alice.want(http.StatusOK, "GET", "/me/discover/library", nil).decode(t, &lib) + + // Bob can't see alice's set, or its feed. + var bobs []httpapi.DiscoverySetSummary + bob.want(http.StatusOK, "GET", "/me/discover/sets", nil).decode(t, &bobs) + if len(bobs) != 0 { + t.Errorf("bob's sets: %+v", bobs) + } + for _, path := range []string{base, base + "/feed"} { + if r := bob.do("GET", path, nil); r.status != http.StatusNotFound { + t.Errorf("bob GET %s: %d", path, r.status) + } + } + alice.want(http.StatusNoContent, "DELETE", base, nil) + alice.want(http.StatusNotFound, "GET", base, nil) +} + +func TestGuestsHaveNoDiscovery(t *testing.T) { + e := newEnv(t) + alice := e.admin() + e.advance(time.Since(e.clock())) + var room httpapi.Room + alice.want(http.StatusCreated, "POST", "/rooms", httpapi.CreateRoomRequest{Name: "Living room"}).decode(t, &room) + alice.want(http.StatusOK, "PATCH", "/rooms/"+room.Id, httpapi.UpdateRoomRequest{Guests: &httpapi.RoomGuests{Allowed: true, MaxSongs: 2}}) + var pass httpapi.GuestPass + alice.want(http.StatusCreated, "POST", "/rooms/"+room.Id+"/guest-pass", httpapi.CreateGuestPassRequest{ExpiresAt: e.clock().Add(time.Hour)}).decode(t, &pass) + guest, _ := e.joinAsGuest(passToken(t, pass), "Gus") + for _, path := range []string{"/me/discover/sets", "/me/discover/library", "/me/discover/preview/1"} { + if r := guest.do("GET", path, nil); r.status != http.StatusForbidden { + t.Errorf("guest GET %s: %d %s", path, r.status, r.body) + } + } +} diff --git a/server/internal/httpapi/server.go b/server/internal/httpapi/server.go index 9eda13f..93877a4 100644 --- a/server/internal/httpapi/server.go +++ b/server/internal/httpapi/server.go @@ -24,7 +24,9 @@ import ( "github.com/madeofpendletonwool/syncphony/server/internal/autopilot" "github.com/madeofpendletonwool/syncphony/server/internal/backup" "github.com/madeofpendletonwool/syncphony/server/internal/clips" + "github.com/madeofpendletonwool/syncphony/server/internal/discover" "github.com/madeofpendletonwool/syncphony/server/internal/games" + "github.com/madeofpendletonwool/syncphony/server/internal/library" "github.com/madeofpendletonwool/syncphony/server/internal/linernotes" "github.com/madeofpendletonwool/syncphony/server/internal/links" "github.com/madeofpendletonwool/syncphony/server/internal/lyrics" @@ -77,6 +79,13 @@ type Server struct { Nights *nights.Service // Playlists keeps Syncphony's own playlists. Playlists *playlists.Service + // Discover keeps users' discovery sets and makes their feeds. + Discover *discover.Service + // Library indexes what users have, for discovery. Optional. + Library *library.Service + // Deezer plays discovery's previews and loads its covers. Nil when + // Deezer is off. + Deezer *musicgraph.Deezer // Games runs the rooms' party games. Nil turns them off. Games *games.Engine // Clips serves the games' song clips. Nil serves none. @@ -336,7 +345,10 @@ func writeError(w http.ResponseWriter, r *http.Request, err error) { var invalidBackup *backup.InvalidInputError var invalidGame *games.InvalidInputError var invalidPlaylist *playlists.InvalidInputError + var invalidDiscover *discover.InvalidInputError switch { + case errors.As(err, &invalidDiscover): + writeJSONError(w, http.StatusBadRequest, "invalid_input", invalidDiscover.Error()) case errors.As(err, &invalidPlaylist): writeJSONError(w, http.StatusBadRequest, "invalid_input", invalidPlaylist.Error()) case errors.As(err, &invalidGame): @@ -416,6 +428,8 @@ var errorCodes = []struct { {playlists.ErrNotFound, http.StatusNotFound, "not_found"}, {playlists.ErrForbidden, http.StatusForbidden, "forbidden"}, {playlists.ErrNothingPlayed, http.StatusConflict, "nothing_played"}, + {discover.ErrNotFound, http.StatusNotFound, "not_found"}, + {discover.ErrTooMany, http.StatusConflict, "too_many"}, {games.ErrNoRound, http.StatusConflict, "round_closed"}, {games.ErrRoundRunning, http.StatusConflict, "round_running"}, {games.ErrForbidden, http.StatusForbidden, "forbidden"}, diff --git a/server/internal/library/library.go b/server/internal/library/library.go new file mode 100644 index 0000000..d635a2e --- /dev/null +++ b/server/internal/library/library.go @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Package library knows what music a user already has, so discovery can +// leave it out (MAD-816, ADR 0017). It indexes the songs on each user's +// own links that can list their whole library (Navidrome's), not shared +// links and not Spotify: what's on your own server is what you have. +// +// The library is only ever a filter. It says nothing about taste: plenty +// of what's on a server isn't its owner's favorite music. +// +// Each link's index is kept in memory, for lookups well under a +// millisecond, and in the database, so a restart doesn't rebuild it. A +// link is indexed the first time its user asks, then rebuilt daily in the +// background, or when they ask. A rebuild is skipped while the service +// says its library hasn't been scanned since. +package library + +import ( + "bytes" + "compress/gzip" + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "log/slog" + "slices" + "strings" + "sync" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/match" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// Links lists and opens users' links. It's links.Service in production. +type Links interface { + List(ctx context.Context, userID string) ([]store.ServiceLink, error) + Open(ctx context.Context, linkID string) (provider.Session, error) +} + +// How big and how often. +const ( + // maxSongs bounds one link's index, against a runaway catalog. + maxSongs = 2_000_000 + // checkEvery is how often Run looks for indexes due a rebuild. + checkEvery = time.Hour +) + +// Service indexes users' libraries. Call Run to keep them fresh. +type Service struct { + db *store.Store + links Links + // Every is how often a link's index is rebuilt. Default a day. + Every time.Duration + // Now is the clock. Default store.Now. + Now func() time.Time + + // build runs one build at a time, so indexing a big library never + // takes more than one request's worth of the server at once. + build sync.Mutex + // ctx is what builds run under: Run's, so they stop with the server. + ctx context.Context + + mu sync.RWMutex + indexes map[string]*index // by link ID + building map[string]bool + // cannot are links whose service can't list its library. + cannot map[string]bool + pending sync.WaitGroup +} + +// New returns a Service. +func New(db *store.Store, links Links) *Service { + return &Service{ + db: db, links: links, Every: 24 * time.Hour, Now: store.Now, ctx: context.Background(), + indexes: map[string]*index{}, building: map[string]bool{}, cannot: map[string]bool{}, + } +} + +// Song is a song to look up. +type Song struct { + Artist, Title string + // ISRC and MBID, when known, are matched before names. + ISRC, MBID string +} + +// index is what one link's library holds, by key. +type index struct { + songs, isrcs, mbids, releases, artists set + scannedAt, builtAt time.Time + count int +} + +type set map[string]struct{} + +func (s set) has(k string) bool { + _, ok := s[k] + return ok +} + +// ArtistKey is how artists are compared: the simplified name, without a +// leading "the". +func ArtistKey(name string) string { + return strings.TrimPrefix(match.Simplify(name), "the ") +} + +// titleKey is a title without its harmless qualifiers (remasters, feat.), +// keeping the ones that make it a different recording: "Song (Live)" isn't +// "Song". +func titleKey(title string) string { + t, variants := match.Title(title) + if len(variants) > 0 { + t += " (" + strings.Join(variants, " ") + ")" + } + return t +} + +// SongKey is how songs are compared: artist and title. +func SongKey(artist, title string) string { return ArtistKey(artist) + "\x00" + titleKey(title) } + +// ReleaseKey is how releases are compared: artist and release title. +func ReleaseKey(artist, release string) string { return ArtistKey(artist) + "\x00" + titleKey(release) } + +// Owned is what one user has, across their links' indexes, at the time +// it was asked for. Its lookups are map reads. +type Owned struct { + indexes []*index + // Building is whether one of the user's links is being indexed now, + // so the answer may be incomplete. + Building bool +} + +// Has reports whether the user has a song: by ISRC or MBID, or else by +// artist and title. +func (o *Owned) Has(s Song) bool { + if o == nil { + return false + } + isrc, mbid := strings.ToUpper(strings.TrimSpace(s.ISRC)), strings.ToLower(strings.TrimSpace(s.MBID)) + k := SongKey(s.Artist, s.Title) + for _, ix := range o.indexes { + if (isrc != "" && ix.isrcs.has(isrc)) || (mbid != "" && ix.mbids.has(mbid)) || ix.songs.has(k) { + return true + } + } + return false +} + +// HasRelease reports whether the user has a release (an album, an EP) by +// an artist. +func (o *Owned) HasRelease(artist, release string) bool { + if o == nil || strings.TrimSpace(release) == "" { + return false + } + k := ReleaseKey(artist, release) + for _, ix := range o.indexes { + if ix.releases.has(k) { + return true + } + } + return false +} + +// KnowsArtist reports whether the user has anything by an artist. It's +// for showing, never for filtering: a new album by an artist you have is +// still new to you. +func (o *Owned) KnowsArtist(artist string) bool { + if o == nil { + return false + } + k := ArtistKey(artist) + for _, ix := range o.indexes { + if ix.artists.has(k) { + return true + } + } + return false +} + +// Holding returns an Owned holding just these songs, as if one link's +// library had them: for testing what uses a library. +func Holding(ts ...provider.Track) *Owned { + ix := newIndex() + for _, t := range ts { + ix.add(t) + } + return &Owned{indexes: []*index{ix}} +} + +// Status says how far a user's library is indexed. +type Status struct { + // Links is how many of their links are indexed, Songs how many songs + // those hold. + Links, Songs int + // BuiltAt is when the oldest of those indexes was built; zero if none. + BuiltAt time.Time + // Building is whether one is being indexed now. + Building bool +} + +// Status reports how far a user's library is indexed, without starting +// anything. +func (o *Owned) Status() Status { + out := Status{Building: o.Building, Links: len(o.indexes)} + for _, ix := range o.indexes { + out.Songs += ix.count + if out.BuiltAt.IsZero() || ix.builtAt.Before(out.BuiltAt) { + out.BuiltAt = ix.builtAt + } + } + return out +} + +// For returns what a user has. Links never indexed are indexed in the +// background, starting now: until they're done, the answer leaves them out. +func (s *Service) For(ctx context.Context, userID string) (*Owned, error) { + rows, err := s.libraryLinks(ctx, userID) + if err != nil { + return nil, err + } + out := &Owned{} + for _, l := range rows { + ix, err := s.load(ctx, l.ID) + if err != nil { + return nil, err + } + if ix != nil { + out.indexes = append(out.indexes, ix) + } else { + s.kick(l.ID, false) + } + s.mu.RLock() + out.Building = out.Building || s.building[l.ID] + s.mu.RUnlock() + } + return out, nil +} + +// Has reports whether a user has a song. Asking about many songs, call For +// once and ask it. +func (s *Service) Has(ctx context.Context, userID string, song Song) (bool, error) { + o, err := s.For(ctx, userID) + return o.Has(song), err +} + +// HasRelease reports whether a user has a release by an artist. +func (s *Service) HasRelease(ctx context.Context, userID, artist, release string) (bool, error) { + o, err := s.For(ctx, userID) + return o.HasRelease(artist, release), err +} + +// KnowsArtist reports whether a user has anything by an artist. +func (s *Service) KnowsArtist(ctx context.Context, userID, artist string) (bool, error) { + o, err := s.For(ctx, userID) + return o.KnowsArtist(artist), err +} + +// Refresh rebuilds a user's indexes in the background, now, even if the +// service says nothing changed: they just added music, perhaps. +func (s *Service) Refresh(ctx context.Context, userID string) error { + rows, err := s.libraryLinks(ctx, userID) + if err != nil { + return err + } + for _, l := range rows { + s.kick(l.ID, true) + } + return nil +} + +// Wait waits for the builds in progress, for tests. +func (s *Service) Wait() { s.pending.Wait() } + +// libraryLinks are a user's own links that may hold a library: not +// expired, and not known to be unable to list one. +func (s *Service) libraryLinks(ctx context.Context, userID string) ([]store.ServiceLink, error) { + rows, err := s.links.List(ctx, userID) + if err != nil { + return nil, err + } + s.mu.RLock() + defer s.mu.RUnlock() + return slices.DeleteFunc(rows, func(l store.ServiceLink) bool { + return l.Status == store.LinkExpired || s.cannot[l.ID] + }), nil +} + +// load returns a link's index from memory, or from the database the +// first time; nil if it has none yet. +func (s *Service) load(ctx context.Context, linkID string) (*index, error) { + s.mu.RLock() + ix, ok := s.indexes[linkID] + s.mu.RUnlock() + if ok { + return ix, nil + } + row, err := s.db.GetLibraryIndex(ctx, linkID) + if store.IsNotFound(err) { + return nil, nil + } else if err != nil { + return nil, err + } + ix, err = decode(row) + if err != nil { + slog.Warn("library: reading a saved index; rebuilding it", "link", linkID, "err", err) + return nil, nil + } + s.mu.Lock() + defer s.mu.Unlock() + if cur, ok := s.indexes[linkID]; ok { + return cur, nil // a build finished meanwhile + } + s.indexes[linkID] = ix + return ix, nil +} + +// kick starts building a link's index in the background, unless it's +// being built already. +func (s *Service) kick(linkID string, force bool) { + s.mu.Lock() + if s.building[linkID] { + s.mu.Unlock() + return + } + s.building[linkID] = true + ctx := s.ctx + s.mu.Unlock() + s.pending.Go(func() { + defer func() { + s.mu.Lock() + delete(s.building, linkID) + s.mu.Unlock() + }() + if err := s.Build(ctx, linkID, force); err != nil && ctx.Err() == nil { + slog.Warn("library: indexing a link", "link", linkID, "err", err) + } + }) +} + +// Run rebuilds indexes older than Every, checking hourly, until ctx is +// done. Builds it starts, and ones For and Refresh start, stop with ctx. +func (s *Service) Run(ctx context.Context) { + s.mu.Lock() + s.ctx = ctx + s.mu.Unlock() + t := time.NewTicker(checkEvery) + defer t.Stop() + for { + s.refreshStale(ctx) + select { + case <-ctx.Done(): + return + case <-t.C: + } + } +} + +// refreshStale rebuilds the indexes that are due. +func (s *Service) refreshStale(ctx context.Context) { + rows, err := s.db.ListAllServiceLinks(ctx) + if err != nil { + if ctx.Err() == nil { + slog.Warn("library: listing links", "err", err) + } + return + } + now := s.Now() + for _, l := range rows { + if l.Status == store.LinkExpired { + continue + } + ix, err := s.load(ctx, l.ID) + if err != nil || ix == nil { + continue // never indexed: its user hasn't asked + } + if now.Sub(ix.builtAt) >= s.Every { + s.kick(l.ID, false) + } + } +} + +// Build indexes one link's library, now, and waits for it. Unless forced, +// it only notes the time when the service says the library hasn't been +// scanned since the last build. +func (s *Service) Build(ctx context.Context, linkID string, force bool) error { + s.build.Lock() + defer s.build.Unlock() + sess, err := s.links.Open(ctx, linkID) + if err != nil { + return err + } + defer sess.Close() + cat, ok := sess.(provider.Cataloger) + if !ok { + s.cannotList(linkID) + return nil + } + scanned, err := cat.LibraryChanged(ctx) + if errors.Is(err, provider.ErrUnsupported) { + s.cannotList(linkID) + return nil + } else if err != nil { + return err + } + prev, err := s.load(ctx, linkID) + if err != nil { + return err + } + now := s.Now() + if !force && prev != nil && !scanned.IsZero() && scanned.Equal(prev.scannedAt) { + if err := s.db.TouchLibraryIndex(ctx, store.TouchLibraryIndexParams{BuiltAt: now, LinkID: linkID}); err != nil { + return err + } + s.mu.Lock() + next := *prev + next.builtAt = now + s.indexes[linkID] = &next + s.mu.Unlock() + return nil + } + + ix := newIndex() + cursor := "" + for { + page, err := cat.CatalogSongs(ctx, cursor) + if errors.Is(err, provider.ErrUnsupported) { + s.cannotList(linkID) + return nil + } else if err != nil { + return err + } + for _, t := range page.Items { + ix.add(t) + } + if page.Next == "" || ix.count >= maxSongs { + break + } + cursor = page.Next + } + ix.scannedAt, ix.builtAt = scanned, now + data, err := encode(ix) + if err != nil { + return err + } + if err := s.db.PutLibraryIndex(ctx, store.PutLibraryIndexParams{ + LinkID: linkID, ScannedAt: sql.NullTime{Time: scanned, Valid: !scanned.IsZero()}, BuiltAt: now, + Songs: int64(ix.count), Data: data, + }); err != nil { + return err + } + s.mu.Lock() + s.indexes[linkID] = ix + s.mu.Unlock() + slog.Debug("library: indexed a link", "link", linkID, "songs", ix.count) + return nil +} + +func (s *Service) cannotList(linkID string) { + s.mu.Lock() + defer s.mu.Unlock() + s.cannot[linkID] = true +} + +func newIndex() *index { + return &index{songs: set{}, isrcs: set{}, mbids: set{}, releases: set{}, artists: set{}} +} + +// add indexes a song under each artist credited on it. +func (ix *index) add(t provider.Track) { + ix.count++ + if isrc := strings.ToUpper(strings.TrimSpace(t.ISRC)); isrc != "" { + ix.isrcs[isrc] = struct{}{} + } + if mbid := strings.ToLower(strings.TrimSpace(t.MBID)); mbid != "" { + ix.mbids[mbid] = struct{}{} + } + for _, a := range t.Artists { + k := ArtistKey(a.Name) + if k == "" { + continue + } + ix.artists[k] = struct{}{} + if t.Title != "" { + ix.songs[SongKey(a.Name, t.Title)] = struct{}{} + } + if t.Album.Title != "" { + ix.releases[ReleaseKey(a.Name, t.Album.Title)] = struct{}{} + } + } +} + +// saved is an index as the database keeps it, gzipped. +type saved struct { + Songs []string `json:"songs"` + ISRCs []string `json:"isrcs"` + MBIDs []string `json:"mbids"` + Releases []string `json:"releases"` + Artists []string `json:"artists"` +} + +func keys(s set) []string { + out := make([]string, 0, len(s)) + for k := range s { + out = append(out, k) + } + slices.Sort(out) + return out +} + +func toSet(ks []string) set { + out := make(set, len(ks)) + for _, k := range ks { + out[k] = struct{}{} + } + return out +} + +func encode(ix *index) ([]byte, error) { + var b bytes.Buffer + zw := gzip.NewWriter(&b) + if err := json.NewEncoder(zw).Encode(saved{ + Songs: keys(ix.songs), ISRCs: keys(ix.isrcs), MBIDs: keys(ix.mbids), Releases: keys(ix.releases), Artists: keys(ix.artists), + }); err != nil { + return nil, err + } + if err := zw.Close(); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func decode(row store.LibraryIndex) (*index, error) { + zr, err := gzip.NewReader(bytes.NewReader(row.Data)) + if err != nil { + return nil, fmt.Errorf("library: index of %s: %w", row.LinkID, err) + } + defer zr.Close() + var sv saved + if err := json.NewDecoder(zr).Decode(&sv); err != nil { + return nil, fmt.Errorf("library: index of %s: %w", row.LinkID, err) + } + return &index{ + songs: toSet(sv.Songs), isrcs: toSet(sv.ISRCs), mbids: toSet(sv.MBIDs), releases: toSet(sv.Releases), artists: toSet(sv.Artists), + scannedAt: row.ScannedAt.Time, builtAt: row.BuiltAt, count: int(row.Songs), + }, nil +} diff --git a/server/internal/library/library_test.go b/server/internal/library/library_test.go new file mode 100644 index 0000000..035b2fb --- /dev/null +++ b/server/internal/library/library_test.go @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package library_test + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "path/filepath" + "strconv" + "strings" + "sync" + "testing" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/library" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" + "github.com/madeofpendletonwool/syncphony/server/internal/provider/navidrome" + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +// subsonic is a tiny Subsonic server whose library is songs, listed by +// search3 with an empty query, a page at a time. +type subsonic struct { + *httptest.Server + mu sync.Mutex + songs []string // JSON song objects + lastScan string + searches int +} + +func newSubsonic(t *testing.T, songs []string) *subsonic { + s := &subsonic{songs: songs, lastScan: "2026-10-01T10:00:00Z"} + s.Server = httptest.NewServer(http.HandlerFunc(s.serve)) + t.Cleanup(s.Close) + return s +} + +func (s *subsonic) serve(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + s.mu.Lock() + defer s.mu.Unlock() + w.Header().Set("Content-Type", "application/json") + ok := func(fields string) { + fmt.Fprintf(w, `{"subsonic-response":{"status":"ok","version":"1.16.1","type":"navidrome","openSubsonic":true,%s}}`, fields) + } + switch strings.TrimPrefix(r.URL.Path, "/rest/") { + case "getScanStatus": + ok(fmt.Sprintf(`"scanStatus":{"scanning":false,"count":%d,"lastScan":%q}`, len(s.songs), s.lastScan)) + case "search3": + if q.Get("query") != "" || q.Get("albumCount") != "0" || q.Get("artistCount") != "0" { + http.Error(w, "not a catalog listing", http.StatusBadRequest) + return + } + s.searches++ + n, _ := strconv.Atoi(q.Get("songCount")) + off, _ := strconv.Atoi(q.Get("songOffset")) + page := s.songs[min(off, len(s.songs)):min(off+n, len(s.songs))] + ok(`"searchResult3":{"song":[` + strings.Join(page, ",") + `]}`) + default: + http.NotFound(w, r) + } +} + +func song(id, artist, title, album, isrc string) string { + b, _ := json.Marshal(map[string]any{ + "id": id, "title": title, "artist": artist, "album": album, "isrc": []string{isrc}, + "artists": []map[string]string{{"name": artist}}, + }) + return string(b) +} + +// links opens Navidrome links straight from their stored credentials. +type links struct { + db *store.Store + p *navidrome.Provider + creds map[string][]byte +} + +func (l *links) List(ctx context.Context, userID string) ([]store.ServiceLink, error) { + return l.db.ListServiceLinks(ctx, userID) +} + +func (l *links) Open(ctx context.Context, linkID string) (provider.Session, error) { + return l.p.Open(ctx, provider.Link{ID: linkID, Credentials: l.creds[linkID]}) +} + +type env struct { + db *store.Store + links *links + svc *library.Service + user string +} + +func newEnv(t *testing.T) *env { + t.Helper() + db, err := store.Open(t.Context(), filepath.Join(t.TempDir(), "test.db")) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { db.Close() }) + u, err := db.CreateUser(t.Context(), store.CreateUserParams{ + ID: store.NewID(), Username: "alice", DisplayName: "Alice", Color: "#000", Role: store.RoleMember, CreatedAt: store.Now(), + }) + if err != nil { + t.Fatal(err) + } + e := &env{db: db, user: u.ID, links: &links{db: db, p: navidrome.New(navidrome.Options{}), creds: map[string][]byte{}}} + e.svc = library.New(db, e.links) + return e +} + +// link links a Subsonic server to alice. +func (e *env) link(t *testing.T, srv *subsonic) string { + t.Helper() + l, err := e.db.CreateServiceLink(t.Context(), store.CreateServiceLinkParams{ + ID: store.NewID(), UserID: e.user, Provider: navidrome.ID, AccountID: srv.URL, AccountLabel: "alice", + EncryptedCredentials: []byte("sealed"), Now: store.Now(), + }) + if err != nil { + t.Fatal(err) + } + e.links.creds[l.ID], _ = json.Marshal(map[string]string{"url": srv.URL, "username": "alice", "password": "pw"}) + return l.ID +} + +func TestHasWhatsOnTheServer(t *testing.T) { + e := newEnv(t) + srv := newSubsonic(t, []string{ + song("1", "Slowdive", "Alison - 2010 Remaster", "Souvlaki", "GBAAA9300001"), + song("2", "The Hum", "Stars", "You'd Prefer an Astronaut", ""), + song("3", "Duster", "Inside Out (Live)", "Live at the Echo", ""), + }) + e.link(t, srv) + + // The first ask starts the index; until it's built, nothing is owned. + o, err := e.svc.For(t.Context(), e.user) + if err != nil { + t.Fatal(err) + } + if o.Has(library.Song{Artist: "Slowdive", Title: "Alison"}) { + t.Fatal("owned before the index was built") + } + e.svc.Wait() + if o, err = e.svc.For(t.Context(), e.user); err != nil { + t.Fatal(err) + } + for _, tc := range []struct { + song library.Song + want bool + }{ + {library.Song{Artist: "Slowdive", Title: "Alison"}, true}, // remaster note trimmed + {library.Song{Artist: "slowdive", Title: "ALISON (feat. Nobody)"}, true}, // case, feat. + {library.Song{Artist: "Someone Else", Title: "Cover", ISRC: "gbaaa9300001"}, true}, + {library.Song{Artist: "Hum", Title: "Stars"}, true}, // "The" ignored + {library.Song{Artist: "Hum", Title: "Stars (Live)"}, false}, + {library.Song{Artist: "Duster", Title: "Inside Out"}, false}, // only the live take is owned + {library.Song{Artist: "Slowdive", Title: "When the Sun Hits"}, false}, + } { + if got := o.Has(tc.song); got != tc.want { + t.Errorf("Has(%+v) = %v, want %v", tc.song, got, tc.want) + } + } + if !o.HasRelease("Slowdive", "Souvlaki (Deluxe Edition)") || o.HasRelease("Slowdive", "Pygmalion") { + t.Error("HasRelease is release-level") + } + if !o.KnowsArtist("hum") || o.KnowsArtist("Low") { + t.Error("KnowsArtist") + } + if st := o.Status(); st.Songs != 3 || st.Links != 1 || st.BuiltAt.IsZero() { + t.Errorf("status: %+v", st) + } +} + +func TestIndexSurvivesARestartAndSkipsUnchangedLibraries(t *testing.T) { + e := newEnv(t) + srv := newSubsonic(t, []string{song("1", "Slowdive", "Alison", "Souvlaki", "")}) + link := e.link(t, srv) + if err := e.svc.Build(t.Context(), link, false); err != nil { + t.Fatal(err) + } + if srv.searches != 1 { + t.Fatalf("%d listings", srv.searches) + } + + // A new Service reads the saved index, without listing the library. + fresh := library.New(e.db, e.links) + if ok, err := fresh.Has(t.Context(), e.user, library.Song{Artist: "Slowdive", Title: "Alison"}); err != nil || !ok { + t.Fatalf("after a restart: %v %v", ok, err) + } + fresh.Wait() + // Not scanned since: nothing to list again. + if err := fresh.Build(t.Context(), link, false); err != nil { + t.Fatal(err) + } + if srv.searches != 1 { + t.Errorf("rebuilt an unchanged library: %d listings", srv.searches) + } + // Scanned since, with a new song. + srv.mu.Lock() + srv.songs = append(srv.songs, song("2", "Hum", "Stars", "Astronaut", "")) + srv.lastScan = "2026-10-02T10:00:00Z" + srv.mu.Unlock() + if err := fresh.Build(t.Context(), link, false); err != nil { + t.Fatal(err) + } + if ok, _ := fresh.Has(t.Context(), e.user, library.Song{Artist: "Hum", Title: "Stars"}); !ok || srv.searches != 2 { + t.Errorf("after a scan: has %v, %d listings", ok, srv.searches) + } + // Refreshing rebuilds even when nothing says it changed. + if err := fresh.Refresh(t.Context(), e.user); err != nil { + t.Fatal(err) + } + fresh.Wait() + if srv.searches != 3 { + t.Errorf("refresh: %d listings", srv.searches) + } +} + +func TestBigLibrary(t *testing.T) { + e := newEnv(t) + const n = 60_000 + songs := make([]string, n) + for i := range songs { + songs[i] = song(strconv.Itoa(i), fmt.Sprintf("Artist %d", i/12), fmt.Sprintf("Song %d", i), fmt.Sprintf("Album %d", i/12), fmt.Sprintf("XX%010d", i)) + } + srv := newSubsonic(t, songs) + e.link(t, srv) + start := time.Now() + if _, err := e.svc.For(t.Context(), e.user); err != nil { + t.Fatal(err) + } + e.svc.Wait() + t.Logf("indexed %d songs in %v, %d pages", n, time.Since(start), srv.searches) + if srv.searches != n/500+1 { + t.Errorf("%d pages, want %d", srv.searches, n/500+1) + } + o, err := e.svc.For(t.Context(), e.user) + if err != nil { + t.Fatal(err) + } + const lookups = 10_000 + start = time.Now() + found := 0 + for i := range lookups { + j := i * 7 % n + if o.Has(library.Song{Artist: fmt.Sprintf("Artist %d", j/12), Title: fmt.Sprintf("Song %d", j)}) { + found++ + } + o.HasRelease("Nobody", "Nothing") + } + per := time.Since(start) / lookups + if found != lookups { + t.Errorf("found %d of %d", found, lookups) + } + if per > time.Millisecond { + t.Errorf("a lookup takes %v, want under a millisecond", per) + } +} diff --git a/server/internal/links/session.go b/server/internal/links/session.go index 425772d..15a9d11 100644 --- a/server/internal/links/session.go +++ b/server/internal/links/session.go @@ -133,6 +133,27 @@ func (w *watcher) AlbumList(ctx context.Context, kind provider.AlbumListKind, li return albums, w.see(ctx, err) } +// Cataloger is on every wrapped session too, like Collection. Sessions +// that can't list their library return ErrUnsupported. +func (w *watcher) CatalogSongs(ctx context.Context, cursor string) (provider.Page[provider.Track], error) { + c, ok := w.inner.(provider.Cataloger) + if !ok { + return provider.Page[provider.Track]{}, provider.ErrUnsupported + } + p, err := c.CatalogSongs(ctx, cursor) + return p, w.see(ctx, err) +} + +// LibraryChanged implements provider.Cataloger. +func (w *watcher) LibraryChanged(ctx context.Context) (time.Time, error) { + c, ok := w.inner.(provider.Cataloger) + if !ok { + return time.Time{}, provider.ErrUnsupported + } + t, err := c.LibraryChanged(ctx) + return t, w.see(ctx, err) +} + type streamer struct{ *watcher } func (w streamer) Stream(ctx context.Context, trackID string, opts provider.StreamOpts) (*provider.AudioStream, error) { diff --git a/server/internal/musicgraph/deezer.go b/server/internal/musicgraph/deezer.go index 514f0a1..fb0dfdb 100644 --- a/server/internal/musicgraph/deezer.go +++ b/server/internal/musicgraph/deezer.go @@ -10,6 +10,7 @@ import ( "io" "net/http" "net/url" + "regexp" "strconv" "time" @@ -20,6 +21,11 @@ import ( // DefaultDeezerURL is Deezer's public API. const DefaultDeezerURL = "https://api.deezer.com" +// DefaultDeezerImageURL is Deezer's image CDN. +const DefaultDeezerImageURL = "https://e-cdns-images.dzcdn.net/images" + +var imagePath = regexp.MustCompile(`/images/(?:cover|artist)/([0-9a-f]{32})/`) + // Deezer error codes we tell apart. const ( deezerQuota = 4 @@ -34,8 +40,9 @@ const deezerTopRank = 1_000_000 // related artists and top songs, and a song's tempo and popularity. It // keeps under Deezer's 50 requests per 5 seconds. type Deezer struct { - base string - c *client + base string + images string + c *client } // DeezerOptions configure a Deezer. @@ -43,6 +50,8 @@ type DeezerOptions struct { UserAgent string // BaseURL is the API. Default DefaultDeezerURL. BaseURL string + // ImageURL is the image CDN. Default DefaultDeezerImageURL. + ImageURL string // Client makes the requests. Default http.DefaultClient. Client *http.Client // Interval is the least time between requests. Default 120ms; @@ -55,10 +64,13 @@ func NewDeezer(opts DeezerOptions) *Deezer { if opts.BaseURL == "" { opts.BaseURL = DefaultDeezerURL } + if opts.ImageURL == "" { + opts.ImageURL = DefaultDeezerImageURL + } if opts.Interval == 0 { opts.Interval = 120 * time.Millisecond } - return &Deezer{base: trimSlash(opts.BaseURL), c: newClient("deezer", opts.UserAgent, opts.Client, opts.Interval)} + return &Deezer{base: trimSlash(opts.BaseURL), images: trimSlash(opts.ImageURL), c: newClient("deezer", opts.UserAgent, opts.Client, opts.Interval)} } // Name implements Source. @@ -68,6 +80,9 @@ type dzArtist struct { ID int64 `json:"id"` Name string `json:"name"` Fans int64 `json:"nb_fan"` + // MD5Image is their picture's ID on Deezer's image CDN. + MD5Image string `json:"md5_image"` + Picture string `json:"picture_medium"` } type dzTrack struct { @@ -78,9 +93,36 @@ type dzTrack struct { Rank float64 `json:"rank"` BPM float64 `json:"bpm"` ReleaseDate string `json:"release_date"` - Artist struct { + // Preview is a 30-second MP3. Its URL is signed and expires, so it's + // never kept: ask for the track again to play it. + Preview string `json:"preview"` + MD5Image string `json:"md5_image"` + Artist struct { Name string `json:"name"` } `json:"artist"` + Album struct { + ID int64 `json:"id"` + Title string `json:"title"` + CoverMedium string `json:"cover_medium"` + MD5Image string `json:"md5_image"` + } `json:"album"` +} + +// cover is the ID of a song's cover on Deezer's image CDN. +func (t dzTrack) cover() string { + if id := cmp.Or(t.Album.MD5Image, t.MD5Image); id != "" { + return id + } + return imageID(t.Album.CoverMedium) +} + +// imageID pulls the image ID out of a Deezer CDN URL +// (https://e-cdns-images.dzcdn.net/images/cover/<id>/250x250-...). +func imageID(u string) string { + if m := imagePath.FindStringSubmatch(u); m != nil { + return m[1] + } + return "" } // Artist implements Source with artist search, then the artist's related @@ -107,7 +149,7 @@ func (d *Deezer) Artist(ctx context.Context, a ArtistRef) (Artist, error) { return Artist{}, fmt.Errorf("deezer: artist %q: %w", a.Name, provider.ErrNotFound) } path := "/artist/" + strconv.FormatInt(id.ID, 10) - out := Artist{Ref: a} + out := Artist{Ref: a, Fans: id.Fans, Picture: cmp.Or(id.MD5Image, imageID(id.Picture))} var related struct { Data []dzArtist `json:"data"` @@ -131,7 +173,10 @@ func (d *Deezer) Artist(ctx context.Context, a ArtistRef) (Artist, error) { } for _, t := range top.Data { // Deezer's rank is already a compressed score, so it's compared as is. - out.Top = append(out.Top, Song{SongRef: SongRef{Title: t.Title, Artist: a, ISRC: t.ISRC}, Score: t.Rank / most}) + out.Top = append(out.Top, Song{ + SongRef: SongRef{Title: t.Title, Artist: a, ISRC: t.ISRC, DeezerID: t.ID, Album: t.Album.Title, Cover: t.cover()}, + Score: t.Rank / most, Rank: min(t.Rank/deezerTopRank, 1), + }) } return out, nil } @@ -169,23 +214,29 @@ func (d *Deezer) Track(ctx context.Context, s SongRef) (Track, error) { // search finds a song's Deezer ID by its artist and title, matched the // way cross-service matching matches. func (d *Deezer) search(ctx context.Context, s SongRef) (int64, error) { + t, err := d.searchFor(ctx, s, s.Artist.Name+" "+s.Title) + return t.ID, err +} + +// searchFor searches Deezer with q and returns the best match for s. +func (d *Deezer) searchFor(ctx context.Context, s SongRef, q string) (dzTrack, error) { var found struct { Data []dzTrack `json:"data"` } - if err := d.get(ctx, "/search", url.Values{"q": {s.Artist.Name + " " + s.Title}, "limit": {"10"}}, &found); err != nil { - return 0, err + if err := d.get(ctx, "/search", url.Values{"q": {q}, "limit": {"10"}}, &found); err != nil { + return dzTrack{}, err } want := provider.Track{Title: s.Title, ISRC: s.ISRC, Artists: []provider.ArtistCredit{{Name: s.Artist.Name}}} - var best int64 + var best dzTrack top := 0.0 for _, t := range found.Data { got := provider.Track{Title: t.Title, Artists: []provider.ArtistCredit{{Name: t.Artist.Name}}} if sc, ok := match.Score(want, got); ok && sc > top { - best, top = t.ID, sc + best, top = t, sc } } - if best == 0 { - return 0, fmt.Errorf("deezer: song %q: %w", s.Title, provider.ErrNotFound) + if best.ID == 0 { + return dzTrack{}, fmt.Errorf("deezer: song %q: %w", s.Title, provider.ErrNotFound) } return best, nil } diff --git a/server/internal/musicgraph/deezer_media.go b/server/internal/musicgraph/deezer_media.go new file mode 100644 index 0000000..f5d648b --- /dev/null +++ b/server/internal/musicgraph/deezer_media.go @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package musicgraph + +import ( + "cmp" + "context" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/madeofpendletonwool/syncphony/server/internal/provider" +) + +// What discovery (ADR 0017) asks Deezer for besides music knowledge: a +// song's ID, a fresh 30-second preview, artists by name, and images. The +// server fetches all of it, so the browser never talks to Deezer. + +// maxImage is the largest image fetched from Deezer's CDN. +const maxImage = 4 << 20 + +// DeezerTrack is a song on Deezer. +type DeezerTrack struct { + ID int64 + Title string + Artist string + // Album is its album's title, Cover the album cover's image ID. + Album string + Cover string + // Rank is how popular it is across all music, from 0 to 1. + Rank float64 + // HasPreview is whether Deezer has a 30-second preview of it. + HasPreview bool +} + +func (t dzTrack) public() DeezerTrack { + return DeezerTrack{ + ID: t.ID, Title: t.Title, Artist: t.Artist.Name, Album: t.Album.Title, Cover: t.cover(), + Rank: min(t.Rank/deezerTopRank, 1), HasPreview: t.Preview != "", + } +} + +// DeezerArtist is an artist on Deezer. +type DeezerArtist struct { + ID int64 + Name string + Fans int64 + Picture string +} + +// FindTrack finds a song on Deezer by its artist and title: an exact +// search first (artist:"x" track:"y"), then a loose one. It's +// provider.ErrNotFound if nothing matches. +func (d *Deezer) FindTrack(ctx context.Context, s SongRef) (DeezerTrack, error) { + if s.Title == "" || s.Artist.Name == "" { + return DeezerTrack{}, fmt.Errorf("deezer: a song with no title or artist: %w", provider.ErrNotFound) + } + q := fmt.Sprintf("artist:%q track:%q", s.Artist.Name, s.Title) + t, err := d.searchFor(ctx, s, q) + if isNotFound(err) { + t, err = d.searchFor(ctx, s, s.Artist.Name+" "+s.Title) + } + if err != nil { + return DeezerTrack{}, err + } + return t.public(), nil +} + +// TrackByID returns a song on Deezer by its ID. +func (d *Deezer) TrackByID(ctx context.Context, id int64) (DeezerTrack, error) { + t, err := d.track(ctx, id) + return t.public(), err +} + +func (d *Deezer) track(ctx context.Context, id int64) (dzTrack, error) { + if id <= 0 { + return dzTrack{}, fmt.Errorf("deezer: track %d: %w", id, provider.ErrNotFound) + } + var t dzTrack + if err := d.get(ctx, "/track/"+strconv.FormatInt(id, 10), nil, &t); err != nil { + return dzTrack{}, err + } + if t.ID == 0 { + return dzTrack{}, fmt.Errorf("deezer: track %d: %w", id, provider.ErrNotFound) + } + return t, nil +} + +// SearchArtists finds artists on Deezer by name, best known first among +// equally good matches, as Deezer orders them. +func (d *Deezer) SearchArtists(ctx context.Context, q string, limit int) ([]DeezerArtist, error) { + var found struct { + Data []dzArtist `json:"data"` + } + if err := d.get(ctx, "/search/artist", url.Values{"q": {q}, "limit": {strconv.Itoa(max(1, min(limit, 50)))}}, &found); err != nil { + return nil, err + } + out := make([]DeezerArtist, 0, len(found.Data)) + for _, a := range found.Data { + out = append(out, DeezerArtist{ID: a.ID, Name: a.Name, Fans: a.Fans, Picture: cmp.Or(a.MD5Image, imageID(a.Picture))}) + } + return out, nil +} + +// OpenPreview streams a song's 30-second preview. Its URL is asked for +// fresh every time, since Deezer signs them to expire; it's never kept. +// r, if set, asks for part of it. It's provider.ErrNotFound if Deezer has +// no preview of the song. +func (d *Deezer) OpenPreview(ctx context.Context, id int64, r *provider.ByteRange) (*provider.AudioStream, error) { + t, err := d.track(ctx, id) + if err != nil { + return nil, err + } + if t.Preview == "" { + return nil, fmt.Errorf("deezer: track %d has no preview: %w", id, provider.ErrNotFound) + } + u, err := url.Parse(t.Preview) + if err != nil || !d.mediaHost(u) { + return nil, fmt.Errorf("deezer: track %d: preview from an unexpected host: %w", id, provider.ErrUnavailable) + } + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + if err != nil { + return nil, err + } + req.Header.Set("User-Agent", d.c.userAgent) + if r != nil { + if r.End >= 0 { + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", r.Start, r.End)) + } else { + req.Header.Set("Range", fmt.Sprintf("bytes=%d-", r.Start)) + } + } + resp, err := d.c.http.Do(req) + if err != nil { + var ue *url.Error + if errors.As(err, &ue) { + err = ue.Err // the URL is signed; keep it out of logs + } + return nil, fmt.Errorf("deezer preview: %w: %w", provider.ErrUnavailable, err) + } + a := &provider.AudioStream{ + Body: resp.Body, ContentType: "audio/mpeg", Length: resp.ContentLength, Size: resp.ContentLength, + Seekable: resp.Header.Get("Accept-Ranges") == "bytes", + } + switch resp.StatusCode { + case http.StatusOK: + case http.StatusPartialContent: + var start, end, size int64 + if _, err := fmt.Sscanf(resp.Header.Get("Content-Range"), "bytes %d-%d/%d", &start, &end, &size); err == nil { + a.Offset, a.Length, a.Size, a.Seekable = start, end-start+1, size, true + } + case http.StatusRequestedRangeNotSatisfiable: + resp.Body.Close() + return nil, fmt.Errorf("deezer preview: %w", provider.ErrRange) + default: + resp.Body.Close() + return nil, fmt.Errorf("deezer preview: HTTP %d: %w", resp.StatusCode, provider.ErrUnavailable) + } + if ct := resp.Header.Get("Content-Type"); strings.HasPrefix(ct, "audio/") { + a.ContentType = ct + } + return a, nil +} + +// mediaHost reports whether u is somewhere Deezer serves media from: its +// CDN, or (for tests) the API's own host. +func (d *Deezer) mediaHost(u *url.URL) bool { + host := strings.ToLower(u.Hostname()) + if base, err := url.Parse(d.base); err == nil && u.Scheme == base.Scheme && strings.EqualFold(u.Host, base.Host) { + return true + } + return u.Scheme == "https" && (strings.HasSuffix(host, ".dzcdn.net") || strings.HasSuffix(host, ".deezer.com")) +} + +// Image kinds on Deezer's CDN. +const ( + ImageCover = "cover" + ImageArtist = "artist" +) + +// imageSizes are the sizes Deezer's CDN serves. +var imageSizes = []int{56, 120, 250, 500, 1000} + +// Image fetches a cover or artist picture from Deezer's CDN by its image +// ID, at about size pixels wide. +func (d *Deezer) Image(ctx context.Context, kind, id string, size int) ([]byte, string, error) { + if (kind != ImageCover && kind != ImageArtist) || !isImageID(id) { + return nil, "", fmt.Errorf("deezer image %s/%s: %w", kind, id, provider.ErrNotFound) + } + px := imageSizes[len(imageSizes)-1] + for _, s := range imageSizes { + if s >= size { + px = s + break + } + } + u := fmt.Sprintf("%s/%s/%s/%dx%d-000000-80-0-0.jpg", d.images, kind, id, px, px) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) + if err != nil { + return nil, "", err + } + req.Header.Set("User-Agent", d.c.userAgent) + resp, err := d.c.http.Do(req) + if err != nil { + return nil, "", fmt.Errorf("deezer image: %w: %w", provider.ErrUnavailable, err) + } + defer resp.Body.Close() + switch { + case resp.StatusCode == http.StatusNotFound: + return nil, "", fmt.Errorf("deezer image %s/%s: %w", kind, id, provider.ErrNotFound) + case resp.StatusCode != http.StatusOK: + return nil, "", fmt.Errorf("deezer image: HTTP %d: %w", resp.StatusCode, provider.ErrUnavailable) + } + ct := resp.Header.Get("Content-Type") + if !strings.HasPrefix(ct, "image/") { + return nil, "", fmt.Errorf("deezer image: not an image (%s): %w", ct, provider.ErrUnavailable) + } + body, err := io.ReadAll(io.LimitReader(resp.Body, maxImage)) + if err != nil { + return nil, "", fmt.Errorf("deezer image: %w: %w", provider.ErrUnavailable, err) + } + return body, ct, nil +} + +// isImageID reports whether id looks like a Deezer image ID: 32 hex digits. +func isImageID(id string) bool { + if len(id) != 32 { + return false + } + for _, r := range id { + if (r < '0' || r > '9') && (r < 'a' || r > 'f') { + return false + } + } + return true +} diff --git a/server/internal/musicgraph/deezer_media_test.go b/server/internal/musicgraph/deezer_media_test.go new file mode 100644 index 0000000..56f55e4 --- /dev/null +++ b/server/internal/musicgraph/deezer_media_test.go @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package musicgraph_test + +import ( + "bytes" + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/musicgraph" + "github.com/madeofpendletonwool/syncphony/server/internal/provider" +) + +const coverID = "0123456789abcdef0123456789abcdef" + +func TestDeezerTopSongsKeepTheirDeezerIDs(t *testing.T) { + e := newEnv(t) + e.http.routes["/deezer/artist/399/top"] = `{"data":[ + {"id":138547415,"title":"Creep","rank":978547,"preview":"https://cdnt-preview.dzcdn.net/x.mp3","artist":{"id":399,"name":"Radiohead"}, + "album":{"id":1,"title":"Pablo Honey","cover_medium":"https://e-cdns-images.dzcdn.net/images/cover/` + coverID + `/250x250-000000-80-0-0.jpg"}}],"total":1}` + e.http.routes["/deezer/search/artist?Radiohead"] = `{"data":[{"id":399,"name":"Radiohead","nb_fan":4101295,"md5_image":"` + coverID + `"}],"total":1}` + a, err := e.svc.Artist(t.Context(), radiohead) + if err != nil { + t.Fatal(err) + } + if a.Fans != 4101295 || a.Picture != coverID { + t.Errorf("fans %d, picture %q", a.Fans, a.Picture) + } + for _, so := range a.Top { + if so.Title != "Creep" { + continue + } + if so.DeezerID != 138547415 || so.Album != "Pablo Honey" || so.Cover != coverID || so.Rank < 0.97 { + t.Errorf("Creep: %+v", so) + } + return + } + t.Fatalf("no Creep in %+v", a.Top) +} + +func TestDeezerFindTrack(t *testing.T) { + e := newEnv(t) + e.http.routes[`/deezer/search?artist:"Hum" track:"Stars"`] = `{"data":[ + {"id":9,"title":"Stars (Live)","artist":{"name":"Hum"}}, + {"id":10,"title":"Stars","rank":400000,"preview":"https://cdnt-preview.dzcdn.net/y.mp3","artist":{"name":"Hum"},"album":{"title":"You'd Prefer an Astronaut","md5_image":"` + coverID + `"}}]}` + d := musicgraph.NewDeezer(musicgraph.DeezerOptions{BaseURL: e.http.URL + "/deezer", Interval: -1}) + got, err := d.FindTrack(t.Context(), musicgraph.SongRef{Title: "Stars", Artist: musicgraph.ArtistRef{Name: "Hum"}}) + if err != nil { + t.Fatal(err) + } + if got.ID != 10 || got.Album != "You'd Prefer an Astronaut" || got.Cover != coverID || !got.HasPreview { + t.Errorf("found %+v", got) + } + // Neither search finds it. + if _, err := d.FindTrack(t.Context(), musicgraph.SongRef{Title: "Nope", Artist: musicgraph.ArtistRef{Name: "Hum"}}); !errors.Is(err, provider.ErrNotFound) { + t.Errorf("a song Deezer doesn't have: %v", err) + } +} + +// previewServer is Deezer's API and CDN: each /track/1 gives a new signed +// preview URL, and only the newest one plays. +type previewServer struct { + *httptest.Server + issued atomic.Int64 +} + +var mp3 = bytes.Repeat([]byte("ID3mp3"), 200) + +func newPreviewServer(t *testing.T) *previewServer { + p := &previewServer{} + p.Server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/track/1": + n := p.issued.Add(1) + fmt.Fprintf(w, `{"id":1,"title":"Stars","preview":"%s/preview.mp3?hdnea=exp=%d","artist":{"name":"Hum"}}`, p.URL, n) + case "/track/2": + fmt.Fprint(w, `{"id":2,"title":"Silence","preview":"","artist":{"name":"Hum"}}`) + case "/track/3": + fmt.Fprint(w, `{"id":3,"title":"Elsewhere","preview":"https://evil.example.com/x.mp3","artist":{"name":"Hum"}}`) + case "/preview.mp3": + if r.URL.Query().Get("hdnea") != fmt.Sprintf("exp=%d", p.issued.Load()) { + http.Error(w, "expired", http.StatusForbidden) + return + } + w.Header().Set("Content-Type", "audio/mpeg") + http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(mp3)) + case "/images/cover/" + coverID + "/250x250-000000-80-0-0.jpg": + w.Header().Set("Content-Type", "image/jpeg") + _, _ = w.Write([]byte("jpeg")) + default: + fmt.Fprint(w, `{"error":{"type":"DataException","message":"no data","code":800}}`) + } + })) + t.Cleanup(p.Close) + return p +} + +func TestDeezerPreviewIsFetchedFresh(t *testing.T) { + p := newPreviewServer(t) + d := musicgraph.NewDeezer(musicgraph.DeezerOptions{BaseURL: p.URL, ImageURL: p.URL + "/images", Interval: -1}) + for range 2 { + a, err := d.OpenPreview(t.Context(), 1, nil) + if err != nil { + t.Fatal(err) + } + body, _ := io.ReadAll(a.Body) + a.Body.Close() + if !bytes.Equal(body, mp3) || a.ContentType != "audio/mpeg" || a.ContentRange() != "" { + t.Fatalf("preview: %d bytes, %s", len(body), a.ContentType) + } + } + if p.issued.Load() != 2 { + t.Errorf("asked for a preview URL %d times, want every time", p.issued.Load()) + } + // A range, for seeking. + a, err := d.OpenPreview(t.Context(), 1, &provider.ByteRange{Start: 100, End: -1}) + if err != nil { + t.Fatal(err) + } + body, _ := io.ReadAll(a.Body) + a.Body.Close() + if a.Offset != 100 || int(a.Length) != len(mp3)-100 || len(body) != len(mp3)-100 || !strings.HasPrefix(a.ContentRange(), "bytes 100-") { + t.Errorf("range: offset %d, length %d, %s", a.Offset, a.Length, a.ContentRange()) + } + if _, err := d.OpenPreview(t.Context(), 2, nil); !errors.Is(err, provider.ErrNotFound) { + t.Errorf("no preview: %v", err) + } + if _, err := d.OpenPreview(t.Context(), 3, nil); !errors.Is(err, provider.ErrUnavailable) { + t.Errorf("a preview somewhere else: %v", err) + } + + img, ct, err := d.Image(t.Context(), musicgraph.ImageCover, coverID, 200) + if err != nil || string(img) != "jpeg" || ct != "image/jpeg" { + t.Errorf("image: %q %s %v", img, ct, err) + } + if _, _, err := d.Image(t.Context(), musicgraph.ImageCover, "../../etc/passwd", 200); !errors.Is(err, provider.ErrNotFound) { + t.Errorf("a bad image ID: %v", err) + } +} diff --git a/server/internal/musicgraph/musicgraph.go b/server/internal/musicgraph/musicgraph.go index 973e494..c83cff3 100644 --- a/server/internal/musicgraph/musicgraph.go +++ b/server/internal/musicgraph/musicgraph.go @@ -48,6 +48,12 @@ type SongRef struct { // MBID is the MusicBrainz recording ID, ISRC the song's ISRC, when known. MBID string `json:"mbid,omitempty"` ISRC string `json:"isrc,omitempty"` + // DeezerID is the song's Deezer track ID, and Album and Cover its + // album's title and Deezer cover image ID, when Deezer listed it. + // Discovery plays Deezer's previews by the ID (ADR 0017). + DeezerID int64 `json:"deezerId,omitempty"` + Album string `json:"album,omitempty"` + Cover string `json:"cover,omitempty"` } // Similar is an artist like another. @@ -67,6 +73,9 @@ type Song struct { // From 0 to 1, merged across sources. Score float64 `json:"score"` Sources []string `json:"sources"` + // Rank is how popular it is across all music, from 0 to 1, when a + // source says (Deezer); 0 if unknown. + Rank float64 `json:"rank,omitempty"` } // Tag is a genre or descriptive tag. @@ -87,6 +96,10 @@ type Artist struct { Tags []Tag `json:"tags,omitempty"` // Sources are the sources that knew them. Sources []string `json:"sources,omitempty"` + // Fans is how many fans they have on Deezer, a measure of how well + // known they are; 0 if unknown. Picture is their Deezer picture's ID. + Fans int64 `json:"fans,omitempty"` + Picture string `json:"picture,omitempty"` } // Track is what the sources know about a song. @@ -673,6 +686,8 @@ func mergeArtist(ref ArtistRef, got []Artist) Artist { if out.Ref.MBID == "" { out.Ref.MBID = a.Ref.MBID } + out.Fans = max(out.Fans, a.Fans) + out.Picture = cmp.Or(out.Picture, a.Picture) if len(a.Similar) > 0 { simW += w for _, sim := range a.Similar { @@ -682,7 +697,7 @@ func mergeArtist(ref ArtistRef, got []Artist) Artist { if len(a.Top) > 0 { topW += w for _, so := range a.Top { - top = append(top, scored{key: match.Simplify(so.Title), score: so.Score * w, source: src, song: so.SongRef}) + top = append(top, scored{key: match.Simplify(so.Title), score: so.Score * w, source: src, song: so.SongRef, rank: so.Rank}) } } if len(a.Tags) > 0 { @@ -702,7 +717,7 @@ func mergeArtist(ref ArtistRef, got []Artist) Artist { for _, m := range combine(top, topW, maxTop) { so := m.song so.Artist = out.Ref - out.Top = append(out.Top, Song{SongRef: so, Score: m.score, Sources: m.sources}) + out.Top = append(out.Top, Song{SongRef: so, Score: m.score, Sources: m.sources, Rank: m.rank}) } for _, m := range combine(tags, tagW, maxTags) { out.Tags = append(out.Tags, Tag{Name: m.key, Weight: m.score}) @@ -752,6 +767,8 @@ type scored struct { source string artist ArtistRef song SongRef + // rank is a song's popularity across all music, if the source says. + rank float64 } // merged is something's combined score. @@ -776,7 +793,7 @@ func combine(in []scored, total float64, n int) []merged { m, ok := byKey[s.key] if !ok { m = &merged{scored: s} - m.score = 0 + m.score, m.rank = 0, 0 byKey[s.key] = m order = append(order, m) } @@ -789,6 +806,10 @@ func combine(in []scored, total float64, n int) []merged { m.song.MBID = cmp.Or(m.song.MBID, s.song.MBID) m.song.ISRC = cmp.Or(m.song.ISRC, s.song.ISRC) m.song.Artist.MBID = cmp.Or(m.song.Artist.MBID, s.song.Artist.MBID) + m.song.DeezerID = cmp.Or(m.song.DeezerID, s.song.DeezerID) + m.song.Album = cmp.Or(m.song.Album, s.song.Album) + m.song.Cover = cmp.Or(m.song.Cover, s.song.Cover) + m.rank = max(m.rank, s.rank) } out := make([]merged, len(order)) for i, m := range order { diff --git a/server/internal/provider/navidrome/catalog.go b/server/internal/provider/navidrome/catalog.go new file mode 100644 index 0000000..25170d6 --- /dev/null +++ b/server/internal/provider/navidrome/catalog.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package navidrome + +import ( + "context" + "fmt" + "net/url" + "strconv" + "time" + + "github.com/madeofpendletonwool/syncphony/server/internal/provider" +) + +var _ provider.Cataloger = (*session)(nil) + +// catalogPage is how many songs a page of the catalog holds: search3's +// most, so a big library takes few requests. +const catalogPage = 500 + +// CatalogSongs implements provider.Cataloger with search3: an empty query +// matches every song, and Navidrome pages through them in a stable order. +// It's cheaper on a big library than walking artists and albums, which +// takes a request per album. +func (s *session) CatalogSongs(ctx context.Context, cursor string) (provider.Page[provider.Track], error) { + offset := 0 + if cursor != "" { + n, err := strconv.Atoi(cursor) + if err != nil || n < 0 { + return provider.Page[provider.Track]{}, fmt.Errorf("navidrome: bad catalog cursor %q", cursor) + } + offset = n + } + r, err := s.api.call(ctx, "search3", url.Values{ + "query": {""}, "artistCount": {"0"}, "albumCount": {"0"}, + "songCount": {strconv.Itoa(catalogPage)}, "songOffset": {strconv.Itoa(offset)}, + }) + if err != nil { + return provider.Page[provider.Track]{}, err + } + var page provider.Page[provider.Track] + if r.SearchResult3 == nil { + return page, nil + } + page.Items = make([]provider.Track, 0, len(r.SearchResult3.Song)) + for _, so := range r.SearchResult3.Song { + page.Items = append(page.Items, s.track(so)) + } + if len(r.SearchResult3.Song) >= catalogPage { + page.Next = strconv.Itoa(offset + len(r.SearchResult3.Song)) + } + return page, nil +} + +// LibraryChanged implements provider.Cataloger with Navidrome's +// getScanStatus, whose lastScan other Subsonic servers don't send. +func (s *session) LibraryChanged(ctx context.Context) (time.Time, error) { + r, err := s.api.call(ctx, "getScanStatus", nil) + if err != nil || r.ScanStatus == nil || r.ScanStatus.LastScan == "" { + return time.Time{}, err + } + t, err := time.Parse(time.RFC3339, r.ScanStatus.LastScan) + if err != nil { + return time.Time{}, nil //nolint:nilerr // a server that says something else just can't say + } + return t.UTC(), nil +} diff --git a/server/internal/provider/navidrome/client.go b/server/internal/provider/navidrome/client.go index 587b107..bfa3ac5 100644 --- a/server/internal/provider/navidrome/client.go +++ b/server/internal/provider/navidrome/client.go @@ -208,6 +208,13 @@ type response struct { Playlist *playlist `json:"playlist"` Starred2 *starred `json:"starred2"` AlbumList2 *albumList `json:"albumList2"` + ScanStatus *scanStatus `json:"scanStatus"` +} + +// scanStatus is getScanStatus's result. lastScan is Navidrome's own. +type scanStatus struct { + Scanning bool `json:"scanning"` + LastScan string `json:"lastScan"` } // songList is the shape of the methods that return a list of songs. diff --git a/server/internal/provider/session.go b/server/internal/provider/session.go index ee9c215..43ad880 100644 --- a/server/internal/provider/session.go +++ b/server/internal/provider/session.go @@ -180,6 +180,19 @@ type Recommender interface { RandomTracks(ctx context.Context, limit int) ([]Track, error) } +// Cataloger is implemented by sessions that can list an account's whole +// library, so discovery knows what a user already has (ADR 0017). Like +// PlayChecker, it needs no capability: the core uses it when it's there. +type Cataloger interface { + // CatalogSongs returns a page of every song in the library, in an order + // that holds while the library doesn't change. Pass "" for the first + // page, then the previous page's Next. + CatalogSongs(ctx context.Context, cursor string) (Page[Track], error) + // LibraryChanged returns when the library last changed (the service's + // last scan of it), or the zero time if the service can't say. + LibraryChanged(ctx context.Context) (time.Time, error) +} + // PlayChecker is implemented by sessions that can tell ahead of time that a // track won't play, so the queue can refuse it instead of skipping it later. type PlayChecker interface { diff --git a/server/internal/store/discovery.sql.gen.go b/server/internal/store/discovery.sql.gen.go new file mode 100644 index 0000000..f1a3413 --- /dev/null +++ b/server/internal/store/discovery.sql.gen.go @@ -0,0 +1,632 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.31.1 +// source: discovery.sql + +package store + +import ( + "context" + "database/sql" + "time" +) + +const addDiscoverySetArtist = `-- name: AddDiscoverySetArtist :exec +INSERT INTO discovery_set_artists (set_id, artist_key, name, mbid, added_from, added_at) +VALUES (?, ?, ?, ?, ?, ?) +ON CONFLICT (set_id, artist_key) DO NOTHING +` + +type AddDiscoverySetArtistParams struct { + SetID string + ArtistKey string + Name string + Mbid sql.NullString + AddedFrom string + AddedAt time.Time +} + +func (q *Queries) AddDiscoverySetArtist(ctx context.Context, arg AddDiscoverySetArtistParams) error { + _, err := q.db.ExecContext(ctx, addDiscoverySetArtist, + arg.SetID, + arg.ArtistKey, + arg.Name, + arg.Mbid, + arg.AddedFrom, + arg.AddedAt, + ) + return err +} + +const addWantItem = `-- name: AddWantItem :exec +INSERT INTO want_items (id, user_id, set_id, kind, item_key, artist, title, release_title, mbid, isrc, deezer_id, added_at) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +ON CONFLICT (user_id, kind, item_key) DO NOTHING +` + +type AddWantItemParams struct { + ID string + UserID string + SetID sql.NullString + Kind string + ItemKey string + Artist string + Title string + ReleaseTitle string + Mbid sql.NullString + Isrc sql.NullString + DeezerID sql.NullInt64 + AddedAt time.Time +} + +func (q *Queries) AddWantItem(ctx context.Context, arg AddWantItemParams) error { + _, err := q.db.ExecContext(ctx, addWantItem, + arg.ID, + arg.UserID, + arg.SetID, + arg.Kind, + arg.ItemKey, + arg.Artist, + arg.Title, + arg.ReleaseTitle, + arg.Mbid, + arg.Isrc, + arg.DeezerID, + arg.AddedAt, + ) + return err +} + +const blockDiscoveryArtist = `-- name: BlockDiscoveryArtist :exec +INSERT INTO discovery_blocks (user_id, artist_key, name, created_at) +VALUES (?, ?, ?, ?) +ON CONFLICT (user_id, artist_key) DO NOTHING +` + +type BlockDiscoveryArtistParams struct { + UserID string + ArtistKey string + Name string + CreatedAt time.Time +} + +func (q *Queries) BlockDiscoveryArtist(ctx context.Context, arg BlockDiscoveryArtistParams) error { + _, err := q.db.ExecContext(ctx, blockDiscoveryArtist, + arg.UserID, + arg.ArtistKey, + arg.Name, + arg.CreatedAt, + ) + return err +} + +const createDiscoverySet = `-- name: CreateDiscoverySet :one + +INSERT INTO discovery_sets (id, user_id, name, explore, mode, created_at, updated_at) +VALUES (?, ?, ?, ?, ?, ?6, ?6) +RETURNING id, user_id, name, explore, mode, created_at, updated_at +` + +type CreateDiscoverySetParams struct { + ID string + UserID string + Name string + Explore int64 + Mode string + Now time.Time +} + +// Personal discovery (MAD-815, ADR 0017). Queries that take a user_id +// only see that user's rows. +func (q *Queries) CreateDiscoverySet(ctx context.Context, arg CreateDiscoverySetParams) (DiscoverySet, error) { + row := q.db.QueryRowContext(ctx, createDiscoverySet, + arg.ID, + arg.UserID, + arg.Name, + arg.Explore, + arg.Mode, + arg.Now, + ) + var i DiscoverySet + err := row.Scan( + &i.ID, + &i.UserID, + &i.Name, + &i.Explore, + &i.Mode, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteDiscoveryFeedback = `-- name: DeleteDiscoveryFeedback :exec +DELETE FROM discovery_feedback WHERE user_id = ? AND song_key = ? +` + +type DeleteDiscoveryFeedbackParams struct { + UserID string + SongKey string +} + +func (q *Queries) DeleteDiscoveryFeedback(ctx context.Context, arg DeleteDiscoveryFeedbackParams) error { + _, err := q.db.ExecContext(ctx, deleteDiscoveryFeedback, arg.UserID, arg.SongKey) + return err +} + +const deleteDiscoverySet = `-- name: DeleteDiscoverySet :execrows +DELETE FROM discovery_sets WHERE id = ? AND user_id = ? +` + +type DeleteDiscoverySetParams struct { + ID string + UserID string +} + +func (q *Queries) DeleteDiscoverySet(ctx context.Context, arg DeleteDiscoverySetParams) (int64, error) { + result, err := q.db.ExecContext(ctx, deleteDiscoverySet, arg.ID, arg.UserID) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const getDeezerSong = `-- name: GetDeezerSong :one +SELECT song_key, deezer_id, album, cover, checked_at FROM deezer_songs WHERE song_key = ? +` + +func (q *Queries) GetDeezerSong(ctx context.Context, songKey string) (DeezerSong, error) { + row := q.db.QueryRowContext(ctx, getDeezerSong, songKey) + var i DeezerSong + err := row.Scan( + &i.SongKey, + &i.DeezerID, + &i.Album, + &i.Cover, + &i.CheckedAt, + ) + return i, err +} + +const getDiscoverySet = `-- name: GetDiscoverySet :one +SELECT id, user_id, name, explore, mode, created_at, updated_at FROM discovery_sets WHERE id = ? AND user_id = ? +` + +type GetDiscoverySetParams struct { + ID string + UserID string +} + +func (q *Queries) GetDiscoverySet(ctx context.Context, arg GetDiscoverySetParams) (DiscoverySet, error) { + row := q.db.QueryRowContext(ctx, getDiscoverySet, arg.ID, arg.UserID) + var i DiscoverySet + err := row.Scan( + &i.ID, + &i.UserID, + &i.Name, + &i.Explore, + &i.Mode, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getLibraryIndex = `-- name: GetLibraryIndex :one +SELECT link_id, scanned_at, built_at, songs, data FROM library_indexes WHERE link_id = ? +` + +func (q *Queries) GetLibraryIndex(ctx context.Context, linkID string) (LibraryIndex, error) { + row := q.db.QueryRowContext(ctx, getLibraryIndex, linkID) + var i LibraryIndex + err := row.Scan( + &i.LinkID, + &i.ScannedAt, + &i.BuiltAt, + &i.Songs, + &i.Data, + ) + return i, err +} + +const listDiscoveryBlocks = `-- name: ListDiscoveryBlocks :many +SELECT user_id, artist_key, name, created_at FROM discovery_blocks WHERE user_id = ? ORDER BY name, artist_key +` + +func (q *Queries) ListDiscoveryBlocks(ctx context.Context, userID string) ([]DiscoveryBlock, error) { + rows, err := q.db.QueryContext(ctx, listDiscoveryBlocks, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []DiscoveryBlock{} + for rows.Next() { + var i DiscoveryBlock + if err := rows.Scan( + &i.UserID, + &i.ArtistKey, + &i.Name, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listDiscoveryFeedback = `-- name: ListDiscoveryFeedback :many +SELECT id, user_id, set_id, kind, song_key, title, artist, mbid, isrc, deezer_id, created_at FROM discovery_feedback WHERE user_id = ? ORDER BY created_at DESC, id +` + +func (q *Queries) ListDiscoveryFeedback(ctx context.Context, userID string) ([]DiscoveryFeedback, error) { + rows, err := q.db.QueryContext(ctx, listDiscoveryFeedback, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []DiscoveryFeedback{} + for rows.Next() { + var i DiscoveryFeedback + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.SetID, + &i.Kind, + &i.SongKey, + &i.Title, + &i.Artist, + &i.Mbid, + &i.Isrc, + &i.DeezerID, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listDiscoverySetArtists = `-- name: ListDiscoverySetArtists :many +SELECT set_id, artist_key, name, mbid, added_from, added_at FROM discovery_set_artists WHERE set_id = ? ORDER BY added_at, artist_key +` + +func (q *Queries) ListDiscoverySetArtists(ctx context.Context, setID string) ([]DiscoverySetArtist, error) { + rows, err := q.db.QueryContext(ctx, listDiscoverySetArtists, setID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []DiscoverySetArtist{} + for rows.Next() { + var i DiscoverySetArtist + if err := rows.Scan( + &i.SetID, + &i.ArtistKey, + &i.Name, + &i.Mbid, + &i.AddedFrom, + &i.AddedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listDiscoverySets = `-- name: ListDiscoverySets :many +SELECT discovery_sets.id, discovery_sets.user_id, discovery_sets.name, discovery_sets.explore, discovery_sets.mode, discovery_sets.created_at, discovery_sets.updated_at, + CAST((SELECT count(*) FROM discovery_set_artists a WHERE a.set_id = discovery_sets.id) AS INTEGER) AS artists +FROM discovery_sets +WHERE user_id = ? +ORDER BY updated_at DESC, id DESC +` + +type ListDiscoverySetsRow struct { + ID string + UserID string + Name string + Explore int64 + Mode string + CreatedAt time.Time + UpdatedAt time.Time + Artists int64 +} + +func (q *Queries) ListDiscoverySets(ctx context.Context, userID string) ([]ListDiscoverySetsRow, error) { + rows, err := q.db.QueryContext(ctx, listDiscoverySets, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ListDiscoverySetsRow{} + for rows.Next() { + var i ListDiscoverySetsRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.Name, + &i.Explore, + &i.Mode, + &i.CreatedAt, + &i.UpdatedAt, + &i.Artists, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const listWantItems = `-- name: ListWantItems :many +SELECT id, user_id, set_id, kind, item_key, artist, title, release_title, mbid, isrc, deezer_id, status, got_at, added_at FROM want_items WHERE user_id = ? ORDER BY added_at DESC, id +` + +func (q *Queries) ListWantItems(ctx context.Context, userID string) ([]WantItem, error) { + rows, err := q.db.QueryContext(ctx, listWantItems, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []WantItem{} + for rows.Next() { + var i WantItem + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.SetID, + &i.Kind, + &i.ItemKey, + &i.Artist, + &i.Title, + &i.ReleaseTitle, + &i.Mbid, + &i.Isrc, + &i.DeezerID, + &i.Status, + &i.GotAt, + &i.AddedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const putDeezerSong = `-- name: PutDeezerSong :exec +INSERT INTO deezer_songs (song_key, deezer_id, album, cover, checked_at) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (song_key) DO UPDATE SET + deezer_id = excluded.deezer_id, album = excluded.album, cover = excluded.cover, checked_at = excluded.checked_at +` + +type PutDeezerSongParams struct { + SongKey string + DeezerID int64 + Album string + Cover string + CheckedAt time.Time +} + +func (q *Queries) PutDeezerSong(ctx context.Context, arg PutDeezerSongParams) error { + _, err := q.db.ExecContext(ctx, putDeezerSong, + arg.SongKey, + arg.DeezerID, + arg.Album, + arg.Cover, + arg.CheckedAt, + ) + return err +} + +const putDiscoveryFeedback = `-- name: PutDiscoveryFeedback :exec +INSERT INTO discovery_feedback (id, user_id, set_id, kind, song_key, title, artist, mbid, isrc, deezer_id, created_at) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +ON CONFLICT (user_id, song_key) DO UPDATE SET + set_id = excluded.set_id, kind = excluded.kind, title = excluded.title, artist = excluded.artist, + mbid = excluded.mbid, isrc = excluded.isrc, deezer_id = excluded.deezer_id, created_at = excluded.created_at +` + +type PutDiscoveryFeedbackParams struct { + ID string + UserID string + SetID sql.NullString + Kind string + SongKey string + Title string + Artist string + Mbid sql.NullString + Isrc sql.NullString + DeezerID sql.NullInt64 + CreatedAt time.Time +} + +// PutDiscoveryFeedback records a thumb on a song, replacing the user's +// earlier one on it. +func (q *Queries) PutDiscoveryFeedback(ctx context.Context, arg PutDiscoveryFeedbackParams) error { + _, err := q.db.ExecContext(ctx, putDiscoveryFeedback, + arg.ID, + arg.UserID, + arg.SetID, + arg.Kind, + arg.SongKey, + arg.Title, + arg.Artist, + arg.Mbid, + arg.Isrc, + arg.DeezerID, + arg.CreatedAt, + ) + return err +} + +const putLibraryIndex = `-- name: PutLibraryIndex :exec +INSERT INTO library_indexes (link_id, scanned_at, built_at, songs, data) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (link_id) DO UPDATE SET + scanned_at = excluded.scanned_at, built_at = excluded.built_at, songs = excluded.songs, data = excluded.data +` + +type PutLibraryIndexParams struct { + LinkID string + ScannedAt sql.NullTime + BuiltAt time.Time + Songs int64 + Data []byte +} + +func (q *Queries) PutLibraryIndex(ctx context.Context, arg PutLibraryIndexParams) error { + _, err := q.db.ExecContext(ctx, putLibraryIndex, + arg.LinkID, + arg.ScannedAt, + arg.BuiltAt, + arg.Songs, + arg.Data, + ) + return err +} + +const removeDiscoverySetArtist = `-- name: RemoveDiscoverySetArtist :execrows +DELETE FROM discovery_set_artists WHERE set_id = ? AND artist_key = ? +` + +type RemoveDiscoverySetArtistParams struct { + SetID string + ArtistKey string +} + +func (q *Queries) RemoveDiscoverySetArtist(ctx context.Context, arg RemoveDiscoverySetArtistParams) (int64, error) { + result, err := q.db.ExecContext(ctx, removeDiscoverySetArtist, arg.SetID, arg.ArtistKey) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const setWantItemStatus = `-- name: SetWantItemStatus :execrows +UPDATE want_items SET status = ?, got_at = ? WHERE id = ? AND user_id = ? +` + +type SetWantItemStatusParams struct { + Status string + GotAt sql.NullTime + ID string + UserID string +} + +func (q *Queries) SetWantItemStatus(ctx context.Context, arg SetWantItemStatusParams) (int64, error) { + result, err := q.db.ExecContext(ctx, setWantItemStatus, + arg.Status, + arg.GotAt, + arg.ID, + arg.UserID, + ) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const touchDiscoverySet = `-- name: TouchDiscoverySet :exec +UPDATE discovery_sets SET updated_at = ? WHERE id = ? +` + +type TouchDiscoverySetParams struct { + UpdatedAt time.Time + ID string +} + +func (q *Queries) TouchDiscoverySet(ctx context.Context, arg TouchDiscoverySetParams) error { + _, err := q.db.ExecContext(ctx, touchDiscoverySet, arg.UpdatedAt, arg.ID) + return err +} + +const touchLibraryIndex = `-- name: TouchLibraryIndex :exec +UPDATE library_indexes SET built_at = ? WHERE link_id = ? +` + +type TouchLibraryIndexParams struct { + BuiltAt time.Time + LinkID string +} + +func (q *Queries) TouchLibraryIndex(ctx context.Context, arg TouchLibraryIndexParams) error { + _, err := q.db.ExecContext(ctx, touchLibraryIndex, arg.BuiltAt, arg.LinkID) + return err +} + +const unblockDiscoveryArtist = `-- name: UnblockDiscoveryArtist :execrows +DELETE FROM discovery_blocks WHERE user_id = ? AND artist_key = ? +` + +type UnblockDiscoveryArtistParams struct { + UserID string + ArtistKey string +} + +func (q *Queries) UnblockDiscoveryArtist(ctx context.Context, arg UnblockDiscoveryArtistParams) (int64, error) { + result, err := q.db.ExecContext(ctx, unblockDiscoveryArtist, arg.UserID, arg.ArtistKey) + if err != nil { + return 0, err + } + return result.RowsAffected() +} + +const updateDiscoverySet = `-- name: UpdateDiscoverySet :exec +UPDATE discovery_sets SET name = ?, explore = ?, mode = ?, updated_at = ? WHERE id = ? AND user_id = ? +` + +type UpdateDiscoverySetParams struct { + Name string + Explore int64 + Mode string + UpdatedAt time.Time + ID string + UserID string +} + +func (q *Queries) UpdateDiscoverySet(ctx context.Context, arg UpdateDiscoverySetParams) error { + _, err := q.db.ExecContext(ctx, updateDiscoverySet, + arg.Name, + arg.Explore, + arg.Mode, + arg.UpdatedAt, + arg.ID, + arg.UserID, + ) + return err +} diff --git a/server/internal/store/discovery_test.go b/server/internal/store/discovery_test.go new file mode 100644 index 0000000..0e8e952 --- /dev/null +++ b/server/internal/store/discovery_test.go @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +package store_test + +import ( + "database/sql" + "testing" + + "github.com/madeofpendletonwool/syncphony/server/internal/store" +) + +func TestDiscoverySets(t *testing.T) { + s := open(t) + ctx := t.Context() + alice, bob := user(t, s, "alice"), user(t, s, "bob") + set, err := s.CreateDiscoverySet(ctx, store.CreateDiscoverySetParams{ + ID: store.NewID(), UserID: alice.ID, Name: "Moody post-rock", Explore: 40, Mode: "both", Now: store.Now(), + }) + if err != nil { + t.Fatal(err) + } + // Bob can't see or change alice's set. + if _, err := s.GetDiscoverySet(ctx, store.GetDiscoverySetParams{ID: set.ID, UserID: bob.ID}); !store.IsNotFound(err) { + t.Fatalf("bob got alice's set: %v", err) + } + if n, err := s.DeleteDiscoverySet(ctx, store.DeleteDiscoverySetParams{ID: set.ID, UserID: bob.ID}); err != nil || n != 0 { + t.Fatalf("bob deleted alice's set: %d %v", n, err) + } + if sets, err := s.ListDiscoverySets(ctx, bob.ID); err != nil || len(sets) != 0 { + t.Fatalf("bob's sets: %v %v", sets, err) + } + + // An artist is in a set once, by its key. + for _, name := range []string{"Slowdive", "Slowdive", "Hum"} { + if err := s.AddDiscoverySetArtist(ctx, store.AddDiscoverySetArtistParams{ + SetID: set.ID, ArtistKey: name, Name: name, AddedFrom: "manual", AddedAt: store.Now(), + }); err != nil { + t.Fatal(err) + } + } + sets, err := s.ListDiscoverySets(ctx, alice.ID) + if err != nil || len(sets) != 1 || sets[0].Artists != 2 { + t.Fatalf("alice's sets: %+v %v", sets, err) + } + if err := s.AddDiscoverySetArtist(ctx, store.AddDiscoverySetArtistParams{ + SetID: set.ID, ArtistKey: "x", Name: "X", AddedFrom: "psychic", AddedAt: store.Now(), + }); err == nil { + t.Error("bad added_from accepted") + } + if err := s.UpdateDiscoverySet(ctx, store.UpdateDiscoverySetParams{ + ID: set.ID, UserID: alice.ID, Name: set.Name, Explore: 101, Mode: "both", UpdatedAt: store.Now(), + }); err == nil { + t.Error("explore over 100 accepted") + } + if err := s.UpdateDiscoverySet(ctx, store.UpdateDiscoverySetParams{ + ID: set.ID, UserID: alice.ID, Name: set.Name, Explore: 50, Mode: "sideways", UpdatedAt: store.Now(), + }); err == nil { + t.Error("bad mode accepted") + } + + // Feedback outlives its set; the set's artists don't. + if err := s.PutDiscoveryFeedback(ctx, store.PutDiscoveryFeedbackParams{ + ID: store.NewID(), UserID: alice.ID, SetID: sql.NullString{String: set.ID, Valid: true}, Kind: "up", + SongKey: "hum\x00stars", Title: "Stars", Artist: "Hum", CreatedAt: store.Now(), + }); err != nil { + t.Fatal(err) + } + if n, err := s.DeleteDiscoverySet(ctx, store.DeleteDiscoverySetParams{ID: set.ID, UserID: alice.ID}); err != nil || n != 1 { + t.Fatalf("deleting: %d %v", n, err) + } + if as, err := s.ListDiscoverySetArtists(ctx, set.ID); err != nil || len(as) != 0 { + t.Fatalf("artists left: %v %v", as, err) + } + fb, err := s.ListDiscoveryFeedback(ctx, alice.ID) + if err != nil || len(fb) != 1 || fb[0].SetID.Valid { + t.Fatalf("feedback after deleting the set: %+v %v", fb, err) + } +} + +func TestDiscoveryFeedbackLatestWins(t *testing.T) { + s := open(t) + ctx := t.Context() + alice, bob := user(t, s, "alice"), user(t, s, "bob") + put := func(u store.User, kind string) { + t.Helper() + if err := s.PutDiscoveryFeedback(ctx, store.PutDiscoveryFeedbackParams{ + ID: store.NewID(), UserID: u.ID, Kind: kind, SongKey: "hum\x00stars", Title: "Stars", Artist: "Hum", + DeezerID: sql.NullInt64{Int64: 42, Valid: true}, CreatedAt: store.Now(), + }); err != nil { + t.Fatal(err) + } + } + put(alice, "up") + put(alice, "down") + put(bob, "up") + fb, err := s.ListDiscoveryFeedback(ctx, alice.ID) + if err != nil || len(fb) != 1 || fb[0].Kind != "down" || fb[0].DeezerID.Int64 != 42 { + t.Fatalf("alice's feedback: %+v %v", fb, err) + } + if fb, _ := s.ListDiscoveryFeedback(ctx, bob.ID); len(fb) != 1 || fb[0].Kind != "up" { + t.Fatalf("bob's feedback: %+v", fb) + } + if err := s.PutDiscoveryFeedback(ctx, store.PutDiscoveryFeedbackParams{ + ID: store.NewID(), UserID: alice.ID, Kind: "meh", SongKey: "x", Title: "X", Artist: "Y", CreatedAt: store.Now(), + }); err == nil { + t.Error("bad kind accepted") + } +} + +func TestDiscoveryBlocksAndWants(t *testing.T) { + s := open(t) + ctx := t.Context() + alice, bob := user(t, s, "alice"), user(t, s, "bob") + for range 2 { + if err := s.BlockDiscoveryArtist(ctx, store.BlockDiscoveryArtistParams{UserID: alice.ID, ArtistKey: "nickelback", Name: "Nickelback", CreatedAt: store.Now()}); err != nil { + t.Fatal(err) + } + } + if bs, _ := s.ListDiscoveryBlocks(ctx, alice.ID); len(bs) != 1 { + t.Fatalf("blocks: %+v", bs) + } + if n, _ := s.UnblockDiscoveryArtist(ctx, store.UnblockDiscoveryArtistParams{UserID: bob.ID, ArtistKey: "nickelback"}); n != 0 { + t.Fatal("bob unblocked alice's block") + } + if n, _ := s.UnblockDiscoveryArtist(ctx, store.UnblockDiscoveryArtistParams{UserID: alice.ID, ArtistKey: "nickelback"}); n != 1 { + t.Fatal("alice couldn't unblock") + } + + want := store.AddWantItemParams{ + UserID: alice.ID, Kind: "track", ItemKey: "hum\x00stars", Artist: "Hum", Title: "Stars", AddedAt: store.Now(), + } + for range 2 { + want.ID = store.NewID() + if err := s.AddWantItem(ctx, want); err != nil { + t.Fatal(err) + } + } + items, err := s.ListWantItems(ctx, alice.ID) + if err != nil || len(items) != 1 || items[0].Status != "wanted" { + t.Fatalf("wants: %+v %v", items, err) + } + if n, _ := s.SetWantItemStatus(ctx, store.SetWantItemStatusParams{Status: "got", ID: items[0].ID, UserID: bob.ID}); n != 0 { + t.Fatal("bob changed alice's want") + } + if n, err := s.SetWantItemStatus(ctx, store.SetWantItemStatusParams{ + Status: "got", GotAt: sql.NullTime{Time: store.Now(), Valid: true}, ID: items[0].ID, UserID: alice.ID, + }); err != nil || n != 1 { + t.Fatalf("marking got: %d %v", n, err) + } + if _, err := s.SetWantItemStatus(ctx, store.SetWantItemStatusParams{Status: "lost", ID: items[0].ID, UserID: alice.ID}); err == nil { + t.Error("bad status accepted") + } +} + +func TestLibraryIndexAndDeezerSongs(t *testing.T) { + s := open(t) + ctx := t.Context() + alice := user(t, s, "alice") + l, err := s.CreateServiceLink(ctx, store.CreateServiceLinkParams{ + ID: store.NewID(), UserID: alice.ID, Provider: "navidrome", AccountID: "alice@music", AccountLabel: "alice", + EncryptedCredentials: []byte("x"), Now: store.Now(), + }) + if err != nil { + t.Fatal(err) + } + for i := range 2 { + if err := s.PutLibraryIndex(ctx, store.PutLibraryIndexParams{ + LinkID: l.ID, BuiltAt: store.Now(), Songs: int64(10 + i), Data: []byte{byte(i)}, + }); err != nil { + t.Fatal(err) + } + } + got, err := s.GetLibraryIndex(ctx, l.ID) + if err != nil || got.Songs != 11 || got.Data[0] != 1 || got.ScannedAt.Valid { + t.Fatalf("index: %+v %v", got, err) + } + // It goes with its link. + if err := s.DeleteServiceLink(ctx, store.DeleteServiceLinkParams{ID: l.ID, UserID: alice.ID}); err != nil { + t.Fatal(err) + } + if _, err := s.GetLibraryIndex(ctx, l.ID); !store.IsNotFound(err) { + t.Fatalf("index outlived its link: %v", err) + } + + if err := s.PutDeezerSong(ctx, store.PutDeezerSongParams{SongKey: "hum\x00stars", DeezerID: 0, CheckedAt: store.Now()}); err != nil { + t.Fatal(err) + } + if err := s.PutDeezerSong(ctx, store.PutDeezerSongParams{SongKey: "hum\x00stars", DeezerID: 7, Album: "You'd Prefer an Astronaut", CheckedAt: store.Now()}); err != nil { + t.Fatal(err) + } + if d, err := s.GetDeezerSong(ctx, "hum\x00stars"); err != nil || d.DeezerID != 7 || d.Album == "" { + t.Fatalf("deezer song: %+v %v", d, err) + } +} diff --git a/server/internal/store/migrations/00029_discovery.sql b/server/internal/store/migrations/00029_discovery.sql new file mode 100644 index 0000000..2cda64c --- /dev/null +++ b/server/internal/store/migrations/00029_discovery.sql @@ -0,0 +1,111 @@ +-- Personal discovery (MAD-815, ADR 0017). Taste comes from seed sets a +-- user builds by hand, not from their library: the library only says what +-- they already have (library_indexes). Every row here is one user's own. + +-- +goose Up +-- A named list of seed artists, each its own discovery feed. +CREATE TABLE discovery_sets ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, + name TEXT NOT NULL, + -- How far the feed strays from the seeds, 0 to 100. + explore INTEGER NOT NULL DEFAULT 40 CHECK (explore BETWEEN 0 AND 100), + -- Which feeds: deep cuts (anything new to you), fresh (recent + -- releases, stage 3), or both. + mode TEXT NOT NULL DEFAULT 'both' CHECK (mode IN ('deep', 'fresh', 'both')), + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); +CREATE INDEX discovery_sets_user ON discovery_sets (user_id, updated_at); + +CREATE TABLE discovery_set_artists ( + set_id TEXT NOT NULL REFERENCES discovery_sets (id) ON DELETE CASCADE, + -- The artist's MBID, else their simplified name (match.Simplify). + artist_key TEXT NOT NULL, + name TEXT NOT NULL, + mbid TEXT, + added_from TEXT NOT NULL DEFAULT 'manual' CHECK (added_from IN ('manual', 'thumb', 'starred', 'room')), + added_at TIMESTAMP NOT NULL, + PRIMARY KEY (set_id, artist_key) +); + +-- Thumbs on songs in a feed. A thumbs-down hides the song from every set +-- of its user's. One per user and song: the latest thumb wins. +CREATE TABLE discovery_feedback ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, + set_id TEXT REFERENCES discovery_sets (id) ON DELETE SET NULL, + kind TEXT NOT NULL CHECK (kind IN ('up', 'down')), + -- The simplified artist and title, which songs are compared by. + song_key TEXT NOT NULL, + title TEXT NOT NULL, + artist TEXT NOT NULL, + mbid TEXT, + isrc TEXT, + deezer_id INTEGER, + created_at TIMESTAMP NOT NULL, + UNIQUE (user_id, song_key) +); + +-- The global "not for me": artists kept out of every set's feed. +CREATE TABLE discovery_blocks ( + user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, + artist_key TEXT NOT NULL, + name TEXT NOT NULL, + created_at TIMESTAMP NOT NULL, + PRIMARY KEY (user_id, artist_key) +); + +-- Songs and releases a user wants, until they turn up in their library +-- (stage 4 fills this; the feed already leaves them out). +CREATE TABLE want_items ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, + set_id TEXT REFERENCES discovery_sets (id) ON DELETE SET NULL, + kind TEXT NOT NULL CHECK (kind IN ('track', 'release')), + -- The simplified artist and title (or release title). + item_key TEXT NOT NULL, + artist TEXT NOT NULL, + title TEXT NOT NULL, + release_title TEXT NOT NULL DEFAULT '', + mbid TEXT, + isrc TEXT, + deezer_id INTEGER, + status TEXT NOT NULL DEFAULT 'wanted' CHECK (status IN ('wanted', 'got', 'dismissed')), + got_at TIMESTAMP, + added_at TIMESTAMP NOT NULL, + UNIQUE (user_id, kind, item_key) +); +CREATE INDEX want_items_user ON want_items (user_id, status, added_at); + +-- What's in a link's library, so discovery can leave it out (MAD-816): +-- the keys of its songs, releases and artists, gzipped JSON, loaded into +-- memory at startup and rebuilt daily. +CREATE TABLE library_indexes ( + link_id TEXT PRIMARY KEY REFERENCES service_links (id) ON DELETE CASCADE, + -- When the service last scanned its library, if it says; a rebuild is + -- skipped while that hasn't changed. + scanned_at TIMESTAMP, + built_at TIMESTAMP NOT NULL, + songs INTEGER NOT NULL, + data BLOB NOT NULL +); + +-- Songs' Deezer track IDs, found by searching once, for previews. 0 is +-- no match. +CREATE TABLE deezer_songs ( + song_key TEXT PRIMARY KEY, + deezer_id INTEGER NOT NULL, + album TEXT NOT NULL DEFAULT '', + cover TEXT NOT NULL DEFAULT '', + checked_at TIMESTAMP NOT NULL +); + +-- +goose Down +DROP TABLE deezer_songs; +DROP TABLE library_indexes; +DROP TABLE want_items; +DROP TABLE discovery_blocks; +DROP TABLE discovery_feedback; +DROP TABLE discovery_set_artists; +DROP TABLE discovery_sets; diff --git a/server/internal/store/models.gen.go b/server/internal/store/models.gen.go index fbfd1da..84cd7bd 100644 --- a/server/internal/store/models.gen.go +++ b/server/internal/store/models.gen.go @@ -41,6 +41,54 @@ type CredentialsPassword struct { UpdatedAt time.Time } +type DeezerSong struct { + SongKey string + DeezerID int64 + Album string + Cover string + CheckedAt time.Time +} + +type DiscoveryBlock struct { + UserID string + ArtistKey string + Name string + CreatedAt time.Time +} + +type DiscoveryFeedback struct { + ID string + UserID string + SetID sql.NullString + Kind string + SongKey string + Title string + Artist string + Mbid sql.NullString + Isrc sql.NullString + DeezerID sql.NullInt64 + CreatedAt time.Time +} + +type DiscoverySet struct { + ID string + UserID string + Name string + Explore int64 + Mode string + CreatedAt time.Time + UpdatedAt time.Time +} + +type DiscoverySetArtist struct { + SetID string + ArtistKey string + Name string + Mbid sql.NullString + AddedFrom string + AddedAt time.Time +} + type Display struct { ID string TokenHash []byte @@ -127,6 +175,14 @@ type Invite struct { UsedAt sql.NullTime } +type LibraryIndex struct { + LinkID string + ScannedAt sql.NullTime + BuiltAt time.Time + Songs int64 + Data []byte +} + type LinerNotesCache struct { Provider string TrackID string @@ -358,3 +414,20 @@ type UserAudit struct { Detail string CreatedAt time.Time } + +type WantItem struct { + ID string + UserID string + SetID sql.NullString + Kind string + ItemKey string + Artist string + Title string + ReleaseTitle string + Mbid sql.NullString + Isrc sql.NullString + DeezerID sql.NullInt64 + Status string + GotAt sql.NullTime + AddedAt time.Time +} diff --git a/server/internal/store/queries/discovery.sql b/server/internal/store/queries/discovery.sql new file mode 100644 index 0000000..827dc91 --- /dev/null +++ b/server/internal/store/queries/discovery.sql @@ -0,0 +1,95 @@ +-- Personal discovery (MAD-815, ADR 0017). Queries that take a user_id +-- only see that user's rows. + +-- name: CreateDiscoverySet :one +INSERT INTO discovery_sets (id, user_id, name, explore, mode, created_at, updated_at) +VALUES (?, ?, ?, ?, ?, sqlc.arg(now), sqlc.arg(now)) +RETURNING *; + +-- name: GetDiscoverySet :one +SELECT * FROM discovery_sets WHERE id = ? AND user_id = ?; + +-- name: ListDiscoverySets :many +SELECT discovery_sets.*, + CAST((SELECT count(*) FROM discovery_set_artists a WHERE a.set_id = discovery_sets.id) AS INTEGER) AS artists +FROM discovery_sets +WHERE user_id = ? +ORDER BY updated_at DESC, id DESC; + +-- name: UpdateDiscoverySet :exec +UPDATE discovery_sets SET name = ?, explore = ?, mode = ?, updated_at = ? WHERE id = ? AND user_id = ?; + +-- name: TouchDiscoverySet :exec +UPDATE discovery_sets SET updated_at = ? WHERE id = ?; + +-- name: DeleteDiscoverySet :execrows +DELETE FROM discovery_sets WHERE id = ? AND user_id = ?; + +-- name: AddDiscoverySetArtist :exec +INSERT INTO discovery_set_artists (set_id, artist_key, name, mbid, added_from, added_at) +VALUES (?, ?, ?, ?, ?, ?) +ON CONFLICT (set_id, artist_key) DO NOTHING; + +-- name: ListDiscoverySetArtists :many +SELECT * FROM discovery_set_artists WHERE set_id = ? ORDER BY added_at, artist_key; + +-- name: RemoveDiscoverySetArtist :execrows +DELETE FROM discovery_set_artists WHERE set_id = ? AND artist_key = ?; + +-- PutDiscoveryFeedback records a thumb on a song, replacing the user's +-- earlier one on it. +-- name: PutDiscoveryFeedback :exec +INSERT INTO discovery_feedback (id, user_id, set_id, kind, song_key, title, artist, mbid, isrc, deezer_id, created_at) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +ON CONFLICT (user_id, song_key) DO UPDATE SET + set_id = excluded.set_id, kind = excluded.kind, title = excluded.title, artist = excluded.artist, + mbid = excluded.mbid, isrc = excluded.isrc, deezer_id = excluded.deezer_id, created_at = excluded.created_at; + +-- name: ListDiscoveryFeedback :many +SELECT * FROM discovery_feedback WHERE user_id = ? ORDER BY created_at DESC, id; + +-- name: DeleteDiscoveryFeedback :exec +DELETE FROM discovery_feedback WHERE user_id = ? AND song_key = ?; + +-- name: BlockDiscoveryArtist :exec +INSERT INTO discovery_blocks (user_id, artist_key, name, created_at) +VALUES (?, ?, ?, ?) +ON CONFLICT (user_id, artist_key) DO NOTHING; + +-- name: UnblockDiscoveryArtist :execrows +DELETE FROM discovery_blocks WHERE user_id = ? AND artist_key = ?; + +-- name: ListDiscoveryBlocks :many +SELECT * FROM discovery_blocks WHERE user_id = ? ORDER BY name, artist_key; + +-- name: AddWantItem :exec +INSERT INTO want_items (id, user_id, set_id, kind, item_key, artist, title, release_title, mbid, isrc, deezer_id, added_at) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +ON CONFLICT (user_id, kind, item_key) DO NOTHING; + +-- name: ListWantItems :many +SELECT * FROM want_items WHERE user_id = ? ORDER BY added_at DESC, id; + +-- name: SetWantItemStatus :execrows +UPDATE want_items SET status = ?, got_at = ? WHERE id = ? AND user_id = ?; + +-- name: PutLibraryIndex :exec +INSERT INTO library_indexes (link_id, scanned_at, built_at, songs, data) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (link_id) DO UPDATE SET + scanned_at = excluded.scanned_at, built_at = excluded.built_at, songs = excluded.songs, data = excluded.data; + +-- name: GetLibraryIndex :one +SELECT * FROM library_indexes WHERE link_id = ?; + +-- name: TouchLibraryIndex :exec +UPDATE library_indexes SET built_at = ? WHERE link_id = ?; + +-- name: GetDeezerSong :one +SELECT * FROM deezer_songs WHERE song_key = ?; + +-- name: PutDeezerSong :exec +INSERT INTO deezer_songs (song_key, deezer_id, album, cover, checked_at) +VALUES (?, ?, ?, ?, ?) +ON CONFLICT (song_key) DO UPDATE SET + deezer_id = excluded.deezer_id, album = excluded.album, cover = excluded.cover, checked_at = excluded.checked_at; diff --git a/web/src/api/schema.gen.ts b/web/src/api/schema.gen.ts index 1dd9cd2..ecd028e 100644 --- a/web/src/api/schema.gen.ts +++ b/web/src/api/schema.gen.ts @@ -2211,6 +2211,278 @@ export interface paths { patch?: never; trace?: never; }; + "/me/discover/sets": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Your discovery sets + * @description Seed sets (ADR 0017): named lists of artists, each its own feed of + * music you don't have yet. Yours alone, most recently changed first. + * Guests have no discovery. + */ + get: operations["listDiscoverySets"]; + put?: never; + /** + * Make a discovery set + * @description With seed artists, if given. At most 50 sets, of 50 artists each (`too_many`). + */ + post: operations["createDiscoverySet"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/sets/{setId}": { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + /** A discovery set and its artists */ + get: operations["getDiscoverySet"]; + put?: never; + post?: never; + /** + * Delete a discovery set + * @description Its thumbs stay. A song you turned down stays down. + */ + delete: operations["deleteDiscoverySet"]; + options?: never; + head?: never; + /** Rename a set, or change how far it explores and which feeds it shows */ + patch: operations["updateDiscoverySet"]; + trace?: never; + }; + "/me/discover/sets/{setId}/artists": { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Add a seed artist to a set + * @description Any artist, whether or not it's in your library. Adding one that's + * there already changes nothing. + */ + post: operations["addDiscoverySetArtist"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/sets/{setId}/artists/{artistKey}": { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + artistKey: string; + }; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Take a seed artist out of a set */ + delete: operations["removeDiscoverySetArtist"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/sets/{setId}/feed": { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + /** + * A page of a set's feed + * @description Songs near the set's seeds that you don't have: not on your own + * Navidrome links, not turned down, not by an artist you blocked. + * Each says which seeds it's near. A feed is built at most every 10 + * minutes (or now, with `refresh`), within 15 seconds; artists the + * music graph didn't know yet are fetched for next time. What you + * thumb down or block leaves every page at once. + */ + get: operations["getDiscoveryFeed"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/feedback": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Thumbs up or down on a song + * @description A thumbs-down hides the song from all your feeds, for good; a later + * thumbs-up replaces it. Thumbs here never touch a room's DJ. + */ + post: operations["postDiscoveryFeedback"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/blocks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Artists you said aren't for you */ + get: operations["listDiscoveryBlocks"]; + put?: never; + /** + * Not for me + * @description Keeps an artist out of every one of your feeds. + */ + post: operations["blockDiscoveryArtist"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/blocks/{artistKey}": { + parameters: { + query?: never; + header?: never; + path: { + artistKey: string; + }; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Let a blocked artist back into your feeds */ + delete: operations["unblockDiscoveryArtist"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/artists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Find artists to seed a set with + * @description Any artist, from Deezer, not only ones in your library. Without + * Deezer it offers the name as typed, which seeds as well as any. + */ + get: operations["searchDiscoveryArtists"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/library": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * How far your library is indexed + * @description Discovery leaves out what's on your own Navidrome links. They're + * indexed the first time you ask, then daily. + */ + get: operations["getDiscoveryLibrary"]; + put?: never; + /** + * Index your library again now + * @description In the background; you just added music, say. + */ + post: operations["refreshDiscoveryLibrary"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/preview/{deezerTrackId}": { + parameters: { + query?: never; + header?: never; + path: { + deezerTrackId: number; + }; + cookie?: never; + }; + /** + * A song's 30-second preview + * @description Deezer's preview, through the server: its URL is asked for fresh + * each time (Deezer's expire) and never kept, and the browser never + * talks to Deezer. Supports byte ranges. `not_found` if Deezer has + * no preview of the song, or Deezer is off. + */ + get: operations["getDiscoveryPreview"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/me/discover/images/{kind}/{imageId}": { + parameters: { + query?: never; + header?: never; + path: { + kind: "cover" | "artist"; + imageId: string; + }; + cookie?: never; + }; + /** A cover or artist picture from Deezer, through the server */ + get: operations["getDiscoveryImage"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/rooms/{roomId}/games/round": { parameters: { query?: never; @@ -5258,6 +5530,125 @@ export interface components { permissions?: components["schemas"]["RoomPermissionsChange"]; skipVotePercent?: components["schemas"]["SkipVotePercent"]; }; + /** + * @description Which feeds a set shows: `deep` cuts (anything new to you), `fresh` + * releases (coming), or `both`. + * @enum {string} + */ + DiscoveryMode: "deep" | "fresh" | "both"; + DiscoverySetSummary: { + id: string; + name: string; + explore: number; + mode: components["schemas"]["DiscoveryMode"]; + artistCount: number; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + DiscoverySet: { + id: string; + name: string; + /** @description How far the feed strays from the seeds, and toward less-known artists. */ + explore: number; + mode: components["schemas"]["DiscoveryMode"]; + artists: components["schemas"]["DiscoverySetArtist"][]; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + DiscoverySetArtist: { + /** @description Their MBID, else their simplified name. Removes them from the set. */ + key: string; + name: string; + mbid?: string; + /** @enum {string} */ + addedFrom: "manual" | "thumb" | "starred" | "room"; + /** Format: date-time */ + addedAt: string; + }; + DiscoverySeed: { + name: string; + mbid?: string; + }; + CreateDiscoverySetRequest: { + name: string; + artists?: components["schemas"]["DiscoverySeed"][]; + }; + UpdateDiscoverySetRequest: { + name?: string; + explore?: number; + mode?: components["schemas"]["DiscoveryMode"]; + }; + /** @description A song you don't have, near a set's seeds. */ + DiscoveryItem: { + key: string; + title: string; + artist: string; + album?: string; + mbid?: string; + isrc?: string; + /** + * Format: int64 + * @description The song on Deezer, for its preview. Absent when it isn't there, or isn't found yet. + */ + deezerId?: number; + /** @description Its cover's image ID, for getDiscoveryImage (kind `cover`). */ + cover?: string; + /** @description The seed artists it's near, nearest first. */ + because: string[]; + /** @description Whether it's a seed artist's own song. */ + seed: boolean; + }; + /** @description How far your library (your own Navidrome links) is indexed. */ + DiscoveryLibrary: { + links: number; + songs: number; + /** Format: date-time */ + builtAt?: string; + building: boolean; + }; + DiscoveryFeed: { + items: components["schemas"]["DiscoveryItem"][]; + /** @description The cursor for the next page. Absent at the end. */ + next?: string; + library: components["schemas"]["DiscoveryLibrary"]; + /** @description The server knows nothing of how music relates (no sources are on), so feeds are empty. */ + noGraph: boolean; + }; + DiscoveryFeedbackRequest: { + /** @enum {string} */ + kind: "up" | "down"; + /** @description The set whose feed it was in. */ + setId?: string; + title: string; + artist: string; + mbid?: string; + isrc?: string; + /** Format: int64 */ + deezerId?: number; + }; + DiscoveryBlock: { + key: string; + name: string; + /** Format: date-time */ + createdAt: string; + }; + BlockDiscoveryArtistRequest: { + name: string; + }; + DiscoveryArtist: { + name: string; + /** + * Format: int64 + * @description Fans on Deezer, a measure of how well known. + */ + fans?: number; + /** @description Their picture's image ID, for getDiscoveryImage (kind `artist`). */ + picture?: string; + }; }; responses: { /** @@ -5299,6 +5690,7 @@ export interface components { RoomId: string; PlaylistId: string; PlaylistSongId: string; + DiscoverySetId: string; QueueGameId: string; }; requestBodies: never; @@ -8169,6 +8561,419 @@ export interface operations { default: components["responses"]["Error"]; }; }; + listDiscoverySets: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Sets */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySetSummary"][]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + createDiscoverySet: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateDiscoverySetRequest"]; + }; + }; + responses: { + /** @description The set */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySet"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + getDiscoverySet: { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The set */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySet"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + deleteDiscoverySet: { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + default: components["responses"]["Error"]; + }; + }; + updateDiscoverySet: { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateDiscoverySetRequest"]; + }; + }; + responses: { + /** @description The set */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySet"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + addDiscoverySetArtist: { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DiscoverySeed"]; + }; + }; + responses: { + /** @description The set */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySet"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + removeDiscoverySetArtist: { + parameters: { + query?: never; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + artistKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The set */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoverySet"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + getDiscoveryFeed: { + parameters: { + query?: { + /** @description The previous page's `next`. */ + cursor?: string; + /** @description Build the feed again now, for the first page. */ + refresh?: boolean; + }; + header?: never; + path: { + setId: components["parameters"]["DiscoverySetId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A page */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryFeed"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + postDiscoveryFeedback: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DiscoveryFeedbackRequest"]; + }; + }; + responses: { + /** @description Kept */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + default: components["responses"]["Error"]; + }; + }; + listDiscoveryBlocks: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Blocked artists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryBlock"][]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + blockDiscoveryArtist: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["BlockDiscoveryArtistRequest"]; + }; + }; + responses: { + /** @description The block */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryBlock"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + unblockDiscoveryArtist: { + parameters: { + query?: never; + header?: never; + path: { + artistKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Unblocked */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + default: components["responses"]["Error"]; + }; + }; + searchDiscoveryArtists: { + parameters: { + query: { + q: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Artists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryArtist"][]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + getDiscoveryLibrary: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The index */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryLibrary"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + refreshDiscoveryLibrary: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Started */ + 202: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DiscoveryLibrary"]; + }; + }; + default: components["responses"]["Error"]; + }; + }; + getDiscoveryPreview: { + parameters: { + query?: never; + header?: { + /** @example bytes=0- */ + Range?: string; + }; + path: { + deezerTrackId: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The preview */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "audio/*": string; + }; + }; + /** @description Part of the preview (see Content-Range) */ + 206: { + headers: { + [name: string]: unknown; + }; + content: { + "audio/*": string; + }; + }; + default: components["responses"]["Error"]; + }; + }; + getDiscoveryImage: { + parameters: { + query?: { + /** @description Wanted width in pixels; a hint. */ + size?: number; + }; + header?: never; + path: { + kind: "cover" | "artist"; + imageId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The image */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "image/*": string; + }; + }; + default: components["responses"]["Error"]; + }; + }; getGameRound: { parameters: { query?: never; diff --git a/web/src/components/back-button.tsx b/web/src/components/back-button.tsx index 84c9574..e6bc5ae 100644 --- a/web/src/components/back-button.tsx +++ b/web/src/components/back-button.tsx @@ -3,7 +3,7 @@ import { ChevronLeft } from 'lucide-react' import { Button } from '@/components/ui/button' /** Back to wherever you came from (usually search results), or to Search. */ -export function BackButton({ fallback = '/search' }: { fallback?: '/search' | '/library' }) { +export function BackButton({ fallback = '/search' }: { fallback?: '/search' | '/library' | '/discover' }) { const router = useRouter() const canGoBack = useCanGoBack() return ( diff --git a/web/src/components/discover/add-to-set.tsx b/web/src/components/discover/add-to-set.tsx new file mode 100644 index 0000000..509c516 --- /dev/null +++ b/web/src/components/discover/add-to-set.tsx @@ -0,0 +1,102 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { Link } from '@tanstack/react-router' +import { Check, Compass, LoaderCircle, Plus } from 'lucide-react' +import { useState } from 'react' +import { errorMessage } from '@/api/errors' +import { Sheet } from '@/components/sheet' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { addArtist, createSet, setChanged, setsQuery } from '@/lib/discover' +import { tap } from '@/lib/haptics' +import { toast } from '@/lib/toast' + +/** Adds an artist to one of your discovery sets, or a new one (artist pages, ADR 0013). */ +export function AddToSetButton({ artist }: { artist: string }) { + const [open, setOpen] = useState(false) + return ( + <> + <Button size="lg" variant="glass" onClick={() => setOpen(true)}> + <Compass data-icon="inline-start" /> + Add to discovery set + </Button> + <AddToSetSheet artist={artist} open={open} onOpenChange={setOpen} /> + </> + ) +} + +function AddToSetSheet({ artist, open, onOpenChange }: { artist: string; open: boolean; onOpenChange: (open: boolean) => void }) { + const qc = useQueryClient() + const sets = useQuery({ ...setsQuery, enabled: open }) + const [name, setName] = useState('') + const [addedTo, setAddedTo] = useState<string>() + const add = useMutation({ + mutationFn: async (target: { id: string } | { name: string }) => + 'id' in target ? addArtist(target.id, artist) : createSet(target.name, [{ name: artist }]), + onMutate: () => tap(), + onSuccess: (set) => { + setChanged(qc, set) + setAddedTo(set.id) + setName('') + toast({ message: `Added ${artist} to ${set.name}` }) + onOpenChange(false) + }, + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + + return ( + <Sheet open={open} onOpenChange={onOpenChange} title="Add to a discovery set" description={`${artist} seeds the set's feed of music you don't have yet.`}> + <form + className="flex gap-2" + onSubmit={(e) => { + e.preventDefault() + if (name.trim()) add.mutate({ name: name.trim() }) + }} + > + <Input value={name} onChange={(e) => setName(e.target.value)} placeholder="New set" aria-label="New set's name" maxLength={100} /> + <Button type="submit" disabled={!name.trim() || add.isPending}> + <Plus data-icon="inline-start" /> + New + </Button> + </form> + {sets.isPending ? ( + <LoaderCircle className="mx-auto animate-spin text-muted-foreground" /> + ) : (sets.data ?? []).length === 0 ? ( + <p className="text-sm text-muted-foreground"> + No sets yet. Name one above. They live in{' '} + <Link to="/discover" className="text-primary" onClick={() => onOpenChange(false)}> + Discover + </Link> + . + </p> + ) : ( + <ul className="-mx-2 flex flex-col"> + {(sets.data ?? []).map((s) => ( + <li key={s.id}> + <button + type="button" + disabled={add.isPending} + onClick={() => add.mutate({ id: s.id })} + className="flex w-full items-center gap-3 rounded-2xl p-2 text-left transition-colors outline-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50" + > + <span className="grid size-12 shrink-0 place-items-center rounded-lg bg-primary/15 text-primary"> + <Compass className="size-5" /> + </span> + <span className="min-w-0 flex-1"> + <span className="block truncate font-medium">{s.name}</span> + <span className="text-sm text-muted-foreground"> + {s.artistCount} artist{s.artistCount === 1 ? '' : 's'} + </span> + </span> + {add.isPending && add.variables && 'id' in add.variables && add.variables.id === s.id ? ( + <LoaderCircle className="size-4 animate-spin" /> + ) : addedTo === s.id ? ( + <Check className="size-4 text-primary" /> + ) : null} + </button> + </li> + ))} + </ul> + )} + </Sheet> + ) +} diff --git a/web/src/components/discover/artist-search.tsx b/web/src/components/discover/artist-search.tsx new file mode 100644 index 0000000..98ef246 --- /dev/null +++ b/web/src/components/discover/artist-search.tsx @@ -0,0 +1,86 @@ +import { useQuery } from '@tanstack/react-query' +import { LoaderCircle, Plus, Search } from 'lucide-react' +import { useEffect, useState } from 'react' +import { Artwork } from '@/components/artwork' +import { Input } from '@/components/ui/input' +import { artistSearchQuery, fansText, imageUrl } from '@/lib/discover' +import { cn } from '@/lib/utils' + +/** + * Finds any artist to seed a set with, not only ones in your library, and + * hands the one picked to onPick. Names already in the set show as added. + */ +export function ArtistSearch({ + onPick, + have, + autoFocus, + className, +}: { + onPick: (name: string) => void + have: ReadonlySet<string> + autoFocus?: boolean + className?: string +}) { + const [text, setText] = useState('') + const [q, setQ] = useState('') + useEffect(() => { + const t = setTimeout(() => setQ(text.trim()), 250) + return () => clearTimeout(t) + }, [text]) + const found = useQuery(artistSearchQuery(q)) + const pick = (name: string) => { + onPick(name) + setText('') + setQ('') + } + + return ( + <div className={cn('flex flex-col gap-2', className)}> + <form + className="relative" + onSubmit={(e) => { + e.preventDefault() + // The top match, or the name as typed. + const name = found.data?.[0]?.name ?? text.trim() + if (name) pick(name) + }} + > + <Search className="pointer-events-none absolute top-1/2 left-3.5 size-4 -translate-y-1/2 text-muted-foreground" /> + <Input + autoFocus={autoFocus} + value={text} + onChange={(e) => setText(e.target.value)} + placeholder="Add an artist" + aria-label="Find an artist to add" + className="pl-10" + maxLength={200} + /> + {found.isFetching && <LoaderCircle className="absolute top-1/2 right-3.5 size-4 -translate-y-1/2 animate-spin text-muted-foreground" />} + </form> + {q && found.data && found.data.length > 0 && ( + <ul className="-mx-2 flex flex-col"> + {found.data.slice(0, 6).map((a) => { + const added = have.has(a.name.toLowerCase()) + return ( + <li key={`${a.name}-${a.picture ?? ''}`}> + <button + type="button" + disabled={added} + onClick={() => pick(a.name)} + className="flex w-full items-center gap-3 rounded-2xl p-2 text-left transition-colors outline-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 disabled:opacity-60" + > + <Artwork src={imageUrl('artist', a.picture, 120)} className="size-10 rounded-full shadow-none" /> + <span className="min-w-0 flex-1"> + <span className="block truncate font-medium">{a.name}</span> + {a.fans ? <span className="text-caption text-muted-foreground">{fansText(a.fans)}</span> : null} + </span> + <span className="text-caption text-muted-foreground">{added ? 'Added' : <Plus className="size-4" />}</span> + </button> + </li> + ) + })} + </ul> + )} + </div> + ) +} diff --git a/web/src/components/discover/feed-card.tsx b/web/src/components/discover/feed-card.tsx new file mode 100644 index 0000000..327eb86 --- /dev/null +++ b/web/src/components/discover/feed-card.tsx @@ -0,0 +1,92 @@ +import { ExternalLink, LoaderCircle, Pause, Play, ThumbsDown, ThumbsUp, UserX } from 'lucide-react' +import { motion } from 'motion/react' +import { Artwork } from '@/components/artwork' +import { Button } from '@/components/ui/button' +import { becauseText, imageUrl, togglePreview, usePreview, youtubeUrl, type DiscoveryItem } from '@/lib/discover' +import { fadeUp } from '@/lib/motion' +import { cn } from '@/lib/utils' + +/** + * A song you don't have yet: why it's here, its 30-second preview, a + * YouTube search for the whole thing, and thumbs. + */ +export function FeedCard({ + item, + onThumb, + onBlock, + thumbed, +}: { + item: DiscoveryItem + onThumb: (kind: 'up' | 'down') => void + onBlock: () => void + thumbed?: 'up' +}) { + const p = usePreview(item.key) + const canPlay = !!item.deezerId && !p.failed + const why = becauseText(item) + return ( + <motion.li variants={fadeUp} layout className="glass flex flex-col gap-3 rounded-3xl p-3 sm:flex-row sm:items-center"> + <div className="flex min-w-0 flex-1 items-center gap-3"> + <button + type="button" + disabled={!canPlay} + onClick={() => togglePreview(item)} + aria-label={!canPlay ? `No preview of ${item.title}` : p.playing ? `Pause ${item.title}` : `Play a preview of ${item.title}`} + className="group relative shrink-0 rounded-xl outline-none focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-default" + > + <Artwork src={imageUrl('cover', item.cover, 250)} className="size-16 rounded-xl shadow-none" /> + {canPlay && ( + <span + className={cn( + 'absolute inset-0 grid place-items-center rounded-xl bg-black/35 text-white transition-opacity', + p.playing || p.loading ? 'opacity-100' : 'opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100 [@media(hover:none)]:opacity-100', + )} + > + {p.loading ? <LoaderCircle className="size-6 animate-spin" /> : p.playing ? <Pause className="size-6 fill-current" /> : <Play className="size-6 fill-current" />} + </span> + )} + {(p.playing || p.progress > 0) && ( + <span className="absolute inset-x-1.5 bottom-1.5 h-1 overflow-hidden rounded-full bg-white/30"> + <span className="block h-full bg-white" style={{ width: `${Math.round(p.progress * 100)}%` }} /> + </span> + )} + </button> + <div className="min-w-0 flex-1"> + <p className="truncate font-medium">{item.title}</p> + <p className="truncate text-sm text-muted-foreground"> + {item.artist} + {item.album ? ` · ${item.album}` : ''} + </p> + <p className="truncate text-caption text-primary"> + {why} + {!item.deezerId && <span className="text-muted-foreground">{why ? ' · ' : ''}No preview</span>} + </p> + </div> + </div> + <div className="flex items-center justify-end gap-1"> + <Button asChild variant="glass" size="sm"> + <a href={youtubeUrl(item)} target="_blank" rel="noopener noreferrer" aria-label={`Open ${item.title} on YouTube`}> + <ExternalLink data-icon="inline-start" /> + YouTube + </a> + </Button> + <Button + variant="ghost" + size="icon-sm" + aria-label={`Thumbs up ${item.title}`} + aria-pressed={thumbed === 'up'} + onClick={() => onThumb('up')} + className={cn(thumbed === 'up' && 'text-primary')} + > + <ThumbsUp className={cn(thumbed === 'up' && 'fill-current')} /> + </Button> + <Button variant="ghost" size="icon-sm" aria-label={`Thumbs down ${item.title}`} onClick={() => onThumb('down')}> + <ThumbsDown /> + </Button> + <Button variant="ghost" size="icon-sm" aria-label={`${item.artist} isn't for me`} title={`${item.artist} isn't for me`} onClick={onBlock}> + <UserX /> + </Button> + </div> + </motion.li> + ) +} diff --git a/web/src/components/shell/bottom-nav.tsx b/web/src/components/shell/bottom-nav.tsx index b791872..a5d6718 100644 --- a/web/src/components/shell/bottom-nav.tsx +++ b/web/src/components/shell/bottom-nav.tsx @@ -1,12 +1,16 @@ import { Link, useRouterState } from '@tanstack/react-router' -import { CircleUserRound, Disc3, Library, Search } from 'lucide-react' +import { useQuery } from '@tanstack/react-query' +import { CircleUserRound, Compass, Disc3, Library, Search } from 'lucide-react' import { motion } from 'motion/react' +import { meQuery } from '@/lib/auth' import { spring } from '@/lib/motion' import { cn } from '@/lib/utils' const tabs = [ { to: '/room', label: 'Room', icon: Disc3, also: ['/history'] }, { to: '/search', label: 'Search', icon: Search, also: ['/album', '/artist'] }, + // Personal discovery (ADR 0017): members only. + { to: '/discover', label: 'Discover', icon: Compass, also: [], members: true }, { to: '/library', label: 'Library', icon: Library, also: [] }, { to: '/me', label: 'Me', icon: CircleUserRound, also: ['/settings'] }, ] as const @@ -15,11 +19,13 @@ const under = (pathname: string, base: string) => pathname === base || pathname. export function BottomNav() { const pathname = useRouterState({ select: (s) => s.location.pathname }) + const guest = !!useQuery(meQuery).data?.guest + const shown = tabs.filter((t) => !('members' in t) || !guest) return ( <nav aria-label="Main" className="glass-strong h-nav rounded-3xl p-1.5 shadow-float"> - <ul className="grid h-full grid-cols-4 gap-1"> - {tabs.map(({ to, label, icon: Icon, also }) => { + <ul className={cn('grid h-full gap-1', shown.length === 5 ? 'grid-cols-5' : 'grid-cols-4')}> + {shown.map(({ to, label, icon: Icon, also }) => { const active = [to, ...also].some((base) => under(pathname, base)) return ( <li key={to} className="relative"> diff --git a/web/src/lib/discover.test.ts b/web/src/lib/discover.test.ts new file mode 100644 index 0000000..27748a3 --- /dev/null +++ b/web/src/lib/discover.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from 'vitest' +import { becauseText, fansText, feedItems, imageUrl, youtubeUrl, type DiscoveryFeed } from './discover' + +const item = (key: string) => ({ key, title: key, artist: 'A', because: ['Slowdive'], seed: false }) +const page = (...keys: string[]): DiscoveryFeed => ({ + items: keys.map(item), + library: { links: 0, songs: 0, building: false }, + noGraph: false, +}) + +describe('becauseText', () => { + it('names the seeds a song is near', () => { + expect(becauseText({ because: ['Slowdive'], seed: false })).toBe('Near Slowdive') + expect(becauseText({ because: ['Slowdive', 'Hum'], seed: false })).toBe('Near Slowdive and Hum') + expect(becauseText({ because: ['Slowdive', 'Hum', 'Duster'], seed: false })).toBe('Near Slowdive, Hum and Duster') + }) + it("says a seed's own song is more from them", () => { + expect(becauseText({ because: ['Hum'], seed: true })).toBe('More from Hum') + }) + it('says nothing without a reason', () => { + expect(becauseText({ because: [], seed: false })).toBe('') + }) +}) + +describe('youtubeUrl', () => { + it('searches YouTube for the artist and title', () => { + expect(youtubeUrl({ artist: 'Hum', title: 'Stars & Stripes?' })).toBe( + 'https://www.youtube.com/results?search_query=Hum%20Stars%20%26%20Stripes%3F', + ) + }) +}) + +describe('feedItems', () => { + it('keeps each song once, across pages', () => { + expect(feedItems([page('a', 'b'), page('b', 'c')]).map((i) => i.key)).toEqual(['a', 'b', 'c']) + expect(feedItems(undefined)).toEqual([]) + }) +}) + +describe('imageUrl', () => { + it('goes through the server', () => { + expect(imageUrl('cover', 'abc', 120)).toBe('/api/me/discover/images/cover/abc?size=120') + expect(imageUrl('artist', undefined)).toBeUndefined() + }) +}) + +describe('fansText', () => { + it('rounds big numbers', () => { + expect(fansText(4_101_295)).toBe('4.1M fans') + expect(fansText(12_000_000)).toBe('12M fans') + expect(fansText(1_000_000)).toBe('1M fans') + expect(fansText(12_400)).toBe('12K fans') + expect(fansText(1)).toBe('1 fan') + expect(fansText(undefined)).toBe('') + }) +}) diff --git a/web/src/lib/discover.ts b/web/src/lib/discover.ts new file mode 100644 index 0000000..92e35b2 --- /dev/null +++ b/web/src/lib/discover.ts @@ -0,0 +1,220 @@ +import { infiniteQueryOptions, queryOptions, type QueryClient } from '@tanstack/react-query' +import { api } from '@/api/client' +import { unwrap } from '@/api/errors' +import type { components } from '@/api/schema.gen' +import { createStore, useStore } from './store' + +// Personal discovery (ADR 0017): seed sets of artists you pick, each a +// feed of music you don't have yet. Yours alone, outside any room. + +export type DiscoverySet = components['schemas']['DiscoverySet'] +export type DiscoverySetSummary = components['schemas']['DiscoverySetSummary'] +export type DiscoveryItem = components['schemas']['DiscoveryItem'] +export type DiscoveryFeed = components['schemas']['DiscoveryFeed'] +export type DiscoveryMode = components['schemas']['DiscoveryMode'] +export type DiscoveryArtist = components['schemas']['DiscoveryArtist'] +export type DiscoveryLibrary = components['schemas']['DiscoveryLibrary'] + +export const setsQuery = queryOptions({ + queryKey: ['discover', 'sets'], + queryFn: () => unwrap(api.GET('/me/discover/sets')), +}) + +export const setQuery = (id: string) => + queryOptions({ + queryKey: ['discover', 'sets', id], + queryFn: () => unwrap(api.GET('/me/discover/sets/{setId}', { params: { path: { setId: id } } })), + }) + +export const feedQuery = (setId: string) => + infiniteQueryOptions({ + queryKey: ['discover', 'feed', setId], + queryFn: ({ pageParam }) => fetchFeed(setId, pageParam), + initialPageParam: '', + getNextPageParam: (page) => page.next, + staleTime: 10 * 60_000, + }) + +function fetchFeed(setId: string, cursor: string, refresh = false) { + return unwrap( + api.GET('/me/discover/sets/{setId}/feed', { + params: { path: { setId }, query: { ...(cursor ? { cursor } : {}), ...(refresh ? { refresh } : {}) } }, + }), + ) +} + +/** Builds a set's feed again now, and starts it over from its first page. */ +export async function refreshFeed(qc: QueryClient, setId: string) { + const first = await fetchFeed(setId, '', true) + qc.setQueryData(feedQuery(setId).queryKey, { pages: [first], pageParams: [''] }) +} + +export const blocksQuery = queryOptions({ + queryKey: ['discover', 'blocks'], + queryFn: () => unwrap(api.GET('/me/discover/blocks')), +}) + +export const libraryQuery = queryOptions({ + queryKey: ['discover', 'library'], + queryFn: () => unwrap(api.GET('/me/discover/library')), + // While it's indexing, look again now and then. + refetchInterval: (q) => (q.state.data?.building ? 5_000 : false), +}) + +export const artistSearchQuery = (q: string) => + queryOptions({ + queryKey: ['discover', 'artists', q], + queryFn: ({ signal }) => unwrap(api.GET('/me/discover/artists', { params: { query: { q } }, signal })), + enabled: q.trim().length > 0, + staleTime: 5 * 60_000, + }) + +/** Puts a changed set in the cache, refreshes the list, and drops its stale feed. */ +export function setChanged(qc: QueryClient, set: DiscoverySet) { + qc.setQueryData(setQuery(set.id).queryKey, set) + void qc.invalidateQueries({ queryKey: setsQuery.queryKey, exact: true }) + void qc.resetQueries({ queryKey: feedQuery(set.id).queryKey }) +} + +export function createSet(name: string, artists: { name: string; mbid?: string }[] = []) { + return unwrap(api.POST('/me/discover/sets', { body: { name, artists } })) +} + +export function updateSet(id: string, body: { name?: string; explore?: number; mode?: DiscoveryMode }) { + return unwrap(api.PATCH('/me/discover/sets/{setId}', { params: { path: { setId: id } }, body })) +} + +export function deleteSet(id: string) { + return unwrap(api.DELETE('/me/discover/sets/{setId}', { params: { path: { setId: id } } })) +} + +export function addArtist(id: string, name: string) { + return unwrap(api.POST('/me/discover/sets/{setId}/artists', { params: { path: { setId: id } }, body: { name } })) +} + +export function removeArtist(id: string, key: string) { + return unwrap(api.DELETE('/me/discover/sets/{setId}/artists/{artistKey}', { params: { path: { setId: id, artistKey: key } } })) +} + +export function thumb(kind: 'up' | 'down', item: DiscoveryItem, setId?: string) { + return unwrap( + api.POST('/me/discover/feedback', { + body: { kind, setId, title: item.title, artist: item.artist, mbid: item.mbid, isrc: item.isrc, deezerId: item.deezerId }, + }), + ) +} + +export function block(name: string) { + return unwrap(api.POST('/me/discover/blocks', { body: { name } })) +} + +export function unblock(key: string) { + return unwrap(api.DELETE('/me/discover/blocks/{artistKey}', { params: { path: { artistKey: key } } })) +} + +export function refreshLibrary() { + return unwrap(api.POST('/me/discover/library')) +} + +/** A feed's songs, once each: a feed rebuilt between pages can repeat one. */ +export function feedItems(pages: readonly DiscoveryFeed[] | undefined): DiscoveryItem[] { + const seen = new Set<string>() + const out: DiscoveryItem[] = [] + for (const p of pages ?? []) { + for (const it of p.items) { + if (seen.has(it.key)) continue + seen.add(it.key) + out.push(it) + } + } + return out +} + +/** "Near Slowdive and Hum", or "More from Slowdive" for a seed's own song. */ +export function becauseText(item: Pick<DiscoveryItem, 'because' | 'seed'>) { + const names = item.because.filter(Boolean) + if (names.length === 0) return '' + if (item.seed) return `More from ${names[0]}` + return `Near ${names.length === 1 ? names[0] : `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`}` +} + +/** A YouTube search for the song: the whole thing, in a new tab. */ +export function youtubeUrl(item: Pick<DiscoveryItem, 'artist' | 'title'>) { + return `https://www.youtube.com/results?search_query=${encodeURIComponent(`${item.artist} ${item.title}`)}` +} + +/** A Deezer cover or artist picture, through the server. */ +export function imageUrl(kind: 'cover' | 'artist', id: string | undefined, size = 250) { + if (!id) return undefined + return `/api/me/discover/images/${kind}/${encodeURIComponent(id)}?size=${size}` +} + +/** "1.2M fans". */ +export function fansText(fans: number | undefined) { + if (!fans) return '' + const n = fans >= 1e6 ? `${(fans / 1e6).toFixed(fans >= 1e7 ? 0 : 1)}M` : fans >= 1e3 ? `${Math.round(fans / 1e3)}K` : String(fans) + return `${n.replace('.0', '')} fan${fans === 1 ? '' : 's'}` +} + +// --- Previews -------------------------------------------------------------- + +// One preview plays at a time, in its own audio element: it plays here +// only, and leaves the room's playback and Media Session alone. + +type PreviewState = { key?: string; playing: boolean; progress: number; loading: boolean; failed?: string } + +const preview = createStore<PreviewState>({ playing: false, progress: 0, loading: false }) +let audio: HTMLAudioElement | undefined + +function element() { + if (audio) return audio + const a = new Audio() + a.preload = 'auto' + const update = () => + preview.set((p) => ({ ...p, progress: a.duration > 0 ? a.currentTime / a.duration : 0, playing: !a.paused && !a.ended })) + a.addEventListener('timeupdate', update) + a.addEventListener('playing', () => preview.set((p) => ({ ...p, loading: false, playing: true }))) + a.addEventListener('pause', update) + a.addEventListener('ended', () => preview.set((p) => ({ ...p, playing: false, progress: 1 }))) + a.addEventListener('error', () => preview.set((p) => ({ ...p, playing: false, loading: false, failed: p.key }))) + audio = a + return a +} + +/** Plays a song's preview, stopping any other; plays or pauses it if it's the one loaded. */ +export function togglePreview(item: Pick<DiscoveryItem, 'key' | 'deezerId'>) { + if (!item.deezerId) return + const a = element() + const cur = preview.get() + if (cur.key === item.key && cur.failed !== item.key) { + if (a.paused) { + if (a.ended || cur.progress >= 1) a.currentTime = 0 + void a.play().catch(() => {}) + } else { + a.pause() + } + return + } + a.pause() + a.src = `/api/me/discover/preview/${item.deezerId}` + preview.set({ key: item.key, playing: false, progress: 0, loading: true }) + void a.play().catch(() => preview.set((p) => ({ ...p, loading: false }))) +} + +/** Stops whatever preview is playing: leaving the page, say. */ +export function stopPreview() { + audio?.pause() + preview.set((p) => ({ ...p, playing: false, loading: false })) +} + +/** How one song's preview is doing. */ +export function usePreview(key: string) { + const p = useStore(preview) + const mine = p.key === key + return { + playing: mine && p.playing, + loading: mine && p.loading, + progress: mine ? p.progress : 0, + failed: p.failed === key, + } +} diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index bd2f2eb..4233c8a 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -23,6 +23,8 @@ import { Route as AppAuthedHistoryRouteImport } from './routes/_app/_authed/hist import { Route as AppAuthedMeRouteImport } from './routes/_app/_authed/me' import { Route as AppAuthedRoomRouteImport } from './routes/_app/_authed/room' import { Route as AppAuthedSearchRouteImport } from './routes/_app/_authed/search' +import { Route as AppAuthedDiscoverIndexRouteImport } from './routes/_app/_authed/discover.index' +import { Route as AppAuthedDiscoverSetIdRouteImport } from './routes/_app/_authed/discover.$setId' import { Route as AppAuthedGenreLinkIdRouteImport } from './routes/_app/_authed/genre.$linkId' import { Route as AppAuthedLibraryIndexRouteImport } from './routes/_app/_authed/library.index' import { Route as AppAuthedLibraryPlaylistIdRouteImport } from './routes/_app/_authed/library.$playlistId' @@ -103,6 +105,16 @@ const AppAuthedSearchRoute = AppAuthedSearchRouteImport.update({ path: '/search', getParentRoute: () => AppAuthedRoute, } as any) +const AppAuthedDiscoverIndexRoute = AppAuthedDiscoverIndexRouteImport.update({ + id: '/discover/', + path: '/discover/', + getParentRoute: () => AppAuthedRoute, +} as any) +const AppAuthedDiscoverSetIdRoute = AppAuthedDiscoverSetIdRouteImport.update({ + id: '/discover/$setId', + path: '/discover/$setId', + getParentRoute: () => AppAuthedRoute, +} as any) const AppAuthedGenreLinkIdRoute = AppAuthedGenreLinkIdRouteImport.update({ id: '/genre/$linkId', path: '/genre/$linkId', @@ -179,6 +191,7 @@ export interface FileRoutesByFullPath { '/me': typeof AppAuthedMeRoute '/room': typeof AppAuthedRoomRoute '/search': typeof AppAuthedSearchRoute + '/discover/$setId': typeof AppAuthedDiscoverSetIdRoute '/genre/$linkId': typeof AppAuthedGenreLinkIdRoute '/library/$playlistId': typeof AppAuthedLibraryPlaylistIdRoute '/settings/people': typeof AppAuthedSettingsPeopleRoute @@ -186,6 +199,7 @@ export interface FileRoutesByFullPath { '/settings/security': typeof AppAuthedSettingsSecurityRoute '/settings/server': typeof AppAuthedSettingsServerRoute '/settings/services': typeof AppAuthedSettingsServicesRoute + '/discover/': typeof AppAuthedDiscoverIndexRoute '/library/': typeof AppAuthedLibraryIndexRoute '/album/$linkId/$albumId': typeof AppAuthedAlbumLinkIdAlbumIdRoute '/artist/$linkId/$artistId': typeof AppAuthedArtistLinkIdArtistIdRoute @@ -204,6 +218,7 @@ export interface FileRoutesByTo { '/me': typeof AppAuthedMeRoute '/room': typeof AppAuthedRoomRoute '/search': typeof AppAuthedSearchRoute + '/discover/$setId': typeof AppAuthedDiscoverSetIdRoute '/genre/$linkId': typeof AppAuthedGenreLinkIdRoute '/library/$playlistId': typeof AppAuthedLibraryPlaylistIdRoute '/settings/people': typeof AppAuthedSettingsPeopleRoute @@ -211,6 +226,7 @@ export interface FileRoutesByTo { '/settings/security': typeof AppAuthedSettingsSecurityRoute '/settings/server': typeof AppAuthedSettingsServerRoute '/settings/services': typeof AppAuthedSettingsServicesRoute + '/discover': typeof AppAuthedDiscoverIndexRoute '/library': typeof AppAuthedLibraryIndexRoute '/album/$linkId/$albumId': typeof AppAuthedAlbumLinkIdAlbumIdRoute '/artist/$linkId/$artistId': typeof AppAuthedArtistLinkIdArtistIdRoute @@ -232,6 +248,7 @@ export interface FileRoutesById { '/_app/_authed/room': typeof AppAuthedRoomRoute '/_app/_authed/search': typeof AppAuthedSearchRoute '/_app/_authed/': typeof AppAuthedIndexRoute + '/_app/_authed/discover/$setId': typeof AppAuthedDiscoverSetIdRoute '/_app/_authed/genre/$linkId': typeof AppAuthedGenreLinkIdRoute '/_app/_authed/library/$playlistId': typeof AppAuthedLibraryPlaylistIdRoute '/_app/_authed/settings/people': typeof AppAuthedSettingsPeopleRoute @@ -239,6 +256,7 @@ export interface FileRoutesById { '/_app/_authed/settings/security': typeof AppAuthedSettingsSecurityRoute '/_app/_authed/settings/server': typeof AppAuthedSettingsServerRoute '/_app/_authed/settings/services': typeof AppAuthedSettingsServicesRoute + '/_app/_authed/discover/': typeof AppAuthedDiscoverIndexRoute '/_app/_authed/library/': typeof AppAuthedLibraryIndexRoute '/_app/_authed/album/$linkId/$albumId': typeof AppAuthedAlbumLinkIdAlbumIdRoute '/_app/_authed/artist/$linkId/$artistId': typeof AppAuthedArtistLinkIdArtistIdRoute @@ -259,6 +277,7 @@ export interface FileRouteTypes { | '/me' | '/room' | '/search' + | '/discover/$setId' | '/genre/$linkId' | '/library/$playlistId' | '/settings/people' @@ -266,6 +285,7 @@ export interface FileRouteTypes { | '/settings/security' | '/settings/server' | '/settings/services' + | '/discover/' | '/library/' | '/album/$linkId/$albumId' | '/artist/$linkId/$artistId' @@ -284,6 +304,7 @@ export interface FileRouteTypes { | '/me' | '/room' | '/search' + | '/discover/$setId' | '/genre/$linkId' | '/library/$playlistId' | '/settings/people' @@ -291,6 +312,7 @@ export interface FileRouteTypes { | '/settings/security' | '/settings/server' | '/settings/services' + | '/discover' | '/library' | '/album/$linkId/$albumId' | '/artist/$linkId/$artistId' @@ -311,6 +333,7 @@ export interface FileRouteTypes { | '/_app/_authed/room' | '/_app/_authed/search' | '/_app/_authed/' + | '/_app/_authed/discover/$setId' | '/_app/_authed/genre/$linkId' | '/_app/_authed/library/$playlistId' | '/_app/_authed/settings/people' @@ -318,6 +341,7 @@ export interface FileRouteTypes { | '/_app/_authed/settings/security' | '/_app/_authed/settings/server' | '/_app/_authed/settings/services' + | '/_app/_authed/discover/' | '/_app/_authed/library/' | '/_app/_authed/album/$linkId/$albumId' | '/_app/_authed/artist/$linkId/$artistId' @@ -434,6 +458,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AppAuthedSearchRouteImport parentRoute: typeof AppAuthedRoute } + '/_app/_authed/discover/': { + id: '/_app/_authed/discover/' + path: '/discover' + fullPath: '/discover/' + preLoaderRoute: typeof AppAuthedDiscoverIndexRouteImport + parentRoute: typeof AppAuthedRoute + } + '/_app/_authed/discover/$setId': { + id: '/_app/_authed/discover/$setId' + path: '/discover/$setId' + fullPath: '/discover/$setId' + preLoaderRoute: typeof AppAuthedDiscoverSetIdRouteImport + parentRoute: typeof AppAuthedRoute + } '/_app/_authed/genre/$linkId': { id: '/_app/_authed/genre/$linkId' path: '/genre/$linkId' @@ -520,6 +558,7 @@ interface AppAuthedRouteChildren { AppAuthedRoomRoute: typeof AppAuthedRoomRoute AppAuthedSearchRoute: typeof AppAuthedSearchRoute AppAuthedIndexRoute: typeof AppAuthedIndexRoute + AppAuthedDiscoverSetIdRoute: typeof AppAuthedDiscoverSetIdRoute AppAuthedGenreLinkIdRoute: typeof AppAuthedGenreLinkIdRoute AppAuthedLibraryPlaylistIdRoute: typeof AppAuthedLibraryPlaylistIdRoute AppAuthedSettingsPeopleRoute: typeof AppAuthedSettingsPeopleRoute @@ -527,6 +566,7 @@ interface AppAuthedRouteChildren { AppAuthedSettingsSecurityRoute: typeof AppAuthedSettingsSecurityRoute AppAuthedSettingsServerRoute: typeof AppAuthedSettingsServerRoute AppAuthedSettingsServicesRoute: typeof AppAuthedSettingsServicesRoute + AppAuthedDiscoverIndexRoute: typeof AppAuthedDiscoverIndexRoute AppAuthedLibraryIndexRoute: typeof AppAuthedLibraryIndexRoute AppAuthedAlbumLinkIdAlbumIdRoute: typeof AppAuthedAlbumLinkIdAlbumIdRoute AppAuthedArtistLinkIdArtistIdRoute: typeof AppAuthedArtistLinkIdArtistIdRoute @@ -539,6 +579,7 @@ const AppAuthedRouteChildren: AppAuthedRouteChildren = { AppAuthedRoomRoute: AppAuthedRoomRoute, AppAuthedSearchRoute: AppAuthedSearchRoute, AppAuthedIndexRoute: AppAuthedIndexRoute, + AppAuthedDiscoverSetIdRoute: AppAuthedDiscoverSetIdRoute, AppAuthedGenreLinkIdRoute: AppAuthedGenreLinkIdRoute, AppAuthedLibraryPlaylistIdRoute: AppAuthedLibraryPlaylistIdRoute, AppAuthedSettingsPeopleRoute: AppAuthedSettingsPeopleRoute, @@ -546,6 +587,7 @@ const AppAuthedRouteChildren: AppAuthedRouteChildren = { AppAuthedSettingsSecurityRoute: AppAuthedSettingsSecurityRoute, AppAuthedSettingsServerRoute: AppAuthedSettingsServerRoute, AppAuthedSettingsServicesRoute: AppAuthedSettingsServicesRoute, + AppAuthedDiscoverIndexRoute: AppAuthedDiscoverIndexRoute, AppAuthedLibraryIndexRoute: AppAuthedLibraryIndexRoute, AppAuthedAlbumLinkIdAlbumIdRoute: AppAuthedAlbumLinkIdAlbumIdRoute, AppAuthedArtistLinkIdArtistIdRoute: AppAuthedArtistLinkIdArtistIdRoute, diff --git a/web/src/routes/_app/_authed/artist.$linkId.$artistId.tsx b/web/src/routes/_app/_authed/artist.$linkId.$artistId.tsx index 71cc34b..6cf170b 100644 --- a/web/src/routes/_app/_authed/artist.$linkId.$artistId.tsx +++ b/web/src/routes/_app/_authed/artist.$linkId.$artistId.tsx @@ -17,6 +17,7 @@ import { } from '@/components/artist-parts' import { Artwork } from '@/components/artwork' import { BackButton } from '@/components/back-button' +import { AddToSetButton } from '@/components/discover/add-to-set' import { Notice } from '@/components/notice' import { ProviderIcon } from '@/components/provider-icon' import { Button } from '@/components/ui/button' @@ -37,6 +38,7 @@ import { } from '@/lib/artist' import { artistQuery, artworkUrl } from '@/lib/browse' import { easeOutExpo, fadeUp, stagger } from '@/lib/motion' +import { useMe } from '@/lib/auth' import { providersQuery, usableLinksQuery } from '@/lib/services' import { toast } from '@/lib/toast' @@ -58,6 +60,7 @@ function Artist() { const elsewhere = useQuery(artistElsewhereQuery(linkId, artistId)) const providers = useQuery(providersQuery) const { add, status } = useAddToLane() + const me = useMe() // The same artist's albums on your other services. const others = useQueries({ @@ -138,6 +141,7 @@ function Artist() { <Shuffle data-icon="inline-start" /> Shuffle </Button> + {!me.guest && <AddToSetButton artist={a.name} />} </motion.div> {elsewhere.data && elsewhere.data.length > 0 && ( <motion.div variants={fadeUp} className="mt-4 flex flex-wrap justify-center gap-2"> diff --git a/web/src/routes/_app/_authed/discover.$setId.tsx b/web/src/routes/_app/_authed/discover.$setId.tsx new file mode 100644 index 0000000..efafd3f --- /dev/null +++ b/web/src/routes/_app/_authed/discover.$setId.tsx @@ -0,0 +1,337 @@ +import { useInfiniteQuery, useMutation, useQuery, useQueryClient, type InfiniteData } from '@tanstack/react-query' +import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { Check, LoaderCircle, Pencil, RefreshCw, Trash2, X } from 'lucide-react' +import { motion } from 'motion/react' +import { useEffect, useMemo, useRef, useState } from 'react' +import { errorMessage } from '@/api/errors' +import { BackButton } from '@/components/back-button' +import { ConfirmButton } from '@/components/confirm-button' +import { ArtistSearch } from '@/components/discover/artist-search' +import { FeedCard } from '@/components/discover/feed-card' +import { Notice } from '@/components/notice' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Skeleton } from '@/components/ui/skeleton' +import { Slider } from '@/components/ui/slider' +import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group' +import { + addArtist, + block, + blocksQuery, + deleteSet, + feedItems, + feedQuery, + refreshFeed, + removeArtist, + setChanged, + setQuery, + setsQuery, + stopPreview, + thumb, + unblock, + updateSet, + type DiscoveryFeed, + type DiscoveryItem, + type DiscoveryMode, + type DiscoverySet, +} from '@/lib/discover' +import { tap } from '@/lib/haptics' +import { stagger } from '@/lib/motion' +import { toast } from '@/lib/toast' + +export const Route = createFileRoute('/_app/_authed/discover/$setId')({ + loader: ({ context, params }) => context.queryClient.prefetchQuery(setQuery(params.setId)), + component: SetPage, +}) + +function SetPage() { + const { setId } = Route.useParams() + const set = useQuery(setQuery(setId)) + // A preview stops when you leave. + useEffect(() => stopPreview, []) + + if (set.isPending) { + return ( + <> + <BackButton fallback="/discover" /> + <Skeleton className="mt-4 h-9 w-56" /> + <Skeleton className="mt-6 h-24 rounded-3xl" /> + </> + ) + } + if (set.isError) { + return ( + <> + <BackButton fallback="/discover" /> + <Notice className="mt-6">{errorMessage(set.error)}</Notice> + </> + ) + } + return ( + <> + <BackButton fallback="/discover" /> + <Header set={set.data} /> + <Seeds set={set.data} /> + <Tuning set={set.data} /> + {set.data.artists.length === 0 ? ( + <p className="mt-8 text-center text-sm text-muted-foreground">Add an artist or two, and songs near them show up here.</p> + ) : ( + <Feed set={set.data} /> + )} + </> + ) +} + +function useSetMutation<T>(fn: (v: T) => Promise<DiscoverySet>) { + const qc = useQueryClient() + return useMutation({ + mutationFn: fn, + onSuccess: (s) => setChanged(qc, s), + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) +} + +function Header({ set }: { set: DiscoverySet }) { + const qc = useQueryClient() + const navigate = useNavigate() + const [editing, setEditing] = useState(false) + const [name, setName] = useState(set.name) + const rename = useSetMutation((n: string) => updateSet(set.id, { name: n })) + const remove = useMutation({ + mutationFn: () => deleteSet(set.id), + onSuccess: () => { + void qc.invalidateQueries({ queryKey: setsQuery.queryKey, exact: true }) + void navigate({ to: '/discover', replace: true }) + }, + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + + return ( + <header className="flex flex-col gap-3 pt-2 pb-4"> + {editing ? ( + <form + className="flex gap-2" + onSubmit={(e) => { + e.preventDefault() + if (!name.trim()) return + rename.mutate(name.trim(), { onSuccess: () => setEditing(false) }) + }} + > + <Input autoFocus value={name} onChange={(e) => setName(e.target.value)} aria-label="Set's name" maxLength={100} /> + <Button type="submit" size="icon" aria-label="Save the name" disabled={!name.trim() || rename.isPending}> + <Check /> + </Button> + </form> + ) : ( + <div className="flex items-start justify-between gap-3"> + <h1 className="min-w-0 text-display break-words">{set.name}</h1> + <div className="flex shrink-0 gap-1 pt-1"> + <Button + variant="ghost" + size="icon-sm" + aria-label="Rename" + onClick={() => { + setName(set.name) + setEditing(true) + }} + > + <Pencil /> + </Button> + <ConfirmButton compact label="Delete set" confirmLabel="Delete" icon={<Trash2 />} pending={remove.isPending} onConfirm={() => remove.mutate()} /> + </div> + </div> + )} + </header> + ) +} + +/** The set's artists, and a search to add more: any artist, not just yours. */ +function Seeds({ set }: { set: DiscoverySet }) { + const add = useSetMutation((name: string) => addArtist(set.id, name)) + const remove = useSetMutation((key: string) => removeArtist(set.id, key)) + const have = useMemo(() => new Set(set.artists.map((a) => a.name.toLowerCase())), [set.artists]) + return ( + <section className="glass flex flex-col gap-3 rounded-3xl p-4"> + {set.artists.length > 0 && ( + <ul className="flex flex-wrap gap-2" aria-label="Seed artists"> + {set.artists.map((a) => ( + <li key={a.key} className="flex items-center gap-1 rounded-full bg-primary/15 py-1 pr-1 pl-3 text-sm font-medium text-primary"> + {a.name} + <Button + variant="ghost" + size="icon-xs" + aria-label={`Take ${a.name} out`} + disabled={remove.isPending} + onClick={() => remove.mutate(a.key)} + className="text-primary hover:bg-primary/15" + > + <X /> + </Button> + </li> + ))} + {add.isPending && ( + <li className="grid place-items-center px-2"> + <LoaderCircle className="size-4 animate-spin text-muted-foreground" /> + </li> + )} + </ul> + )} + <ArtistSearch have={have} autoFocus={set.artists.length === 0} onPick={(name) => add.mutate(name)} /> + </section> + ) +} + +/** How far the feed strays, and which feeds it shows. */ +function Tuning({ set }: { set: DiscoverySet }) { + // While dragging, and until the change is saved. + const [dragged, setDragged] = useState<number>() + const explore = dragged ?? set.explore + const update = useSetMutation((body: { explore?: number; mode?: DiscoveryMode }) => updateSet(set.id, body)) + return ( + <section className="mt-3 grid gap-4 px-1 sm:grid-cols-[1fr_auto] sm:items-center"> + <label className="flex flex-col gap-1"> + <span className="flex justify-between text-caption text-muted-foreground"> + <span>Close to the seeds</span> + <span>Far out</span> + </span> + <Slider + aria-label="How far to explore" + min={0} + max={100} + step={5} + value={[explore]} + onValueChange={([v]) => setDragged(v)} + onValueCommit={([v]) => update.mutate({ explore: v }, { onSettled: () => setDragged(undefined) })} + /> + </label> + <ToggleGroup + type="single" + value={set.mode} + onValueChange={(v) => v && update.mutate({ mode: v as DiscoveryMode })} + aria-label="Which feeds" + > + <ToggleGroupItem value="deep">Deep cuts</ToggleGroupItem> + <ToggleGroupItem value="fresh" title="New releases arrive in a later update"> + Fresh + </ToggleGroupItem> + <ToggleGroupItem value="both">Both</ToggleGroupItem> + </ToggleGroup> + </section> + ) +} + +function Feed({ set }: { set: DiscoverySet }) { + const qc = useQueryClient() + const pages = useInfiniteQuery(feedQuery(set.id)) + const [thumbed, setThumbed] = useState<ReadonlySet<string>>(new Set()) + const items = feedItems(pages.data?.pages) + const first = pages.data?.pages[0] + const { hasNextPage, isFetchingNextPage, fetchNextPage } = pages + + // Load the next page as the end of the list scrolls into view. + const end = useRef<HTMLDivElement>(null) + useEffect(() => { + const el = end.current + if (!el || !hasNextPage) return + const io = new IntersectionObserver( + (es) => { + if (es.some((e) => e.isIntersecting) && !isFetchingNextPage) void fetchNextPage() + }, + { rootMargin: '600px' }, + ) + io.observe(el) + return () => io.disconnect() + }, [hasNextPage, isFetchingNextPage, fetchNextPage]) + + const refresh = useMutation({ + mutationFn: () => refreshFeed(qc, set.id), + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + + // Take songs out of the feed shown, as the server will from now on. + const drop = (keep: (it: DiscoveryItem) => boolean) => + qc.setQueryData<InfiniteData<DiscoveryFeed, string>>(feedQuery(set.id).queryKey, (d) => + d ? { ...d, pages: d.pages.map((p) => ({ ...p, items: p.items.filter(keep) })) } : d, + ) + + const rate = useMutation({ + mutationFn: ({ kind, item }: { kind: 'up' | 'down'; item: DiscoveryItem }) => thumb(kind, item, set.id), + onMutate: ({ kind, item }) => { + tap() + if (kind === 'down') drop((it) => it.key !== item.key) + else setThumbed((s) => new Set(s).add(item.key)) + }, + onSuccess: (_, { kind, item }) => + toast({ message: kind === 'up' ? `Glad you like “${item.title}”` : `You won't see “${item.title}” again` }), + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + const notForMe = useMutation({ + mutationFn: (item: DiscoveryItem) => block(item.artist), + onMutate: (item) => { + tap() + drop((it) => it.artist.toLowerCase() !== item.artist.toLowerCase()) + }, + onSuccess: (b) => { + void qc.invalidateQueries({ queryKey: blocksQuery.queryKey }) + toast({ + message: `No more ${b.name}`, + action: { + label: 'Undo', + onClick: () => + void unblock(b.key).then(() => { + void qc.invalidateQueries({ queryKey: blocksQuery.queryKey }) + void qc.invalidateQueries({ queryKey: feedQuery(set.id).queryKey }) + }), + }, + }) + }, + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + + return ( + <section className="mt-8"> + <div className="mb-3 flex items-center justify-between gap-3 px-1"> + <h2 className="text-headline">New to you</h2> + <Button variant="ghost" size="sm" disabled={refresh.isPending || pages.isPending} onClick={() => refresh.mutate()}> + <RefreshCw data-icon="inline-start" className={refresh.isPending ? 'animate-spin' : undefined} /> + Refresh + </Button> + </div> + {first?.library.building && ( + <p className="mb-3 px-1 text-caption text-muted-foreground">Still indexing your library, so a song you have might slip through.</p> + )} + {pages.isPending || refresh.isPending ? ( + <div className="flex flex-col gap-3"> + <p className="px-1 text-sm text-muted-foreground">Walking out from your artists…</p> + {[0, 1, 2, 3].map((i) => ( + <Skeleton key={i} className="h-[5.5rem] rounded-3xl" /> + ))} + </div> + ) : pages.isError && !pages.data ? ( + <Notice>{errorMessage(pages.error)}</Notice> + ) : items.length === 0 ? ( + <p className="glass rounded-3xl p-5 text-sm text-muted-foreground"> + {first?.noGraph + ? "This server doesn't know how music relates yet: its admin can turn on Last.fm, ListenBrainz or Deezer." + : "Nothing new turned up yet. Artists the server didn't know are being looked up; refresh in a minute, or add another artist."} + </p> + ) : ( + <motion.ul variants={stagger} initial="hidden" animate="show" className="flex flex-col gap-3"> + {items.map((it) => ( + <FeedCard + key={it.key} + item={it} + thumbed={thumbed.has(it.key) ? 'up' : undefined} + onThumb={(kind) => rate.mutate({ kind, item: it })} + onBlock={() => notForMe.mutate(it)} + /> + ))} + </motion.ul> + )} + <div ref={end} className="flex justify-center py-6"> + {isFetchingNextPage && <LoaderCircle className="size-5 animate-spin text-muted-foreground" />} + {!hasNextPage && items.length > 0 && <p className="text-caption text-muted-foreground">That's all for now. Refresh for another walk.</p>} + </div> + </section> + ) +} diff --git a/web/src/routes/_app/_authed/discover.index.tsx b/web/src/routes/_app/_authed/discover.index.tsx new file mode 100644 index 0000000..2ff9f29 --- /dev/null +++ b/web/src/routes/_app/_authed/discover.index.tsx @@ -0,0 +1,209 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { createFileRoute, Link, useNavigate } from '@tanstack/react-router' +import { Compass, LoaderCircle, Plus, RefreshCw, X } from 'lucide-react' +import { motion } from 'motion/react' +import { useState } from 'react' +import { errorMessage } from '@/api/errors' +import { PageHeader } from '@/components/page-header' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Skeleton } from '@/components/ui/skeleton' +import { useMe } from '@/lib/auth' +import { + blocksQuery, + createSet, + libraryQuery, + refreshLibrary, + setChanged, + setsQuery, + unblock, + type DiscoveryLibrary, + type DiscoverySetSummary, +} from '@/lib/discover' +import { fadeUp, stagger } from '@/lib/motion' +import { relativeTime } from '@/lib/time' +import { toast } from '@/lib/toast' + +export const Route = createFileRoute('/_app/_authed/discover/')({ + loader: ({ context }) => context.queryClient.prefetchQuery(setsQuery), + component: Discover, +}) + +const modeLabel = { deep: 'Deep cuts', fresh: 'Fresh', both: 'Deep cuts and fresh' } as const + +/** Your discovery sets: artists you pick, each a feed of music you don't have yet. */ +function Discover() { + const me = useMe() + const sets = useQuery({ ...setsQuery, enabled: !me.guest }) + const [naming, setNaming] = useState(false) + + if (me.guest) { + return ( + <> + <PageHeader title="Discover" /> + <p className="glass rounded-3xl p-5 text-sm text-muted-foreground">Discover is for members. Guests can queue in the room they joined.</p> + </> + ) + } + const all = sets.data ?? [] + return ( + <> + <PageHeader + title="Discover" + subtitle="Music you don't have yet, near artists you pick" + actions={ + <Button variant="glass" size="icon" aria-label="New set" onClick={() => setNaming((n) => !n)}> + <Plus className="size-5" /> + </Button> + } + /> + {naming && <NewSet onDone={() => setNaming(false)} />} + {sets.isPending ? ( + <div className="grid grid-cols-1 gap-3 sm:grid-cols-2"> + {[0, 1, 2].map((i) => ( + <Skeleton key={i} className="h-24 rounded-3xl" /> + ))} + </div> + ) : all.length === 0 ? ( + <div className="glass flex flex-col items-start gap-3 rounded-3xl p-5 text-sm text-muted-foreground"> + <p> + Make a set of artists you love, like “Moody post-rock” or “90s alt”, and Discover finds songs near them that + aren't in your library. Listen to a preview, then find the whole song on YouTube. + </p> + {!naming && ( + <Button size="sm" onClick={() => setNaming(true)}> + <Plus data-icon="inline-start" /> + New set + </Button> + )} + </div> + ) : ( + <motion.ul variants={stagger} initial="hidden" animate="show" className="grid grid-cols-1 gap-3 sm:grid-cols-2"> + {all.map((s) => ( + <motion.li key={s.id} variants={fadeUp}> + <SetCard set={s} /> + </motion.li> + ))} + </motion.ul> + )} + <LibraryStatus /> + <Blocks /> + </> + ) +} + +function NewSet({ onDone }: { onDone: () => void }) { + const qc = useQueryClient() + const navigate = useNavigate() + const [name, setName] = useState('') + const create = useMutation({ + mutationFn: () => createSet(name.trim()), + onSuccess: (s) => { + setChanged(qc, s) + onDone() + void navigate({ to: '/discover/$setId', params: { setId: s.id } }) + }, + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + return ( + <motion.form + initial={{ opacity: 0, y: -8 }} + animate={{ opacity: 1, y: 0 }} + className="glass mb-6 flex gap-2 rounded-3xl p-3" + onSubmit={(e) => { + e.preventDefault() + if (name.trim()) create.mutate() + }} + > + <Input autoFocus value={name} onChange={(e) => setName(e.target.value)} placeholder="Name it: Moody post-rock" aria-label="New set's name" maxLength={100} /> + <Button type="submit" disabled={!name.trim() || create.isPending}> + Create + </Button> + </motion.form> + ) +} + +function SetCard({ set: s }: { set: DiscoverySetSummary }) { + return ( + <Link + to="/discover/$setId" + params={{ setId: s.id }} + className="glass flex items-center gap-4 rounded-3xl p-4 transition-transform outline-none hover:scale-[1.01] focus-visible:ring-3 focus-visible:ring-ring/50" + > + <span className="grid size-14 shrink-0 place-items-center rounded-2xl bg-primary/15 text-primary"> + <Compass className="size-6" /> + </span> + <span className="min-w-0 flex-1"> + <span className="block truncate font-medium">{s.name}</span> + <span className="block truncate text-caption text-muted-foreground"> + {s.artistCount} artist{s.artistCount === 1 ? '' : 's'} · {modeLabel[s.mode]} + </span> + </span> + </Link> + ) +} + +/** What's left out: the songs on your own Navidrome, indexed in the background. */ +function LibraryStatus() { + const qc = useQueryClient() + const lib = useQuery(libraryQuery) + const again = useMutation({ + mutationFn: refreshLibrary, + onSuccess: (l) => qc.setQueryData(libraryQuery.queryKey, l), + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + if (!lib.data) return null + return ( + <section className="mt-10"> + <h2 className="mb-2 px-1 text-headline">Your library</h2> + <div className="glass flex items-center gap-3 rounded-3xl p-4 text-sm"> + <p className="min-w-0 flex-1 text-muted-foreground">{libraryText(lib.data)}</p> + {lib.data.links > 0 || lib.data.building ? ( + <Button variant="ghost" size="sm" disabled={lib.data.building || again.isPending} onClick={() => again.mutate()}> + {lib.data.building ? <LoaderCircle data-icon="inline-start" className="animate-spin" /> : <RefreshCw data-icon="inline-start" />} + {lib.data.building ? 'Indexing' : 'Index again'} + </Button> + ) : null} + </div> + </section> + ) +} + +function libraryText(l: DiscoveryLibrary) { + if (l.links === 0 && !l.building) { + return "No Navidrome of yours is linked, so nothing is left out. Link one in Settings → Services and Discover skips what's on it." + } + if (l.links === 0) return 'Indexing your library, so Discover can skip what you have.' + const when = l.builtAt ? `, as of ${relativeTime(l.builtAt)}` : '' + return `Skipping the ${l.songs.toLocaleString()} songs on your Navidrome${when}.` +} + +/** Artists you said aren't for you. */ +function Blocks() { + const qc = useQueryClient() + const blocks = useQuery(blocksQuery) + const undo = useMutation({ + mutationFn: unblock, + onSuccess: () => { + void qc.invalidateQueries({ queryKey: blocksQuery.queryKey }) + qc.removeQueries({ queryKey: ['discover', 'feed'] }) + }, + onError: (e) => toast({ message: errorMessage(e), tone: 'error' }), + }) + if (!blocks.data || blocks.data.length === 0) return null + return ( + <section className="mt-10"> + <h2 className="mb-2 px-1 text-headline">Not for me</h2> + <ul className="flex flex-wrap gap-2"> + {blocks.data.map((b) => ( + <li key={b.key} className="glass flex items-center gap-1 rounded-full py-1 pr-1 pl-3 text-sm"> + {b.name} + <Button variant="ghost" size="icon-xs" aria-label={`Let ${b.name} back in`} disabled={undo.isPending} onClick={() => undo.mutate(b.key)}> + <X /> + </Button> + </li> + ))} + </ul> + </section> + ) +}