Skip to content

Commit

Permalink
Switch ytdl-core to play-dl
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoCoreDuo committed May 17, 2024
1 parent cc1f18b commit 52af27b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 226 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"libsodium-wrappers": "^0.7.9",
"make-dir": "^3.1.0",
"node-emoji": "^1.10.0",
"node-fetch": "^3.3.2",
"nodesplash": "^0.1.1",
"ora": "^6.1.0",
"p-event": "^5.0.1",
Expand All @@ -117,6 +118,7 @@
"pagination.djs": "^4.0.10",
"parse-duration": "1.0.2",
"patch-package": "^8.0.0",
"play-dl": "^1.9.7",
"postinstall-postinstall": "^2.1.0",
"read-pkg": "7.1.0",
"reflect-metadata": "^0.1.13",
Expand All @@ -126,7 +128,6 @@
"sync-fetch": "^0.3.1",
"tsx": "3.8.2",
"xbytes": "^1.7.0",
"ytdl-core": "^4.11.5",
"ytsr": "^3.8.4"
},
"resolutions": {
Expand Down
172 changes: 0 additions & 172 deletions patches/ytdl-core+4.11.5.patch

This file was deleted.

62 changes: 31 additions & 31 deletions src/services/player.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {VoiceChannel, Snowflake} from 'discord.js';
import {Readable} from 'stream';
import hasha from 'hasha';
import ytdl, {videoFormat} from 'ytdl-core';
import {InfoData, video_basic_info} from 'play-dl';
import {WriteStream} from 'fs-capacitor';
import ffmpeg from 'fluent-ffmpeg';
import shuffle from 'array-shuffle';
import fetch from 'node-fetch';
import {
AudioPlayer,
AudioPlayerState,
Expand Down Expand Up @@ -57,8 +58,6 @@ export interface PlayerEvents {
statusChange: (oldStatus: STATUS, newStatus: STATUS) => void;
}

type YTDLVideoFormat = videoFormat & {loudnessDb?: number};

export const DEFAULT_VOLUME = 100;

export default class {
Expand Down Expand Up @@ -437,55 +436,56 @@ export default class {
const ffmpegInputOptions: string[] = [];
let shouldCacheVideo = false;

let format: YTDLVideoFormat | undefined;
let format: InfoData['format'][0] | undefined;

ffmpegInput = await this.fileCache.getPathFor(this.getHashForCache(song.url));

if (!ffmpegInput) {
// Not yet cached, must download
const info = await ytdl.getInfo(song.url);
const info = await video_basic_info(song.url);

const formats = info.formats as YTDLVideoFormat[];
if (info.LiveStreamData.isLive) {
const hlsUrl = info.LiveStreamData.hlsManifestUrl;

const filter = (format: ytdl.videoFormat): boolean => format.codecs === 'opus' && format.container === 'webm' && format.audioSampleRate !== undefined && parseInt(format.audioSampleRate, 10) === 48000;
if (hlsUrl === null) {
throw new Error('No HLS manifest URL found.');
}

format = formats.find(filter);
const audioBitrates: Record<number, number> = {128: 96, 127: 96, 120: 128, 96: 256, 95: 256, 94: 128, 93: 128};

const nextBestFormat = (formats: ytdl.videoFormat[]): ytdl.videoFormat | undefined => {
if (formats[0].isLive) {
formats = formats.sort((a, b) => (b as unknown as {audioBitrate: number}).audioBitrate - (a as unknown as {audioBitrate: number}).audioBitrate); // Bad typings
let formats: Array<{itag: number; url: string; audioBitrate?: number; loudnessDb: undefined}> = [];

return formats.find(format => [128, 127, 120, 96, 95, 94, 93].includes(parseInt(format.itag as unknown as string, 10))); // Bad typings
}
const m3u8_data = await fetch(hlsUrl).then(async res => res.text());

formats = formats
.filter(format => format.averageBitrate)
.sort((a, b) => {
if (a && b) {
return b.averageBitrate! - a.averageBitrate!;
m3u8_data
.split('\n')
.filter(line => /^https?:\/\//.test(line))
.forEach(line => {
let itag: RegExpExecArray | number | null = /\/itag\/(\d+)\//.exec(line);
if (itag !== null) {
itag = parseInt(itag[1], 10);
formats.unshift({itag, url: line, audioBitrate: audioBitrates[itag], loudnessDb: undefined});
}

return 0;
});
return formats.find(format => !format.bitrate) ?? formats[0];
};

if (!format) {
format = nextBestFormat(info.formats);
formats = formats.sort((a, b) => (b as unknown as {audioBitrate: number}).audioBitrate - (a as unknown as {audioBitrate: number}).audioBitrate);

if (!format) {
// If still no format is found, throw
throw new Error('Can\'t find suitable format.');
}
format = formats.find(format => [128, 127, 120, 96, 95, 94, 93].includes(format.itag));
} else {
format = info.format.at(info.format.length - 1);
}

debug('Using format', format);
if (!format) {
// If no format is found, throw
throw new Error('Can\'t find suitable format.');
}

ffmpegInput = format.url;
debug('Using format', format);
ffmpegInput = format.url!;

// Don't cache livestreams or long videos
const MAX_CACHE_LENGTH_SECONDS = 30 * 60; // 30 minutes
shouldCacheVideo = !info.player_response.videoDetails.isLiveContent && parseInt(info.videoDetails.lengthSeconds, 10) < MAX_CACHE_LENGTH_SECONDS && !options.seek;
shouldCacheVideo = !info.video_details.live && info.video_details.durationInSec < MAX_CACHE_LENGTH_SECONDS && !options.seek;

debug(shouldCacheVideo ? 'Caching video' : 'Not caching video');

Expand Down
Loading

0 comments on commit 52af27b

Please sign in to comment.