@kattowo/distube 6.2.0 → 6.2.2
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.d.mts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +61 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +61 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -343,7 +343,49 @@ type CrossfadeOptions = {
|
|
|
343
343
|
* @default 5
|
|
344
344
|
*/
|
|
345
345
|
warmup: number;
|
|
346
|
+
/**
|
|
347
|
+
* Prepare the fading-out song's playback input for the crossfade FFmpeg
|
|
348
|
+
* process. It is invoked right before the transition stream is spawned,
|
|
349
|
+
* with the song's stream url and the position (in seconds, counted from the
|
|
350
|
+
* beginning of the song) where the fade window begins.
|
|
351
|
+
*
|
|
352
|
+
* Streaming inputs that cannot fast-seek (for example HLS playlists) force
|
|
353
|
+
* FFmpeg to re-download the whole stream and discard everything before the
|
|
354
|
+
* seek position, which can miss the swap window on slow sources. The
|
|
355
|
+
* adapter can return a replacement input that starts near the boundary —
|
|
356
|
+
* a local playlist trimmed to the fade position, for example — along with
|
|
357
|
+
* the seek offset inside it and its own FFmpeg input options. Return `null`
|
|
358
|
+
* or `undefined` to use the url as-is.
|
|
359
|
+
*/
|
|
360
|
+
preparePrimaryInput?: PrepareCrossfadeInput;
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* The replacement input returned by {@link CrossfadeOptions.preparePrimaryInput}.
|
|
364
|
+
*/
|
|
365
|
+
type PreparedCrossfadeInput = {
|
|
366
|
+
/**
|
|
367
|
+
* The replacement input url or path, for example a local playlist file
|
|
368
|
+
* trimmed to start at the fade boundary.
|
|
369
|
+
*/
|
|
370
|
+
url: string;
|
|
371
|
+
/**
|
|
372
|
+
* The initial seek of the replacement input, in seconds relative to it.
|
|
373
|
+
* When omitted, the input is assumed to start exactly at the fade boundary.
|
|
374
|
+
*/
|
|
375
|
+
seek?: number;
|
|
376
|
+
/**
|
|
377
|
+
* FFmpeg input options of the replacement input. They replace the default
|
|
378
|
+
* input options, which are tuned for http(s) streaming urls.
|
|
379
|
+
*/
|
|
380
|
+
inputArgs?: FFmpegArg;
|
|
346
381
|
};
|
|
382
|
+
/**
|
|
383
|
+
* The {@link CrossfadeOptions.preparePrimaryInput} adapter type.
|
|
384
|
+
*/
|
|
385
|
+
type PrepareCrossfadeInput = (url: string, boundary: {
|
|
386
|
+
seek: number;
|
|
387
|
+
song: Song;
|
|
388
|
+
}) => Awaitable<PreparedCrossfadeInput | null | undefined>;
|
|
347
389
|
/**
|
|
348
390
|
* DisTube options
|
|
349
391
|
*/
|
|
@@ -447,6 +489,9 @@ type DisTubeOptions = {
|
|
|
447
489
|
* - `curve`: the FFmpeg `acrossfade` fade curve (@default "qsin")
|
|
448
490
|
* - `warmup`: seconds before the fade window when the transition stream is
|
|
449
491
|
* spawned to warm up its buffers (@default 5)
|
|
492
|
+
* - `preparePrimaryInput`: an optional adapter preparing the fading-out
|
|
493
|
+
* song's FFmpeg input before the transition stream is spawned. Useful for
|
|
494
|
+
* streaming inputs that cannot fast-seek ({@link CrossfadeOptions.preparePrimaryInput}).
|
|
450
495
|
* @default { duration: 0, curve: "qsin", warmup: 5 }
|
|
451
496
|
*/
|
|
452
497
|
crossfade?: {
|
|
@@ -462,6 +507,11 @@ type DisTubeOptions = {
|
|
|
462
507
|
* Seconds before the fade window when the transition stream is spawned.
|
|
463
508
|
*/
|
|
464
509
|
warmup?: number;
|
|
510
|
+
/**
|
|
511
|
+
* Optional adapter preparing the fading-out song's FFmpeg input
|
|
512
|
+
* ({@link CrossfadeOptions.preparePrimaryInput}).
|
|
513
|
+
*/
|
|
514
|
+
preparePrimaryInput?: PrepareCrossfadeInput;
|
|
465
515
|
};
|
|
466
516
|
/**
|
|
467
517
|
* FFmpeg options
|
|
@@ -1408,6 +1458,14 @@ interface CrossfadeStreamOptions {
|
|
|
1408
1458
|
* @default "qsin"
|
|
1409
1459
|
*/
|
|
1410
1460
|
inCurve?: string;
|
|
1461
|
+
/**
|
|
1462
|
+
* FFmpeg input options of the first (fading out) input. When set, they
|
|
1463
|
+
* replace the default input options, which are tuned for http(s) streaming
|
|
1464
|
+
* urls. Use it for inputs that need different flags — a local playlist
|
|
1465
|
+
* file, for example, requires the `protocol_whitelist` option and no
|
|
1466
|
+
* reconnect flags.
|
|
1467
|
+
*/
|
|
1468
|
+
primaryInputArgs?: FFmpegArg;
|
|
1411
1469
|
}
|
|
1412
1470
|
/**
|
|
1413
1471
|
* Check that FFmpeg is installed and can be spawned.
|
|
@@ -1444,6 +1502,15 @@ declare class DisTubeStream extends TypedEmitter<{
|
|
|
1444
1502
|
* The seek time in seconds that this stream started from
|
|
1445
1503
|
*/
|
|
1446
1504
|
readonly seekTime: number;
|
|
1505
|
+
/**
|
|
1506
|
+
* Whether FFmpeg has already produced audio that is waiting to be read.
|
|
1507
|
+
*
|
|
1508
|
+
* The stream is spawned ahead of the playback (crossfade warmup) and the
|
|
1509
|
+
* pipe backs up once its buffers are full, so this is `true` as soon as the
|
|
1510
|
+
* first frame exists. A stream that is still `false` at playback time would
|
|
1511
|
+
* leave the audio player buffering until FFmpeg catches up.
|
|
1512
|
+
*/
|
|
1513
|
+
get hasBufferedAudio(): boolean;
|
|
1447
1514
|
/**
|
|
1448
1515
|
* Create a DisTubeStream to play with {@link DisTubeVoice}
|
|
1449
1516
|
* @param url - Stream URL
|
|
@@ -3614,4 +3681,4 @@ declare function handleUnhandledError(error: Error, behavior?: UnhandledErrorBeh
|
|
|
3614
3681
|
declare const checkEncryptionLibraries: () => Promise<boolean>;
|
|
3615
3682
|
|
|
3616
3683
|
export { AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, BaseManager, CROSSFADE_DRIFT_TOLERANCE_SECS, DEFAULT_CROSSFADE_CURVE, DEFAULT_CROSSFADE_DURATION_SECS, DEFAULT_CROSSFADE_WARMUP_SECS, DEFAULT_PRELOAD_THRESHOLD_SECS, DEFAULT_VOLUME, DisTube, DisTubeBase, DisTubeError, DisTubeHandler, DisTubeStream, DisTubeVoice, DisTubeVoiceManager, Events, ExtractorPlugin, FilterManager, GuildIdManager, HTTP_REDIRECT_CODES, InfoExtractorPlugin, JOIN_TIMEOUT_MS, MAX_CROSSFADE_DURATION_SECS, MAX_REDIRECT_DEPTH, Options, PlayableExtractorPlugin, Playlist, Plugin, PluginError, PluginErrorCode, PluginType, Queue, QueueManager, RECONNECT_MAX_ATTEMPTS, RECONNECT_TIMEOUT_MS, RepeatMode, STUCK_THRESHOLD_MS, SearchResult, SearchResultType, Song, StreamServer, TaskQueue, checkEncryptionLibraries, checkFFmpeg, checkIntents, checkInvalidKey, DisTube as default, defaultFilters, defaultOptions, formatDuration, handleUnhandledError, isClientInstance, isGuildInstance, isMemberInstance, isMessageInstance, isNsfwChannel, isObject, isSnowflake, isSupportedVoiceChannel, isTextChannelInstance, isTruthy, isURL, isVoiceChannelEmpty, objectKeys, resolveGuildId, version };
|
|
3617
|
-
export type { Awaitable, CrossfadeOptions, CrossfadeStreamOptions, CustomPlaylistOptions, DisTubeEvents, DisTubeOptions, DisTubePlugin, DisTubeVoiceEvents, Disposable, FFmpegArg, FFmpegArgs, FFmpegOptions, Falsy, Filter, FilterResolvable, Filters, GuildIdResolvable, JumpOptions, KeyOf, PlayHandlerOptions, PlayOptions, PlaylistInfo, PreloadOptions, RelatedSong, ResolveOptions, ResolvePlaylistOptions, SearchOptions, SongInfo, StreamHandler, StreamOptions, StreamRequest, StreamResponse, StreamServerOptions, TypedDisTubeEvents, UnhandledErrorBehavior };
|
|
3684
|
+
export type { Awaitable, CrossfadeOptions, CrossfadeStreamOptions, CustomPlaylistOptions, DisTubeEvents, DisTubeOptions, DisTubePlugin, DisTubeVoiceEvents, Disposable, FFmpegArg, FFmpegArgs, FFmpegOptions, Falsy, Filter, FilterResolvable, Filters, GuildIdResolvable, JumpOptions, KeyOf, PlayHandlerOptions, PlayOptions, PlaylistInfo, PreloadOptions, PrepareCrossfadeInput, PreparedCrossfadeInput, RelatedSong, ResolveOptions, ResolvePlaylistOptions, SearchOptions, SongInfo, StreamHandler, StreamOptions, StreamRequest, StreamResponse, StreamServerOptions, TypedDisTubeEvents, UnhandledErrorBehavior };
|
package/dist/index.d.ts
CHANGED
|
@@ -343,7 +343,49 @@ type CrossfadeOptions = {
|
|
|
343
343
|
* @default 5
|
|
344
344
|
*/
|
|
345
345
|
warmup: number;
|
|
346
|
+
/**
|
|
347
|
+
* Prepare the fading-out song's playback input for the crossfade FFmpeg
|
|
348
|
+
* process. It is invoked right before the transition stream is spawned,
|
|
349
|
+
* with the song's stream url and the position (in seconds, counted from the
|
|
350
|
+
* beginning of the song) where the fade window begins.
|
|
351
|
+
*
|
|
352
|
+
* Streaming inputs that cannot fast-seek (for example HLS playlists) force
|
|
353
|
+
* FFmpeg to re-download the whole stream and discard everything before the
|
|
354
|
+
* seek position, which can miss the swap window on slow sources. The
|
|
355
|
+
* adapter can return a replacement input that starts near the boundary —
|
|
356
|
+
* a local playlist trimmed to the fade position, for example — along with
|
|
357
|
+
* the seek offset inside it and its own FFmpeg input options. Return `null`
|
|
358
|
+
* or `undefined` to use the url as-is.
|
|
359
|
+
*/
|
|
360
|
+
preparePrimaryInput?: PrepareCrossfadeInput;
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* The replacement input returned by {@link CrossfadeOptions.preparePrimaryInput}.
|
|
364
|
+
*/
|
|
365
|
+
type PreparedCrossfadeInput = {
|
|
366
|
+
/**
|
|
367
|
+
* The replacement input url or path, for example a local playlist file
|
|
368
|
+
* trimmed to start at the fade boundary.
|
|
369
|
+
*/
|
|
370
|
+
url: string;
|
|
371
|
+
/**
|
|
372
|
+
* The initial seek of the replacement input, in seconds relative to it.
|
|
373
|
+
* When omitted, the input is assumed to start exactly at the fade boundary.
|
|
374
|
+
*/
|
|
375
|
+
seek?: number;
|
|
376
|
+
/**
|
|
377
|
+
* FFmpeg input options of the replacement input. They replace the default
|
|
378
|
+
* input options, which are tuned for http(s) streaming urls.
|
|
379
|
+
*/
|
|
380
|
+
inputArgs?: FFmpegArg;
|
|
346
381
|
};
|
|
382
|
+
/**
|
|
383
|
+
* The {@link CrossfadeOptions.preparePrimaryInput} adapter type.
|
|
384
|
+
*/
|
|
385
|
+
type PrepareCrossfadeInput = (url: string, boundary: {
|
|
386
|
+
seek: number;
|
|
387
|
+
song: Song;
|
|
388
|
+
}) => Awaitable<PreparedCrossfadeInput | null | undefined>;
|
|
347
389
|
/**
|
|
348
390
|
* DisTube options
|
|
349
391
|
*/
|
|
@@ -447,6 +489,9 @@ type DisTubeOptions = {
|
|
|
447
489
|
* - `curve`: the FFmpeg `acrossfade` fade curve (@default "qsin")
|
|
448
490
|
* - `warmup`: seconds before the fade window when the transition stream is
|
|
449
491
|
* spawned to warm up its buffers (@default 5)
|
|
492
|
+
* - `preparePrimaryInput`: an optional adapter preparing the fading-out
|
|
493
|
+
* song's FFmpeg input before the transition stream is spawned. Useful for
|
|
494
|
+
* streaming inputs that cannot fast-seek ({@link CrossfadeOptions.preparePrimaryInput}).
|
|
450
495
|
* @default { duration: 0, curve: "qsin", warmup: 5 }
|
|
451
496
|
*/
|
|
452
497
|
crossfade?: {
|
|
@@ -462,6 +507,11 @@ type DisTubeOptions = {
|
|
|
462
507
|
* Seconds before the fade window when the transition stream is spawned.
|
|
463
508
|
*/
|
|
464
509
|
warmup?: number;
|
|
510
|
+
/**
|
|
511
|
+
* Optional adapter preparing the fading-out song's FFmpeg input
|
|
512
|
+
* ({@link CrossfadeOptions.preparePrimaryInput}).
|
|
513
|
+
*/
|
|
514
|
+
preparePrimaryInput?: PrepareCrossfadeInput;
|
|
465
515
|
};
|
|
466
516
|
/**
|
|
467
517
|
* FFmpeg options
|
|
@@ -1408,6 +1458,14 @@ interface CrossfadeStreamOptions {
|
|
|
1408
1458
|
* @default "qsin"
|
|
1409
1459
|
*/
|
|
1410
1460
|
inCurve?: string;
|
|
1461
|
+
/**
|
|
1462
|
+
* FFmpeg input options of the first (fading out) input. When set, they
|
|
1463
|
+
* replace the default input options, which are tuned for http(s) streaming
|
|
1464
|
+
* urls. Use it for inputs that need different flags — a local playlist
|
|
1465
|
+
* file, for example, requires the `protocol_whitelist` option and no
|
|
1466
|
+
* reconnect flags.
|
|
1467
|
+
*/
|
|
1468
|
+
primaryInputArgs?: FFmpegArg;
|
|
1411
1469
|
}
|
|
1412
1470
|
/**
|
|
1413
1471
|
* Check that FFmpeg is installed and can be spawned.
|
|
@@ -1444,6 +1502,15 @@ declare class DisTubeStream extends TypedEmitter<{
|
|
|
1444
1502
|
* The seek time in seconds that this stream started from
|
|
1445
1503
|
*/
|
|
1446
1504
|
readonly seekTime: number;
|
|
1505
|
+
/**
|
|
1506
|
+
* Whether FFmpeg has already produced audio that is waiting to be read.
|
|
1507
|
+
*
|
|
1508
|
+
* The stream is spawned ahead of the playback (crossfade warmup) and the
|
|
1509
|
+
* pipe backs up once its buffers are full, so this is `true` as soon as the
|
|
1510
|
+
* first frame exists. A stream that is still `false` at playback time would
|
|
1511
|
+
* leave the audio player buffering until FFmpeg catches up.
|
|
1512
|
+
*/
|
|
1513
|
+
get hasBufferedAudio(): boolean;
|
|
1447
1514
|
/**
|
|
1448
1515
|
* Create a DisTubeStream to play with {@link DisTubeVoice}
|
|
1449
1516
|
* @param url - Stream URL
|
|
@@ -3616,4 +3683,4 @@ declare const checkEncryptionLibraries: () => Promise<boolean>;
|
|
|
3616
3683
|
// @ts-ignore
|
|
3617
3684
|
export = DisTube;
|
|
3618
3685
|
export { AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, BaseManager, CROSSFADE_DRIFT_TOLERANCE_SECS, DEFAULT_CROSSFADE_CURVE, DEFAULT_CROSSFADE_DURATION_SECS, DEFAULT_CROSSFADE_WARMUP_SECS, DEFAULT_PRELOAD_THRESHOLD_SECS, DEFAULT_VOLUME, DisTube, DisTubeBase, DisTubeError, DisTubeHandler, DisTubeStream, DisTubeVoice, DisTubeVoiceManager, Events, ExtractorPlugin, FilterManager, GuildIdManager, HTTP_REDIRECT_CODES, InfoExtractorPlugin, JOIN_TIMEOUT_MS, MAX_CROSSFADE_DURATION_SECS, MAX_REDIRECT_DEPTH, Options, PlayableExtractorPlugin, Playlist, Plugin, PluginError, PluginErrorCode, PluginType, Queue, QueueManager, RECONNECT_MAX_ATTEMPTS, RECONNECT_TIMEOUT_MS, RepeatMode, STUCK_THRESHOLD_MS, SearchResult, SearchResultType, Song, StreamServer, TaskQueue, checkEncryptionLibraries, checkFFmpeg, checkIntents, checkInvalidKey, defaultFilters, defaultOptions, formatDuration, handleUnhandledError, isClientInstance, isGuildInstance, isMemberInstance, isMessageInstance, isNsfwChannel, isObject, isSnowflake, isSupportedVoiceChannel, isTextChannelInstance, isTruthy, isURL, isVoiceChannelEmpty, objectKeys, resolveGuildId, version };
|
|
3619
|
-
export type { Awaitable, CrossfadeOptions, CrossfadeStreamOptions, CustomPlaylistOptions, DisTubeEvents, DisTubeOptions, DisTubePlugin, DisTubeVoiceEvents, Disposable, FFmpegArg, FFmpegArgs, FFmpegOptions, Falsy, Filter, FilterResolvable, Filters, GuildIdResolvable, JumpOptions, KeyOf, PlayHandlerOptions, PlayOptions, PlaylistInfo, PreloadOptions, RelatedSong, ResolveOptions, ResolvePlaylistOptions, SearchOptions, SongInfo, StreamHandler, StreamOptions, StreamRequest, StreamResponse, StreamServerOptions, TypedDisTubeEvents, UnhandledErrorBehavior };
|
|
3686
|
+
export type { Awaitable, CrossfadeOptions, CrossfadeStreamOptions, CustomPlaylistOptions, DisTubeEvents, DisTubeOptions, DisTubePlugin, DisTubeVoiceEvents, Disposable, FFmpegArg, FFmpegArgs, FFmpegOptions, Falsy, Filter, FilterResolvable, Filters, GuildIdResolvable, JumpOptions, KeyOf, PlayHandlerOptions, PlayOptions, PlaylistInfo, PreloadOptions, PrepareCrossfadeInput, PreparedCrossfadeInput, RelatedSong, ResolveOptions, ResolvePlaylistOptions, SearchOptions, SongInfo, StreamHandler, StreamOptions, StreamRequest, StreamResponse, StreamServerOptions, TypedDisTubeEvents, UnhandledErrorBehavior };
|
package/dist/index.js
CHANGED
|
@@ -102,7 +102,7 @@ __export(index_exports, {
|
|
|
102
102
|
module.exports = __toCommonJS(index_exports);
|
|
103
103
|
|
|
104
104
|
// src/constant.ts
|
|
105
|
-
var version = "6.2.
|
|
105
|
+
var version = "6.2.2";
|
|
106
106
|
var AUDIO_SAMPLE_RATE = 48e3;
|
|
107
107
|
var AUDIO_CHANNELS = 2;
|
|
108
108
|
var DEFAULT_VOLUME = 50;
|
|
@@ -2641,8 +2641,8 @@ var Options = class {
|
|
|
2641
2641
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
2642
2642
|
throw new DisTubeError("INVALID_TYPE", "object", value, "DisTubeOptions.crossfade");
|
|
2643
2643
|
}
|
|
2644
|
-
checkInvalidKey(value, ["duration", "curve", "warmup"], "DisTubeOptions.crossfade");
|
|
2645
|
-
const { duration, curve, warmup } = value;
|
|
2644
|
+
checkInvalidKey(value, ["duration", "curve", "warmup", "preparePrimaryInput"], "DisTubeOptions.crossfade");
|
|
2645
|
+
const { duration, curve, warmup, preparePrimaryInput } = value;
|
|
2646
2646
|
if (duration !== void 0 && (typeof duration !== "number" || Number.isNaN(duration) || duration < 0)) {
|
|
2647
2647
|
throw new DisTubeError(
|
|
2648
2648
|
"INVALID_TYPE",
|
|
@@ -2665,10 +2665,19 @@ var Options = class {
|
|
|
2665
2665
|
if (warmup !== void 0 && (typeof warmup !== "number" || Number.isNaN(warmup) || warmup < 0)) {
|
|
2666
2666
|
throw new DisTubeError("INVALID_TYPE", "number >= 0", warmup, "DisTubeOptions.crossfade.warmup");
|
|
2667
2667
|
}
|
|
2668
|
+
if (preparePrimaryInput !== void 0 && typeof preparePrimaryInput !== "function") {
|
|
2669
|
+
throw new DisTubeError(
|
|
2670
|
+
"INVALID_TYPE",
|
|
2671
|
+
"function",
|
|
2672
|
+
preparePrimaryInput,
|
|
2673
|
+
"DisTubeOptions.crossfade.preparePrimaryInput"
|
|
2674
|
+
);
|
|
2675
|
+
}
|
|
2668
2676
|
return {
|
|
2669
2677
|
duration: duration ?? DEFAULT_CROSSFADE_DURATION_SECS,
|
|
2670
2678
|
curve: curve ?? DEFAULT_CROSSFADE_CURVE,
|
|
2671
|
-
warmup: warmup ?? DEFAULT_CROSSFADE_WARMUP_SECS
|
|
2679
|
+
warmup: warmup ?? DEFAULT_CROSSFADE_WARMUP_SECS,
|
|
2680
|
+
preparePrimaryInput
|
|
2672
2681
|
};
|
|
2673
2682
|
}
|
|
2674
2683
|
#validateOptions(options = this) {
|
|
@@ -2793,6 +2802,17 @@ var DisTubeStream = class extends import_tiny_typed_emitter2.TypedEmitter {
|
|
|
2793
2802
|
* The seek time in seconds that this stream started from
|
|
2794
2803
|
*/
|
|
2795
2804
|
seekTime;
|
|
2805
|
+
/**
|
|
2806
|
+
* Whether FFmpeg has already produced audio that is waiting to be read.
|
|
2807
|
+
*
|
|
2808
|
+
* The stream is spawned ahead of the playback (crossfade warmup) and the
|
|
2809
|
+
* pipe backs up once its buffers are full, so this is `true` as soon as the
|
|
2810
|
+
* first frame exists. A stream that is still `false` at playback time would
|
|
2811
|
+
* leave the audio player buffering until FFmpeg catches up.
|
|
2812
|
+
*/
|
|
2813
|
+
get hasBufferedAudio() {
|
|
2814
|
+
return this.stream.readableLength > 0;
|
|
2815
|
+
}
|
|
2796
2816
|
/**
|
|
2797
2817
|
* Create a DisTubeStream to play with {@link DisTubeVoice}
|
|
2798
2818
|
* @param url - Stream URL
|
|
@@ -2880,13 +2900,15 @@ var DisTubeStream = class extends import_tiny_typed_emitter2.TypedEmitter {
|
|
|
2880
2900
|
const extraFilters = typeof outputArgs.af === "string" ? outputArgs.af : Array.isArray(outputArgs.af) ? outputArgs.af.filter(Boolean).join(",") : void 0;
|
|
2881
2901
|
delete outputArgs.af;
|
|
2882
2902
|
const primaryOpts = {
|
|
2883
|
-
reconnect: 1,
|
|
2884
|
-
reconnect_streamed: 1,
|
|
2885
|
-
reconnect_delay_max: 5,
|
|
2886
|
-
analyzeduration: 0,
|
|
2887
2903
|
hide_banner: true,
|
|
2888
2904
|
...ffmpeg.args.global,
|
|
2889
|
-
...
|
|
2905
|
+
...crossfade.primaryInputArgs ?? {
|
|
2906
|
+
reconnect: 1,
|
|
2907
|
+
reconnect_streamed: 1,
|
|
2908
|
+
reconnect_delay_max: 5,
|
|
2909
|
+
analyzeduration: 0,
|
|
2910
|
+
...ffmpeg.args.input
|
|
2911
|
+
},
|
|
2890
2912
|
ss: typeof primarySeek === "number" && primarySeek > 0 ? primarySeek.toString() : null,
|
|
2891
2913
|
i: url
|
|
2892
2914
|
};
|
|
@@ -3465,7 +3487,28 @@ var QueueManager = class extends GuildIdManager {
|
|
|
3465
3487
|
if (!primary?.stream.playFromSource || !primary.stream.url) return;
|
|
3466
3488
|
if (!secondary?.stream.playFromSource || !secondary.stream.url) return;
|
|
3467
3489
|
this.debug(`[${queue.id}] Warming up crossfade stream: ${song} -> ${nextSong}`);
|
|
3468
|
-
|
|
3490
|
+
const boundarySeek = Math.max(0, songDuration - fade);
|
|
3491
|
+
let primaryUrl = primary.stream.url;
|
|
3492
|
+
let primarySeek = boundarySeek;
|
|
3493
|
+
let primaryInputArgs;
|
|
3494
|
+
const prepare = this.options.crossfade.preparePrimaryInput;
|
|
3495
|
+
if (prepare) {
|
|
3496
|
+
try {
|
|
3497
|
+
const prepared = await prepare(primary.stream.url, { seek: boundarySeek, song });
|
|
3498
|
+
if (prepared?.url) {
|
|
3499
|
+
primaryUrl = prepared.url;
|
|
3500
|
+
if (typeof prepared.seek === "number" && Number.isFinite(prepared.seek) && prepared.seek >= 0) {
|
|
3501
|
+
primarySeek = prepared.seek;
|
|
3502
|
+
}
|
|
3503
|
+
primaryInputArgs = prepared.inputArgs;
|
|
3504
|
+
this.debug(`[${queue.id}] Crossfade primary input prepared by the adapter`);
|
|
3505
|
+
}
|
|
3506
|
+
} catch (e) {
|
|
3507
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
3508
|
+
this.debug(`[${queue.id}] Crossfade primary input preparation failed: ${errorMessage}`);
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
transitionStream = new DisTubeStream(primaryUrl, {
|
|
3469
3512
|
ffmpeg: {
|
|
3470
3513
|
path: this.options.ffmpeg.path,
|
|
3471
3514
|
args: {
|
|
@@ -3476,10 +3519,11 @@ var QueueManager = class extends GuildIdManager {
|
|
|
3476
3519
|
},
|
|
3477
3520
|
crossfade: {
|
|
3478
3521
|
duration: fade,
|
|
3479
|
-
primarySeek
|
|
3522
|
+
primarySeek,
|
|
3480
3523
|
secondaryUrl: secondary.stream.url,
|
|
3481
3524
|
inCurve: this.options.crossfade.curve,
|
|
3482
|
-
outCurve: this.options.crossfade.curve
|
|
3525
|
+
outCurve: this.options.crossfade.curve,
|
|
3526
|
+
primaryInputArgs
|
|
3483
3527
|
}
|
|
3484
3528
|
});
|
|
3485
3529
|
transitionStream.on("debug", (data) => this.emit("ffmpegDebug" /* FFMPEG_DEBUG */, `[${queue.id}] [crossfade] ${data}`));
|
|
@@ -3489,7 +3533,7 @@ var QueueManager = class extends GuildIdManager {
|
|
|
3489
3533
|
}
|
|
3490
3534
|
queue._crossfadeWarmup = transitionStream;
|
|
3491
3535
|
transitionStream.spawn();
|
|
3492
|
-
const boundaryMs = Math.max(0, (
|
|
3536
|
+
const boundaryMs = Math.max(0, (songDuration - queue.currentTime - fade) * 1e3);
|
|
3493
3537
|
queue._crossfadeTimeout = setTimeout(() => {
|
|
3494
3538
|
queue._crossfadeTimeout = void 0;
|
|
3495
3539
|
void this.#crossfadeSwapTask(queue, transitionStream);
|
|
@@ -3527,6 +3571,10 @@ var QueueManager = class extends GuildIdManager {
|
|
|
3527
3571
|
if (queue.stopped || queue.paused || queue.songs[0] !== song || queue._crossfadeWarmup !== transitionStream) {
|
|
3528
3572
|
return abort();
|
|
3529
3573
|
}
|
|
3574
|
+
if (!transitionStream.hasBufferedAudio) {
|
|
3575
|
+
this.debug(`[${queue.id}] Crossfade aborted: the transition stream is not ready`);
|
|
3576
|
+
return abort();
|
|
3577
|
+
}
|
|
3530
3578
|
this.debug(`[${queue.id}] Starting crossfade: ${song} -> ${queue.songs.length > 1 ? queue.songs[1] : song}`);
|
|
3531
3579
|
await queue.voice.play(transitionStream);
|
|
3532
3580
|
queue._crossfadeWarmup = void 0;
|