ziplayer 0.2.1 → 0.2.3-dev-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/dist/structures/FilterManager.d.ts +1 -0
- package/dist/structures/FilterManager.d.ts.map +1 -1
- package/dist/structures/FilterManager.js +49 -10
- package/dist/structures/FilterManager.js.map +1 -1
- package/dist/structures/Player.d.ts +15 -2
- package/dist/structures/Player.d.ts.map +1 -1
- package/dist/structures/Player.js +123 -37
- package/dist/structures/Player.js.map +1 -1
- package/dist/types/extension.d.ts +114 -0
- package/dist/types/extension.d.ts.map +1 -0
- package/dist/types/extension.js +3 -0
- package/dist/types/extension.js.map +1 -0
- package/dist/types/fillter.d.ts +44 -0
- package/dist/types/fillter.d.ts.map +1 -0
- package/dist/types/fillter.js +226 -0
- package/dist/types/fillter.js.map +1 -0
- package/dist/types/index.d.ts +14 -209
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +17 -223
- package/dist/types/index.js.map +1 -1
- package/dist/types/plugin.d.ts +58 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +21 -0
- package/dist/types/plugin.js.map +1 -0
- package/package.json +7 -2
- package/src/structures/FilterManager.ts +303 -262
- package/src/structures/Player.ts +135 -41
- package/src/types/extension.ts +129 -0
- package/src/types/fillter.ts +264 -0
- package/src/types/index.ts +15 -443
- package/src/types/plugin.ts +57 -0
- package/dist/plugins/SoundCloudPlugin.d.ts +0 -22
- package/dist/plugins/SoundCloudPlugin.d.ts.map +0 -1
- package/dist/plugins/SoundCloudPlugin.js +0 -171
- package/dist/plugins/SoundCloudPlugin.js.map +0 -1
- package/dist/plugins/SpotifyPlugin.d.ts +0 -26
- package/dist/plugins/SpotifyPlugin.d.ts.map +0 -1
- package/dist/plugins/SpotifyPlugin.js +0 -183
- package/dist/plugins/SpotifyPlugin.js.map +0 -1
- package/dist/plugins/YouTubePlugin.d.ts +0 -25
- package/dist/plugins/YouTubePlugin.d.ts.map +0 -1
- package/dist/plugins/YouTubePlugin.js +0 -314
- package/dist/plugins/YouTubePlugin.js.map +0 -1
package/src/structures/Player.ts
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
StreamType,
|
|
14
14
|
} from "@discordjs/voice";
|
|
15
15
|
|
|
16
|
-
import { VoiceChannel } from "discord.js";
|
|
17
16
|
import { Readable } from "stream";
|
|
18
17
|
import type { BaseExtension } from "../extensions";
|
|
19
18
|
import type {
|
|
@@ -26,6 +25,7 @@ import type {
|
|
|
26
25
|
LoopMode,
|
|
27
26
|
StreamInfo,
|
|
28
27
|
SaveOptions,
|
|
28
|
+
VoiceChannel,
|
|
29
29
|
ExtensionPlayRequest,
|
|
30
30
|
ExtensionPlayResponse,
|
|
31
31
|
ExtensionAfterPlayPayload,
|
|
@@ -160,6 +160,25 @@ export class Player extends EventEmitter {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Destroy current stream to prevent memory leaks
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
private destroyCurrentStream(): void {
|
|
168
|
+
try {
|
|
169
|
+
// Get the metadata from current resource to find the stream
|
|
170
|
+
if (this.currentResource) {
|
|
171
|
+
const stream = (this.currentResource as any)?.metadata?.stream || (this.currentResource as any)?.stream;
|
|
172
|
+
if (stream && typeof stream.destroy === "function") {
|
|
173
|
+
stream.destroy();
|
|
174
|
+
this.debug(`[Player] Destroyed current stream`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
this.debug(`[Player] Error destroying current stream:`, error);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
163
182
|
//#region Search
|
|
164
183
|
|
|
165
184
|
/**
|
|
@@ -335,13 +354,21 @@ export class Player extends EventEmitter {
|
|
|
335
354
|
};
|
|
336
355
|
}
|
|
337
356
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Get related tracks for a given track
|
|
359
|
+
* @param {Track} track Track to find related tracks for
|
|
360
|
+
* @returns {Track[]} Related tracks or empty array
|
|
361
|
+
* @example
|
|
362
|
+
* const related = await player.getRelatedTracks(track);
|
|
363
|
+
* console.log(`Found ${related.length} related tracks`);
|
|
364
|
+
*/
|
|
365
|
+
async getRelatedTracks(track: Track): Promise<Track[]> {
|
|
366
|
+
if (!track) return [];
|
|
367
|
+
|
|
368
|
+
const preferred = this.pluginManager.findPlugin(track.url) || this.pluginManager.get(track.source);
|
|
341
369
|
|
|
342
|
-
// Build list of candidate plugins: preferred first, then others with getRelatedTracks
|
|
343
|
-
const preferred = this.pluginManager.findPlugin(lastTrack.url) || this.pluginManager.get(lastTrack.source);
|
|
344
370
|
const all = this.pluginManager.getAll();
|
|
371
|
+
|
|
345
372
|
const candidates = [...(preferred ? [preferred] : []), ...all.filter((p) => p !== preferred)].filter(
|
|
346
373
|
(p) => typeof (p as any).getRelatedTracks === "function",
|
|
347
374
|
);
|
|
@@ -350,7 +377,7 @@ export class Player extends EventEmitter {
|
|
|
350
377
|
try {
|
|
351
378
|
this.debug(`[Player] Trying related from plugin: ${p.name}`);
|
|
352
379
|
const related = await withTimeout(
|
|
353
|
-
(p as any).getRelatedTracks(
|
|
380
|
+
(p as any).getRelatedTracks(track.url, {
|
|
354
381
|
limit: 10,
|
|
355
382
|
history: this.queue.previousTracks,
|
|
356
383
|
}),
|
|
@@ -359,20 +386,29 @@ export class Player extends EventEmitter {
|
|
|
359
386
|
);
|
|
360
387
|
|
|
361
388
|
if (Array.isArray(related) && related.length > 0) {
|
|
362
|
-
|
|
363
|
-
const nextTrack = this.queue.nextTrack ? this.queue.nextTrack : related[randomchoice];
|
|
364
|
-
this.queue.willNextTrack(nextTrack);
|
|
365
|
-
this.queue.relatedTracks(related);
|
|
366
|
-
this.debug(`[Player] Will next track if autoplay: ${nextTrack?.title} (via ${p.name})`);
|
|
367
|
-
this.emit("willPlay", nextTrack, related);
|
|
368
|
-
return; // success
|
|
389
|
+
return related; // success
|
|
369
390
|
}
|
|
370
391
|
this.debug(`[Player] ${p.name} returned no related tracks`);
|
|
371
392
|
} catch (err) {
|
|
372
393
|
this.debug(`[Player] getRelatedTracks error from ${p.name}:`, err);
|
|
394
|
+
return [];
|
|
373
395
|
// try next candidate
|
|
374
396
|
}
|
|
375
397
|
}
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private async generateWillNext(): Promise<void> {
|
|
402
|
+
const lastTrack = this.queue.previousTracks[this.queue.previousTracks.length - 1] ?? this.queue.currentTrack;
|
|
403
|
+
if (!lastTrack) return;
|
|
404
|
+
const related = await this.getRelatedTracks(lastTrack);
|
|
405
|
+
if (!related || related.length === 0) return;
|
|
406
|
+
const randomchoice = Math.floor(Math.random() * related.length);
|
|
407
|
+
const nextTrack = this.queue.nextTrack ? this.queue.nextTrack : related[randomchoice];
|
|
408
|
+
this.queue.willNextTrack(nextTrack);
|
|
409
|
+
this.queue.relatedTracks(related);
|
|
410
|
+
this.debug(`[Player] Will next track if autoplay: ${nextTrack?.title}]`);
|
|
411
|
+
this.emit("willPlay", nextTrack, related);
|
|
376
412
|
}
|
|
377
413
|
//#endregion
|
|
378
414
|
//#region Play
|
|
@@ -393,13 +429,10 @@ export class Player extends EventEmitter {
|
|
|
393
429
|
*/
|
|
394
430
|
async play(query: string | Track | SearchResult | null, requestedBy?: string): Promise<boolean> {
|
|
395
431
|
const debugInfo =
|
|
396
|
-
query === null
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
: "tracks" in query
|
|
401
|
-
? `${query.tracks.length} tracks`
|
|
402
|
-
: query.title || "unknown";
|
|
432
|
+
query === null ? "null"
|
|
433
|
+
: typeof query === "string" ? query
|
|
434
|
+
: "tracks" in query ? `${query.tracks.length} tracks`
|
|
435
|
+
: query.title || "unknown";
|
|
403
436
|
this.debug(`[Player] Play called with query: ${debugInfo}`);
|
|
404
437
|
this.clearLeaveTimeout();
|
|
405
438
|
let tracksToAdd: Track[] = [];
|
|
@@ -567,11 +600,9 @@ export class Player extends EventEmitter {
|
|
|
567
600
|
const resource = createAudioResource(stream, {
|
|
568
601
|
metadata: track,
|
|
569
602
|
inputType:
|
|
570
|
-
streamInfo.type === "webm/opus"
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
? StreamType.OggOpus
|
|
574
|
-
: StreamType.Arbitrary,
|
|
603
|
+
streamInfo.type === "webm/opus" ? StreamType.WebmOpus
|
|
604
|
+
: streamInfo.type === "ogg/opus" ? StreamType.OggOpus
|
|
605
|
+
: StreamType.Arbitrary,
|
|
575
606
|
inlineVolume: true,
|
|
576
607
|
});
|
|
577
608
|
|
|
@@ -583,11 +614,9 @@ export class Player extends EventEmitter {
|
|
|
583
614
|
const resource = createAudioResource(streamInfo.stream, {
|
|
584
615
|
metadata: track,
|
|
585
616
|
inputType:
|
|
586
|
-
streamInfo.type === "webm/opus"
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
? StreamType.OggOpus
|
|
590
|
-
: StreamType.Arbitrary,
|
|
617
|
+
streamInfo.type === "webm/opus" ? StreamType.WebmOpus
|
|
618
|
+
: streamInfo.type === "ogg/opus" ? StreamType.OggOpus
|
|
619
|
+
: StreamType.Arbitrary,
|
|
591
620
|
inlineVolume: true,
|
|
592
621
|
});
|
|
593
622
|
return resource;
|
|
@@ -615,6 +644,18 @@ export class Player extends EventEmitter {
|
|
|
615
644
|
// Kiểm tra nếu có stream thực sự để tạo AudioResource
|
|
616
645
|
if (streamInfo && (streamInfo as any).stream) {
|
|
617
646
|
try {
|
|
647
|
+
// Destroy the old stream and resource before creating a new one
|
|
648
|
+
this.destroyCurrentStream();
|
|
649
|
+
if (this.currentResource) {
|
|
650
|
+
try {
|
|
651
|
+
const oldStream = (this.currentResource as any)._readableState?.stream || (this.currentResource as any).stream;
|
|
652
|
+
if (oldStream && typeof oldStream.destroy === "function") {
|
|
653
|
+
oldStream.destroy();
|
|
654
|
+
}
|
|
655
|
+
} catch {}
|
|
656
|
+
this.currentResource = null;
|
|
657
|
+
}
|
|
658
|
+
|
|
618
659
|
this.currentResource = await this.createResource(streamInfo, track, 0);
|
|
619
660
|
if (this.volumeInterval) {
|
|
620
661
|
clearInterval(this.volumeInterval);
|
|
@@ -635,11 +676,9 @@ export class Player extends EventEmitter {
|
|
|
635
676
|
const fallbackResource = createAudioResource(streamInfo.stream, {
|
|
636
677
|
metadata: track,
|
|
637
678
|
inputType:
|
|
638
|
-
streamInfo.type === "webm/opus"
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
? StreamType.OggOpus
|
|
642
|
-
: StreamType.Arbitrary,
|
|
679
|
+
streamInfo.type === "webm/opus" ? StreamType.WebmOpus
|
|
680
|
+
: streamInfo.type === "ogg/opus" ? StreamType.OggOpus
|
|
681
|
+
: StreamType.Arbitrary,
|
|
643
682
|
inlineVolume: true,
|
|
644
683
|
});
|
|
645
684
|
|
|
@@ -735,6 +774,9 @@ export class Player extends EventEmitter {
|
|
|
735
774
|
this.audioPlayer.state.status === AudioPlayerStatus.Playing ||
|
|
736
775
|
this.audioPlayer.state.status === AudioPlayerStatus.Buffering;
|
|
737
776
|
|
|
777
|
+
let ttsResource: AudioResource | null = null;
|
|
778
|
+
let ttsStream: any = null;
|
|
779
|
+
|
|
738
780
|
try {
|
|
739
781
|
if (!this.connection) throw new Error("No voice connection for TTS");
|
|
740
782
|
const ttsPlayer = this.ensureTTSPlayer();
|
|
@@ -744,10 +786,12 @@ export class Player extends EventEmitter {
|
|
|
744
786
|
if (!streamInfo) {
|
|
745
787
|
throw new Error("No stream available for track: ${track.title}");
|
|
746
788
|
}
|
|
789
|
+
ttsStream = streamInfo.stream;
|
|
747
790
|
const resource = await this.createResource(streamInfo as StreamInfo, track);
|
|
748
791
|
if (!resource) {
|
|
749
792
|
throw new Error("No resource available for track: ${track.title}");
|
|
750
793
|
}
|
|
794
|
+
ttsResource = resource;
|
|
751
795
|
if (resource.volume) {
|
|
752
796
|
resource.volume.setVolume((this.options?.tts?.volume ?? this?.volume ?? 100) / 100);
|
|
753
797
|
}
|
|
@@ -767,8 +811,15 @@ export class Player extends EventEmitter {
|
|
|
767
811
|
// Derive timeoutMs from resource/track duration when available, with a sensible cap
|
|
768
812
|
const md: any = (resource as any)?.metadata ?? {};
|
|
769
813
|
const declared =
|
|
770
|
-
typeof md.duration === "number" ? md.duration
|
|
771
|
-
|
|
814
|
+
typeof md.duration === "number" ? md.duration
|
|
815
|
+
: typeof track?.duration === "number" ? track.duration
|
|
816
|
+
: undefined;
|
|
817
|
+
const declaredMs =
|
|
818
|
+
declared ?
|
|
819
|
+
declared > 1000 ?
|
|
820
|
+
declared
|
|
821
|
+
: declared * 1000
|
|
822
|
+
: undefined;
|
|
772
823
|
const cap = this.options?.tts?.Max_Time_TTS ?? 60_000;
|
|
773
824
|
const idleTimeout = declaredMs ? Math.min(cap, Math.max(1_000, declaredMs + 1_500)) : cap;
|
|
774
825
|
await entersState(ttsPlayer, AudioPlayerStatus.Idle, idleTimeout).catch(() => null);
|
|
@@ -779,6 +830,15 @@ export class Player extends EventEmitter {
|
|
|
779
830
|
this.debug("[TTS] error while playing:", err);
|
|
780
831
|
this.emit("playerError", err as Error);
|
|
781
832
|
} finally {
|
|
833
|
+
// Clean up TTS stream and resource
|
|
834
|
+
try {
|
|
835
|
+
if (ttsStream && typeof ttsStream.destroy === "function") {
|
|
836
|
+
ttsStream.destroy();
|
|
837
|
+
}
|
|
838
|
+
} catch (error) {
|
|
839
|
+
this.debug("[TTS] Error destroying stream:", error);
|
|
840
|
+
}
|
|
841
|
+
|
|
782
842
|
if (wasPlaying) {
|
|
783
843
|
try {
|
|
784
844
|
this.resume();
|
|
@@ -1052,9 +1112,20 @@ export class Player extends EventEmitter {
|
|
|
1052
1112
|
|
|
1053
1113
|
// Apply filters if any are active
|
|
1054
1114
|
let finalStream = streamInfo.stream;
|
|
1055
|
-
|
|
1115
|
+
|
|
1116
|
+
if (saveOptions.filter || saveOptions.seek) {
|
|
1117
|
+
try {
|
|
1118
|
+
this.filter.clearAll();
|
|
1119
|
+
this.filter.applyFilters(saveOptions.filter || []);
|
|
1120
|
+
} catch (err) {
|
|
1121
|
+
this.debug(`[Player] Error applying save filters:`, err);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1056
1124
|
this.debug(`[Player] Applying filters to save stream: ${this.filter.getFilterString() || "none"}`);
|
|
1057
|
-
finalStream = await this.filter.applyFiltersAndSeek(streamInfo.stream)
|
|
1125
|
+
finalStream = await this.filter.applyFiltersAndSeek(streamInfo.stream, saveOptions.seek || 0).catch((err) => {
|
|
1126
|
+
this.debug(`[Player] Error applying filters to save stream:`, err);
|
|
1127
|
+
return streamInfo!.stream; // Fallback to original stream
|
|
1128
|
+
});
|
|
1058
1129
|
}
|
|
1059
1130
|
|
|
1060
1131
|
// Return the stream directly - caller can pipe it to fs.createWriteStream()
|
|
@@ -1338,6 +1409,9 @@ export class Player extends EventEmitter {
|
|
|
1338
1409
|
this.leaveTimeout = null;
|
|
1339
1410
|
}
|
|
1340
1411
|
|
|
1412
|
+
// Destroy current stream before stopping audio
|
|
1413
|
+
this.destroyCurrentStream();
|
|
1414
|
+
|
|
1341
1415
|
this.audioPlayer.stop(true);
|
|
1342
1416
|
|
|
1343
1417
|
if (this.ttsPlayer) {
|
|
@@ -1358,6 +1432,13 @@ export class Player extends EventEmitter {
|
|
|
1358
1432
|
this.extensionManager.destroy();
|
|
1359
1433
|
this.isPlaying = false;
|
|
1360
1434
|
this.isPaused = false;
|
|
1435
|
+
|
|
1436
|
+
// Clear any remaining intervals
|
|
1437
|
+
if (this.volumeInterval) {
|
|
1438
|
+
clearInterval(this.volumeInterval);
|
|
1439
|
+
this.volumeInterval = null;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1361
1442
|
this.emit("playerDestroy");
|
|
1362
1443
|
this.removeAllListeners();
|
|
1363
1444
|
}
|
|
@@ -1409,11 +1490,24 @@ export class Player extends EventEmitter {
|
|
|
1409
1490
|
// Create AudioResource with filters and seek to current position
|
|
1410
1491
|
const resource = await this.createResource(streaminfo, track, currentPosition);
|
|
1411
1492
|
|
|
1412
|
-
// Stop current playback and
|
|
1493
|
+
// Stop current playback and destroy old resource/stream
|
|
1413
1494
|
const wasPlaying = this.isPlaying;
|
|
1414
1495
|
const wasPaused = this.isPaused;
|
|
1415
1496
|
|
|
1416
1497
|
this.audioPlayer.stop();
|
|
1498
|
+
|
|
1499
|
+
// Properly destroy the old resource and stream
|
|
1500
|
+
try {
|
|
1501
|
+
if (this.currentResource) {
|
|
1502
|
+
const oldStream = (this.currentResource as any)._readableState?.stream || (this.currentResource as any).stream;
|
|
1503
|
+
if (oldStream && typeof oldStream.destroy === "function") {
|
|
1504
|
+
oldStream.destroy();
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
this.debug(`[Player] Error destroying old stream in refeshPlayerResource:`, error);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1417
1511
|
this.currentResource = resource;
|
|
1418
1512
|
|
|
1419
1513
|
// Subscribe to new resource
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { VoiceConnection } from "@discordjs/voice";
|
|
2
|
+
import type { Player } from "../structures/Player";
|
|
3
|
+
import type { PlayerManager } from "../structures/PlayerManager";
|
|
4
|
+
import type { Track, SearchResult, StreamInfo } from ".";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extension interface
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const extension: SourceExtension = {
|
|
11
|
+
* name: "YouTube",
|
|
12
|
+
* version: "1.0.0"
|
|
13
|
+
* };
|
|
14
|
+
*/
|
|
15
|
+
export interface SourceExtension {
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
connection?: VoiceConnection;
|
|
19
|
+
player: Player | null;
|
|
20
|
+
active(alas: any): boolean | Promise<boolean>;
|
|
21
|
+
onRegister?(context: ExtensionContext): void | Promise<void>;
|
|
22
|
+
onDestroy?(context: ExtensionContext): void | Promise<void>;
|
|
23
|
+
beforePlay?(
|
|
24
|
+
context: ExtensionContext,
|
|
25
|
+
payload: ExtensionPlayRequest,
|
|
26
|
+
): Promise<ExtensionPlayResponse | void> | ExtensionPlayResponse | void;
|
|
27
|
+
afterPlay?(context: ExtensionContext, payload: ExtensionAfterPlayPayload): Promise<void> | void;
|
|
28
|
+
provideSearch?(
|
|
29
|
+
context: ExtensionContext,
|
|
30
|
+
payload: ExtensionSearchRequest,
|
|
31
|
+
): Promise<SearchResult | null | undefined> | SearchResult | null | undefined;
|
|
32
|
+
provideStream?(
|
|
33
|
+
context: ExtensionContext,
|
|
34
|
+
payload: ExtensionStreamRequest,
|
|
35
|
+
): Promise<StreamInfo | null | undefined> | StreamInfo | null | undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Context for the extension
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* const context: ExtensionContext = {
|
|
43
|
+
* player: player,
|
|
44
|
+
* manager: manager
|
|
45
|
+
* };
|
|
46
|
+
*/
|
|
47
|
+
export interface ExtensionContext {
|
|
48
|
+
player: Player;
|
|
49
|
+
manager: PlayerManager;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Request for the extension to play a track
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* const request: ExtensionPlayRequest = {
|
|
57
|
+
* query: "Song Name",
|
|
58
|
+
* requestedBy: "user123"
|
|
59
|
+
* };
|
|
60
|
+
*/
|
|
61
|
+
export interface ExtensionPlayRequest {
|
|
62
|
+
query: string | Track;
|
|
63
|
+
requestedBy?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Response for the extension to play a track
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const response: ExtensionPlayResponse = {
|
|
71
|
+
* handled: true,
|
|
72
|
+
* query: "Song Name",
|
|
73
|
+
* requestedBy: "user123"
|
|
74
|
+
* };
|
|
75
|
+
*/
|
|
76
|
+
export interface ExtensionPlayResponse {
|
|
77
|
+
handled?: boolean;
|
|
78
|
+
query?: string | Track;
|
|
79
|
+
requestedBy?: string;
|
|
80
|
+
tracks?: Track[];
|
|
81
|
+
isPlaylist?: boolean;
|
|
82
|
+
success?: boolean;
|
|
83
|
+
error?: Error;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Payload for the extension to play a track
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const payload: ExtensionAfterPlayPayload = {
|
|
91
|
+
* success: true,
|
|
92
|
+
* query: "Song Name",
|
|
93
|
+
* requestedBy: "user123"
|
|
94
|
+
* };
|
|
95
|
+
*/
|
|
96
|
+
export interface ExtensionAfterPlayPayload {
|
|
97
|
+
success: boolean;
|
|
98
|
+
query: string | Track;
|
|
99
|
+
requestedBy?: string;
|
|
100
|
+
tracks?: Track[];
|
|
101
|
+
isPlaylist?: boolean;
|
|
102
|
+
error?: Error;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Request for the extension to stream a track
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* const request: ExtensionStreamRequest = {
|
|
110
|
+
* track: track
|
|
111
|
+
* };
|
|
112
|
+
*/
|
|
113
|
+
export interface ExtensionStreamRequest {
|
|
114
|
+
track: Track;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Request for the extension to search for a track
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* const request: ExtensionSearchRequest = {
|
|
122
|
+
* query: "Song Name",
|
|
123
|
+
* requestedBy: "user123"
|
|
124
|
+
* };
|
|
125
|
+
*/
|
|
126
|
+
export interface ExtensionSearchRequest {
|
|
127
|
+
query: string;
|
|
128
|
+
requestedBy: string;
|
|
129
|
+
}
|