@spikebot/discord-ytdl-core
Version:
Simple ytdl wrapper for discord bots with custom ffmpeg args support.
166 lines (165 loc) • 5.02 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const ytdl_core_1 = __importDefault(require("@spikebot/ytdl-core"));
const prism_media_1 = require("prism-media");
// ytdl events
const evn = [
'info',
'progress',
'abort',
'request',
'response',
'error',
'redirect',
'retry',
'reconnect',
];
/**
* Create an opus stream for your video with provided encoder args
* @param url - YouTube URL of the video
* @param options - YTDL options
* @example */
const StreamDownloader = (url, options) => {
if (!url) {
throw new Error('No input url provided');
}
if (typeof url !== 'string') {
throw new SyntaxError(`input URL must be a string. Received ${typeof url}!`);
}
options !== null && options !== void 0 ? options : (options = {});
let FFmpegArgs = [
'-analyzeduration',
'0',
'-loglevel',
'0',
'-f',
`${typeof options.fmt === 'string' ? options.fmt : 's16le'}`,
'-ar',
'48000',
'-ac',
'2',
];
if (!isNaN(options.seek)) {
FFmpegArgs.unshift('-ss', options.seek.toString());
}
if (Array.isArray(options.encoderArgs)) {
FFmpegArgs = FFmpegArgs.concat(options.encoderArgs);
}
const transcoder = new prism_media_1.FFmpeg({
args: FFmpegArgs,
});
const inputStream = (0, ytdl_core_1.default)(url, options);
const output = inputStream.pipe(transcoder);
if (options && !options.opusEncoded) {
for (const event of evn) {
inputStream.on(event, (...args) => output.emit(event, ...args));
}
inputStream.on('error', () => transcoder.destroy());
output.on('close', () => transcoder.destroy());
return output;
}
const opus = new prism_media_1.opus.Encoder({
rate: 48000,
channels: 2,
frameSize: 960,
});
const outputStream = output.pipe(opus);
output.on('error', (e) => outputStream.emit('error', e));
for (const event of evn) {
inputStream.on(event, (...args) => outputStream.emit(event, ...args));
}
outputStream.on('close', () => {
transcoder.destroy();
opus.destroy();
});
return outputStream;
};
/**
* Creates arbitraryStream
* @param stream Any readable stream source
* @param options Stream options
* @example const streamSource = "https://listen.moe/kpop/opus";
* let stream = ytdl.arbitraryStream(streamSource, {
* encoderArgs: ["-af", "asetrate=44100*1.25"],
* fmt: "mp3"
* });
*
* stream.pipe(fs.createWriteStream("kpop.mp3"));
*/
const arbitraryStream = (stream, options) => {
if (!stream) {
throw new Error('No stream source provided');
}
options !== null && options !== void 0 ? options : (options = {});
let FFmpegArgs;
if (typeof stream === 'string') {
FFmpegArgs = [
'-reconnect',
'1',
'-reconnect_streamed',
'1',
'-reconnect_delay_max',
'5',
'-i',
stream,
'-analyzeduration',
'0',
'-loglevel',
'0',
'-f',
`${typeof options.fmt === 'string' ? options.fmt : 's16le'}`,
'-ar',
'48000',
'-ac',
'2',
];
}
else {
FFmpegArgs = [
'-analyzeduration',
'0',
'-loglevel',
'0',
'-f',
`${typeof options.fmt === 'string' ? options.fmt : 's16le'}`,
'-ar',
'48000',
'-ac',
'2',
];
}
if (!isNaN(options.seek)) {
FFmpegArgs.unshift('-ss', options.seek.toString());
}
if (Array.isArray(options.encoderArgs)) {
FFmpegArgs = FFmpegArgs.concat(options.encoderArgs);
}
let transcoder = new prism_media_1.FFmpeg({
args: FFmpegArgs,
});
if (typeof stream !== 'string') {
transcoder = stream.pipe(transcoder);
stream.on('error', () => transcoder.destroy());
}
if (options && !options.opusEncoded) {
transcoder.on('close', () => transcoder.destroy());
return transcoder;
}
const opus = new prism_media_1.opus.Encoder({
rate: 48000,
channels: 2,
frameSize: 960,
});
const outputStream = transcoder.pipe(opus);
outputStream.on('close', () => {
transcoder.destroy();
opus.destroy();
});
return outputStream;
};
StreamDownloader.arbitraryStream = arbitraryStream;
StreamDownloader.version = require('./package.json').version;
const DiscordYTDLCore = Object.assign(StreamDownloader, ytdl_core_1.default);
module.exports = DiscordYTDLCore;