@omelhorsite/sdk 0.4.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 +4 -4
- package/dist/index.js +4 -4
- 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 +1 -2
- 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 +14 -17
- 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 +110 -152
- package/dist/types/resources/chests.d.ts +27 -31
- 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 +28 -40
- package/dist/types/resources/media.d.ts +48 -61
- package/dist/types/resources/music/artists.d.ts +179 -245
- package/dist/types/resources/music/imports.d.ts +181 -210
- package/dist/types/resources/music/index.d.ts +8 -7
- package/dist/types/resources/music/playlists.d.ts +77 -110
- package/dist/types/resources/music/social.d.ts +153 -228
- package/dist/types/resources/music/songs.d.ts +160 -206
- package/dist/types/resources/realtime.d.ts +75 -88
- package/dist/types/resources/shortLinks.d.ts +33 -45
- package/dist/types/resources/storage/upload.d.ts +42 -56
- package/dist/types/resources/storage.d.ts +71 -104
- 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
|
|
@@ -77,16 +68,16 @@ import type { VocalSeparation } from "../tools/vocalSeparation";
|
|
|
77
68
|
* primary keys; `users`, `sessions`, `fs_nodes`, `playback_states` and
|
|
78
69
|
* `vocal_separations` are string uuids. Both spellings are accepted wherever a
|
|
79
70
|
* song id is taken as an argument, because a caller that read the id off a
|
|
80
|
-
*
|
|
81
|
-
* carries a number.
|
|
71
|
+
* realtime message is holding a string, but the JSON these methods RETURN
|
|
72
|
+
* always carries a number.
|
|
82
73
|
*/
|
|
83
74
|
export type SongId = number | string;
|
|
84
75
|
/** How an artist is credited on a track. */
|
|
85
76
|
export type SongArtistRole = "primary" | "featured" | "with";
|
|
86
77
|
/**
|
|
87
|
-
* One
|
|
78
|
+
* One artist credit, nested under {@link Song.artists}.
|
|
88
79
|
*
|
|
89
|
-
* `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
|
|
90
81
|
* `artist_id`. Getting those two the wrong way round is how a link to an artist
|
|
91
82
|
* page ends up pointing at a random other artist, so prefer `slug` for routing
|
|
92
83
|
* and keep `artist_id` for lookups.
|
|
@@ -98,14 +89,14 @@ export type SongArtistRole = "primary" | "featured" | "with";
|
|
|
98
89
|
* `picture_xl`) lives on the artist record.
|
|
99
90
|
*/
|
|
100
91
|
export interface SongArtistCredit extends Omit<BaseRecord, "id"> {
|
|
101
|
-
/** Id of the
|
|
92
|
+
/** Id of the credit row. NOT the artist id. */
|
|
102
93
|
readonly id: number;
|
|
103
94
|
readonly song_id: number;
|
|
104
95
|
readonly artist_id: number;
|
|
105
96
|
/** Ordering within the credits. Sort by it; the server does not. */
|
|
106
97
|
readonly position: number;
|
|
107
98
|
readonly role: SongArtistRole;
|
|
108
|
-
/** `null` only if the
|
|
99
|
+
/** `null` only if the credit outlived its artist, which the server prevents. */
|
|
109
100
|
readonly name: string | null;
|
|
110
101
|
readonly slug: string | null;
|
|
111
102
|
/** Artist avatar the user uploaded, as a storage node id. Usually `null`. */
|
|
@@ -126,15 +117,10 @@ export type SongSourceKind = "upload" | "yt_dlp" | "spotify_sync";
|
|
|
126
117
|
/**
|
|
127
118
|
* A track in the library.
|
|
128
119
|
*
|
|
129
|
-
*
|
|
130
|
-
* 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,
|
|
131
121
|
* show, update and import alike. There is no narrower view to guard against.
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* `track_number` and `disc_number` (they are optional there and always
|
|
135
|
-
* `undefined`), and neither does the legacy `artist` string column, which was
|
|
136
|
-
* dropped when `song_artists` landed. {@link Song.artists} is the only artist
|
|
137
|
-
* 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.
|
|
138
124
|
*/
|
|
139
125
|
export interface Song extends Omit<BaseRecord, "id"> {
|
|
140
126
|
/** Integer primary key. See {@link SongId}. */
|
|
@@ -181,7 +167,7 @@ export interface Song extends Omit<BaseRecord, "id"> {
|
|
|
181
167
|
/**
|
|
182
168
|
* Stamped when a separation starts and cleared when it settles, so a
|
|
183
169
|
* non-null value means "a separation is in flight". It can go stale if a
|
|
184
|
-
*
|
|
170
|
+
* run dies; `GET /songs/:id/separation` clears it as a side effect, which
|
|
185
171
|
* is one reason to poll that route rather than re-reading the song.
|
|
186
172
|
*/
|
|
187
173
|
readonly vocal_separation_started_at: Timestamp | null;
|
|
@@ -220,8 +206,8 @@ export interface Song extends Omit<BaseRecord, "id"> {
|
|
|
220
206
|
/**
|
|
221
207
|
* A row of `GET /songs/albums`.
|
|
222
208
|
*
|
|
223
|
-
* Not a
|
|
224
|
-
*
|
|
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
|
|
225
211
|
* album, and it is a legitimate row rather than an error.
|
|
226
212
|
*/
|
|
227
213
|
export interface SongAlbumSummary {
|
|
@@ -262,8 +248,7 @@ export interface SongSeparationStatus {
|
|
|
262
248
|
* The run itself, or `null` when this song has never had one.
|
|
263
249
|
*
|
|
264
250
|
* The same `VocalSeparation` record the `tools.vocalSeparation` namespace
|
|
265
|
-
* returns
|
|
266
|
-
* 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
|
|
267
252
|
* `instrumental_url` are permanently `null`: the stems are written onto the
|
|
268
253
|
* song as storage nodes, not attached to this row.
|
|
269
254
|
*/
|
|
@@ -277,7 +262,7 @@ export interface LikedSong extends Omit<BaseRecord, "id"> {
|
|
|
277
262
|
readonly song_id: number;
|
|
278
263
|
/** The cursor {@link ListLikedSongsParams.before} pages on. */
|
|
279
264
|
readonly liked_at: Timestamp;
|
|
280
|
-
/** Always present
|
|
265
|
+
/** Always present. */
|
|
281
266
|
readonly song: Song;
|
|
282
267
|
}
|
|
283
268
|
/** Lyrics for one track. */
|
|
@@ -317,10 +302,8 @@ export interface ArtistMetadataSimilar {
|
|
|
317
302
|
/**
|
|
318
303
|
* The legacy payload `GET /artist_metadata/:name` answers with.
|
|
319
304
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* with NO `created_at` / `updated_at`. It also never 404s - see
|
|
323
|
-
* {@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}.
|
|
324
307
|
*/
|
|
325
308
|
export interface ArtistMetadata {
|
|
326
309
|
/** `null` on the not-found branch. Integer when the artist exists. */
|
|
@@ -358,10 +341,9 @@ export interface ArtistMetadata {
|
|
|
358
341
|
/**
|
|
359
342
|
* Where an external-search hit came from.
|
|
360
343
|
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* 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.
|
|
365
347
|
*/
|
|
366
348
|
export type MusicExternalSource = "spotify" | "itunes" | "youtube" | "soundcloud" | "bandcamp";
|
|
367
349
|
/** What to ask the external providers for. */
|
|
@@ -428,9 +410,9 @@ export interface SongFilters {
|
|
|
428
410
|
/**
|
|
429
411
|
* Partial title match, sent as `search[title]`.
|
|
430
412
|
*
|
|
431
|
-
* The comparison is slug-shaped: the server lowercases, strips accents
|
|
432
|
-
*
|
|
433
|
-
*
|
|
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
|
|
434
416
|
* "Café", `"nao quero"` finds "Não Quero", and punctuation is irrelevant. It
|
|
435
417
|
* is not a full-text index and there is no ranking.
|
|
436
418
|
*
|
|
@@ -441,9 +423,8 @@ export interface SongFilters {
|
|
|
441
423
|
readonly title?: string;
|
|
442
424
|
/**
|
|
443
425
|
* Exact album, sent as `exact_search[album]`. Pass `null` for the no-album
|
|
444
|
-
* bucket: the transport encodes it as the
|
|
445
|
-
*
|
|
446
|
-
* 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.
|
|
447
428
|
*
|
|
448
429
|
* Not a substring match. `search[album]` exists and IS partial, but it can
|
|
449
430
|
* never express the null bucket, so this field takes the exact route and the
|
|
@@ -457,10 +438,9 @@ export interface SongFilters {
|
|
|
457
438
|
/**
|
|
458
439
|
* Narrow to one artist, by canonical name OR by slug.
|
|
459
440
|
*
|
|
460
|
-
* This one is not a column and does not behave like the others. The
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* `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:
|
|
464
444
|
*
|
|
465
445
|
* - it is EXACT even though it is spelled like a search. `search[artist]`
|
|
466
446
|
* and `exact_search[artist]` are the same code path; there is no partial
|
|
@@ -468,8 +448,7 @@ export interface SongFilters {
|
|
|
468
448
|
* filter client-side or go through `oms.music.artists`;
|
|
469
449
|
* - an artist you do not have resolves to nothing and yields an EMPTY list,
|
|
470
450
|
* not a 404 and not an error. An empty page is genuinely ambiguous here;
|
|
471
|
-
* - it changes what {@link MusicSongsNamespace.albums} deduplicates on
|
|
472
|
-
* is the point of that endpoint's `filter_artist_id`.
|
|
451
|
+
* - it changes what {@link MusicSongsNamespace.albums} deduplicates on.
|
|
473
452
|
*/
|
|
474
453
|
readonly artist?: string;
|
|
475
454
|
/**
|
|
@@ -490,23 +469,21 @@ export interface ListSongsParams extends SongFilters, ListParams<(typeof SONG_FI
|
|
|
490
469
|
* Defaults to `"created_at:asc"`, which is also the endpoint's own base
|
|
491
470
|
* order and the one that makes paging stable. Two traps:
|
|
492
471
|
*
|
|
493
|
-
* - a column the
|
|
494
|
-
* is an allowed key so the request is not rejected
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
* `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.
|
|
502
480
|
*
|
|
503
481
|
* A third `:`-separated segment pins specific values first
|
|
504
|
-
* (`"album:asc:Clube da Esquina,Acabou Chorare"`)
|
|
505
|
-
* `SELECT DISTINCT` over the column.
|
|
482
|
+
* (`"album:asc:Clube da Esquina,Acabou Chorare"`).
|
|
506
483
|
*/
|
|
507
484
|
readonly order?: string;
|
|
508
485
|
/**
|
|
509
|
-
* `modifiers[random]=true` - shuffle server-side
|
|
486
|
+
* `modifiers[random]=true` - shuffle server-side.
|
|
510
487
|
*
|
|
511
488
|
* Mutually destructive with paging: the ordering is re-evaluated per request,
|
|
512
489
|
* so page 2 of a random listing is a fresh shuffle and shares rows with page
|
|
@@ -529,7 +506,7 @@ export interface ListSongAlbumsParams extends SongFilters, ListParams<(typeof SO
|
|
|
529
506
|
/**
|
|
530
507
|
* Fields {@link MusicSongsNamespace.update} can change.
|
|
531
508
|
*
|
|
532
|
-
* Four real
|
|
509
|
+
* Four real fields and three virtual inputs. The virtual ones are the
|
|
533
510
|
* complicated half; each carries its own note.
|
|
534
511
|
*/
|
|
535
512
|
export interface UpdateSongInput {
|
|
@@ -545,14 +522,14 @@ export interface UpdateSongInput {
|
|
|
545
522
|
* there is no comma-splitting heuristic, so a name that genuinely contains a
|
|
546
523
|
* comma survives.
|
|
547
524
|
*
|
|
548
|
-
* An EMPTY array is not "remove every artist":
|
|
549
|
-
*
|
|
550
|
-
*
|
|
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.
|
|
551
528
|
*/
|
|
552
529
|
readonly artistNames?: string[];
|
|
553
530
|
/**
|
|
554
531
|
* The featured credits, replacing whatever is there. Sending this key at all
|
|
555
|
-
* is what switches the
|
|
532
|
+
* is what switches the server out of its legacy mode.
|
|
556
533
|
*
|
|
557
534
|
* That legacy mode is a heuristic over the TITLE: with no `featured_artist_
|
|
558
535
|
* names` key present, the server re-reads `"Song (feat. X)"` and rebuilds the
|
|
@@ -568,7 +545,7 @@ export interface UpdateSongInput {
|
|
|
568
545
|
/**
|
|
569
546
|
* Legacy single-line artist input, re-parsed server-side (it splits on
|
|
570
547
|
* commas and on "feat."). Prefer {@link UpdateSongInput.artistNames}; this
|
|
571
|
-
* exists for
|
|
548
|
+
* exists for compatibility.
|
|
572
549
|
*/
|
|
573
550
|
readonly artist?: string;
|
|
574
551
|
/**
|
|
@@ -593,16 +570,15 @@ export interface ListLikedSongsParams {
|
|
|
593
570
|
*
|
|
594
571
|
* Deliberately not an offset. The list is ordered by `liked_at` descending
|
|
595
572
|
* and liking one track mid-scroll shifts every later offset page by one,
|
|
596
|
-
* which shows a duplicate and hides a row. A `Date` is encoded as ISO-8601
|
|
597
|
-
*
|
|
598
|
-
* `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"`.
|
|
599
575
|
*/
|
|
600
576
|
readonly before?: string | Date;
|
|
601
577
|
}
|
|
602
578
|
/** Arguments for {@link MusicSongsNamespace.startSeparation}. */
|
|
603
579
|
export interface StartSongSeparationInput {
|
|
604
580
|
/**
|
|
605
|
-
* Which
|
|
581
|
+
* Which separation model to run. Omit for the default. The selectable list is
|
|
606
582
|
* `oms.tools.vocalSeparation.models()`; an id that is not on it is a
|
|
607
583
|
* `400 "Unknown model"`.
|
|
608
584
|
*/
|
|
@@ -624,9 +600,8 @@ export interface ModifySongMetadataInput {
|
|
|
624
600
|
/** The file to retag. Hard cap 50 MiB, enforced before anything else happens. */
|
|
625
601
|
readonly audio: FileInput | NativeFile;
|
|
626
602
|
/**
|
|
627
|
-
* At least one tag is REQUIRED. An empty bag
|
|
628
|
-
*
|
|
629
|
-
* 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.
|
|
630
605
|
*/
|
|
631
606
|
readonly metadata: SongFileMetadata;
|
|
632
607
|
}
|
|
@@ -668,14 +643,14 @@ export declare function isMusicExternalSearchRateLimited(error: unknown): boolea
|
|
|
668
643
|
* `"Chico Buarque, Milton Nascimento (feat. Elis Regina)"`: primaries joined
|
|
669
644
|
* with `", "`, then a `feat.` clause. Pure string building, no request.
|
|
670
645
|
*
|
|
671
|
-
* `with` credits are excluded unless `includeWith` is set
|
|
672
|
-
*
|
|
673
|
-
*
|
|
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.
|
|
674
649
|
*
|
|
675
|
-
* Written here because {@link Song.artists} arrives UNSORTED and
|
|
676
|
-
*
|
|
677
|
-
*
|
|
678
|
-
*
|
|
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.
|
|
679
654
|
*/
|
|
680
655
|
export declare function songArtistsLine(song: Pick<Song, "artists"> & Partial<Pick<Song, "artist_names">>, includeWith?: boolean): string;
|
|
681
656
|
/** The `music.songs` namespace, reachable as `oms.music.songs`. */
|
|
@@ -683,15 +658,13 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
683
658
|
/**
|
|
684
659
|
* `GET /songs` - the caller's library, oldest first.
|
|
685
660
|
*
|
|
686
|
-
* Pagination is FORCED here and nowhere else in this namespace:
|
|
687
|
-
*
|
|
688
|
-
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
*
|
|
693
|
-
* and {@link Paginated.pageSize} always reports the size the rows were
|
|
694
|
-
* 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.
|
|
695
668
|
*
|
|
696
669
|
* Order defaults to `created_at:asc`, the endpoint's own base order, which is
|
|
697
670
|
* what makes a paged walk stable. See {@link ListSongsParams.order} before
|
|
@@ -704,14 +677,12 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
704
677
|
* @throws {OmsAuthError} 401 when anonymous, 403 for an OAuth token.
|
|
705
678
|
* @throws {OmsApiError} 400 naming the offending key when a filter is not in
|
|
706
679
|
* {@link SONG_FILTER_COLUMNS}. Filters fail closed on purpose: silently
|
|
707
|
-
* dropping an unknown one
|
|
680
|
+
* dropping an unknown one would answer with the UNFILTERED set.
|
|
708
681
|
*/
|
|
709
682
|
list(params?: ListSongsParams, options?: RequestOptions): Promise<Paginated<Song>>;
|
|
710
683
|
/**
|
|
711
|
-
* `GET /songs/:id` - one track.
|
|
712
|
-
*
|
|
713
|
-
* Renders the `:extended` view, which `SongBlueprint` leaves identical to the
|
|
714
|
-
* 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.
|
|
715
686
|
*
|
|
716
687
|
* @throws {OmsApiError} 404 `"Resource not found"` - for an id that does not
|
|
717
688
|
* exist AND for one that belongs to somebody else, indistinguishably. The
|
|
@@ -722,18 +693,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
722
693
|
* `PATCH /songs/:id` - edits metadata, and optionally replaces the artwork.
|
|
723
694
|
*
|
|
724
695
|
* JSON normally; multipart as soon as {@link UpdateSongInput.artwork} is
|
|
725
|
-
* present, because that is the only way to carry a file. Both encodings
|
|
726
|
-
* the same
|
|
727
|
-
* where they would otherwise
|
|
728
|
-
*
|
|
729
|
-
* - **clearing a
|
|
730
|
-
* there is no `null` to send. The
|
|
731
|
-
* update
|
|
732
|
-
* as that one character and clears the
|
|
733
|
-
* claims multipart cannot express this and splits the request in two; it
|
|
734
|
-
* 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.
|
|
735
704
|
* - **an empty `featuredArtistNames`.** Appending an empty array appends
|
|
736
|
-
* nothing, and an absent key is what puts the
|
|
705
|
+
* nothing, and an absent key is what puts the server back into its
|
|
737
706
|
* title-parsing legacy mode - the opposite of what "no featured artists"
|
|
738
707
|
* means. This sends the single empty string the server reads as an explicit
|
|
739
708
|
* empty list.
|
|
@@ -742,8 +711,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
742
711
|
* credits you did not touch. Send `featuredArtistNames` whenever you care
|
|
743
712
|
* about them.
|
|
744
713
|
*
|
|
745
|
-
* @throws {OmsAuthError} 401 when the song is not yours -
|
|
746
|
-
* `updatable_by?` and answers 401, not 403 or 404.
|
|
714
|
+
* @throws {OmsAuthError} 401 when the song is not yours - not 403 or 404.
|
|
747
715
|
* @throws {OmsApiError} 400 `"Music storage quota exceeded"` when the artwork
|
|
748
716
|
* would not fit in the music quota.
|
|
749
717
|
*/
|
|
@@ -768,20 +736,20 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
768
736
|
*
|
|
769
737
|
* Answers **200**, not 201, with the created song. Do not branch on the code.
|
|
770
738
|
*
|
|
771
|
-
* Two size limits and they are not the same one.
|
|
772
|
-
* {@link SONG_IMPORT_MAX_BYTES} (1 GiB) with a 400 - but
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
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.
|
|
777
745
|
*
|
|
778
746
|
* On React Native pass the picker's `{ uri, name, type }` object directly -
|
|
779
747
|
* it is appended verbatim and streamed off disk by the native layer.
|
|
780
748
|
*
|
|
781
749
|
* @throws {OmsApiError} 400 for a missing file, a file over 1 GiB, an
|
|
782
750
|
* extension outside {@link SONG_IMPORT_EXTENSIONS}, or
|
|
783
|
-
* `"Music storage quota exceeded"`; 415 with
|
|
784
|
-
*
|
|
751
|
+
* `"Music storage quota exceeded"`; 415 with validation messages when the
|
|
752
|
+
* audio itself will not import.
|
|
785
753
|
*/
|
|
786
754
|
import(file: FileInput | NativeFile, options?: RequestOptions): Promise<Song>;
|
|
787
755
|
/**
|
|
@@ -790,10 +758,9 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
790
758
|
* Takes the same filters as {@link list}, and is the endpoint every album
|
|
791
759
|
* grid is built on. It is also the most expensive read in this namespace, for
|
|
792
760
|
* a reason worth understanding: the forced pagination that protects
|
|
793
|
-
* `GET /songs`
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
* 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.
|
|
797
764
|
*
|
|
798
765
|
* Paging it does not fix that and is usually a mistake:
|
|
799
766
|
* {@link ListSongAlbumsParams.page} pages the SONGS that get scanned, and the
|
|
@@ -814,8 +781,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
814
781
|
*
|
|
815
782
|
* A flat array of strings, ordered by name, and that is the whole payload.
|
|
816
783
|
*
|
|
817
|
-
* It IGNORES every filter you could send it:
|
|
818
|
-
*
|
|
784
|
+
* It IGNORES every filter you could send it: it reads names straight off the
|
|
785
|
+
* roster. This method
|
|
819
786
|
* therefore takes no parameters at all rather than accepting some that would
|
|
820
787
|
* do nothing. It also does not go through `/artists`, so despite the shared
|
|
821
788
|
* subject it does NOT spend the 60/min external-proxy budget.
|
|
@@ -830,9 +797,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
830
797
|
* artist you already have.
|
|
831
798
|
*
|
|
832
799
|
* Lookup only: an artist absent from your roster returns `[]` and no stub row
|
|
833
|
-
* is created, which is deliberate -
|
|
834
|
-
*
|
|
835
|
-
* 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.
|
|
836
802
|
*
|
|
837
803
|
* The array holds zero or one entry. Zero means either "not your artist" or
|
|
838
804
|
* "Deezer has never given us a picture for them", and the two are not
|
|
@@ -854,8 +820,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
854
820
|
*
|
|
855
821
|
* The odd one out in this namespace: it writes nothing to the library, reads
|
|
856
822
|
* nothing from it, and answers with BINARY rather than JSON. The file is
|
|
857
|
-
* remuxed with
|
|
858
|
-
*
|
|
823
|
+
* remuxed with the new tags (the audio is never re-encoded) and, when given
|
|
824
|
+
* one, an embedded cover.
|
|
859
825
|
*
|
|
860
826
|
* The result is buffered fully into memory in every runtime. That is
|
|
861
827
|
* unavoidable - there is no URL to hand a downloader - but it means a 50 MiB
|
|
@@ -863,17 +829,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
863
829
|
* the server suggested in `Content-Disposition`.
|
|
864
830
|
*
|
|
865
831
|
* At least one tag must be present, and this method enforces that locally
|
|
866
|
-
* because the server does not fail gracefully: an empty `metadata`
|
|
867
|
-
*
|
|
868
|
-
* 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.
|
|
869
834
|
*
|
|
870
|
-
*
|
|
871
|
-
*
|
|
835
|
+
* `metadata[track_number]` is dropped in silence server-side, so it is not
|
|
836
|
+
* offered here.
|
|
872
837
|
*
|
|
873
838
|
* @throws {TypeError} when `metadata` carries no usable tag.
|
|
874
839
|
* @throws {OmsApiError} 413 `"File too big"` above
|
|
875
840
|
* {@link SONG_METADATA_MAX_BYTES}, checked before the body is read. Note
|
|
876
|
-
* that
|
|
841
|
+
* that the CDN's own ~100 MB body limit sits above it and never fires
|
|
877
842
|
* first.
|
|
878
843
|
*/
|
|
879
844
|
modifyMetadata(input: ModifySongMetadataInput, options?: RequestOptions): Promise<FileOutput>;
|
|
@@ -886,18 +851,14 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
886
851
|
* enqueued. So there is no need to guard the call site - but also no way to
|
|
887
852
|
* force a re-run without deleting the stems first.
|
|
888
853
|
*
|
|
889
|
-
* **Rate limit:** 20 requests per minute, from
|
|
890
|
-
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
* sidecar; a load generator that walked a library firing one separation per
|
|
894
|
-
* song pushed the machine into swap, which is exactly what this budget now
|
|
895
|
-
* 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.
|
|
896
858
|
*
|
|
897
859
|
* The run itself is asynchronous. Poll {@link separation} roughly every three
|
|
898
860
|
* seconds; the returned row's `status` moves `pending` to `processing` to
|
|
899
|
-
* `complete` or `failed`, and there is no `canceled
|
|
900
|
-
* frontend's own type says.
|
|
861
|
+
* `complete` or `failed`, and there is no `canceled`.
|
|
901
862
|
*
|
|
902
863
|
* @throws {OmsQuotaError} 429 when the shared expensive-tools budget is spent.
|
|
903
864
|
* @throws {OmsAuthError} 401 when the song is not yours.
|
|
@@ -915,16 +876,15 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
915
876
|
* `complete` a moment before the stems are attached, and a song can have
|
|
916
877
|
* stems from a run that was swept long ago.
|
|
917
878
|
*
|
|
918
|
-
* Reading this has a SIDE EFFECT, and it is a useful one:
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
* 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
|
|
922
882
|
* separation is in flight" from the song record alone can therefore be stuck
|
|
923
883
|
* on a spinner that only this call will clear.
|
|
924
884
|
*
|
|
925
885
|
* Poll at about three seconds. Nothing on this route is throttled beyond the
|
|
926
|
-
* general ceiling, but `progress_percent` is fetched live
|
|
927
|
-
*
|
|
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.
|
|
928
888
|
*
|
|
929
889
|
* @throws {OmsApiError} 404 for a song that is not yours.
|
|
930
890
|
*/
|
|
@@ -953,18 +913,17 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
953
913
|
* End of list is a short page, as everywhere in this API. There is no count.
|
|
954
914
|
*
|
|
955
915
|
* Each row carries a whole {@link Song} with its credits, so 500 likes is a
|
|
956
|
-
* large response
|
|
957
|
-
* still bytes. 100 is the size the clients actually use.
|
|
916
|
+
* large response. 100 is a sensible size.
|
|
958
917
|
*
|
|
959
|
-
* @throws {OmsApiError} 400 `"Invalid before timestamp"` for a cursor
|
|
960
|
-
*
|
|
918
|
+
* @throws {OmsApiError} 400 `"Invalid before timestamp"` for a cursor the
|
|
919
|
+
* server cannot parse. Pass a `Date` and this cannot happen.
|
|
961
920
|
*/
|
|
962
921
|
listLiked(params?: ListLikedSongsParams, options?: RequestOptions): Promise<LikedSong[]>;
|
|
963
922
|
/**
|
|
964
923
|
* `GET /liked_songs/ids` - just the song ids, as integers.
|
|
965
924
|
*
|
|
966
|
-
* The cheap way to render heart icons over a listing. It
|
|
967
|
-
*
|
|
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
|
|
968
927
|
* array - which is the point, and also means it grows without bound. At a few
|
|
969
928
|
* thousand likes it is still a handful of kilobytes.
|
|
970
929
|
*
|
|
@@ -975,8 +934,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
975
934
|
/**
|
|
976
935
|
* `POST /liked_songs` - likes a track. Answers `201` with the new row.
|
|
977
936
|
*
|
|
978
|
-
* Genuinely idempotent:
|
|
979
|
-
*
|
|
937
|
+
* Genuinely idempotent: liking twice returns the same row rather than
|
|
938
|
+
* erroring or creating a duplicate.
|
|
980
939
|
* That is why this is one of the few `POST`s in the SDK that opts INTO the
|
|
981
940
|
* retry policy - a replay after a lost answer cannot produce a second like,
|
|
982
941
|
* and the alternative is a heart that silently did nothing.
|
|
@@ -1033,17 +992,16 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1033
992
|
* view. Cached per song, target and lyrics digest, which means the second
|
|
1034
993
|
* request for a translation is free and a lyrics refetch invalidates it.
|
|
1035
994
|
*
|
|
1036
|
-
* **Retries are disabled and this one really matters.** The hourly cap
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
* 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
|
|
1040
998
|
* carries no `Retry-After`, so the transport would back off by its own
|
|
1041
999
|
* schedule - a few hundred milliseconds - into a limit measured in hours.
|
|
1042
1000
|
* Wait out the window instead. Pass `retry` explicitly if you disagree.
|
|
1043
1001
|
*
|
|
1044
|
-
* **Two limits at once:** 60 fresh translations per user per HOUR (429,
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
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.
|
|
1047
1005
|
*
|
|
1048
1006
|
* @throws {OmsQuotaError} 429 from either budget.
|
|
1049
1007
|
* @throws {OmsApiError} 400 `"Unsupported target"` for a locale outside
|
|
@@ -1058,8 +1016,8 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1058
1016
|
* `POST /lyrics/sync` - generates LRC timestamps for plain-text lyrics.
|
|
1059
1017
|
*
|
|
1060
1018
|
* Answers `201 { job_id }` and does the work in the background: it separates
|
|
1061
|
-
* the vocals if there are no stems, transcribes them
|
|
1062
|
-
*
|
|
1019
|
+
* the vocals if there are no stems, transcribes them and aligns the known
|
|
1020
|
+
* lines against the segments. Minutes of machine time
|
|
1063
1021
|
* per call, which is what the 10-per-hour cap is protecting.
|
|
1064
1022
|
*
|
|
1065
1023
|
* Wait for it either way: `oms.jobs.wait({ id: job_id })`, or simply re-read
|
|
@@ -1085,8 +1043,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1085
1043
|
* exceeded"`, not `429`.** Every handler that routes by status code reads
|
|
1086
1044
|
* that as a malformed query and does the worst possible thing - rewords it
|
|
1087
1045
|
* and tries again, spending more of a budget that is already gone. The limit
|
|
1088
|
-
* is 30 requests per minute per user
|
|
1089
|
-
* in rack-attack, which is why it never reaches the 429 path.
|
|
1046
|
+
* is 30 requests per minute per user.
|
|
1090
1047
|
* {@link isMusicExternalSearchRateLimited} is the check to use, and the
|
|
1091
1048
|
* transport will not retry a 400 on its own, so nothing recovers silently.
|
|
1092
1049
|
*
|
|
@@ -1104,7 +1061,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1104
1061
|
* A blank query short-circuits to three empty lists WITHOUT spending budget,
|
|
1105
1062
|
* which makes it safe to wire straight to an input. A cached hit does spend
|
|
1106
1063
|
* it: the rate check runs before the 15-minute cache is consulted. Debounce
|
|
1107
|
-
* and require two characters
|
|
1064
|
+
* and require two characters.
|
|
1108
1065
|
*
|
|
1109
1066
|
* Every failing upstream is swallowed server-side, so a partial answer and a
|
|
1110
1067
|
* complete one are indistinguishable - an empty `tracks` may mean "no
|
|
@@ -1120,13 +1077,10 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1120
1077
|
* **It never 404s.** An artist outside your roster comes back as `200` with
|
|
1121
1078
|
* every field `null` except `name`, echoed back verbatim, and
|
|
1122
1079
|
* `similar: []`. There is no error to catch and no flag to read: check
|
|
1123
|
-
* whether `id` is null. That branch also creates nothing
|
|
1124
|
-
* be handed slugs and joined display strings and would mint stub artists from
|
|
1125
|
-
* them.
|
|
1080
|
+
* whether `id` is null. That branch also creates nothing.
|
|
1126
1081
|
*
|
|
1127
1082
|
* The payload has no `created_at` / `updated_at`, unlike essentially every
|
|
1128
|
-
* other record in this API
|
|
1129
|
-
* `Blueprinter::Base` directly to pin the exact legacy key set.
|
|
1083
|
+
* other record in this API.
|
|
1130
1084
|
*
|
|
1131
1085
|
* Reading a stale artist triggers a lazy background refresh from Last.fm and
|
|
1132
1086
|
* MusicBrainz, so the first call after a while may be slower and the second
|
|
@@ -1148,7 +1102,7 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1148
1102
|
* Builds the query for `/songs` and `/songs/albums`.
|
|
1149
1103
|
*
|
|
1150
1104
|
* `artist_role` is deliberately TOP LEVEL and not inside `exact_search`: the
|
|
1151
|
-
*
|
|
1105
|
+
* server reads it as a plain parameter, and nesting it would both miss the
|
|
1152
1106
|
* filter and trip the unknown-key check.
|
|
1153
1107
|
*/
|
|
1154
1108
|
private songQuery;
|
|
@@ -1157,9 +1111,9 @@ export declare class MusicSongsNamespace extends Resource {
|
|
|
1157
1111
|
/**
|
|
1158
1112
|
* Multipart fields for an update, with the two encoding differences fixed.
|
|
1159
1113
|
*
|
|
1160
|
-
* `null` becomes the `\b` sentinel, which
|
|
1161
|
-
* for update
|
|
1162
|
-
* 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`
|
|
1163
1117
|
* becomes a single empty string, because appending an empty array appends
|
|
1164
1118
|
* nothing and an absent key means the opposite thing.
|
|
1165
1119
|
*/
|