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,318 +0,0 @@
1
- const { describe, it, beforeEach } = require('node:test');
2
- const assert = require('node:assert');
3
-
4
- describe('Error Handling', () => {
5
- describe('YouTube Provider Errors', () => {
6
- const youtube = require('../src/providers/youtube');
7
- const mockConfig = {
8
- ytdlpPath: 'yt-dlp',
9
- ffmpegPath: 'ffmpeg',
10
- cookiesPath: null
11
- };
12
-
13
- it('should handle missing binary gracefully', async () => {
14
- const badConfig = { ...mockConfig, ytdlpPath: 'nonexistent-binary' };
15
-
16
- await assert.rejects(
17
- () => youtube.search('test', 1, badConfig),
18
- Error
19
- );
20
- });
21
-
22
- it('should handle malformed video ID', async () => {
23
- await assert.rejects(
24
- () => youtube.getInfo('!!!invalid!!!', mockConfig),
25
- Error
26
- );
27
- });
28
-
29
- it('should handle empty search results', async () => {
30
- const results = await youtube.search('xyznonexistent123456789abcdef', 1, mockConfig);
31
- assert(Array.isArray(results.tracks));
32
- });
33
- });
34
-
35
- describe('Spotify Provider Errors', () => {
36
- const spotify = require('../src/providers/spotify');
37
-
38
- it('should throw clear error without credentials', async () => {
39
- const badConfig = { spotify: {} };
40
-
41
- await assert.rejects(
42
- () => spotify.search('test', 1, badConfig),
43
- /credentials/i
44
- );
45
- });
46
-
47
- it('should throw clear error with invalid credentials', async () => {
48
- const badConfig = {
49
- spotify: {
50
- clientId: 'invalid',
51
- clientSecret: 'invalid'
52
- }
53
- };
54
-
55
- await assert.rejects(
56
- () => spotify.search('test', 1, badConfig),
57
- Error
58
- );
59
- });
60
- });
61
-
62
- describe('SoundCloud Provider Errors', () => {
63
- const soundcloud = require('../src/providers/soundcloud');
64
- const mockConfig = {
65
- ytdlpPath: 'yt-dlp'
66
- };
67
-
68
- it('should return results array for search', async () => {
69
- const results = await soundcloud.search('test', 1, mockConfig);
70
- assert(results.tracks, 'Should have tracks array');
71
- assert(Array.isArray(results.tracks));
72
- });
73
- });
74
-
75
- describe('Local Provider Errors', () => {
76
- const local = require('../src/providers/local');
77
-
78
- it('should throw for non-existent files', async () => {
79
- await assert.rejects(
80
- () => local.getInfo('/nonexistent/path/file.mp3', {}),
81
- /not found/i
82
- );
83
- });
84
-
85
- it('should throw for directories', async () => {
86
- await assert.rejects(
87
- () => local.getInfo('/tmp', {}),
88
- /directory/i
89
- );
90
- });
91
- });
92
-
93
- describe('HTTP Provider Errors', () => {
94
- const http = require('../src/providers/http');
95
-
96
- it('should handle invalid URLs', async () => {
97
- await assert.rejects(
98
- () => http.getInfo('not-a-valid-url', {}),
99
- Error
100
- );
101
- });
102
-
103
- it('should return track info for valid URL format', async () => {
104
- const info = await http.getInfo('http://example.com/audio.mp3', {});
105
- assert(info.id, 'Should have id');
106
- assert(info.uri, 'Should have uri');
107
- assert.strictEqual(info.source, 'http');
108
- });
109
- });
110
-
111
- describe('Stream Controller Errors', () => {
112
- const { createStream } = require('../src/discord/Stream');
113
- const mockConfig = {
114
- ytdlpPath: 'yt-dlp',
115
- ffmpegPath: 'ffmpeg',
116
- ytdlp: { format: 'bestaudio/best', additionalArgs: [] },
117
- audio: { bitrate: '128k', format: 'opus' }
118
- };
119
-
120
- it('should handle destroyed stream gracefully', async () => {
121
- const track = { id: 'test', title: 'Test', source: 'youtube' };
122
- const stream = createStream(track, {}, mockConfig);
123
-
124
- stream.destroy();
125
-
126
- await assert.rejects(
127
- () => stream.create(),
128
- /destroyed/
129
- );
130
- });
131
-
132
- it('should handle double destroy', () => {
133
- const track = { id: 'test', title: 'Test', source: 'youtube' };
134
- const stream = createStream(track, {}, mockConfig);
135
-
136
- assert.doesNotThrow(() => {
137
- stream.destroy();
138
- stream.destroy();
139
- stream.destroy();
140
- });
141
- });
142
-
143
- it('should handle missing track ID', async () => {
144
- const track = { title: 'Test', source: 'youtube' };
145
- const stream = createStream(track, {}, mockConfig);
146
-
147
- await assert.rejects(
148
- () => stream.create(),
149
- /Invalid track ID/
150
- );
151
- });
152
- });
153
-
154
- describe('Queue Errors', () => {
155
- const Queue = require('../src/discord/Queue');
156
-
157
- it('should handle negative index in remove', () => {
158
- const queue = new Queue();
159
- queue.add({ id: '1', title: 'Track 1' });
160
-
161
- const removed = queue.remove(-1);
162
- assert.strictEqual(removed, null);
163
- });
164
-
165
- it('should handle out of bounds index in remove', () => {
166
- const queue = new Queue();
167
- queue.add({ id: '1', title: 'Track 1' });
168
-
169
- const removed = queue.remove(100);
170
- assert.strictEqual(removed, null);
171
- });
172
-
173
- it('should handle move with invalid indices', () => {
174
- const queue = new Queue();
175
- queue.add({ id: '1', title: 'Track 1' });
176
- queue.add({ id: '2', title: 'Track 2' });
177
-
178
- assert.strictEqual(queue.move(-1, 0), false);
179
- assert.strictEqual(queue.move(0, 100), false);
180
- assert.strictEqual(queue.move(100, 0), false);
181
- });
182
-
183
- it('should handle shift on empty queue', () => {
184
- const queue = new Queue();
185
- const result = queue.shift();
186
- assert.strictEqual(result, null);
187
- });
188
-
189
- it('should handle unshift on empty history', () => {
190
- const queue = new Queue();
191
- const result = queue.unshift();
192
- assert.strictEqual(result, null);
193
- });
194
- });
195
-
196
- describe('Config Errors', () => {
197
- const config = require('../src/config');
198
-
199
- it('should use defaults for missing options', () => {
200
- const loaded = config.load({});
201
-
202
- assert(loaded.port);
203
- assert(loaded.host);
204
- assert(loaded.ytdlpPath);
205
- assert(loaded.ffmpegPath);
206
- });
207
-
208
- it('should handle null options', () => {
209
- assert.doesNotThrow(() => {
210
- config.load(null);
211
- });
212
- });
213
-
214
- it('should handle undefined options', () => {
215
- assert.doesNotThrow(() => {
216
- config.load(undefined);
217
- });
218
- });
219
- });
220
-
221
- describe('Filter Errors', () => {
222
- const { buildFfmpegArgs, applyEffectPreset } = require('../src/filters/ffmpeg');
223
- const mockConfig = { audio: { bitrate: '128k', format: 'opus' } };
224
-
225
- it('should handle empty filters', () => {
226
- assert.doesNotThrow(() => {
227
- buildFfmpegArgs({}, mockConfig);
228
- });
229
- });
230
-
231
- it('should handle null filters', () => {
232
- assert.doesNotThrow(() => {
233
- buildFfmpegArgs(null, mockConfig);
234
- });
235
- });
236
-
237
- it('should handle undefined filters', () => {
238
- assert.doesNotThrow(() => {
239
- buildFfmpegArgs(undefined, mockConfig);
240
- });
241
- });
242
-
243
- it('should return null for unknown preset', () => {
244
- const result = applyEffectPreset('nonexistent');
245
- assert.strictEqual(result, null);
246
- });
247
-
248
- it('should handle invalid equalizer values', () => {
249
- assert.doesNotThrow(() => {
250
- buildFfmpegArgs({ equalizer: 'not an array' }, mockConfig);
251
- });
252
- });
253
-
254
- it('should handle invalid tremolo object', () => {
255
- assert.doesNotThrow(() => {
256
- buildFfmpegArgs({ tremolo: 'not an object' }, mockConfig);
257
- });
258
- });
259
- });
260
-
261
- describe('Cache Edge Cases', () => {
262
- const cache = require('../src/cache');
263
-
264
- beforeEach(() => {
265
- cache.clear();
266
- });
267
-
268
- it('should handle getting undefined key', () => {
269
- assert.doesNotThrow(() => {
270
- cache.get(undefined);
271
- });
272
- });
273
-
274
- it('should handle setting undefined value', () => {
275
- assert.doesNotThrow(() => {
276
- cache.set('key', undefined);
277
- });
278
- });
279
-
280
- it('should handle deleting non-existent key', () => {
281
- assert.doesNotThrow(() => {
282
- cache.del('nonexistent');
283
- });
284
- });
285
-
286
- it('should handle clearing already empty cache', () => {
287
- assert.doesNotThrow(() => {
288
- cache.clear();
289
- cache.clear();
290
- });
291
- });
292
- });
293
-
294
- describe('Stream Utils Errors', () => {
295
- const streamUtils = require('../src/utils/stream');
296
-
297
- it('should handle unregistering non-existent stream', () => {
298
- assert.doesNotThrow(() => {
299
- streamUtils.unregisterStream('nonexistent');
300
- });
301
- });
302
-
303
- it('should return null for non-existent stream position', () => {
304
- const position = streamUtils.getStreamPosition('nonexistent');
305
- assert.strictEqual(position, null);
306
- });
307
-
308
- it('should return undefined for non-existent stream by ID', () => {
309
- const stream = streamUtils.getStreamById('nonexistent');
310
- assert.strictEqual(stream, undefined);
311
- });
312
-
313
- it('should return null when updating non-existent stream', () => {
314
- const result = streamUtils.updateStreamFilters('nonexistent', { bass: 10 });
315
- assert.strictEqual(result, null);
316
- });
317
- });
318
- });
@@ -1,66 +0,0 @@
1
- const test = require('node:test');
2
- const assert = require('node:assert');
3
- const { buildFfmpegArgs, applyEffectPreset } = require('../src/filters/ffmpeg');
4
-
5
- test('ffmpeg filters: buildFfmpegArgs', async (t) => {
6
- await t.test('should return default args with no filters', () => {
7
- const args = buildFfmpegArgs();
8
- assert.ok(args.includes('-acodec'));
9
- assert.ok(args.includes('libopus'));
10
- assert.ok(args.includes('-f'));
11
- assert.ok(args.includes('ogg'));
12
- });
13
-
14
- await t.test('should include volume filter', () => {
15
- const args = buildFfmpegArgs({ volume: 50 });
16
- const afIndex = args.indexOf('-af');
17
- assert.ok(afIndex !== -1);
18
- assert.ok(args[afIndex + 1].includes('volume=0.5'));
19
- });
20
-
21
- await t.test('should include bass filter', () => {
22
- const args = buildFfmpegArgs({ bass: 10 });
23
- const afIndex = args.indexOf('-af');
24
- assert.ok(args[afIndex + 1].includes('bass=g=10'));
25
- });
26
-
27
- await t.test('should include multiple filters', () => {
28
- const args = buildFfmpegArgs({ volume: 150, speed: 1.5 });
29
- const afIndex = args.indexOf('-af');
30
- assert.ok(args[afIndex + 1].includes('volume=1.5'));
31
- assert.ok(args[afIndex + 1].includes('atempo=1.5'));
32
- });
33
-
34
- await t.test('should handle nightcore preset', () => {
35
- const args = buildFfmpegArgs({ nightcore: true });
36
- const afIndex = args.indexOf('-af');
37
- assert.ok(args[afIndex + 1].includes('atempo=1.25'));
38
- assert.ok(args[afIndex + 1].includes('asetrate=48000*1.25'));
39
- });
40
-
41
- await t.test('should respect audio config', () => {
42
- const config = { audio: { bitrate: '192k', format: 'mp3' } };
43
- const args = buildFfmpegArgs({}, config);
44
- assert.ok(args.includes('192k'));
45
- assert.ok(args.includes('libmp3lame'));
46
- assert.ok(args.includes('mp3'));
47
- });
48
- });
49
-
50
- test('ffmpeg filters: applyEffectPreset', async (t) => {
51
- await t.test('should return correct filters for bassboost', () => {
52
- const effect = applyEffectPreset('bassboost');
53
- assert.strictEqual(effect.bass, 12);
54
- assert.ok(Array.isArray(effect.equalizer));
55
- });
56
-
57
- await t.test('should scale with intensity', () => {
58
- const effect = applyEffectPreset('bassboost', 0.5);
59
- assert.strictEqual(effect.bass, 6);
60
- });
61
-
62
- await t.test('should return null for unknown preset', () => {
63
- const effect = applyEffectPreset('nonexistent');
64
- assert.strictEqual(effect, null);
65
- });
66
- });