streamify-audio 2.3.1 → 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.
- package/package.json +1 -1
- package/docs/README.md +0 -31
- package/docs/automation.md +0 -186
- package/docs/configuration.md +0 -198
- package/docs/discord/events.md +0 -206
- package/docs/discord/manager.md +0 -195
- package/docs/discord/player.md +0 -263
- package/docs/discord/queue.md +0 -197
- package/docs/examples/advanced-bot.md +0 -391
- package/docs/examples/basic-bot.md +0 -182
- package/docs/examples/lavalink.md +0 -156
- package/docs/filters.md +0 -347
- package/docs/http/endpoints.md +0 -224
- package/docs/http/server.md +0 -174
- package/docs/plans/2026-02-22-stream-revamp-design.md +0 -88
- package/docs/plans/2026-02-22-stream-revamp-plan.md +0 -814
- package/docs/quick-start.md +0 -92
- package/docs/sources.md +0 -189
- package/docs/sponsorblock.md +0 -95
- package/tests/cache.test.js +0 -234
- package/tests/config.test.js +0 -44
- package/tests/error-handling.test.js +0 -318
- package/tests/ffmpeg.test.js +0 -66
- package/tests/filters-edge.test.js +0 -333
- package/tests/http.test.js +0 -24
- package/tests/integration.test.js +0 -325
- package/tests/local.test.js +0 -37
- package/tests/queue.test.js +0 -94
- package/tests/spotify.test.js +0 -238
- package/tests/stream.test.js +0 -217
- package/tests/twitch.test.js +0 -42
- package/tests/utils.test.js +0 -60
- package/tests/youtube.test.js +0 -219
- package/youtube-cookies.txt +0 -26
package/docs/http/server.md
DELETED
|
@@ -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
|