Skip to content

Commit de5fc30

Browse files
committed
1 parent 3713579 commit de5fc30

File tree

5 files changed

+76
-109
lines changed

5 files changed

+76
-109
lines changed

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"dependencies": {
3030
"@discordjs/opus": "^0.9.0",
3131
"@discordjs/voice": "^0.17.0",
32-
"@distube/ytdl-core": "^4.13.5",
3332
"discord.js": "^14.11.0",
3433
"dotenv": "^16.3.1",
3534
"ffmpeg-static": "^5.2.0",

src/commands/music/Play.ts

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export default class Play extends Command {
118118
thumbnailUrl: info.video_details.thumbnails[0].url,
119119
duration: info.video_details.durationInSec,
120120
url: info.video_details.url,
121+
id: info.video_details.id,
121122
requestedBy: member
122123
};
123124
queue.list.push(song);
@@ -138,6 +139,7 @@ export default class Play extends Command {
138139
thumbnailUrl: info.thumbnails[0].url,
139140
duration: info.durationInSec,
140141
url: info.url,
142+
id: info.id,
141143
requestedBy: member
142144
})));
143145

src/components/MusicQueue.ts

+3-16
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,18 @@ import { type VoiceChannel, BaseGuildTextChannel, BaseGuildVoiceChannel, Guild,
1818

1919
import fetch from "node-fetch";
2020
import play from "play-dl";
21-
import ytdl, { Filter } from "@distube/ytdl-core";
2221
import { YMApi } from "ym-api";
2322

2423
import config from "../config";
2524
import { LoopMode, MusicServices } from "../enums";
2625
import { Song } from "../interfaces/music";
2726
import { critical } from "./messages";
28-
import { cookieHeaderParser } from "./utils";
27+
import { streamYTAudio } from "./ytdl";
2928

3029
const { music: { youtube, spotify, yandex, volumeDefault } } = config;
3130
const wait = promisify(setTimeout);
3231
const ymApi = new YMApi();
3332

34-
const ytdlOptions = {
35-
filter: "audioonly" as Filter,
36-
highWaterMark: 1 << 62,
37-
liveBuffer: 1 << 62,
38-
dlChunkSize: 0,
39-
quality: "highestaudio",
40-
// requestOptions: {
41-
// ...youtube.cookie && { headers: youtube }
42-
// }
43-
agent: ytdl.createAgent(cookieHeaderParser(youtube.cookie))
44-
};
45-
4633
export default class MusicQueue {
4734
guild: Guild;
4835
textChannel: BaseGuildTextChannel;
@@ -179,7 +166,7 @@ export default class MusicQueue {
179166
if (song.duration > 61 * 60)
180167
throw new Error("Sorry. Due to some technical limitations, I can't play tracks longer than 60 minutes");
181168

182-
stream = ytdl(song.url, ytdlOptions);
169+
stream = await streamYTAudio(song.id as string);
183170
}
184171
if (song.service === MusicServices.SoundCloud) {
185172
const pdl = await play.stream(song.url);
@@ -195,7 +182,7 @@ export default class MusicQueue {
195182
if (res[0].durationInSec > 61 * 60)
196183
throw new Error("Sorry. Due to some technical limitations, I can't play tracks longer than 60 minutes");
197184

198-
stream = ytdl(res[0].url, ytdlOptions);
185+
stream = await streamYTAudio(res[0].id as string);
199186
}
200187
if (song.service === MusicServices.Yandex) {
201188
const downloadInfo = await ymApi.getTrackDownloadInfo(song.id as number);

src/components/ytdl.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Readable } from "node:stream";
2+
import fetch from "node-fetch";
3+
4+
export enum AudioQuality {
5+
Low = "AUDIO_QUALITY_LOW",
6+
Medium = "AUDIO_QUALITY_MEDIUM",
7+
High = "AUDIO_QUALITY_HIGH"
8+
}
9+
10+
export interface VideoInfo {
11+
streamingData: {
12+
expiresInSeconds: string;
13+
adaptiveFormats: {
14+
url: string;
15+
mimeType: string;
16+
bitrate: number;
17+
width?: number;
18+
height?: number;
19+
fps?: number;
20+
quality: string;
21+
audioQuality?: string;
22+
qualityLabel?: string;
23+
audioSampleRate?: string;
24+
}[];
25+
};
26+
}
27+
28+
export async function getYTInfo(videoId: string): Promise<VideoInfo> {
29+
// hard-coded from https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/youtube.py
30+
const apiKey = "AIzaSyB-63vPrdThhKuerbB2N_l7Kwwcxj6yUAc";
31+
32+
const headers = {
33+
"X-YouTube-Client-Name": "5",
34+
"X-YouTube-Client-Version": "19.09.3",
35+
Origin: "https://www.youtube.com",
36+
"User-Agent": "com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)",
37+
"content-type": "application/json"
38+
};
39+
40+
const b = {
41+
context: {
42+
client: {
43+
clientName: "IOS",
44+
clientVersion: "19.09.3",
45+
deviceModel: "iPhone14,3",
46+
userAgent: "com.google.ios.youtube/19.09.3 (iPhone14,3; U; CPU iOS 15_6 like Mac OS X)",
47+
hl: "en",
48+
timeZone: "UTC",
49+
utcOffsetMinutes: 0
50+
}
51+
},
52+
videoId,
53+
playbackContext: { contentPlaybackContext: { html5Preference: "HTML5_PREF_WANTS" } },
54+
contentCheckOk: true,
55+
racyCheckOk: true
56+
};
57+
58+
return fetch(`https://www.youtube.com/youtubei/v1/player?key${apiKey}&prettyPrint=false`, { method: "POST", body: JSON.stringify(b), headers }).then(r => r.json());
59+
}
60+
61+
export async function streamYTAudio(videoId: string, quality: AudioQuality = AudioQuality.Medium) {
62+
const info = await getYTInfo(videoId);
63+
const audio = info.streamingData.adaptiveFormats.find(f => f.audioQuality === quality);
64+
65+
if (!audio)
66+
throw new Error(`No audio found for quality ${quality}`);
67+
68+
const { body } = await fetch(audio.url);
69+
70+
return Readable.from(body);
71+
}

yarn.lock

-92
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,6 @@
112112
tslib "^2.5.0"
113113
ws "^8.13.0"
114114

115-
"@distube/ytdl-core@^4.13.5":
116-
version "4.13.5"
117-
resolved "https://registry.yarnpkg.com/@distube/ytdl-core/-/ytdl-core-4.13.5.tgz#f9bacaa43225953d0ccd2a682a31d9dbbc378973"
118-
integrity sha512-g+4UJIR/auAJbia7iB0aWvaJDbs22P53NySWa47b1NT4xMTDJYguxHFArPrvRkcJrb/AgKjv/XoSZGghpL0CJA==
119-
dependencies:
120-
http-cookie-agent "^6.0.5"
121-
m3u8stream "^0.8.6"
122-
miniget "^4.2.3"
123-
sax "^1.4.1"
124-
tough-cookie "^4.1.4"
125-
undici "^6.19.2"
126-
127115
"@eslint-community/eslint-utils@^4.2.0":
128116
version "4.4.0"
129117
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -420,13 +408,6 @@ agent-base@6:
420408
dependencies:
421409
debug "4"
422410

423-
agent-base@^7.1.1:
424-
version "7.1.1"
425-
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
426-
integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
427-
dependencies:
428-
debug "^4.3.4"
429-
430411
ajv@^6.10.0, ajv@^6.12.4:
431412
version "6.12.6"
432413
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -1045,13 +1026,6 @@ has-unicode@^2.0.1:
10451026
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
10461027
integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
10471028

1048-
http-cookie-agent@^6.0.5:
1049-
version "6.0.5"
1050-
resolved "https://registry.yarnpkg.com/http-cookie-agent/-/http-cookie-agent-6.0.5.tgz#23b490439464424a689d80ea7f3a560a4a893ab8"
1051-
integrity sha512-sfZ8fDgDP3B1YB+teqSnAK1aPgBu8reUUGxSsndP2XnYN6cM29EURXWXZqQQiaRdor3B4QjpkUNfv21syaO4DA==
1052-
dependencies:
1053-
agent-base "^7.1.1"
1054-
10551029
http-response-object@^3.0.1:
10561030
version "3.0.2"
10571031
resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810"
@@ -1213,14 +1187,6 @@ lru-cache@^6.0.0:
12131187
dependencies:
12141188
yallist "^4.0.0"
12151189

1216-
m3u8stream@^0.8.6:
1217-
version "0.8.6"
1218-
resolved "https://registry.yarnpkg.com/m3u8stream/-/m3u8stream-0.8.6.tgz#0d6de4ce8ee69731734e6b616e7b05dd9d9a55b1"
1219-
integrity sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==
1220-
dependencies:
1221-
miniget "^4.2.2"
1222-
sax "^1.2.4"
1223-
12241190
make-dir@^3.1.0:
12251191
version "3.1.0"
12261192
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -1258,11 +1224,6 @@ mime-types@^2.1.12:
12581224
dependencies:
12591225
mime-db "1.52.0"
12601226

1261-
miniget@^4.2.2, miniget@^4.2.3:
1262-
version "4.2.3"
1263-
resolved "https://registry.yarnpkg.com/miniget/-/miniget-4.2.3.tgz#3707a24c7c11c25d359473291638ab28aab349bd"
1264-
integrity sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==
1265-
12661227
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
12671228
version "3.1.2"
12681229
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -1486,11 +1447,6 @@ progress@^2.0.3:
14861447
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
14871448
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
14881449

1489-
psl@^1.1.33:
1490-
version "1.9.0"
1491-
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
1492-
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
1493-
14941450
pstree.remy@^1.1.8:
14951451
version "1.1.8"
14961452
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
@@ -1501,16 +1457,6 @@ punycode@^2.1.0:
15011457
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
15021458
integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
15031459

1504-
punycode@^2.1.1:
1505-
version "2.3.1"
1506-
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
1507-
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
1508-
1509-
querystringify@^2.1.1:
1510-
version "2.2.0"
1511-
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
1512-
integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
1513-
15141460
queue-microtask@^1.2.2:
15151461
version "1.2.3"
15161462
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@@ -1539,11 +1485,6 @@ readdirp@~3.6.0:
15391485
dependencies:
15401486
picomatch "^2.2.1"
15411487

1542-
requires-port@^1.0.0:
1543-
version "1.0.0"
1544-
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
1545-
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
1546-
15471488
resolve-from@^4.0.0:
15481489
version "4.0.0"
15491490
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -1578,11 +1519,6 @@ sax@>=0.6.0:
15781519
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
15791520
integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
15801521

1581-
sax@^1.2.4, sax@^1.4.1:
1582-
version "1.4.1"
1583-
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
1584-
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
1585-
15861522
semver@^5.7.1:
15871523
version "5.7.1"
15881524
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
@@ -1741,16 +1677,6 @@ touch@^3.1.0:
17411677
dependencies:
17421678
nopt "~1.0.10"
17431679

1744-
tough-cookie@^4.1.4:
1745-
version "4.1.4"
1746-
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36"
1747-
integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==
1748-
dependencies:
1749-
psl "^1.1.33"
1750-
punycode "^2.1.1"
1751-
universalify "^0.2.0"
1752-
url-parse "^1.5.3"
1753-
17541680
tr46@~0.0.3:
17551681
version "0.0.3"
17561682
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@@ -1836,16 +1762,6 @@ undici@^5.22.0:
18361762
dependencies:
18371763
busboy "^1.6.0"
18381764

1839-
undici@^6.19.2:
1840-
version "6.19.2"
1841-
resolved "https://registry.yarnpkg.com/undici/-/undici-6.19.2.tgz#231bc5de78d0dafb6260cf454b294576c2f3cd31"
1842-
integrity sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==
1843-
1844-
universalify@^0.2.0:
1845-
version "0.2.0"
1846-
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
1847-
integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
1848-
18491765
unws@^0.2.3:
18501766
version "0.2.3"
18511767
resolved "https://registry.yarnpkg.com/unws/-/unws-0.2.3.tgz#c9152a542e3e30f13be006d68caec3f3e2e08856"
@@ -1858,14 +1774,6 @@ uri-js@^4.2.2:
18581774
dependencies:
18591775
punycode "^2.1.0"
18601776

1861-
url-parse@^1.5.3:
1862-
version "1.5.10"
1863-
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
1864-
integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
1865-
dependencies:
1866-
querystringify "^2.1.1"
1867-
requires-port "^1.0.0"
1868-
18691777
util-deprecate@^1.0.1:
18701778
version "1.0.2"
18711779
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"

0 commit comments

Comments
 (0)