@omelhorsite/sdk 0.4.1 → 0.4.3
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/dist/index.js +58 -48
- package/dist/types/resources/account.d.ts +7 -0
- package/dist/types/resources/music/imports.d.ts +1 -115
- package/dist/types/resources/tools/captions.d.ts +13 -0
- package/dist/types/resources/tools/index.d.ts +4 -0
- package/dist/types/resources/tools/srMachine.d.ts +114 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10106,6 +10106,9 @@ class AccountSessionsNamespace extends Resource {
|
|
|
10106
10106
|
const session = await this.current(options);
|
|
10107
10107
|
await this.http.delete(`/sessions/${encodeURIComponent(session.id)}`, options);
|
|
10108
10108
|
}
|
|
10109
|
+
async revoke(id, options = {}) {
|
|
10110
|
+
await this.http.delete(`/sessions/${encodeURIComponent(id)}`, options);
|
|
10111
|
+
}
|
|
10109
10112
|
}
|
|
10110
10113
|
|
|
10111
10114
|
class AccountNamespace extends Resource {
|
|
@@ -12560,11 +12563,9 @@ function songImportProgress(record) {
|
|
|
12560
12563
|
|
|
12561
12564
|
class MusicImportsNamespace extends Resource {
|
|
12562
12565
|
spotify;
|
|
12563
|
-
srMachine;
|
|
12564
12566
|
constructor(http) {
|
|
12565
12567
|
super(http);
|
|
12566
12568
|
this.spotify = new SpotifySyncNamespace(http);
|
|
12567
|
-
this.srMachine = new SRMachineNamespace(http);
|
|
12568
12569
|
}
|
|
12569
12570
|
async list(params = {}, options = {}) {
|
|
12570
12571
|
const base = {
|
|
@@ -12658,48 +12659,6 @@ class SpotifySyncNamespace extends Resource {
|
|
|
12658
12659
|
};
|
|
12659
12660
|
}
|
|
12660
12661
|
}
|
|
12661
|
-
|
|
12662
|
-
class SRMachineNamespace extends Resource {
|
|
12663
|
-
async metadata(url, options = {}) {
|
|
12664
|
-
return this.http.get("/s_r_machine/metadata", {
|
|
12665
|
-
timeoutMs: 120000,
|
|
12666
|
-
...options,
|
|
12667
|
-
query: { url },
|
|
12668
|
-
retry: options.retry ?? false
|
|
12669
|
-
});
|
|
12670
|
-
}
|
|
12671
|
-
async artwork(url, options = {}) {
|
|
12672
|
-
return this.http.download("/s_r_machine/artwork", {
|
|
12673
|
-
timeoutMs: 120000,
|
|
12674
|
-
...options,
|
|
12675
|
-
query: { url },
|
|
12676
|
-
retry: options.retry ?? false
|
|
12677
|
-
});
|
|
12678
|
-
}
|
|
12679
|
-
async audio(url, options = {}) {
|
|
12680
|
-
return this.http.download("/s_r_machine/audio", {
|
|
12681
|
-
timeoutMs: 600000,
|
|
12682
|
-
...options,
|
|
12683
|
-
query: { url },
|
|
12684
|
-
retry: options.retry ?? false
|
|
12685
|
-
});
|
|
12686
|
-
}
|
|
12687
|
-
async convertToOpus(file2, options = {}) {
|
|
12688
|
-
const form = await buildFormData({ file: file2 });
|
|
12689
|
-
const response = await this.http.raw("POST", "/s_r_machine/convert-opus", {
|
|
12690
|
-
timeoutMs: 600000,
|
|
12691
|
-
...options,
|
|
12692
|
-
body: form
|
|
12693
|
-
});
|
|
12694
|
-
const data = await response.blob();
|
|
12695
|
-
return {
|
|
12696
|
-
data,
|
|
12697
|
-
filename: filenameFromDisposition(response.headers.get("content-disposition")),
|
|
12698
|
-
contentType: response.headers.get("content-type") ?? undefined,
|
|
12699
|
-
size: data.size
|
|
12700
|
-
};
|
|
12701
|
-
}
|
|
12702
|
-
}
|
|
12703
12662
|
function spotifySyncProgress(status) {
|
|
12704
12663
|
const playlists = status.sync_progress?.playlists ?? [];
|
|
12705
12664
|
let loaded = 0;
|
|
@@ -14818,23 +14777,29 @@ class CaptionsNamespace extends Resource {
|
|
|
14818
14777
|
return this.http.get(`/caption_jobs/${encodeURIComponent(id)}`, options);
|
|
14819
14778
|
}
|
|
14820
14779
|
async transcribe(id, input, options = {}) {
|
|
14821
|
-
const started = await this.
|
|
14780
|
+
const started = await this.startTranscribe(id, input, options);
|
|
14781
|
+
return this.settle(id, started, options, "the transcription");
|
|
14782
|
+
}
|
|
14783
|
+
async startTranscribe(id, input, options = {}) {
|
|
14784
|
+
return this.http.post(`/caption_jobs/${encodeURIComponent(id)}/transcribe`, {
|
|
14822
14785
|
start: input.start,
|
|
14823
14786
|
end: input.end,
|
|
14824
14787
|
...input.language === undefined ? {} : { language: input.language }
|
|
14825
14788
|
}, { ...options, retry: options.retry ?? false });
|
|
14826
|
-
return this.settle(id, started, options, "the transcription");
|
|
14827
14789
|
}
|
|
14828
14790
|
async render(id, input = {}, options = {}) {
|
|
14791
|
+
const started = await this.startRender(id, input, options);
|
|
14792
|
+
return this.settle(id, started, options, "the render");
|
|
14793
|
+
}
|
|
14794
|
+
async startRender(id, input = {}, options = {}) {
|
|
14829
14795
|
const words = input.words ?? (await this.get(id, options)).words ?? [];
|
|
14830
14796
|
if (words.length === 0) {
|
|
14831
14797
|
throw new OmsError(`Caption job ${id} has no words to render. Transcribe a window first with transcribe(), ` + `or pass an edited list as \`words\`.`, "conflict");
|
|
14832
14798
|
}
|
|
14833
|
-
|
|
14799
|
+
return this.http.post(`/caption_jobs/${encodeURIComponent(id)}/render`, {
|
|
14834
14800
|
words,
|
|
14835
14801
|
...input.style === undefined ? {} : { style: input.style }
|
|
14836
14802
|
}, { ...options, retry: options.retry ?? false });
|
|
14837
|
-
return this.settle(id, started, options, "the render");
|
|
14838
14803
|
}
|
|
14839
14804
|
async delete(id, options = {}) {
|
|
14840
14805
|
await this.http.delete(`/caption_jobs/${encodeURIComponent(id)}`, options);
|
|
@@ -15136,6 +15101,49 @@ class UpscaleNamespace extends Resource {
|
|
|
15136
15101
|
}
|
|
15137
15102
|
}
|
|
15138
15103
|
|
|
15104
|
+
// src/resources/tools/srMachine.ts
|
|
15105
|
+
class SRMachineNamespace extends Resource {
|
|
15106
|
+
async metadata(url, options = {}) {
|
|
15107
|
+
return this.http.get("/s_r_machine/metadata", {
|
|
15108
|
+
timeoutMs: 120000,
|
|
15109
|
+
...options,
|
|
15110
|
+
query: { url },
|
|
15111
|
+
retry: options.retry ?? false
|
|
15112
|
+
});
|
|
15113
|
+
}
|
|
15114
|
+
async artwork(url, options = {}) {
|
|
15115
|
+
return this.http.download("/s_r_machine/artwork", {
|
|
15116
|
+
timeoutMs: 120000,
|
|
15117
|
+
...options,
|
|
15118
|
+
query: { url },
|
|
15119
|
+
retry: options.retry ?? false
|
|
15120
|
+
});
|
|
15121
|
+
}
|
|
15122
|
+
async audio(url, options = {}) {
|
|
15123
|
+
return this.http.download("/s_r_machine/audio", {
|
|
15124
|
+
timeoutMs: 600000,
|
|
15125
|
+
...options,
|
|
15126
|
+
query: { url },
|
|
15127
|
+
retry: options.retry ?? false
|
|
15128
|
+
});
|
|
15129
|
+
}
|
|
15130
|
+
async convertToOpus(file2, options = {}) {
|
|
15131
|
+
const form = await buildFormData({ file: file2 });
|
|
15132
|
+
const response = await this.http.raw("POST", "/s_r_machine/convert-opus", {
|
|
15133
|
+
timeoutMs: 600000,
|
|
15134
|
+
...options,
|
|
15135
|
+
body: form
|
|
15136
|
+
});
|
|
15137
|
+
const data = await response.blob();
|
|
15138
|
+
return {
|
|
15139
|
+
data,
|
|
15140
|
+
filename: filenameFromDisposition(response.headers.get("content-disposition")),
|
|
15141
|
+
contentType: response.headers.get("content-type") ?? undefined,
|
|
15142
|
+
size: data.size
|
|
15143
|
+
};
|
|
15144
|
+
}
|
|
15145
|
+
}
|
|
15146
|
+
|
|
15139
15147
|
// src/resources/tools/vocalSeparation.ts
|
|
15140
15148
|
function vocalSeparationProgress(record) {
|
|
15141
15149
|
const base = toolProgress(record);
|
|
@@ -15267,6 +15275,7 @@ class ToolsNamespace extends Resource {
|
|
|
15267
15275
|
captions;
|
|
15268
15276
|
jumpstyle;
|
|
15269
15277
|
downloader;
|
|
15278
|
+
srMachine;
|
|
15270
15279
|
constructor(http) {
|
|
15271
15280
|
super(http);
|
|
15272
15281
|
this.backgroundRemoval = new BackgroundRemovalNamespace(http);
|
|
@@ -15276,6 +15285,7 @@ class ToolsNamespace extends Resource {
|
|
|
15276
15285
|
this.captions = new CaptionsNamespace(http);
|
|
15277
15286
|
this.jumpstyle = new JumpstyleNamespace(http);
|
|
15278
15287
|
this.downloader = new DownloaderNamespace(http);
|
|
15288
|
+
this.srMachine = new SRMachineNamespace(http);
|
|
15279
15289
|
}
|
|
15280
15290
|
}
|
|
15281
15291
|
|
|
@@ -229,6 +229,13 @@ export declare class AccountSessionsNamespace extends Resource {
|
|
|
229
229
|
* endpoint ignores it, so the call stays correct if that is ever fixed.
|
|
230
230
|
*/
|
|
231
231
|
revokeCurrent(options?: RequestOptions): Promise<void>;
|
|
232
|
+
/**
|
|
233
|
+
* `DELETE /sessions/:id` - ends one of YOUR sessions, e.g. another device's.
|
|
234
|
+
* Ending the calling session clears its cookie as well.
|
|
235
|
+
*
|
|
236
|
+
* @throws {OmsApiError} 404 for a session that is not yours or no longer exists.
|
|
237
|
+
*/
|
|
238
|
+
revoke(id: Id, options?: RequestOptions): Promise<void>;
|
|
232
239
|
}
|
|
233
240
|
/** The `account` namespace, reachable as `oms.account`. */
|
|
234
241
|
export declare class AccountNamespace extends Resource {
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* | `/song_imports` | one track, downloaded from a URL or found by search | any signed-in user |
|
|
11
11
|
* | `/playlist_imports/preview` | read a playlist URL without importing it | any signed-in user |
|
|
12
12
|
* | `/spotify_syncs/*` | mirror a Spotify account into playlists | Spotify-enabled accounts only |
|
|
13
|
-
* | `/s_r_machine/*` | raw fetch + transcode helpers | **admins only** |
|
|
14
13
|
*
|
|
15
14
|
* ## An import is not a `Job`
|
|
16
15
|
*
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
*/
|
|
49
48
|
import { type ApiClient, Resource } from "../../http";
|
|
50
49
|
import type { ListParams } from "../../listing";
|
|
51
|
-
import type { BaseRecord,
|
|
50
|
+
import type { BaseRecord, Id, Paginated, Progress, RequestOptions, Timestamp, WaitOptions } from "../../types";
|
|
52
51
|
import type { DownloaderPreview } from "../tools/downloader";
|
|
53
52
|
/**
|
|
54
53
|
* Primary key of a song import. An **integer**, like `songs` and `playlists`
|
|
@@ -314,8 +313,6 @@ export declare function songImportProgress(record: SongImport): Progress;
|
|
|
314
313
|
export declare class MusicImportsNamespace extends Resource {
|
|
315
314
|
/** Spotify account mirroring. Spotify-enabled accounts only - see the class. */
|
|
316
315
|
readonly spotify: SpotifySyncNamespace;
|
|
317
|
-
/** Admin-only fetch and transcode helpers. */
|
|
318
|
-
readonly srMachine: SRMachineNamespace;
|
|
319
316
|
constructor(http: ApiClient);
|
|
320
317
|
/**
|
|
321
318
|
* `GET /song_imports` - your import history, newest first only if you ask.
|
|
@@ -788,117 +785,6 @@ export declare class SpotifySyncNamespace extends Resource {
|
|
|
788
785
|
/** The one description of "watching a sync", shared by the two watchers. */
|
|
789
786
|
private syncPollPlan;
|
|
790
787
|
}
|
|
791
|
-
/** What `GET /s_r_machine/metadata` answers. Two keys, both nullable. */
|
|
792
|
-
export interface SRMachineMetadata {
|
|
793
|
-
readonly title: string | null;
|
|
794
|
-
readonly artist: string | null;
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* The SR Machine helpers, reachable as `oms.music.imports.srMachine`.
|
|
798
|
-
*
|
|
799
|
-
* ## Admin only, and the check is blunt
|
|
800
|
-
*
|
|
801
|
-
* Every route answers `403 "You SHALL NOT use this resource"` to anyone who is
|
|
802
|
-
* not an administrator. There is no allowlist, no scope and no per-user
|
|
803
|
-
* quota.
|
|
804
|
-
*
|
|
805
|
-
* ## What it is
|
|
806
|
-
*
|
|
807
|
-
* Four unrelated primitives left over from the "slowed + reverb" video tool:
|
|
808
|
-
* fetch the artwork behind a URL, fetch its audio, read its title and artist,
|
|
809
|
-
* and transcode an arbitrary audio blob to Opus. Nothing here touches the
|
|
810
|
-
* library - no song is created, nothing is stored, and the bytes come back in
|
|
811
|
-
* the response body. If you want a track IN the library, use
|
|
812
|
-
* {@link MusicImportsNamespace.create} instead; this is the raw pipe.
|
|
813
|
-
*
|
|
814
|
-
* Three of the four fetch a caller-supplied URL and hold a server thread while
|
|
815
|
-
* they do it, exactly like {@link MusicImportsNamespace.previewPlaylist} - but
|
|
816
|
-
* they have no budget of their own, so the only ceiling is the general
|
|
817
|
-
* 600/min. The admin gate is what stands in for a budget here. Do not build a
|
|
818
|
-
* batch loop on top of these.
|
|
819
|
-
*
|
|
820
|
-
* A YouTube URL carrying `?list=` is truncated at the `?list=` before the fetch,
|
|
821
|
-
* so a link copied from inside a playlist resolves to the single video rather
|
|
822
|
-
* than the playlist. That happens server-side, in all three fetchers.
|
|
823
|
-
*
|
|
824
|
-
* All three fetchers respond with `Content-Disposition: attachment` and a
|
|
825
|
-
* fixed filename (`artwork.jpg`, `audio.opus`), so `FileOutput.filename` is
|
|
826
|
-
* that constant rather than anything derived from the source.
|
|
827
|
-
*/
|
|
828
|
-
export declare class SRMachineNamespace extends Resource {
|
|
829
|
-
/**
|
|
830
|
-
* `GET /s_r_machine/metadata` - the title and artist read off a URL.
|
|
831
|
-
*
|
|
832
|
-
* Both keys can be `null` for a source that carries no tags; it is a
|
|
833
|
-
* best-effort read, not a lookup.
|
|
834
|
-
*
|
|
835
|
-
* Not retried by default: it parks a server thread for up to 60 seconds,
|
|
836
|
-
* and a failure means the source refused.
|
|
837
|
-
*
|
|
838
|
-
* @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
|
|
839
|
-
* non-admin.
|
|
840
|
-
* @throws {OmsApiError} 400 `"url is not allowed"` for a URL that is not
|
|
841
|
-
* public http(s); 500 when the fetch itself fails - an upstream failure
|
|
842
|
-
* surfaces as a server error here, not as a 502.
|
|
843
|
-
*/
|
|
844
|
-
metadata(url: string, options?: RequestOptions): Promise<SRMachineMetadata>;
|
|
845
|
-
/**
|
|
846
|
-
* `GET /s_r_machine/artwork` - the cover behind a URL, as `image/jpeg`.
|
|
847
|
-
*
|
|
848
|
-
* Buffered fully into memory in every runtime, React Native included. It is a
|
|
849
|
-
* cover, so that is fine; {@link SRMachineNamespace.audio} is where it is not.
|
|
850
|
-
*
|
|
851
|
-
* @throws {OmsAuthError} 403 for a non-admin.
|
|
852
|
-
* @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
|
|
853
|
-
*/
|
|
854
|
-
artwork(url: string, options?: RequestOptions): Promise<FileOutput>;
|
|
855
|
-
/**
|
|
856
|
-
* `GET /s_r_machine/audio` - the audio behind a URL, as `audio/opus`.
|
|
857
|
-
*
|
|
858
|
-
* The whole track is downloaded server-side, held in memory there, and sent
|
|
859
|
-
* back in one body which this then buffers into memory again on the client.
|
|
860
|
-
* Nothing streams. On a phone that is a whole track in the JavaScript heap,
|
|
861
|
-
* and there is no signed-URL alternative here the way there is for library
|
|
862
|
-
* media - this endpoint has no storage node behind it. Reach for it on
|
|
863
|
-
* desktop, think twice on React Native, and never for a batch.
|
|
864
|
-
*
|
|
865
|
-
* Generous `timeoutMs` by default because a long track legitimately takes
|
|
866
|
-
* minutes.
|
|
867
|
-
*
|
|
868
|
-
* @throws {OmsAuthError} 403 for a non-admin.
|
|
869
|
-
* @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
|
|
870
|
-
*/
|
|
871
|
-
audio(url: string, options?: RequestOptions): Promise<FileOutput>;
|
|
872
|
-
/**
|
|
873
|
-
* `POST /s_r_machine/convert-opus` - transcode an audio file to Opus.
|
|
874
|
-
*
|
|
875
|
-
* Multipart, field name `file`, and the only method in this namespace that
|
|
876
|
-
* uploads. The response is `audio/opus` bytes, not JSON.
|
|
877
|
-
*
|
|
878
|
-
* Works on all three runtimes: a React Native `{ uri, name, type }` descriptor
|
|
879
|
-
* goes into the `FormData` verbatim and is streamed off disk by the native
|
|
880
|
-
* layer, while a browser or Bun caller passes a `FileInput` carrying a Blob
|
|
881
|
-
* or a `Uint8Array`. A `ReadableStream` is buffered first, because
|
|
882
|
-
* `FormData` has no streaming entry.
|
|
883
|
-
*
|
|
884
|
-
* The upload has no client-side size cap here because the server declares
|
|
885
|
-
* none - but the CDN in front of the API rejects a request body over roughly
|
|
886
|
-
* 100 MB with a 413 that never reaches it. There is no chunked path for this
|
|
887
|
-
* route, so a file above that simply cannot go through it.
|
|
888
|
-
*
|
|
889
|
-
* The server reads the whole part into memory before transcoding, so a large
|
|
890
|
-
* input is a large allocation on both sides.
|
|
891
|
-
*
|
|
892
|
-
* @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
|
|
893
|
-
* non-admin.
|
|
894
|
-
* @throws {OmsApiError} 500 when no `file` part was sent or when the input
|
|
895
|
-
* cannot be transcoded. Neither is a graceful 400.
|
|
896
|
-
* @throws {TypeError} when a React Native descriptor is passed on a runtime
|
|
897
|
-
* whose `FormData` is the web one, which would otherwise upload the literal
|
|
898
|
-
* text `"[object Object]"` and answer 500.
|
|
899
|
-
*/
|
|
900
|
-
convertToOpus(file: FileInput | NativeFile, options?: RequestOptions): Promise<FileOutput>;
|
|
901
|
-
}
|
|
902
788
|
/**
|
|
903
789
|
* Renders a sync run as the SDK's shared {@link Progress}.
|
|
904
790
|
*
|
|
@@ -506,6 +506,13 @@ export declare class CaptionsNamespace extends Resource {
|
|
|
506
506
|
* quota is spent either way and the words still land on the row.
|
|
507
507
|
*/
|
|
508
508
|
transcribe(id: Id, input: TranscribeCaptionInput, options?: ToolRunOptions): Promise<CaptionJob>;
|
|
509
|
+
/**
|
|
510
|
+
* `POST /caption_jobs/:id/transcribe` without waiting: answers the row as
|
|
511
|
+
* soon as it is `"transcribing"`. For a screen that polls {@link get} itself
|
|
512
|
+
* and shows progress meanwhile. Same errors as {@link transcribe}, minus the
|
|
513
|
+
* timeouts.
|
|
514
|
+
*/
|
|
515
|
+
startTranscribe(id: Id, input: TranscribeCaptionInput, options?: RequestOptions): Promise<CaptionJob>;
|
|
509
516
|
/**
|
|
510
517
|
* `POST /caption_jobs/:id/render` - step 3.
|
|
511
518
|
*
|
|
@@ -532,6 +539,12 @@ export declare class CaptionsNamespace extends Resource {
|
|
|
532
539
|
* `code: "aborted"` when the signal fires. Neither cancels the render.
|
|
533
540
|
*/
|
|
534
541
|
render(id: Id, input?: RenderCaptionInput, options?: ToolRunOptions): Promise<CaptionJob>;
|
|
542
|
+
/**
|
|
543
|
+
* `POST /caption_jobs/:id/render` without waiting: answers the row as soon
|
|
544
|
+
* as it is `"rendering"`. Same word handling and errors as {@link render},
|
|
545
|
+
* minus the timeouts.
|
|
546
|
+
*/
|
|
547
|
+
startRender(id: Id, input?: RenderCaptionInput, options?: RequestOptions): Promise<CaptionJob>;
|
|
535
548
|
/**
|
|
536
549
|
* `DELETE /caption_jobs/:id` - drops the job and its uploaded video.
|
|
537
550
|
*
|
|
@@ -40,6 +40,7 @@ import { DownloaderNamespace } from "./downloader";
|
|
|
40
40
|
import { JumpstyleNamespace } from "./jumpstyle";
|
|
41
41
|
import { TranscriptionNamespace } from "./transcription";
|
|
42
42
|
import { UpscaleNamespace } from "./upscale";
|
|
43
|
+
import { SRMachineNamespace } from "./srMachine";
|
|
43
44
|
import { VocalSeparationNamespace } from "./vocalSeparation";
|
|
44
45
|
export * from "./backgroundRemoval";
|
|
45
46
|
export * from "./captions";
|
|
@@ -47,6 +48,7 @@ export * from "./downloader";
|
|
|
47
48
|
export * from "./jumpstyle";
|
|
48
49
|
export * from "./transcription";
|
|
49
50
|
export * from "./upscale";
|
|
51
|
+
export * from "./srMachine";
|
|
50
52
|
export * from "./vocalSeparation";
|
|
51
53
|
/**
|
|
52
54
|
* Lifecycle of a tool row.
|
|
@@ -255,5 +257,7 @@ export declare class ToolsNamespace extends Resource {
|
|
|
255
257
|
readonly jumpstyle: JumpstyleNamespace;
|
|
256
258
|
/** Fetches media from a public URL. */
|
|
257
259
|
readonly downloader: DownloaderNamespace;
|
|
260
|
+
/** Fetch, convert and package a track. Administrators only. */
|
|
261
|
+
readonly srMachine: SRMachineNamespace;
|
|
258
262
|
constructor(http: ApiClient);
|
|
259
263
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/** The `tools.srMachine` namespace: fetch a track's audio, artwork and metadata by URL, and transcode audio to Opus. Administrators only. */
|
|
2
|
+
import { Resource } from "../../http";
|
|
3
|
+
import type { FileInput, FileOutput, NativeFile, RequestOptions } from "../../types";
|
|
4
|
+
/** What `GET /s_r_machine/metadata` answers. Two keys, both nullable. */
|
|
5
|
+
export interface SRMachineMetadata {
|
|
6
|
+
readonly title: string | null;
|
|
7
|
+
readonly artist: string | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The SR Machine helpers, reachable as `oms.tools.srMachine`.
|
|
11
|
+
*
|
|
12
|
+
* ## Admin only, and the check is blunt
|
|
13
|
+
*
|
|
14
|
+
* Every route answers `403 "You SHALL NOT use this resource"` to anyone who is
|
|
15
|
+
* not an administrator. There is no allowlist, no scope and no per-user
|
|
16
|
+
* quota.
|
|
17
|
+
*
|
|
18
|
+
* ## What it is
|
|
19
|
+
*
|
|
20
|
+
* Four unrelated primitives left over from the "slowed + reverb" video tool:
|
|
21
|
+
* fetch the artwork behind a URL, fetch its audio, read its title and artist,
|
|
22
|
+
* and transcode an arbitrary audio blob to Opus. Nothing here touches the
|
|
23
|
+
* library - no song is created, nothing is stored, and the bytes come back in
|
|
24
|
+
* the response body. If you want a track IN the library, use
|
|
25
|
+
* `oms.music.imports.create()` instead; this is the raw pipe.
|
|
26
|
+
*
|
|
27
|
+
* Three of the four fetch a caller-supplied URL and hold a server thread while
|
|
28
|
+
* they do it, exactly like `oms.music.imports.previewPlaylist()` - but
|
|
29
|
+
* they have no budget of their own, so the only ceiling is the general
|
|
30
|
+
* 600/min. The admin gate is what stands in for a budget here. Do not build a
|
|
31
|
+
* batch loop on top of these.
|
|
32
|
+
*
|
|
33
|
+
* A YouTube URL carrying `?list=` is truncated at the `?list=` before the fetch,
|
|
34
|
+
* so a link copied from inside a playlist resolves to the single video rather
|
|
35
|
+
* than the playlist. That happens server-side, in all three fetchers.
|
|
36
|
+
*
|
|
37
|
+
* All three fetchers respond with `Content-Disposition: attachment` and a
|
|
38
|
+
* fixed filename (`artwork.jpg`, `audio.opus`), so `FileOutput.filename` is
|
|
39
|
+
* that constant rather than anything derived from the source.
|
|
40
|
+
*/
|
|
41
|
+
export declare class SRMachineNamespace extends Resource {
|
|
42
|
+
/**
|
|
43
|
+
* `GET /s_r_machine/metadata` - the title and artist read off a URL.
|
|
44
|
+
*
|
|
45
|
+
* Both keys can be `null` for a source that carries no tags; it is a
|
|
46
|
+
* best-effort read, not a lookup.
|
|
47
|
+
*
|
|
48
|
+
* Not retried by default: it parks a server thread for up to 60 seconds,
|
|
49
|
+
* and a failure means the source refused.
|
|
50
|
+
*
|
|
51
|
+
* @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
|
|
52
|
+
* non-admin.
|
|
53
|
+
* @throws {OmsApiError} 400 `"url is not allowed"` for a URL that is not
|
|
54
|
+
* public http(s); 500 when the fetch itself fails - an upstream failure
|
|
55
|
+
* surfaces as a server error here, not as a 502.
|
|
56
|
+
*/
|
|
57
|
+
metadata(url: string, options?: RequestOptions): Promise<SRMachineMetadata>;
|
|
58
|
+
/**
|
|
59
|
+
* `GET /s_r_machine/artwork` - the cover behind a URL, as `image/jpeg`.
|
|
60
|
+
*
|
|
61
|
+
* Buffered fully into memory in every runtime, React Native included. It is a
|
|
62
|
+
* cover, so that is fine; {@link SRMachineNamespace.audio} is where it is not.
|
|
63
|
+
*
|
|
64
|
+
* @throws {OmsAuthError} 403 for a non-admin.
|
|
65
|
+
* @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
|
|
66
|
+
*/
|
|
67
|
+
artwork(url: string, options?: RequestOptions): Promise<FileOutput>;
|
|
68
|
+
/**
|
|
69
|
+
* `GET /s_r_machine/audio` - the audio behind a URL, as `audio/opus`.
|
|
70
|
+
*
|
|
71
|
+
* The whole track is downloaded server-side, held in memory there, and sent
|
|
72
|
+
* back in one body which this then buffers into memory again on the client.
|
|
73
|
+
* Nothing streams. On a phone that is a whole track in the JavaScript heap,
|
|
74
|
+
* and there is no signed-URL alternative here the way there is for library
|
|
75
|
+
* media - this endpoint has no storage node behind it. Reach for it on
|
|
76
|
+
* desktop, think twice on React Native, and never for a batch.
|
|
77
|
+
*
|
|
78
|
+
* Generous `timeoutMs` by default because a long track legitimately takes
|
|
79
|
+
* minutes.
|
|
80
|
+
*
|
|
81
|
+
* @throws {OmsAuthError} 403 for a non-admin.
|
|
82
|
+
* @throws {OmsApiError} 400 `"url is not allowed"`; 500 on a fetch failure.
|
|
83
|
+
*/
|
|
84
|
+
audio(url: string, options?: RequestOptions): Promise<FileOutput>;
|
|
85
|
+
/**
|
|
86
|
+
* `POST /s_r_machine/convert-opus` - transcode an audio file to Opus.
|
|
87
|
+
*
|
|
88
|
+
* Multipart, field name `file`, and the only method in this namespace that
|
|
89
|
+
* uploads. The response is `audio/opus` bytes, not JSON.
|
|
90
|
+
*
|
|
91
|
+
* Works on all three runtimes: a React Native `{ uri, name, type }` descriptor
|
|
92
|
+
* goes into the `FormData` verbatim and is streamed off disk by the native
|
|
93
|
+
* layer, while a browser or Bun caller passes a `FileInput` carrying a Blob
|
|
94
|
+
* or a `Uint8Array`. A `ReadableStream` is buffered first, because
|
|
95
|
+
* `FormData` has no streaming entry.
|
|
96
|
+
*
|
|
97
|
+
* The upload has no client-side size cap here because the server declares
|
|
98
|
+
* none - but the CDN in front of the API rejects a request body over roughly
|
|
99
|
+
* 100 MB with a 413 that never reaches it. There is no chunked path for this
|
|
100
|
+
* route, so a file above that simply cannot go through it.
|
|
101
|
+
*
|
|
102
|
+
* The server reads the whole part into memory before transcoding, so a large
|
|
103
|
+
* input is a large allocation on both sides.
|
|
104
|
+
*
|
|
105
|
+
* @throws {OmsAuthError} 403 `"You SHALL NOT use this resource"` for a
|
|
106
|
+
* non-admin.
|
|
107
|
+
* @throws {OmsApiError} 500 when no `file` part was sent or when the input
|
|
108
|
+
* cannot be transcoded. Neither is a graceful 400.
|
|
109
|
+
* @throws {TypeError} when a React Native descriptor is passed on a runtime
|
|
110
|
+
* whose `FormData` is the web one, which would otherwise upload the literal
|
|
111
|
+
* text `"[object Object]"` and answer 500.
|
|
112
|
+
*/
|
|
113
|
+
convertToOpus(file: FileInput | NativeFile, options?: RequestOptions): Promise<FileOutput>;
|
|
114
|
+
}
|
package/package.json
CHANGED