summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/research.md
blob: 5ff33dd2f6b03091e5d87df293521096e688d7c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
# Discord Music Bot Development — Tool Research Report

> **Query:** What tools are needed to develop a Discord bot that streams YouTube audio to voice channels, with queue management via user commands — preferring JavaScript/TypeScript.

---

## Executive Summary

Building a Discord music bot that streams YouTube audio to voice channels in 2025 requires a carefully chosen stack due to YouTube's frequently changing API restrictions and the deprecation of several once-popular libraries. The recommended modern stack centers on **Discord.js v14** (Discord API framework), **@discordjs/voice** (low-level voice layer), a high-level music framework (**discord-player** or **DisTube**), and a YouTube extraction backend using **youtubei.js** (via `discord-player-youtubei` extractor or DisTube's plugin system). For large-scale or production bots, **Lavalink v4** (a Java-based audio server) offers superior performance. TypeScript is natively supported by all recommended libraries and is strongly advisable.

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                        Discord API (WebSocket + REST)           │
└────────────────────────┬────────────────────────────────────────┘
                         │
                ┌────────▼────────┐
                │   discord.js    │  ← Bot framework (JS/TS)
                │     v14         │
                └────────┬────────┘
                         │
          ┌──────────────┴───────────────┐
          │                              │
 ┌────────▼──────────┐        ┌──────────▼──────────┐
 │  Music Framework  │        │  @discordjs/voice   │
 │ (discord-player   │───────▶│  (low-level voice   │
 │  OR DisTube)      │        │   connections)      │
 └────────┬──────────┘        └──────────┬──────────┘
          │                              │
 ┌────────▼──────────┐        ┌──────────▼──────────┐
 │  YouTube Extractor│        │  Audio Processing   │
 │  (youtubei.js /   │        │  FFmpeg + Opus      │
 │   yt-dlp)         │        │  (encoding/decoding)│
 └───────────────────┘        └─────────────────────┘

                  ─── OR, for large bots ───

┌──────────────────────────────────────────────────────────────────┐
│                    Lavalink v4 (Java server)                     │
│   Lavaplayer + youtube-source plugin → streams audio via WS      │
│   Node.js client: lavalink-client npm package                   │
└──────────────────────────────────────────────────────────────────┘
```

---

## Component 1: Discord Bot Framework — Discord.js v14

**Repository:** [discordjs/discord.js](https://github.com/discordjs/discord.js)  
**NPM:** `discord.js`  
**Language:** TypeScript (ships `.d.ts` declarations)

Discord.js is the overwhelmingly dominant Discord API library for Node.js, offering complete coverage of the Discord REST API and Gateway WebSocket events.[^1] v14 introduced native TypeScript support, slash command builders, interaction handling, and the `GatewayIntentBits` enum.

### Required Intents for a Music Bot

```typescript
import { Client, GatewayIntentBits } from 'discord.js';

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,          // required for slash commands
    GatewayIntentBits.GuildVoiceStates, // required for voice channel management
    GatewayIntentBits.GuildMessages,    // for prefix commands (if used)
    GatewayIntentBits.MessageContent,  // PRIVILEGED: required to read message content
  ],
});
```

> **Note:** `MessageContent` is a **privileged intent** — it must be enabled manually in the [Discord Developer Portal](https://discord.com/developers/applications). For a slash-command-only bot, it's not needed.

### Slash Command Structure

Modern bots use slash commands (`/play`, `/skip`, `/queue`, etc.) registered via the REST API. The recommended structure:

```
src/
  commands/
    play.ts
    skip.ts
    queue.ts
    stop.ts
  events/
    ready.ts
    interactionCreate.ts
  deploy-commands.ts
  index.ts
```

---

## Component 2: Voice Layer — @discordjs/voice

**Repository:** [discordjs/voice](https://github.com/discordjs/voice)  
**NPM:** `@discordjs/voice`

This is the **official, low-level Discord voice library** from the discord.js team.[^2] It handles:
- Joining and leaving voice channels
- Creating and managing audio players
- Creating audio resources from streams
- Subscribing voice connections to audio players

It is the backbone used by all higher-level music frameworks (DisTube, discord-player).

### Key APIs

```typescript
import {
  joinVoiceChannel,
  createAudioPlayer,
  createAudioResource,
  AudioPlayerStatus,
  VoiceConnectionStatus,
} from '@discordjs/voice';
```

### Required Peer Dependencies

From the official README[^2], you need to install one option from each category:

| Category | Recommended | Alternatives | Purpose |
|---|---|---|---|
| **Opus** | `@discordjs/opus` | `opusscript`, `mediaplex` | Audio encoding (Opus codec for Discord) |
| **Encryption** | `sodium-native` | `sodium`, `libsodium-wrappers`, `tweetnacl` | Encrypting voice data |
| **FFmpeg** | System FFmpeg | `ffmpeg-static` (npm) | Media transcoding |

```bash
npm install @discordjs/voice @discordjs/opus sodium-native
# Install FFmpeg: sudo apt install ffmpeg (Linux) or brew install ffmpeg (Mac)
# OR: npm install ffmpeg-static
```

> **Important:** As of 2024, Node.js 16+ is required by `@discordjs/voice`; Node.js 20+ is recommended for modern discord.js projects.[^3]

---

## Component 3: Music Frameworks (High-Level Abstractions)

Rather than building queue management, audio resource handling, and track searching from scratch, use one of these frameworks that sit on top of `@discordjs/voice`.

### Option A: discord-player (Recommended for TypeScript/Flexibility)

**Repository:** [Androz2091/discord-player](https://github.com/Androz2091/discord-player)  
**NPM:** `discord-player` + `@discord-player/extractor`  
**Docs:** [discord-player.js.org](https://discord-player.js.org)

discord-player is a robust, TypeScript-first music framework providing:[^4]
- Built-in queue management with repeat, shuffle, volume control
- 64+ built-in audio filter presets
- Extensible Extractor API (pluggable source backends)
- `useMainPlayer()` hooks for clean code patterns
- Automatic voice state handling
- IP rotation support
- Object-oriented design with events system

```bash
npm install discord-player @discord-player/extractor mediaplex
```

```typescript
import { Player } from 'discord-player';
import { DefaultExtractors } from '@discord-player/extractor';
import { YoutubeiExtractor } from 'discord-player-youtubei';

const player = new Player(client);
await player.extractors.loadMulti(DefaultExtractors);
// Register the YouTube extractor (see Component 4 below)
await player.extractors.register(YoutubeiExtractor, {});

player.events.on('playerStart', (queue, track) => {
  queue.metadata.channel.send(`▶️ Now playing: **${track.cleanTitle}**`);
});
```

**Play command example:**
```typescript
import { useMainPlayer } from 'discord-player';

const player = useMainPlayer();
const { track } = await player.play(voiceChannel, query, {
  nodeOptions: { metadata: interaction },
});
await interaction.followUp(`✅ Enqueued: **${track.cleanTitle}**`);
```

> **Note:** discord-player v6+ uses `discord-voip` (a fork of `@discordjs/voice`) as its internal voice layer.[^4]

---

### Option B: DisTube (Batteries-Included)

**Repository:** [skick1234/DisTube](https://github.com/distubejs/distube)  
**NPM:** `distube`  
**Docs:** [distube.js.org](https://distube.js.org)

DisTube is a high-level, all-in-one music bot library offering more out-of-the-box functionality:[^5]
- Built-in queue, playlist, and voice connection management
- 20+ built-in audio filters (bassboost, nightcore, echo, karaoke, etc.)
- Plugin system supporting YouTube, Spotify, SoundCloud, Bandcamp, and 700+ other sites
- Full TypeScript support
- Requires `discord.js v14` and `@discordjs/voice`

```bash
npm install distube @discordjs/voice @discordjs/opus
```

```javascript
import { DisTube } from 'distube';

const distube = new DisTube(client, { emitNewSongOnly: true });

distube.on('playSong', (queue, song) =>
  queue.textChannel?.send(`▶️ Playing \`${song.name}\` - \`${song.formattedDuration}\``)
);

// Play command handler
distube.play(message.member!.voice.channel!, query, {
  message,
  textChannel: message.channel,
  member: message.member!,
});
```

### Option A vs. B Comparison

| Feature | discord-player | DisTube |
|---|---|---|
| Abstraction Level | Medium-High | High |
| TypeScript Quality | Excellent | Good |
| Queue Management | Built-in | Built-in |
| Audio Filters | 64+ presets | 20+ built-in |
| Plugin/Extractor System | Extractor API | Plugin system |
| Customizability | High | Moderate |
| Ease of Setup | Moderate | Simple |
| Supports 700+ sites | Via extractors | Via plugins (yt-dlp plugin) |
| Community Size | Large | Large |
| Voice Library | `discord-voip` (fork) | `@discordjs/voice` |

**Recommendation:** Use **discord-player** for TypeScript-first, flexible development. Use **DisTube** if you want maximum out-of-the-box features with minimal setup.

---

## Component 4: YouTube Audio Extraction — The Critical Piece

YouTube is the most complex component due to frequent API changes and the **deprecation of ytdl-core** in August 2024.[^6]

### ⚠️ What NOT to Use Anymore

| Library | Status | Reason |
|---|---|---|
| `ytdl-core` | **Deprecated (Aug 2024)** | No longer maintained; frequently broken |
| `@distube/ytdl-core` | **Deprecated** | Maintenance stopped; recommends migration to youtubei.js |
| `play-dl` | **Archived (Jun 2025)** | Repository archived; no new updates |

### ✅ Current Recommended Options

#### Option 1: `discord-player-youtubei` (Best for discord-player)

**Repository:** [retrouser955/discord-player-youtubei](https://github.com/retrouser955/discord-player-youtubei)  
**NPM:** `discord-player-youtubei`

Built on top of `youtubei.js` (YouTube's InnerTube API), this extractor plugin is the current community standard for discord-player YouTube support.[^7]

```bash
npm install discord-player-youtubei
```

```typescript
import { YoutubeiExtractor } from 'discord-player-youtubei';

// Register once at startup - not in every command
await player.extractors.register(YoutubeiExtractor, {
  // Optional: authenticate with YouTube account for higher rate limits
  // authentication: 'OAUTH_TOKEN'
});
```

#### Option 2: `youtubei.js` (LuanRT) — Direct Usage

**Repository:** [LuanRT/YouTube.js](https://github.com/LuanRT/YouTube.js)  
**NPM:** `youtubei.js`  
**Docs:** [ytjs.dev](https://ytjs.dev)

A full JavaScript client for YouTube's private InnerTube API. Enables searching, metadata fetching, and stream URL extraction. Used under the hood by `discord-player-youtubei` and referenced as the recommended successor to `ytdl-core`.[^6]

#### Option 3: `yt-dlp` (via subprocess — Most Robust)

**Binary:** [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) (Python, installed separately)  
**Node wrapper:** `yt-dlp-wrap` npm package

`yt-dlp` is a Python CLI tool that is the most actively maintained YouTube downloader. It handles YouTube's anti-bot measures most robustly.[^8] It can be called from Node.js as a subprocess:

```typescript
import { spawn } from 'child_process';
import { createAudioResource, StreamType } from '@discordjs/voice';

function getYtDlpStream(url: string) {
  const proc = spawn('yt-dlp', [
    '-f', 'bestaudio',
    '--no-playlist',
    '-o', '-',  // output to stdout
    url,
  ], { stdio: ['ignore', 'pipe', 'ignore'] });

  return createAudioResource(proc.stdout, {
    inputType: StreamType.Arbitrary,
  });
}
```

> **Note:** Requires `yt-dlp` binary to be installed on the host system (`pip install yt-dlp` or system package manager). Can also be used via DisTube's `@distube/yt-dlp` plugin.

#### Option 4: DisTube YouTube Plugin

For DisTube users, the official `@distube/youtube` plugin or the `@distube/yt-dlp` plugin handles YouTube extraction natively within the DisTube ecosystem.[^5]

---

## Component 5: Lavalink — For Production/Large-Scale Bots

**Repository:** [lavalink-devs/Lavalink](https://github.com/lavalink-devs/Lavalink)  
**Docs:** [lavalink.dev](https://lavalink.dev)  
**Version:** v4 (stable)

Lavalink is a **standalone Java audio server** that offloads all audio processing from your bot's Node.js process.[^9] It communicates with your bot over WebSocket and is used in production by major bots (FredBoat, Dyno, etc.).

### Why Lavalink?

- **Performance**: Audio transcoding happens in a separate JVM process — your bot stays fast
- **Scalability**: Supports multiple nodes for horizontal scaling
- **Seeking**: Built-in seeking support
- **Volume control**: Precise volume control
- **Filters**: Equalizer, timescale, tremolo, vibrato, rotation, distortion filters
- **YouTube support**: Via the official `youtube-source` plugin for Lavaplayer[^10]

### Requirements

- **Java 17 LTS or newer** (runs as a separate process)
- Your Node.js bot connects as a client via WebSocket

### Setup Overview

1. **Download** the Lavalink JAR from [GitHub Releases](https://github.com/lavalink-devs/Lavalink/releases)
2. **Configure** `application.yml`:
```yaml
server:
  port: 2333
lavalink:
  server:
    password: "your-strong-password"
plugins:
  youtube:
    enabled: true
    clients: ["MUSIC", "ANDROID_VR", "WEB", "WEBEMBEDDED"]
```
3. **Run**: `java -jar Lavalink.jar`
4. **Connect** your Node.js bot using `lavalink-client`:

```bash
npm install lavalink-client
```

```typescript
import { LavalinkManager } from 'lavalink-client';

client.lavalink = new LavalinkManager({
  nodes: [{
    authorization: 'your-strong-password',
    host: 'localhost',
    port: 2333,
    id: 'main-node',
  }],
  sendToShard: (guildId, payload) =>
    client.guilds.cache.get(guildId)?.shard?.send(payload),
  client: { id: process.env.CLIENT_ID!, username: 'MusicBot' },
});

client.on('raw', d => client.lavalink.sendRawData(d));
client.on('ready', () => client.lavalink.init({ ...client.user! }));
```

### Node.js Lavalink Clients

| Package | Notes |
|---|---|
| `lavalink-client` | Most actively maintained; full TypeScript support |
| `shoukaku` | Performant, popular choice |
| `lavacord` | Lightweight; [lavacord.js.org](https://lavacord.js.org) |
| `moonlink.js` | Alternative with good TS support |

### Lavalink YouTube Source Plugin

The official [`youtube-source`](https://github.com/lavalink-devs/youtube-source) plugin for Lavaplayer uses multiple InnerTube clients to maximize success rate against YouTube's anti-bot measures.[^10] Configure in `application.yml` as shown above.

---

## Component 6: Development Toolchain

### TypeScript Setup

```bash
npm install -D typescript @types/node ts-node tsup
```

**Recommended `tsconfig.json`:**
```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "commonjs",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```

**Build tool:** Use **`tsup`** (fast, zero-config TypeScript bundler) or plain `tsc`.

### Environment Variables

Use **`dotenv`** for managing secrets:
```bash
npm install dotenv
```

```
# .env
DISCORD_TOKEN=your_bot_token
CLIENT_ID=your_application_id
GUILD_ID=optional_test_guild_id
```

### Project Scaffolding Options

| Template | Description |
|---|---|
| [KevinNovak/Discord-Bot-TypeScript-Template](https://github.com/KevinNovak/Discord-Bot-TypeScript-Template) | Production-ready TS template with PM2/Docker support |
| [MericcaN41/discordjs-v14-template-ts](https://github.com/MericcaN41/discordjs-v14-template-ts) | Handlers, MongoDB, permissions, cooldowns |

---

## Component 7: Persistence & State Management

For queue persistence across restarts or advanced features:

| Need | Tool |
|---|---|
| Simple key-value / queue state | **Redis** (`ioredis` npm) |
| Relational data (playlists, server settings) | **PostgreSQL** via `pg` or **SQLite** via `better-sqlite3` |
| ORM | **Prisma** (excellent TypeScript support) |
| In-memory only (simplest) | Native `Map<string, Queue>` (no persistence) |

For most bots, an in-memory `Map` per guild is sufficient for queue state. Persist only playlists/settings to a database.

---

## Component 8: Deployment & Hosting

### Minimum Hardware Requirements

- **RAM:** 512 MB minimum; 1 GB recommended (2+ GB if running Lavalink on the same host)
- **CPU:** 1 vCPU minimum
- **OS:** Ubuntu 22.04+ LTS recommended
- **Java:** Required only if running Lavalink on the same host (Java 17+)

### Process Management

**PM2** (simpler, Node.js-native):
```bash
npm install -g pm2
pm2 start dist/index.js --name music-bot
pm2 save && pm2 startup
```

**Docker** (more portable, production-grade):
```dockerfile
FROM node:20-alpine
WORKDIR /app
RUN apk add --no-cache ffmpeg python3 py3-pip && pip3 install yt-dlp
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./dist/
CMD ["node", "dist/index.js"]
```

Use `docker-compose.yml` to run the bot + Lavalink together.

### Hosting Providers

| Provider | Type | Notes |
|---|---|---|
| DigitalOcean Droplet | VPS | $6/mo for 1GB RAM; full control |
| Linode/Akamai | VPS | Similar to DigitalOcean |
| Hetzner Cloud | VPS | Cheapest per-GB in EU |
| Railway.app | PaaS | Easy deploy, free tier available |
| Fly.io | PaaS | Free tier with containers |
| VPS self-hosted | VPS | Maximum control |

> **Avoid serverless platforms** (Lambda, Vercel) — Discord bots require persistent WebSocket connections.

---

## Full Recommended Stack Summary

### For a Starter/Personal Bot (Simpler)

```bash
npm install discord.js @discordjs/voice discord-player @discord-player/extractor \
            discord-player-youtubei mediaplex ffmpeg-static sodium dotenv
npm install -D typescript @types/node ts-node tsup
```

| Layer | Choice |
|---|---|
| Discord API | `discord.js` v14 |
| Voice | `@discordjs/voice` (via discord-player internally) |
| Music Framework | `discord-player` v6+ |
| YouTube Backend | `discord-player-youtubei` (uses `youtubei.js`) |
| Opus Encoding | `mediaplex` |
| FFmpeg | `ffmpeg-static` or system install |
| Encryption | `sodium` |
| Language | TypeScript |
| Deployment | PM2 on a VPS |

### For a Production Bot (Large Scale)

```bash
npm install discord.js lavalink-client dotenv
npm install -D typescript @types/node tsup
# On server: Java 17+, then run Lavalink JAR
```

| Layer | Choice |
|---|---|
| Discord API | `discord.js` v14 |
| Voice/Streaming | Lavalink v4 (Java server) + `lavalink-client` |
| YouTube Backend | Lavalink `youtube-source` plugin |
| Language | TypeScript |
| Deployment | Docker Compose (bot + Lavalink) on VPS |

---

## Legal & ToS Considerations

> ⚠️ **Important:** Streaming YouTube audio directly to Discord may violate [YouTube's Terms of Service](https://www.youtube.com/static?template=terms), specifically Section 5.B which prohibits downloading content except through YouTube's explicitly permitted mechanisms.

Key considerations:
- **Private bots** (in your own server) face significantly less legal risk than public bots
- Two of the largest music bots — **Groovy** and **Rythm** — were shut down in 2021 following legal pressure from YouTube/Google
- YouTube's Music API and official embeds are the ToS-compliant alternatives
- Bots using Spotify typically use Spotify's search to find the song name, then stream the YouTube equivalent (since Spotify doesn't provide audio streams)
- Consider using **SoundCloud** or other platforms with permissive APIs as alternatives or fallbacks

---

## Key Repositories Summary

| Repository | Purpose | Language |
|---|---|---|
| [discordjs/discord.js](https://github.com/discordjs/discord.js) | Discord API client library | TypeScript |
| [discordjs/voice](https://github.com/discordjs/voice) | Discord voice connections | TypeScript |
| [Androz2091/discord-player](https://github.com/Androz2091/discord-player) | High-level music framework | TypeScript |
| [skick1234/DisTube](https://github.com/distubejs/distube) | All-in-one music library | TypeScript |
| [retrouser955/discord-player-youtubei](https://github.com/retrouser955/discord-player-youtubei) | YouTube extractor for discord-player | TypeScript |
| [LuanRT/YouTube.js](https://github.com/LuanRT/YouTube.js) | InnerTube API client | TypeScript |
| [lavalink-devs/Lavalink](https://github.com/lavalink-devs/Lavalink) | Audio server for large bots | Java |
| [lavalink-devs/youtube-source](https://github.com/lavalink-devs/youtube-source) | YouTube plugin for Lavalink | Java |
| [lavalink-devs/lavalink-client](https://github.com/lavalink-devs/lavalink-client) | Node.js Lavalink client | TypeScript |
| [yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) | YouTube downloader CLI | Python |

---

## Confidence Assessment

| Finding | Confidence | Notes |
|---|---|---|
| discord.js v14 is the standard | **Very High** | Unambiguous community consensus |
| `ytdl-core` is deprecated (Aug 2024) | **Very High** | Confirmed via npm README + GitHub |
| `play-dl` is archived (Jun 2025) | **Very High** | Confirmed via GitHub repo status |
| `discord-player-youtubei` is recommended | **High** | Multiple community sources + GitHub |
| `discord-player` uses `discord-voip` fork | **High** | Confirmed via official README[^4] |
| Lavalink v4 is stable | **Very High** | Confirmed via official README[^9] |
| Lavalink youtube-source uses InnerTube | **Very High** | Confirmed via repo README[^10] |
| `mediaplex` is recommended over `@discordjs/opus` for discord-player | **High** | Stated in discord-player README[^4] |
| Legal risks around YouTube streaming | **High** | Based on precedent (Groovy/Rythm) + YouTube ToS |

---

## Footnotes

[^1]: [discordjs/discord.js](https://github.com/discordjs/discord.js) — Official Discord.js repository; docs at [discord.js.org](https://discord.js.org)

[^2]: [discordjs/voice README.md](https://github.com/discordjs/voice/blob/main/README.md) — Lists all required optional dependencies (encryption, Opus, FFmpeg)

[^3]: [discordjs/voice installation docs](https://discordjs.guide/voice) — Node.js 16+ required; 20+ recommended

[^4]: [Androz2091/discord-player README.md](https://github.com/Androz2091/discord-player/blob/master/README.md) — Full setup instructions, mediaplex recommendation, FFmpeg notes

[^5]: [skick1234/DisTube README.md](https://github.com/distubejs/distube/blob/main/README.md) — Official README; plugin architecture; install `distube @discordjs/voice @discordjs/opus`

[^6]: [ytdl-core deprecation discussion](https://stackoverflow.com/questions/78824388/ytdl-core-is-returning-a-stream-with-nothing-in-it) — Community discussion on ytdl-core being broken; `@distube/ytdl-core` points to `youtubei.js` as successor; [npm @distube/ytdl-core](https://www.npmjs.com/package/@distube/ytdl-core)

[^7]: [retrouser955/discord-player-youtubei GitHub](https://github.com/retrouser955/discord-player-youtubei) — YouTube extractor built on youtubei.js for discord-player v6/v7

[^8]: [yt-dlp PyPI](https://pypi.org/project/yt-dlp/) — Most actively maintained YouTube downloader; regularly updated against YouTube's bot detection

[^9]: [lavalink-devs/Lavalink README.md](https://github.com/lavalink-devs/Lavalink/blob/master/README.md) — v4 is stable; Java 17 required; used by FredBoat, Dyno in production

[^10]: [lavalink-devs/youtube-source README.md](https://github.com/lavalink-devs/youtube-source) — YouTube plugin for Lavaplayer using multiple InnerTube clients for robustness