streamify-audio 2.2.13 → 2.3.0
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/docs/plans/2026-02-22-stream-revamp-design.md +88 -0
- package/docs/plans/2026-02-22-stream-revamp-plan.md +814 -0
- package/package.json +1 -1
- package/src/config.js +14 -2
- package/src/discord/Player.js +74 -20
- package/src/discord/Stream.js +253 -87
- package/src/filters/ffmpeg.js +4 -3
- package/youtube-cookies.txt +26 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Stream System Revamp — Design Document
|
|
2
|
+
|
|
3
|
+
## Problem Statement
|
|
4
|
+
|
|
5
|
+
The current stream system has critical issues:
|
|
6
|
+
1. `_waitForData()` resolves on timeout (15s), allowing broken/silent streams to start playback
|
|
7
|
+
2. yt-dlp spawns per-play are slow — format negotiation adds seconds of latency
|
|
8
|
+
3. No URL caching — direct URLs aren't reused for replays/seeks
|
|
9
|
+
4. Prefetch only resolves metadata, doesn't prepare the actual stream pipeline
|
|
10
|
+
5. Error swallowing hides real failures from yt-dlp/ffmpeg stderr
|
|
11
|
+
|
|
12
|
+
## Architecture: Two-Phase StreamController
|
|
13
|
+
|
|
14
|
+
### Phase 1: `prepare()` — URL Extraction
|
|
15
|
+
- Check `StreamURLCache` for cached direct URL
|
|
16
|
+
- Cache miss → spawn `yt-dlp --get-url -f bestaudio` to extract direct stream URL
|
|
17
|
+
- Cache the URL (key: `{videoId}:{format}`, TTL: 30 min)
|
|
18
|
+
- For Spotify: resolve to YouTube ID first (existing behavior)
|
|
19
|
+
- For live streams: skip (can't pre-extract live URLs)
|
|
20
|
+
|
|
21
|
+
### Phase 2: `start()` — Stream Creation
|
|
22
|
+
- Spawn ffmpeg with `-i <directURL>` (no yt-dlp pipe for non-live)
|
|
23
|
+
- Wait for first byte with configurable timeout (default: 8s, live: 15s)
|
|
24
|
+
- **Reject on timeout** — never proceed without data
|
|
25
|
+
- Return AudioResource ready for playback
|
|
26
|
+
|
|
27
|
+
### Fallback for live/non-YouTube sources
|
|
28
|
+
- Spawn yt-dlp piped to ffmpeg (current behavior)
|
|
29
|
+
- Same timeout/rejection behavior
|
|
30
|
+
|
|
31
|
+
## StreamURLCache
|
|
32
|
+
|
|
33
|
+
Module-level cache in Stream.js:
|
|
34
|
+
- `Map<string, { url, headers, expiry }>`
|
|
35
|
+
- `get(key)` — returns null if expired
|
|
36
|
+
- `set(key, url, headers, ttl)`
|
|
37
|
+
- `invalidate(key)` — for 403/gone errors
|
|
38
|
+
- Auto-cleanup every 5 minutes
|
|
39
|
+
|
|
40
|
+
## Player.js — Aggressive Prefetch
|
|
41
|
+
|
|
42
|
+
### `_prefetchNext()` Rewrite
|
|
43
|
+
- Triggers on `trackStart` (current track begins)
|
|
44
|
+
- Creates full StreamController for queue[0]
|
|
45
|
+
- Runs `prepare()` + `start()` — ffmpeg spawned, audio buffered
|
|
46
|
+
- Stores as `_prefetchedStream` / `_prefetchedTrack`
|
|
47
|
+
|
|
48
|
+
### `_playTrack()` Changes
|
|
49
|
+
- Check prefetch match → instant play (zero startup)
|
|
50
|
+
- Otherwise: create StreamController, prepare() + start()
|
|
51
|
+
- On error: emit trackError, auto-skip
|
|
52
|
+
|
|
53
|
+
### Prefetch Lifecycle
|
|
54
|
+
- Clear on: filter/volume change, stop, destroy, queue reorder
|
|
55
|
+
- Ignore failures: log and fall back to normal creation
|
|
56
|
+
|
|
57
|
+
## Config Additions
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
stream: {
|
|
61
|
+
dataTimeout: 8000, // ms to wait for first byte
|
|
62
|
+
liveDataTimeout: 15000, // ms for live streams
|
|
63
|
+
urlCacheTTL: 1800, // 30 min
|
|
64
|
+
bufferSize: '1M', // yt-dlp buffer (up from 256K)
|
|
65
|
+
maxRetries: 2 // extraction retries before skip
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Error Handling
|
|
70
|
+
|
|
71
|
+
- `_waitForData()`: reject on timeout (not resolve)
|
|
72
|
+
- URL extraction failure: retry once before giving up
|
|
73
|
+
- 403/expired URL: invalidate cache, retry with fresh extraction
|
|
74
|
+
- ffmpeg stderr: parse for actionable errors, log properly
|
|
75
|
+
- yt-dlp stderr: count "Retrying fragment" occurrences, fail after threshold
|
|
76
|
+
|
|
77
|
+
## Files Modified
|
|
78
|
+
|
|
79
|
+
1. `src/discord/Stream.js` — Full rewrite (StreamController + StreamURLCache)
|
|
80
|
+
2. `src/discord/Player.js` — Prefetch rewrite, _playTrack changes
|
|
81
|
+
3. `src/config.js` — New `stream` config section
|
|
82
|
+
|
|
83
|
+
## Files NOT Modified
|
|
84
|
+
|
|
85
|
+
- `src/filters/ffmpeg.js` — Unchanged (filter building is solid)
|
|
86
|
+
- `src/providers/youtube.js` — Unchanged (search/info/playlist untouched)
|
|
87
|
+
- `src/discord/Queue.js` — Unchanged
|
|
88
|
+
- `src/discord/Manager.js` — Unchanged
|