streamify-audio 2.3.0 → 2.3.2

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.
Files changed (39) hide show
  1. package/index.d.ts +9 -0
  2. package/package.json +1 -1
  3. package/src/config.js +11 -0
  4. package/src/discord/Manager.js +1 -1
  5. package/src/discord/Stream.js +9 -12
  6. package/src/providers/spotify.js +2 -2
  7. package/docs/README.md +0 -31
  8. package/docs/automation.md +0 -186
  9. package/docs/configuration.md +0 -198
  10. package/docs/discord/events.md +0 -206
  11. package/docs/discord/manager.md +0 -195
  12. package/docs/discord/player.md +0 -263
  13. package/docs/discord/queue.md +0 -197
  14. package/docs/examples/advanced-bot.md +0 -391
  15. package/docs/examples/basic-bot.md +0 -182
  16. package/docs/examples/lavalink.md +0 -156
  17. package/docs/filters.md +0 -347
  18. package/docs/http/endpoints.md +0 -224
  19. package/docs/http/server.md +0 -174
  20. package/docs/plans/2026-02-22-stream-revamp-design.md +0 -88
  21. package/docs/plans/2026-02-22-stream-revamp-plan.md +0 -814
  22. package/docs/quick-start.md +0 -92
  23. package/docs/sources.md +0 -189
  24. package/docs/sponsorblock.md +0 -95
  25. package/tests/cache.test.js +0 -234
  26. package/tests/config.test.js +0 -44
  27. package/tests/error-handling.test.js +0 -318
  28. package/tests/ffmpeg.test.js +0 -66
  29. package/tests/filters-edge.test.js +0 -333
  30. package/tests/http.test.js +0 -24
  31. package/tests/integration.test.js +0 -325
  32. package/tests/local.test.js +0 -37
  33. package/tests/queue.test.js +0 -94
  34. package/tests/spotify.test.js +0 -238
  35. package/tests/stream.test.js +0 -217
  36. package/tests/twitch.test.js +0 -42
  37. package/tests/utils.test.js +0 -60
  38. package/tests/youtube.test.js +0 -219
  39. package/youtube-cookies.txt +0 -26
@@ -1,224 +0,0 @@
1
- # HTTP Endpoints
2
-
3
- ## YouTube
4
-
5
- ### Search
6
-
7
- ```
8
- GET /youtube/search?q=query&limit=10
9
- ```
10
-
11
- **Response:**
12
- ```json
13
- {
14
- "tracks": [
15
- {
16
- "id": "dQw4w9WgXcQ",
17
- "title": "Rick Astley - Never Gonna Give You Up",
18
- "author": "Rick Astley",
19
- "duration": 213,
20
- "thumbnail": "https://...",
21
- "uri": "https://youtube.com/watch?v=dQw4w9WgXcQ",
22
- "streamUrl": "/youtube/stream/dQw4w9WgXcQ",
23
- "source": "youtube"
24
- }
25
- ],
26
- "source": "youtube",
27
- "searchTime": 1234
28
- }
29
- ```
30
-
31
- ### Get Info
32
-
33
- ```
34
- GET /youtube/info/:videoId
35
- ```
36
-
37
- **Response:**
38
- ```json
39
- {
40
- "id": "dQw4w9WgXcQ",
41
- "title": "Rick Astley - Never Gonna Give You Up",
42
- "author": "Rick Astley",
43
- "duration": 213,
44
- "thumbnail": "https://...",
45
- "uri": "https://youtube.com/watch?v=dQw4w9WgXcQ",
46
- "streamUrl": "/youtube/stream/dQw4w9WgXcQ",
47
- "source": "youtube"
48
- }
49
- ```
50
-
51
- ### Stream
52
-
53
- ```
54
- GET /youtube/stream/:videoId
55
- GET /youtube/stream/:videoId?bass=10&nightcore=true&start=30
56
- ```
57
-
58
- **Query Parameters:**
59
- - All [filters](../filters.md) are supported
60
- - `start` - Seek to position in seconds
61
-
62
- **Response:** Audio stream (`audio/ogg`)
63
-
64
- ## Spotify
65
-
66
- ### Search
67
-
68
- ```
69
- GET /spotify/search?q=query&limit=10
70
- ```
71
-
72
- ### Get Info
73
-
74
- ```
75
- GET /spotify/info/:trackId
76
- ```
77
-
78
- ### Stream
79
-
80
- ```
81
- GET /spotify/stream/:trackId
82
- GET /spotify/stream/:trackId?bass=10
83
- ```
84
-
85
- Spotify tracks are resolved to YouTube and streamed from there.
86
-
87
- ## SoundCloud
88
-
89
- ### Search
90
-
91
- ```
92
- GET /soundcloud/search?q=query&limit=10
93
- ```
94
-
95
- ### Stream
96
-
97
- ```
98
- GET /soundcloud/stream/:trackUrl
99
- ```
100
-
101
- Note: `trackUrl` should be URL-encoded.
102
-
103
- ## Generic Routes
104
-
105
- ### Search
106
-
107
- ```
108
- GET /search?q=query&source=youtube&limit=10
109
- ```
110
-
111
- **Query Parameters:**
112
- - `q` - Search query
113
- - `source` - `youtube`, `spotify`, `soundcloud`, `twitch`, `mixcloud`, `bandcamp`, `local`, `http`
114
- - `limit` - Number of results
115
-
116
- ### Stream
117
-
118
- ```
119
- GET /stream/:source/:id
120
- ```
121
-
122
- **Example:**
123
- ```
124
- GET /stream/twitch/monstercat
125
- GET /stream/local/L2hvbWUvdXNlci9tdXNpYy9zbmFyZS53YXY= (Base64 path)
126
- ```
127
-
128
- ## Stream Management
129
-
130
- ### List Active Streams
131
-
132
- ```
133
- GET /streams
134
- ```
135
-
136
- **Response:**
137
- ```json
138
- {
139
- "streams": [
140
- {
141
- "id": "yt-dQw4w9WgXcQ-1234567890",
142
- "source": "youtube",
143
- "trackId": "dQw4w9WgXcQ",
144
- "filters": { "bass": 10 },
145
- "startTime": 1234567890,
146
- "bytesReceived": 1048576,
147
- "bytesSent": 524288
148
- }
149
- ],
150
- "count": 1
151
- }
152
- ```
153
-
154
- ### Get Stream Info
155
-
156
- ```
157
- GET /streams/:streamId
158
- ```
159
-
160
- **Response:**
161
- ```json
162
- {
163
- "id": "yt-dQw4w9WgXcQ-1234567890",
164
- "source": "youtube",
165
- "trackId": "dQw4w9WgXcQ",
166
- "filters": { "bass": 10 },
167
- "startTime": 1234567890,
168
- "elapsed": 45000,
169
- "bytesReceived": 1048576,
170
- "bytesSent": 524288
171
- }
172
- ```
173
-
174
- ### Get Stream Position
175
-
176
- ```
177
- GET /streams/:streamId/position
178
- ```
179
-
180
- **Response:**
181
- ```json
182
- {
183
- "position": 45.5,
184
- "elapsed": 45000
185
- }
186
- ```
187
-
188
- Position is in seconds, useful for seeking when applying filters.
189
-
190
- ## Filter Parameters
191
-
192
- All stream endpoints accept filter query parameters:
193
-
194
- | Parameter | Type | Description |
195
- |-----------|------|-------------|
196
- | `bass` | number | -20 to 20 |
197
- | `treble` | number | -20 to 20 |
198
- | `speed` | number | 0.5 to 2.0 |
199
- | `pitch` | number | 0.5 to 2.0 |
200
- | `volume` | number | 0 to 200 |
201
- | `nightcore` | boolean | true |
202
- | `vaporwave` | boolean | true |
203
- | `bassboost` | boolean | true |
204
- | `8d` | boolean | true |
205
- | `start` | number | Seek seconds |
206
-
207
- **Example:**
208
- ```
209
- GET /youtube/stream/dQw4w9WgXcQ?bass=10&speed=1.25&nightcore=true&start=30
210
- ```
211
-
212
- ## Error Responses
213
-
214
- ```json
215
- {
216
- "error": "Track not found",
217
- "code": 404
218
- }
219
- ```
220
-
221
- Common error codes:
222
- - `400` - Invalid parameters
223
- - `404` - Track/stream not found
224
- - `500` - Internal error (yt-dlp/ffmpeg failure)
@@ -1,174 +0,0 @@
1
- # HTTP Server
2
-
3
- The HTTP server mode provides a REST API for audio streaming. Use it with Lavalink, web apps, or any HTTP client.
4
-
5
- ## Starting the Server
6
-
7
- ```javascript
8
- const Streamify = require('streamify-audio');
9
-
10
- const streamify = new Streamify({
11
- port: 8787,
12
- host: '0.0.0.0',
13
- cookiesPath: './cookies.txt',
14
- spotify: {
15
- clientId: process.env.SPOTIFY_CLIENT_ID,
16
- clientSecret: process.env.SPOTIFY_CLIENT_SECRET
17
- }
18
- });
19
-
20
- await streamify.start();
21
- console.log(`Server running at ${streamify.getBaseUrl()}`);
22
- // Server running at http://127.0.0.1:8787
23
- ```
24
-
25
- ## Configuration
26
-
27
- ```javascript
28
- const streamify = new Streamify({
29
- // Server
30
- port: 8787,
31
- host: '0.0.0.0',
32
-
33
- // Paths
34
- ytdlpPath: '/usr/local/bin/yt-dlp',
35
- ffmpegPath: '/usr/bin/ffmpeg',
36
-
37
- // YouTube cookies
38
- cookiesPath: './cookies.txt',
39
-
40
- // Spotify
41
- spotify: {
42
- clientId: 'xxx',
43
- clientSecret: 'xxx'
44
- },
45
-
46
- // Audio output
47
- audio: {
48
- bitrate: '128k',
49
- format: 'opus' // opus, mp3, aac
50
- },
51
-
52
- // Logging
53
- logLevel: 'info',
54
- silent: false,
55
- colors: true
56
- });
57
- ```
58
-
59
- ## Methods
60
-
61
- ### start()
62
-
63
- Starts the HTTP server.
64
-
65
- ```javascript
66
- await streamify.start();
67
- ```
68
-
69
- ### stop()
70
-
71
- Stops the HTTP server.
72
-
73
- ```javascript
74
- await streamify.stop();
75
- ```
76
-
77
- ### getBaseUrl()
78
-
79
- Returns the server URL.
80
-
81
- ```javascript
82
- const url = streamify.getBaseUrl();
83
- // http://127.0.0.1:8787
84
- ```
85
-
86
- ## Programmatic API
87
-
88
- ### Search
89
-
90
- ```javascript
91
- // General
92
- const results = await streamify.search('youtube', 'query', 10);
93
-
94
- // Shorthand
95
- const results = await streamify.youtube.search('query');
96
- const results = await streamify.spotify.search('query');
97
- const results = await streamify.soundcloud.search('query');
98
- const info = await streamify.twitch.getInfo('channel');
99
- const url = streamify.local.getStreamUrl('/path/to/file.mp3');
100
- ```
101
-
102
- ### Get Info
103
-
104
- ```javascript
105
- const info = await streamify.getInfo('youtube', 'dQw4w9WgXcQ');
106
- const info = await streamify.youtube.getInfo('dQw4w9WgXcQ');
107
- ```
108
-
109
- ### Get Stream URL
110
-
111
- ```javascript
112
- // Without filters
113
- const url = streamify.youtube.getStreamUrl('dQw4w9WgXcQ');
114
-
115
- // With filters
116
- const url = streamify.youtube.getStreamUrl('dQw4w9WgXcQ', {
117
- bass: 10,
118
- nightcore: true,
119
- start: 30
120
- });
121
- // http://127.0.0.1:8787/youtube/stream/dQw4w9WgXcQ?bass=10&nightcore=true&start=30
122
- ```
123
-
124
- ### Get Raw Stream
125
-
126
- ```javascript
127
- const stream = await streamify.youtube.getStream('dQw4w9WgXcQ');
128
- // Returns a readable stream
129
- ```
130
-
131
- ## Events
132
-
133
- ```javascript
134
- streamify.on('streamStart', (event) => {
135
- console.log(`Stream started: ${event.trackId}`);
136
- // { id, source, trackId, filters, startTime }
137
- });
138
-
139
- streamify.on('streamEnd', (event) => {
140
- console.log(`Stream ended: ${event.trackId} (${event.duration}ms)`);
141
- // { id, source, trackId, filters, startTime, duration, code }
142
- });
143
-
144
- streamify.on('streamError', (event) => {
145
- console.error(`Stream error: ${event.error.message}`);
146
- // { id, source, trackId, filters, startTime, error }
147
- });
148
- ```
149
-
150
- ## Active Streams
151
-
152
- ```javascript
153
- // Get all active streams
154
- const streams = await streamify.getActiveStreams();
155
-
156
- // Get specific stream info
157
- const info = await streamify.getStreamInfo(streamId);
158
-
159
- // Get stream position
160
- const position = await streamify.getPosition(streamId);
161
- ```
162
-
163
- ## CLI Usage
164
-
165
- ```bash
166
- # Install globally
167
- npm install -g streamify-audio
168
-
169
- # Run
170
- streamify --port 8787 --cookies ./cookies.txt
171
-
172
- # With environment variables
173
- PORT=8787 COOKIES_PATH=./cookies.txt streamify
174
- ```
@@ -1,88 +0,0 @@
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