@omelhorsite/sdk 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -131
- package/dist/index.js +1049 -1246
- package/dist/types/auth/device.d.ts +1 -1
- package/dist/types/auth/index.d.ts +2 -2
- package/dist/types/auth/tokens.d.ts +15 -15
- package/dist/types/client.d.ts +10 -10
- package/dist/types/errors.d.ts +12 -15
- package/dist/types/http.d.ts +74 -118
- package/dist/types/index.d.ts +2 -2
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- package/dist/types/local/qr.d.ts +1 -1
- package/dist/types/local/wordlist.d.ts +2 -3
- package/dist/types/resources/account.d.ts +19 -19
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +17 -13
- package/dist/types/resources/auth/index.d.ts +1 -1
- package/dist/types/resources/auth/passkeys.d.ts +127 -163
- package/dist/types/resources/auth/sessions.d.ts +116 -161
- package/dist/types/resources/chests.d.ts +27 -31
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +41 -236
- package/dist/types/resources/dynamicQrs.d.ts +29 -45
- package/dist/types/resources/forms.d.ts +37 -58
- package/dist/types/resources/jobs.d.ts +35 -44
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +20 -22
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +27 -53
- package/dist/types/resources/music/artists.d.ts +182 -246
- package/dist/types/resources/music/imports.d.ts +190 -218
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +85 -117
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +165 -227
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +38 -47
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +21 -3
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +94 -109
- package/dist/types/resources/tickets.d.ts +19 -10
- package/dist/types/resources/tools/backgroundRemoval.d.ts +11 -13
- package/dist/types/resources/tools/captions.d.ts +107 -135
- package/dist/types/resources/tools/upscale.d.ts +12 -16
- package/dist/types/types.d.ts +29 -38
- package/package.json +1 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The `music.songs` namespace: the library, its lyrics and its stems.
|
|
3
3
|
*
|
|
4
|
-
* Everything under here is strictly single-tenant
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* is a `404 "Resource not found"`, never a `403`. The same is true of
|
|
4
|
+
* Everything under here is strictly single-tenant: there is no such thing as
|
|
5
|
+
* reading somebody else's track by id. A foreign id is a
|
|
6
|
+
* `404 "Resource not found"`, never a `403`. The same is true of
|
|
8
7
|
* `liked_songs`, of `/artist_metadata/:name` (which resolves against YOUR
|
|
9
8
|
* artist roster, not a global one) and of `/songs/artist_pictures`. Cross-user
|
|
10
9
|
* song payloads exist in this API, but they arrive through jams and social
|
|
@@ -14,50 +13,42 @@
|
|
|
14
13
|
*
|
|
15
14
|
* **Song ids are integers.** So are `liked_songs` ids. The ids sitting NEXT to
|
|
16
15
|
* them are not: `user_id` is a string uuid, every `*_media_id` is a string, and
|
|
17
|
-
* a vocal separation's own `id` is a string. On
|
|
18
|
-
* come back as strings. Compare with `===` against the right type or
|
|
19
|
-
* will ever match.
|
|
16
|
+
* a vocal separation's own `id` is a string. On the realtime stream the same
|
|
17
|
+
* song ids come back as strings. Compare with `===` against the right type or
|
|
18
|
+
* nothing will ever match.
|
|
20
19
|
*
|
|
21
20
|
* **Media never travels inline.** A song carries ids of storage nodes, not
|
|
22
21
|
* bytes and not URLs. Resolve one with `oms.media` (`GET /media/:id/data_url`
|
|
23
|
-
* hands back a short-lived signed URL, which is what you give a player).
|
|
24
|
-
* `
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* album grid that reaches for them takes seconds per tile.
|
|
22
|
+
* hands back a short-lived signed URL, which is what you give a player).
|
|
23
|
+
* `GET /fs_nodes/:id/data_url` is a legacy alias that reaches the same bytes;
|
|
24
|
+
* new code should ask `oms.media`. Prefer the compressed twin either way:
|
|
25
|
+
* `compressed_audio_media_id` before `audio_media_id`,
|
|
26
|
+
* `compressed_artwork_media_id` before `artwork_media_id`. The originals are
|
|
27
|
+
* lossless files on slow storage and an album grid that reaches for them takes
|
|
28
|
+
* seconds per tile.
|
|
31
29
|
*
|
|
32
|
-
* **Every key that names a media node is sent TWICE.** `
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* server-side without a major version of this SDK.
|
|
30
|
+
* **Every key that names a media node is sent TWICE.** `<name>_media_id` and
|
|
31
|
+
* `<name>_fs_node_id` carry the identical value, the second being a legacy
|
|
32
|
+
* alias. Read the `_media_id` spelling; the twin is declared here only so that
|
|
33
|
+
* older code keeps type-checking, and it will be removed server-side without a
|
|
34
|
+
* major version of this SDK.
|
|
38
35
|
*
|
|
39
36
|
* ## An OAuth token cannot reach any of this
|
|
40
37
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* the action runs. Music needs a session cookie or a personal token. That is a
|
|
46
|
-
* server-side gap rather than a design decision, so it may open later; until it
|
|
47
|
-
* does, an {@link OmsAuthError} with status 403 and that body means "wrong kind
|
|
48
|
-
* of credential", not "wrong user".
|
|
38
|
+
* An OAuth access token gets `403 {"error":"insufficient_scope"}` on EVERY
|
|
39
|
+
* method here. Music needs a session cookie or a personal token. That gap may
|
|
40
|
+
* close later; until it does, an {@link OmsAuthError} with status 403 and that
|
|
41
|
+
* body means "wrong kind of credential", not "wrong user".
|
|
49
42
|
*
|
|
50
43
|
* ## The 60-per-minute bucket nobody expects to share
|
|
51
44
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* enough to be the sixty-first. Pace a backfill at roughly one request per
|
|
60
|
-
* second and it will never be seen.
|
|
45
|
+
* `/lyrics*`, `/artists/*`, `/artist_metadata/*` and `/music_radios/*` share
|
|
46
|
+
* ONE budget of 60 requests per minute, keyed by the `Authorization` header,
|
|
47
|
+
* because all four proxy to somebody else's servers (lrclib, Genius, Last.fm,
|
|
48
|
+
* Wikipedia, Deezer). One counter, four route families: fetching lyrics for
|
|
49
|
+
* sixty tracks in a minute leaves zero budget for artist metadata, and the 429
|
|
50
|
+
* lands on whichever call is unlucky enough to be the sixty-first. Pace a
|
|
51
|
+
* backfill at roughly one request per second and it will never be seen.
|
|
61
52
|
*
|
|
62
53
|
* The rest of the namespace lives under the general ceiling (600/min
|
|
63
54
|
* authenticated), with two exceptions that have their own budgets and their own
|
|
@@ -66,7 +57,8 @@
|
|
|
66
57
|
* (30/min, and it does NOT answer 429 - read that method).
|
|
67
58
|
*/
|
|
68
59
|
import { Resource } from "../../http";
|
|
69
|
-
import
|
|
60
|
+
import type { ListParams } from "../../listing";
|
|
61
|
+
import { type BaseRecord, type FileInput, type FileOutput, type Id, type NativeFile, type Paginated, type RequestOptions, type Timestamp } from "../../types";
|
|
70
62
|
import type { VocalSeparation } from "../tools/vocalSeparation";
|
|
71
63
|
/**
|
|
72
64
|
* Primary key of a song. An **integer**, unlike most ids in this API.
|
|
@@ -76,16 +68,16 @@ import type { VocalSeparation } from "../tools/vocalSeparation";
|
|
|
76
68
|
* primary keys; `users`, `sessions`, `fs_nodes`, `playback_states` and
|
|
77
69
|
* `vocal_separations` are string uuids. Both spellings are accepted wherever a
|
|
78
70
|
* song id is taken as an argument, because a caller that read the id off a
|
|
79
|
-
*
|
|
80
|
-
* carries a number.
|
|
71
|
+
* realtime message is holding a string, but the JSON these methods RETURN
|
|
72
|
+
* always carries a number.
|
|
81
73
|
*/
|
|
82
74
|
export type SongId = number | string;
|
|
83
75
|
/** How an artist is credited on a track. */
|
|
84
76
|
export type SongArtistRole = "primary" | "featured" | "with";
|
|
85
77
|
/**
|
|
86
|
-
* One
|
|
78
|
+
* One artist credit, nested under {@link Song.artists}.
|
|
87
79
|
*
|
|
88
|
-
* `id` is the id of the
|
|
80
|
+
* `id` is the id of the credit row, not of the artist - the artist's own id is
|
|
89
81
|
* `artist_id`. Getting those two the wrong way round is how a link to an artist
|
|
90
82
|
* page ends up pointing at a random other artist, so prefer `slug` for routing
|
|
91
83
|
* and keep `artist_id` for lookups.
|
|
@@ -97,14 +89,14 @@ export type SongArtistRole = "primary" | "featured" | "with";
|
|
|
97
89
|
* `picture_xl`) lives on the artist record.
|
|
98
90
|
*/
|
|
99
91
|
export interface SongArtistCredit extends Omit<BaseRecord, "id"> {
|
|
100
|
-
/** Id of the
|
|
92
|
+
/** Id of the credit row. NOT the artist id. */
|
|
101
93
|
readonly id: number;
|
|
102
94
|
readonly song_id: number;
|
|
103
95
|
readonly artist_id: number;
|
|
104
96
|
/** Ordering within the credits. Sort by it; the server does not. */
|
|
105
97
|
readonly position: number;
|
|
106
98
|
readonly role: SongArtistRole;
|
|
107
|
-
/** `null` only if the
|
|
99
|
+
/** `null` only if the credit outlived its artist, which the server prevents. */
|
|
108
100
|
readonly name: string | null;
|
|
109
101
|
readonly slug: string | null;
|
|
110
102
|
/** Artist avatar the user uploaded, as a storage node id. Usually `null`. */
|
|
@@ -125,15 +117,10 @@ export type SongSourceKind = "upload" | "yt_dlp" | "spotify_sync";
|
|
|
125
117
|
/**
|
|
126
118
|
* A track in the library.
|
|
127
119
|
*
|
|
128
|
-
*
|
|
129
|
-
* shape below is what every route in this namespace answers with - index,
|
|
120
|
+
* The shape below is what every route in this namespace answers with - index,
|
|
130
121
|
* show, update and import alike. There is no narrower view to guard against.
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* `track_number` and `disc_number` (they are optional there and always
|
|
134
|
-
* `undefined`), and neither does the legacy `artist` string column, which was
|
|
135
|
-
* dropped when `song_artists` landed. {@link Song.artists} is the only artist
|
|
136
|
-
* source.
|
|
122
|
+
* There is no `track_number`, no `disc_number` and no legacy `artist` string
|
|
123
|
+
* on the wire; {@link Song.artists} is the only artist source.
|
|
137
124
|
*/
|
|
138
125
|
export interface Song extends Omit<BaseRecord, "id"> {
|
|
139
126
|
/** Integer primary key. See {@link SongId}. */
|
|
@@ -180,7 +167,7 @@ export interface Song extends Omit<BaseRecord, "id"> {
|
|
|
180
167
|
/**
|
|
181
168
|
* Stamped when a separation starts and cleared when it settles, so a
|
|
182
169
|
* non-null value means "a separation is in flight". It can go stale if a
|
|
183
|
-
*
|
|
170
|
+
* run dies; `GET /songs/:id/separation` clears it as a side effect, which
|
|
184
171
|
* is one reason to poll that route rather than re-reading the song.
|
|
185
172
|
*/
|
|
186
173
|
readonly vocal_separation_started_at: Timestamp | null;
|
|
@@ -219,8 +206,8 @@ export interface Song extends Omit<BaseRecord, "id"> {
|
|
|
219
206
|
/**
|
|
220
207
|
* A row of `GET /songs/albums`.
|
|
221
208
|
*
|
|
222
|
-
* Not a
|
|
223
|
-
*
|
|
209
|
+
* Not a stored record: the endpoint groups the caller's songs and this is the
|
|
210
|
+
* summary it builds. `name: null` is the bucket of songs with no
|
|
224
211
|
* album, and it is a legitimate row rather than an error.
|
|
225
212
|
*/
|
|
226
213
|
export interface SongAlbumSummary {
|
|
@@ -261,8 +248,7 @@ export interface SongSeparationStatus {
|
|
|
261
248
|
* The run itself, or `null` when this song has never had one.
|
|
262
249
|
*
|
|
263
250
|
* The same `VocalSeparation` record the `tools.vocalSeparation` namespace
|
|
264
|
-
* returns
|
|
265
|
-
* than redeclared here. For a song-owned run `vocals_url` and
|
|
251
|
+
* returns, so it is imported rather than redeclared here. For a song-owned run `vocals_url` and
|
|
266
252
|
* `instrumental_url` are permanently `null`: the stems are written onto the
|
|
267
253
|
* song as storage nodes, not attached to this row.
|
|
268
254
|
*/
|
|
@@ -276,7 +262,7 @@ export interface LikedSong extends Omit<BaseRecord, "id"> {
|
|
|
276
262
|
readonly song_id: number;
|
|
277
263
|
/** The cursor {@link ListLikedSongsParams.before} pages on. */
|
|
278
264
|
readonly liked_at: Timestamp;
|
|
279
|
-
/** Always present
|
|
265
|
+
/** Always present. */
|
|
280
266
|
readonly song: Song;
|
|
281
267
|
}
|
|
282
268
|
/** Lyrics for one track. */
|
|
@@ -316,10 +302,8 @@ export interface ArtistMetadataSimilar {
|
|
|
316
302
|
/**
|
|
317
303
|
* The legacy payload `GET /artist_metadata/:name` answers with.
|
|
318
304
|
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* with NO `created_at` / `updated_at`. It also never 404s - see
|
|
322
|
-
* {@link MusicSongsNamespace.artistMetadata}.
|
|
305
|
+
* One of the very few records in the API with NO `created_at` / `updated_at`.
|
|
306
|
+
* It also never 404s - see {@link MusicSongsNamespace.artistMetadata}.
|
|
323
307
|
*/
|
|
324
308
|
export interface ArtistMetadata {
|
|
325
309
|
/** `null` on the not-found branch. Integer when the artist exists. */
|
|
@@ -357,10 +341,9 @@ export interface ArtistMetadata {
|
|
|
357
341
|
/**
|
|
358
342
|
* Where an external-search hit came from.
|
|
359
343
|
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
* ported code that does, but do not wait for them.
|
|
344
|
+
* `"soundcloud"` and `"bandcamp"` are kept for compatibility only: the search
|
|
345
|
+
* queries Spotify, iTunes and YouTube and nothing else, so they never appear
|
|
346
|
+
* today.
|
|
364
347
|
*/
|
|
365
348
|
export type MusicExternalSource = "spotify" | "itunes" | "youtube" | "soundcloud" | "bandcamp";
|
|
366
349
|
/** What to ask the external providers for. */
|
|
@@ -419,7 +402,7 @@ export interface MusicExternalSearchResult {
|
|
|
419
402
|
* `artist` is on the list but is not a column - see
|
|
420
403
|
* {@link ListSongsParams.artist}.
|
|
421
404
|
*/
|
|
422
|
-
export declare const SONG_FILTER_COLUMNS: readonly
|
|
405
|
+
export declare const SONG_FILTER_COLUMNS: readonly ["id", "created_at", "updated_at", "title", "album", "position", "year", "artist"];
|
|
423
406
|
/** Columns the backend will accept in `modifiers[order]`. */
|
|
424
407
|
export declare const SONG_ORDER_COLUMNS: readonly string[];
|
|
425
408
|
/** Filters shared by `GET /songs` and `GET /songs/albums`. */
|
|
@@ -427,9 +410,9 @@ export interface SongFilters {
|
|
|
427
410
|
/**
|
|
428
411
|
* Partial title match, sent as `search[title]`.
|
|
429
412
|
*
|
|
430
|
-
* The comparison is slug-shaped: the server lowercases, strips accents
|
|
431
|
-
*
|
|
432
|
-
*
|
|
413
|
+
* The comparison is slug-shaped: the server lowercases, strips accents,
|
|
414
|
+
* replaces every run of non-alphanumerics with a hyphen and then does a
|
|
415
|
+
* substring match on both sides. So `"cafe"` finds
|
|
433
416
|
* "Café", `"nao quero"` finds "Não Quero", and punctuation is irrelevant. It
|
|
434
417
|
* is not a full-text index and there is no ranking.
|
|
435
418
|
*
|
|
@@ -440,9 +423,8 @@ export interface SongFilters {
|
|
|
440
423
|
readonly title?: string;
|
|
441
424
|
/**
|
|
442
425
|
* Exact album, sent as `exact_search[album]`. Pass `null` for the no-album
|
|
443
|
-
* bucket: the transport encodes it as the
|
|
444
|
-
*
|
|
445
|
-
* the only way to ask for it.
|
|
426
|
+
* bucket: the transport encodes it as the server's `\b` null sentinel, which
|
|
427
|
+
* is the only way to ask for it.
|
|
446
428
|
*
|
|
447
429
|
* Not a substring match. `search[album]` exists and IS partial, but it can
|
|
448
430
|
* never express the null bucket, so this field takes the exact route and the
|
|
@@ -456,10 +438,9 @@ export interface SongFilters {
|
|
|
456
438
|
/**
|
|
457
439
|
* Narrow to one artist, by canonical name OR by slug.
|
|
458
440
|
*
|
|
459
|
-
* This one is not a column and does not behave like the others. The
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
* `song_artists`. Consequences:
|
|
441
|
+
* This one is not a column and does not behave like the others. The server
|
|
442
|
+
* resolves it against YOUR artist roster (canonical name first, then slug)
|
|
443
|
+
* and matches on credits. Consequences:
|
|
463
444
|
*
|
|
464
445
|
* - it is EXACT even though it is spelled like a search. `search[artist]`
|
|
465
446
|
* and `exact_search[artist]` are the same code path; there is no partial
|
|
@@ -467,8 +448,7 @@ export interface SongFilters {
|
|
|
467
448
|
* filter client-side or go through `oms.music.artists`;
|
|
468
449
|
* - an artist you do not have resolves to nothing and yields an EMPTY list,
|
|
469
450
|
* not a 404 and not an error. An empty page is genuinely ambiguous here;
|
|
470
|
-
* - it changes what {@link MusicSongsNamespace.albums} deduplicates on
|
|
471
|
-
* is the point of that endpoint's `filter_artist_id`.
|
|
451
|
+
* - it changes what {@link MusicSongsNamespace.albums} deduplicates on.
|
|
472
452
|
*/
|
|
473
453
|
readonly artist?: string;
|
|
474
454
|
/**
|
|
@@ -480,49 +460,30 @@ export interface SongFilters {
|
|
|
480
460
|
* excluded even if they also appear as a feature.
|
|
481
461
|
*/
|
|
482
462
|
readonly artistRole?: SongArtistRole;
|
|
483
|
-
/**
|
|
484
|
-
* Escape hatch for a partial match on a column {@link SongFilters} does not
|
|
485
|
-
* name, sent verbatim as `search[...]`.
|
|
486
|
-
*
|
|
487
|
-
* Only the keys in {@link SONG_FILTER_COLUMNS} are accepted and an unknown
|
|
488
|
-
* one is a 400, so do not forward user-controlled keys. Two behaviours
|
|
489
|
-
* surprise people: on a NUMBER column (`year`, `position`, `id`) `search` is
|
|
490
|
-
* an exact `IN`, not a range or a prefix; and any blank value is dropped
|
|
491
|
-
* instead of matching nothing.
|
|
492
|
-
*/
|
|
493
|
-
readonly search?: Readonly<Record<string, QueryValue>>;
|
|
494
|
-
/**
|
|
495
|
-
* Escape hatch for an equality filter, sent verbatim as `exact_search[...]`.
|
|
496
|
-
* Same allowlist, same fail-closed 400. An array becomes `IN`, `null`
|
|
497
|
-
* becomes `IS NULL`.
|
|
498
|
-
*/
|
|
499
|
-
readonly exactSearch?: Readonly<Record<string, QueryValue>>;
|
|
500
463
|
}
|
|
501
464
|
/** Arguments for {@link MusicSongsNamespace.list}. */
|
|
502
|
-
export interface ListSongsParams extends SongFilters,
|
|
465
|
+
export interface ListSongsParams extends SongFilters, ListParams<(typeof SONG_FILTER_COLUMNS)[number]> {
|
|
503
466
|
/**
|
|
504
467
|
* `modifiers[order]`, as `"column:asc"` or `"column:desc"`.
|
|
505
468
|
*
|
|
506
469
|
* Defaults to `"created_at:asc"`, which is also the endpoint's own base
|
|
507
470
|
* order and the one that makes paging stable. Two traps:
|
|
508
471
|
*
|
|
509
|
-
* - a column the
|
|
510
|
-
* is an allowed key so the request is not rejected
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
*
|
|
517
|
-
* `created_at` or `id` for anything you intend to page through.
|
|
472
|
+
* - a column the record does not have is IGNORED, silently. `modifiers[order]`
|
|
473
|
+
* is an allowed key so the request is not rejected; the base order is
|
|
474
|
+
* handed back instead. A typo costs you nothing but the sort you asked for;
|
|
475
|
+
* - a real column REPLACES the base order, tie breaker included. Ordering
|
|
476
|
+
* 4000 tracks by `title:asc` when several share a title lets the database
|
|
477
|
+
* return them in a different sequence per page, which duplicates and drops
|
|
478
|
+
* rows across a paged walk. Prefer `created_at` or `id` for anything you
|
|
479
|
+
* intend to page through.
|
|
518
480
|
*
|
|
519
481
|
* A third `:`-separated segment pins specific values first
|
|
520
|
-
* (`"album:asc:Clube da Esquina,Acabou Chorare"`)
|
|
521
|
-
* `SELECT DISTINCT` over the column.
|
|
482
|
+
* (`"album:asc:Clube da Esquina,Acabou Chorare"`).
|
|
522
483
|
*/
|
|
523
484
|
readonly order?: string;
|
|
524
485
|
/**
|
|
525
|
-
* `modifiers[random]=true` - shuffle server-side
|
|
486
|
+
* `modifiers[random]=true` - shuffle server-side.
|
|
526
487
|
*
|
|
527
488
|
* Mutually destructive with paging: the ordering is re-evaluated per request,
|
|
528
489
|
* so page 2 of a random listing is a fresh shuffle and shares rows with page
|
|
@@ -532,7 +493,7 @@ export interface ListSongsParams extends SongFilters, PageParams {
|
|
|
532
493
|
readonly random?: boolean;
|
|
533
494
|
}
|
|
534
495
|
/** Arguments for {@link MusicSongsNamespace.albums}. */
|
|
535
|
-
export interface ListSongAlbumsParams extends SongFilters {
|
|
496
|
+
export interface ListSongAlbumsParams extends SongFilters, ListParams<(typeof SONG_FILTER_COLUMNS)[number]> {
|
|
536
497
|
/**
|
|
537
498
|
* Page of SONGS to scan, not of albums. Read
|
|
538
499
|
* {@link MusicSongsNamespace.albums} before setting it; omitting it is
|
|
@@ -545,7 +506,7 @@ export interface ListSongAlbumsParams extends SongFilters {
|
|
|
545
506
|
/**
|
|
546
507
|
* Fields {@link MusicSongsNamespace.update} can change.
|
|
547
508
|
*
|
|
548
|
-
* Four real
|
|
509
|
+
* Four real fields and three virtual inputs. The virtual ones are the
|
|
549
510
|
* complicated half; each carries its own note.
|
|
550
511
|
*/
|
|
551
512
|
export interface UpdateSongInput {
|
|
@@ -561,14 +522,14 @@ export interface UpdateSongInput {
|
|
|
561
522
|
* there is no comma-splitting heuristic, so a name that genuinely contains a
|
|
562
523
|
* comma survives.
|
|
563
524
|
*
|
|
564
|
-
* An EMPTY array is not "remove every artist":
|
|
565
|
-
*
|
|
566
|
-
*
|
|
525
|
+
* An EMPTY array is not "remove every artist": the server treats it as
|
|
526
|
+
* absent and re-runs the legacy parser. There is no way through this
|
|
527
|
+
* endpoint to leave a song with no artists at all.
|
|
567
528
|
*/
|
|
568
529
|
readonly artistNames?: string[];
|
|
569
530
|
/**
|
|
570
531
|
* The featured credits, replacing whatever is there. Sending this key at all
|
|
571
|
-
* is what switches the
|
|
532
|
+
* is what switches the server out of its legacy mode.
|
|
572
533
|
*
|
|
573
534
|
* That legacy mode is a heuristic over the TITLE: with no `featured_artist_
|
|
574
535
|
* names` key present, the server re-reads `"Song (feat. X)"` and rebuilds the
|
|
@@ -584,7 +545,7 @@ export interface UpdateSongInput {
|
|
|
584
545
|
/**
|
|
585
546
|
* Legacy single-line artist input, re-parsed server-side (it splits on
|
|
586
547
|
* commas and on "feat."). Prefer {@link UpdateSongInput.artistNames}; this
|
|
587
|
-
* exists for
|
|
548
|
+
* exists for compatibility.
|
|
588
549
|
*/
|
|
589
550
|
readonly artist?: string;
|
|
590
551
|
/**
|
|
@@ -609,16 +570,15 @@ export interface ListLikedSongsParams {
|
|
|
609
570
|
*
|
|
610
571
|
* Deliberately not an offset. The list is ordered by `liked_at` descending
|
|
611
572
|
* and liking one track mid-scroll shifts every later offset page by one,
|
|
612
|
-
* which shows a duplicate and hides a row. A `Date` is encoded as ISO-8601
|
|
613
|
-
*
|
|
614
|
-
* `400 "Invalid before timestamp"`.
|
|
573
|
+
* which shows a duplicate and hides a row. A `Date` is encoded as ISO-8601;
|
|
574
|
+
* an unparseable string is a `400 "Invalid before timestamp"`.
|
|
615
575
|
*/
|
|
616
576
|
readonly before?: string | Date;
|
|
617
577
|
}
|
|
618
578
|
/** Arguments for {@link MusicSongsNamespace.startSeparation}. */
|
|
619
579
|
export interface StartSongSeparationInput {
|
|
620
580
|
/**
|
|
621
|
-
* Which
|
|
581
|
+
* Which separation model to run. Omit for the default. The selectable list is
|
|
622
582
|
* `oms.tools.vocalSeparation.models()`; an id that is not on it is a
|
|
623
583
|
* `400 "Unknown model"`.
|
|
624
584
|
*/
|
|
@@ -640,9 +600,8 @@ export interface ModifySongMetadataInput {
|
|
|
640
600
|
/** The file to retag. Hard cap 50 MiB, enforced before anything else happens. */
|
|
641
601
|
readonly audio: FileInput | NativeFile;
|
|
642
602
|
/**
|
|
643
|
-
* At least one tag is REQUIRED. An empty bag
|
|
644
|
-
*
|
|
645
|
-
* locally instead.
|
|
603
|
+
* At least one tag is REQUIRED. An empty bag comes back as a 500, so this
|
|
604
|
+
* method rejects it locally instead.
|
|
646
605
|
*/
|
|
647
606
|
readonly metadata: SongFileMetadata;
|
|
648
607
|
}
|
|
@@ -684,14 +643,14 @@ export declare function isMusicExternalSearchRateLimited(error: unknown): boolea
|
|
|
684
643
|
* `"Chico Buarque, Milton Nascimento (feat. Elis Regina)"`: primaries joined
|
|
685
644
|
* with `", "`, then a `feat.` clause. Pure string building, no request.
|
|
686
645
|
*
|
|
687
|
-
* `with` credits are excluded unless `includeWith` is set
|
|
688
|
-
*
|
|
689
|
-
*
|
|
646
|
+
* `with` credits are excluded unless `includeWith` is set; they belong in a
|
|
647
|
+
* credits dialog and in media session metadata, where completeness beats line
|
|
648
|
+
* length.
|
|
690
649
|
*
|
|
691
|
-
* Written here because {@link Song.artists} arrives UNSORTED and
|
|
692
|
-
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
650
|
+
* Written here because {@link Song.artists} arrives UNSORTED and forgetting to
|
|
651
|
+
* sort by `position` prints the credits in insertion order, which is roughly
|
|
652
|
+
* random. It also copes with a jam entry, whose `artist_names` is a pre-joined
|
|
653
|
+
* string and whose `artists` array is empty.
|
|
695
654
|
*/
|
|
696
655
|
export declare function songArtistsLine(song: Pick<Song, "artists"> & Partial<Pick<Song, "artist_names">>, includeWith?: boolean): string;
|
|
697
656
|
/** The `music.songs` namespace, reachable as `oms.music.songs`. */
|
|
@@ -699,15 +658,13 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
699
658
|
/**
|
|
700
659
|
* `GET /songs` - the caller's library, oldest first.
|
|
701
660
|
*
|
|
702
|
-
* Pagination is FORCED here and nowhere else in this namespace:
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
*
|
|
709
|
-
* and {@link Paginated.pageSize} always reports the size the rows were
|
|
710
|
-
* counted against.
|
|
661
|
+
* Pagination is FORCED here and nowhere else in this namespace: a request
|
|
662
|
+
* with no page modifier is given `1:500` and one asking for more than 500 is
|
|
663
|
+
* clamped to it. That is a guard, not tidiness - a five-thousand-track
|
|
664
|
+
* library serialises megabytes of JSON with every credit inlined. The SDK
|
|
665
|
+
* sends a page modifier every time, so the clamp never surprises you and
|
|
666
|
+
* {@link Paginated.pageSize} always reports the size the rows were counted
|
|
667
|
+
* against.
|
|
711
668
|
*
|
|
712
669
|
* Order defaults to `created_at:asc`, the endpoint's own base order, which is
|
|
713
670
|
* what makes a paged walk stable. See {@link ListSongsParams.order} before
|
|
@@ -720,14 +677,12 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
720
677
|
* @throws {OmsAuthError} 401 when anonymous, 403 for an OAuth token.
|
|
721
678
|
* @throws {OmsApiError} 400 naming the offending key when a filter is not in
|
|
722
679
|
* {@link SONG_FILTER_COLUMNS}. Filters fail closed on purpose: silently
|
|
723
|
-
* dropping an unknown one
|
|
680
|
+
* dropping an unknown one would answer with the UNFILTERED set.
|
|
724
681
|
*/
|
|
725
682
|
list(params?: ListSongsParams, options?: RequestOptions): Promise<Paginated<Song>>;
|
|
726
683
|
/**
|
|
727
|
-
* `GET /songs/:id` - one track.
|
|
728
|
-
*
|
|
729
|
-
* Renders the `:extended` view, which `SongBlueprint` leaves identical to the
|
|
730
|
-
* default one, so this returns exactly what a row of {@link list} carries.
|
|
684
|
+
* `GET /songs/:id` - one track. Returns exactly what a row of {@link list}
|
|
685
|
+
* carries.
|
|
731
686
|
*
|
|
732
687
|
* @throws {OmsApiError} 404 `"Resource not found"` - for an id that does not
|
|
733
688
|
* exist AND for one that belongs to somebody else, indistinguishably. The
|
|
@@ -738,18 +693,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
738
693
|
* `PATCH /songs/:id` - edits metadata, and optionally replaces the artwork.
|
|
739
694
|
*
|
|
740
695
|
* JSON normally; multipart as soon as {@link UpdateSongInput.artwork} is
|
|
741
|
-
* present, because that is the only way to carry a file. Both encodings
|
|
742
|
-
* the same
|
|
743
|
-
* where they would otherwise
|
|
744
|
-
*
|
|
745
|
-
* - **clearing a
|
|
746
|
-
* there is no `null` to send. The
|
|
747
|
-
* update
|
|
748
|
-
* as that one character and clears the
|
|
749
|
-
* claims multipart cannot express this and splits the request in two; it
|
|
750
|
-
* can, and it does not need to.)
|
|
696
|
+
* present, because that is the only way to carry a file. Both encodings
|
|
697
|
+
* behave the same server-side, and this method papers over the two places
|
|
698
|
+
* where they would otherwise differ:
|
|
699
|
+
*
|
|
700
|
+
* - **clearing a field in multipart.** Every form field is a string, so
|
|
701
|
+
* there is no `null` to send. The server's `\b` null sentinel is decoded
|
|
702
|
+
* for update fields exactly as it is for filters, so `album: null` is
|
|
703
|
+
* written as that one character and clears the field.
|
|
751
704
|
* - **an empty `featuredArtistNames`.** Appending an empty array appends
|
|
752
|
-
* nothing, and an absent key is what puts the
|
|
705
|
+
* nothing, and an absent key is what puts the server back into its
|
|
753
706
|
* title-parsing legacy mode - the opposite of what "no featured artists"
|
|
754
707
|
* means. This sends the single empty string the server reads as an explicit
|
|
755
708
|
* empty list.
|
|
@@ -758,8 +711,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
758
711
|
* credits you did not touch. Send `featuredArtistNames` whenever you care
|
|
759
712
|
* about them.
|
|
760
713
|
*
|
|
761
|
-
* @throws {OmsAuthError} 401 when the song is not yours -
|
|
762
|
-
* `updatable_by?` and answers 401, not 403 or 404.
|
|
714
|
+
* @throws {OmsAuthError} 401 when the song is not yours - not 403 or 404.
|
|
763
715
|
* @throws {OmsApiError} 400 `"Music storage quota exceeded"` when the artwork
|
|
764
716
|
* would not fit in the music quota.
|
|
765
717
|
*/
|
|
@@ -784,20 +736,20 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
784
736
|
*
|
|
785
737
|
* Answers **200**, not 201, with the created song. Do not branch on the code.
|
|
786
738
|
*
|
|
787
|
-
* Two size limits and they are not the same one.
|
|
788
|
-
* {@link SONG_IMPORT_MAX_BYTES} (1 GiB) with a 400 - but
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
739
|
+
* Two size limits and they are not the same one. The API rejects anything
|
|
740
|
+
* over {@link SONG_IMPORT_MAX_BYTES} (1 GiB) with a 400 - but the CDN in
|
|
741
|
+
* front of it refuses a request body over roughly 100 MB with its own `413`
|
|
742
|
+
* before the API ever sees it. A big FLAC therefore fails with an HTML-ish
|
|
743
|
+
* 413 that says nothing about songs. There is no chunked import route; that
|
|
744
|
+
* ceiling is real.
|
|
793
745
|
*
|
|
794
746
|
* On React Native pass the picker's `{ uri, name, type }` object directly -
|
|
795
747
|
* it is appended verbatim and streamed off disk by the native layer.
|
|
796
748
|
*
|
|
797
749
|
* @throws {OmsApiError} 400 for a missing file, a file over 1 GiB, an
|
|
798
750
|
* extension outside {@link SONG_IMPORT_EXTENSIONS}, or
|
|
799
|
-
* `"Music storage quota exceeded"`; 415 with
|
|
800
|
-
*
|
|
751
|
+
* `"Music storage quota exceeded"`; 415 with validation messages when the
|
|
752
|
+
* audio itself will not import.
|
|
801
753
|
*/
|
|
802
754
|
import(file: FileInput | NativeFile, options?: RequestOptions): Promise<Song>;
|
|
803
755
|
/**
|
|
@@ -806,10 +758,9 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
806
758
|
* Takes the same filters as {@link list}, and is the endpoint every album
|
|
807
759
|
* grid is built on. It is also the most expensive read in this namespace, for
|
|
808
760
|
* a reason worth understanding: the forced pagination that protects
|
|
809
|
-
* `GET /songs`
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
* a full table scan per call.
|
|
761
|
+
* `GET /songs` does not apply here, so this route loads the whole filtered
|
|
762
|
+
* library and deduplicates by `[album, primary artist]`. On a
|
|
763
|
+
* five-thousand-track library that is a full scan per call.
|
|
813
764
|
*
|
|
814
765
|
* Paging it does not fix that and is usually a mistake:
|
|
815
766
|
* {@link ListSongAlbumsParams.page} pages the SONGS that get scanned, and the
|
|
@@ -830,8 +781,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
830
781
|
*
|
|
831
782
|
* A flat array of strings, ordered by name, and that is the whole payload.
|
|
832
783
|
*
|
|
833
|
-
* It IGNORES every filter you could send it:
|
|
834
|
-
*
|
|
784
|
+
* It IGNORES every filter you could send it: it reads names straight off the
|
|
785
|
+
* roster. This method
|
|
835
786
|
* therefore takes no parameters at all rather than accepting some that would
|
|
836
787
|
* do nothing. It also does not go through `/artists`, so despite the shared
|
|
837
788
|
* subject it does NOT spend the 60/min external-proxy budget.
|
|
@@ -846,9 +797,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
846
797
|
* artist you already have.
|
|
847
798
|
*
|
|
848
799
|
* Lookup only: an artist absent from your roster returns `[]` and no stub row
|
|
849
|
-
* is created, which is deliberate -
|
|
850
|
-
*
|
|
851
|
-
* polluted the artist table with them.
|
|
800
|
+
* is created, which is deliberate - a slug or a joined display string
|
|
801
|
+
* ("100 gecs, Lil West, Tony Velour") must not mint stub artists.
|
|
852
802
|
*
|
|
853
803
|
* The array holds zero or one entry. Zero means either "not your artist" or
|
|
854
804
|
* "Deezer has never given us a picture for them", and the two are not
|
|
@@ -870,8 +820,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
870
820
|
*
|
|
871
821
|
* The odd one out in this namespace: it writes nothing to the library, reads
|
|
872
822
|
* nothing from it, and answers with BINARY rather than JSON. The file is
|
|
873
|
-
* remuxed with
|
|
874
|
-
*
|
|
823
|
+
* remuxed with the new tags (the audio is never re-encoded) and, when given
|
|
824
|
+
* one, an embedded cover.
|
|
875
825
|
*
|
|
876
826
|
* The result is buffered fully into memory in every runtime. That is
|
|
877
827
|
* unavoidable - there is no URL to hand a downloader - but it means a 50 MiB
|
|
@@ -879,17 +829,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
879
829
|
* the server suggested in `Content-Disposition`.
|
|
880
830
|
*
|
|
881
831
|
* At least one tag must be present, and this method enforces that locally
|
|
882
|
-
* because the server does not fail gracefully: an empty `metadata`
|
|
883
|
-
*
|
|
884
|
-
* A missing audio file does the same. Both are avoided here.
|
|
832
|
+
* because the server does not fail gracefully: an empty `metadata` bag is a
|
|
833
|
+
* 500, and so is a missing audio file. Both are avoided here.
|
|
885
834
|
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
835
|
+
* `metadata[track_number]` is dropped in silence server-side, so it is not
|
|
836
|
+
* offered here.
|
|
888
837
|
*
|
|
889
838
|
* @throws {TypeError} when `metadata` carries no usable tag.
|
|
890
839
|
* @throws {OmsApiError} 413 `"File too big"` above
|
|
891
840
|
* {@link SONG_METADATA_MAX_BYTES}, checked before the body is read. Note
|
|
892
|
-
* that
|
|
841
|
+
* that the CDN's own ~100 MB body limit sits above it and never fires
|
|
893
842
|
* first.
|
|
894
843
|
*/
|
|
895
844
|
modifyMetadata(input: ModifySongMetadataInput, options?: RequestOptions): Promise<FileOutput>;
|
|
@@ -902,18 +851,14 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
902
851
|
* enqueued. So there is no need to guard the call site - but also no way to
|
|
903
852
|
* force a re-run without deleting the stems first.
|
|
904
853
|
*
|
|
905
|
-
* **Rate limit:** 20 requests per minute, from
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
* sidecar; a load generator that walked a library firing one separation per
|
|
910
|
-
* song pushed the machine into swap, which is exactly what this budget now
|
|
911
|
-
* prevents. Do not batch a library through it.
|
|
854
|
+
* **Rate limit:** 20 requests per minute, from a bucket SHARED with
|
|
855
|
+
* `POST /vocal_separations`, the upscaler, transcriptions, caption jobs,
|
|
856
|
+
* jumpstyle and the downloader previews. Each call schedules minutes of CPU
|
|
857
|
+
* and gigabytes of RAM. Do not batch a library through it.
|
|
912
858
|
*
|
|
913
859
|
* The run itself is asynchronous. Poll {@link separation} roughly every three
|
|
914
860
|
* seconds; the returned row's `status` moves `pending` to `processing` to
|
|
915
|
-
* `complete` or `failed`, and there is no `canceled
|
|
916
|
-
* frontend's own type says.
|
|
861
|
+
* `complete` or `failed`, and there is no `canceled`.
|
|
917
862
|
*
|
|
918
863
|
* @throws {OmsQuotaError} 429 when the shared expensive-tools budget is spent.
|
|
919
864
|
* @throws {OmsAuthError} 401 when the song is not yours.
|
|
@@ -931,16 +876,15 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
931
876
|
* `complete` a moment before the stems are attached, and a song can have
|
|
932
877
|
* stems from a run that was swept long ago.
|
|
933
878
|
*
|
|
934
|
-
* Reading this has a SIDE EFFECT, and it is a useful one:
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
* worker that died mid-run leaves it set forever). A UI that decides "a
|
|
879
|
+
* Reading this has a SIDE EFFECT, and it is a useful one: the server first
|
|
880
|
+
* clears {@link Song.vocal_separation_started_at} when the flag outlived its
|
|
881
|
+
* run (a run that died midway leaves it set forever). A UI that decides "a
|
|
938
882
|
* separation is in flight" from the song record alone can therefore be stuck
|
|
939
883
|
* on a spinner that only this call will clear.
|
|
940
884
|
*
|
|
941
885
|
* Poll at about three seconds. Nothing on this route is throttled beyond the
|
|
942
|
-
* general ceiling, but `progress_percent` is fetched live
|
|
943
|
-
*
|
|
886
|
+
* general ceiling, but `progress_percent` is fetched live on every call
|
|
887
|
+
* while the run is processing, so a tighter loop costs real work.
|
|
944
888
|
*
|
|
945
889
|
* @throws {OmsApiError} 404 for a song that is not yours.
|
|
946
890
|
*/
|
|
@@ -969,18 +913,17 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
969
913
|
* End of list is a short page, as everywhere in this API. There is no count.
|
|
970
914
|
*
|
|
971
915
|
* Each row carries a whole {@link Song} with its credits, so 500 likes is a
|
|
972
|
-
* large response
|
|
973
|
-
* still bytes. 100 is the size the clients actually use.
|
|
916
|
+
* large response. 100 is a sensible size.
|
|
974
917
|
*
|
|
975
|
-
* @throws {OmsApiError} 400 `"Invalid before timestamp"` for a cursor
|
|
976
|
-
*
|
|
918
|
+
* @throws {OmsApiError} 400 `"Invalid before timestamp"` for a cursor the
|
|
919
|
+
* server cannot parse. Pass a `Date` and this cannot happen.
|
|
977
920
|
*/
|
|
978
921
|
listLiked(params?: ListLikedSongsParams, options?: RequestOptions): Promise<LikedSong[]>;
|
|
979
922
|
/**
|
|
980
923
|
* `GET /liked_songs/ids` - just the song ids, as integers.
|
|
981
924
|
*
|
|
982
|
-
* The cheap way to render heart icons over a listing. It
|
|
983
|
-
*
|
|
925
|
+
* The cheap way to render heart icons over a listing. It is a single flat
|
|
926
|
+
* list with no pagination and no cap, so it returns EVERY like in one
|
|
984
927
|
* array - which is the point, and also means it grows without bound. At a few
|
|
985
928
|
* thousand likes it is still a handful of kilobytes.
|
|
986
929
|
*
|
|
@@ -991,8 +934,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
991
934
|
/**
|
|
992
935
|
* `POST /liked_songs` - likes a track. Answers `201` with the new row.
|
|
993
936
|
*
|
|
994
|
-
* Genuinely idempotent:
|
|
995
|
-
*
|
|
937
|
+
* Genuinely idempotent: liking twice returns the same row rather than
|
|
938
|
+
* erroring or creating a duplicate.
|
|
996
939
|
* That is why this is one of the few `POST`s in the SDK that opts INTO the
|
|
997
940
|
* retry policy - a replay after a lost answer cannot produce a second like,
|
|
998
941
|
* and the alternative is a heart that silently did nothing.
|
|
@@ -1049,17 +992,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1049
992
|
* view. Cached per song, target and lyrics digest, which means the second
|
|
1050
993
|
* request for a translation is free and a lyrics refetch invalidates it.
|
|
1051
994
|
*
|
|
1052
|
-
* **Retries are disabled and this one really matters.** The hourly cap
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1055
|
-
* three further past the cap without ever getting an answer. The 429 also
|
|
995
|
+
* **Retries are disabled and this one really matters.** The hourly cap
|
|
996
|
+
* counts a rejected call too: a client that retries a 429 three times has
|
|
997
|
+
* pushed itself three further past the cap without ever getting an answer. The 429 also
|
|
1056
998
|
* carries no `Retry-After`, so the transport would back off by its own
|
|
1057
999
|
* schedule - a few hundred milliseconds - into a limit measured in hours.
|
|
1058
1000
|
* Wait out the window instead. Pass `retry` explicitly if you disagree.
|
|
1059
1001
|
*
|
|
1060
|
-
* **Two limits at once:** 60 fresh translations per user per HOUR (429,
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1002
|
+
* **Two limits at once:** 60 fresh translations per user per HOUR (429), on
|
|
1003
|
+
* top of the shared 60/min external-proxy bucket that every `/lyrics*` call
|
|
1004
|
+
* draws on.
|
|
1063
1005
|
*
|
|
1064
1006
|
* @throws {OmsQuotaError} 429 from either budget.
|
|
1065
1007
|
* @throws {OmsApiError} 400 `"Unsupported target"` for a locale outside
|
|
@@ -1074,8 +1016,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1074
1016
|
* `POST /lyrics/sync` - generates LRC timestamps for plain-text lyrics.
|
|
1075
1017
|
*
|
|
1076
1018
|
* Answers `201 { job_id }` and does the work in the background: it separates
|
|
1077
|
-
* the vocals if there are no stems, transcribes them
|
|
1078
|
-
*
|
|
1019
|
+
* the vocals if there are no stems, transcribes them and aligns the known
|
|
1020
|
+
* lines against the segments. Minutes of machine time
|
|
1079
1021
|
* per call, which is what the 10-per-hour cap is protecting.
|
|
1080
1022
|
*
|
|
1081
1023
|
* Wait for it either way: `oms.jobs.wait({ id: job_id })`, or simply re-read
|
|
@@ -1101,8 +1043,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1101
1043
|
* exceeded"`, not `429`.** Every handler that routes by status code reads
|
|
1102
1044
|
* that as a malformed query and does the worst possible thing - rewords it
|
|
1103
1045
|
* and tries again, spending more of a budget that is already gone. The limit
|
|
1104
|
-
* is 30 requests per minute per user
|
|
1105
|
-
* in rack-attack, which is why it never reaches the 429 path.
|
|
1046
|
+
* is 30 requests per minute per user.
|
|
1106
1047
|
* {@link isMusicExternalSearchRateLimited} is the check to use, and the
|
|
1107
1048
|
* transport will not retry a 400 on its own, so nothing recovers silently.
|
|
1108
1049
|
*
|
|
@@ -1120,7 +1061,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1120
1061
|
* A blank query short-circuits to three empty lists WITHOUT spending budget,
|
|
1121
1062
|
* which makes it safe to wire straight to an input. A cached hit does spend
|
|
1122
1063
|
* it: the rate check runs before the 15-minute cache is consulted. Debounce
|
|
1123
|
-
* and require two characters
|
|
1064
|
+
* and require two characters.
|
|
1124
1065
|
*
|
|
1125
1066
|
* Every failing upstream is swallowed server-side, so a partial answer and a
|
|
1126
1067
|
* complete one are indistinguishable - an empty `tracks` may mean "no
|
|
@@ -1136,13 +1077,10 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1136
1077
|
* **It never 404s.** An artist outside your roster comes back as `200` with
|
|
1137
1078
|
* every field `null` except `name`, echoed back verbatim, and
|
|
1138
1079
|
* `similar: []`. There is no error to catch and no flag to read: check
|
|
1139
|
-
* whether `id` is null. That branch also creates nothing
|
|
1140
|
-
* be handed slugs and joined display strings and would mint stub artists from
|
|
1141
|
-
* them.
|
|
1080
|
+
* whether `id` is null. That branch also creates nothing.
|
|
1142
1081
|
*
|
|
1143
1082
|
* The payload has no `created_at` / `updated_at`, unlike essentially every
|
|
1144
|
-
* other record in this API
|
|
1145
|
-
* `Blueprinter::Base` directly to pin the exact legacy key set.
|
|
1083
|
+
* other record in this API.
|
|
1146
1084
|
*
|
|
1147
1085
|
* Reading a stale artist triggers a lazy background refresh from Last.fm and
|
|
1148
1086
|
* MusicBrainz, so the first call after a while may be slower and the second
|
|
@@ -1164,7 +1102,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1164
1102
|
* Builds the query for `/songs` and `/songs/albums`.
|
|
1165
1103
|
*
|
|
1166
1104
|
* `artist_role` is deliberately TOP LEVEL and not inside `exact_search`: the
|
|
1167
|
-
*
|
|
1105
|
+
* server reads it as a plain parameter, and nesting it would both miss the
|
|
1168
1106
|
* filter and trip the unknown-key check.
|
|
1169
1107
|
*/
|
|
1170
1108
|
private songQuery;
|
|
@@ -1173,9 +1111,9 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1173
1111
|
/**
|
|
1174
1112
|
* Multipart fields for an update, with the two encoding differences fixed.
|
|
1175
1113
|
*
|
|
1176
|
-
* `null` becomes the `\b` sentinel, which
|
|
1177
|
-
* for update
|
|
1178
|
-
* other way to say "clear this
|
|
1114
|
+
* `null` becomes the `\b` sentinel, which the server decodes back to null
|
|
1115
|
+
* for update fields exactly as it does for filters - a form field has no
|
|
1116
|
+
* other way to say "clear this field". An empty `featured_artist_names`
|
|
1179
1117
|
* becomes a single empty string, because appending an empty array appends
|
|
1180
1118
|
* nothing and an absent key means the opposite thing.
|
|
1181
1119
|
*/
|