streamify-audio 2.0.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.
@@ -0,0 +1,172 @@
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
+ ```
99
+
100
+ ### Get Info
101
+
102
+ ```javascript
103
+ const info = await streamify.getInfo('youtube', 'dQw4w9WgXcQ');
104
+ const info = await streamify.youtube.getInfo('dQw4w9WgXcQ');
105
+ ```
106
+
107
+ ### Get Stream URL
108
+
109
+ ```javascript
110
+ // Without filters
111
+ const url = streamify.youtube.getStreamUrl('dQw4w9WgXcQ');
112
+
113
+ // With filters
114
+ const url = streamify.youtube.getStreamUrl('dQw4w9WgXcQ', {
115
+ bass: 10,
116
+ nightcore: true,
117
+ start: 30
118
+ });
119
+ // http://127.0.0.1:8787/youtube/stream/dQw4w9WgXcQ?bass=10&nightcore=true&start=30
120
+ ```
121
+
122
+ ### Get Raw Stream
123
+
124
+ ```javascript
125
+ const stream = await streamify.youtube.getStream('dQw4w9WgXcQ');
126
+ // Returns a readable stream
127
+ ```
128
+
129
+ ## Events
130
+
131
+ ```javascript
132
+ streamify.on('streamStart', (event) => {
133
+ console.log(`Stream started: ${event.trackId}`);
134
+ // { id, source, trackId, filters, startTime }
135
+ });
136
+
137
+ streamify.on('streamEnd', (event) => {
138
+ console.log(`Stream ended: ${event.trackId} (${event.duration}ms)`);
139
+ // { id, source, trackId, filters, startTime, duration, code }
140
+ });
141
+
142
+ streamify.on('streamError', (event) => {
143
+ console.error(`Stream error: ${event.error.message}`);
144
+ // { id, source, trackId, filters, startTime, error }
145
+ });
146
+ ```
147
+
148
+ ## Active Streams
149
+
150
+ ```javascript
151
+ // Get all active streams
152
+ const streams = await streamify.getActiveStreams();
153
+
154
+ // Get specific stream info
155
+ const info = await streamify.getStreamInfo(streamId);
156
+
157
+ // Get stream position
158
+ const position = await streamify.getPosition(streamId);
159
+ ```
160
+
161
+ ## CLI Usage
162
+
163
+ ```bash
164
+ # Install globally
165
+ npm install -g streamify-audio
166
+
167
+ # Run
168
+ streamify --port 8787 --cookies ./cookies.txt
169
+
170
+ # With environment variables
171
+ PORT=8787 COOKIES_PATH=./cookies.txt streamify
172
+ ```
@@ -0,0 +1,92 @@
1
+ # Quick Start
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ npm install streamify-audio @discordjs/voice @discordjs/opus
7
+ ```
8
+
9
+ ## Requirements
10
+
11
+ - Node.js 18+
12
+ - [yt-dlp](https://github.com/yt-dlp/yt-dlp) — `pip install yt-dlp`
13
+ - [ffmpeg](https://ffmpeg.org/) — `apt install ffmpeg`
14
+
15
+ ## Discord Bot (5 minutes)
16
+
17
+ ```javascript
18
+ const { Client, GatewayIntentBits } = require('discord.js');
19
+ const Streamify = require('streamify-audio');
20
+
21
+ const client = new Client({
22
+ intents: [
23
+ GatewayIntentBits.Guilds,
24
+ GatewayIntentBits.GuildVoiceStates,
25
+ GatewayIntentBits.GuildMessages,
26
+ GatewayIntentBits.MessageContent
27
+ ]
28
+ });
29
+
30
+ const manager = new Streamify.Manager(client, {
31
+ ytdlpPath: '/usr/local/bin/yt-dlp',
32
+ ffmpegPath: '/usr/bin/ffmpeg'
33
+ });
34
+
35
+ client.on('messageCreate', async (message) => {
36
+ if (!message.content.startsWith('!')) return;
37
+
38
+ const [cmd, ...args] = message.content.slice(1).split(' ');
39
+ const query = args.join(' ');
40
+
41
+ if (cmd === 'play') {
42
+ const vc = message.member.voice.channel;
43
+ if (!vc) return message.reply('Join a voice channel first!');
44
+
45
+ const result = await manager.search(query);
46
+ if (!result.tracks.length) return message.reply('No results found.');
47
+
48
+ const player = await manager.create(message.guild.id, vc.id, message.channel.id);
49
+
50
+ player.on('trackStart', (track) => {
51
+ message.channel.send(`Now playing: **${track.title}**`);
52
+ });
53
+
54
+ await player.play(result.tracks[0]);
55
+ }
56
+
57
+ if (cmd === 'skip') {
58
+ const player = manager.get(message.guild.id);
59
+ if (player) await player.skip();
60
+ }
61
+
62
+ if (cmd === 'stop') {
63
+ const player = manager.get(message.guild.id);
64
+ if (player) player.destroy();
65
+ }
66
+ });
67
+
68
+ client.login(process.env.TOKEN);
69
+ ```
70
+
71
+ ## HTTP Server (3 minutes)
72
+
73
+ ```javascript
74
+ const Streamify = require('streamify-audio');
75
+
76
+ const streamify = new Streamify({ port: 8787 });
77
+ await streamify.start();
78
+
79
+ // Search
80
+ const results = await streamify.youtube.search('never gonna give you up');
81
+ console.log(results.tracks[0].title);
82
+
83
+ // Get stream URL
84
+ const url = streamify.youtube.getStreamUrl(results.tracks[0].id);
85
+ // http://127.0.0.1:8787/youtube/stream/dQw4w9WgXcQ
86
+ ```
87
+
88
+ ## Next Steps
89
+
90
+ - [Configuration](./configuration.md) — Add Spotify, cookies, filters
91
+ - [Discord Player](./discord/manager.md) — Full player documentation
92
+ - [HTTP Server](./http/server.md) — API endpoints
@@ -0,0 +1,141 @@
1
+ # Sources
2
+
3
+ Streamify supports YouTube, Spotify, and SoundCloud.
4
+
5
+ ## Supported Features
6
+
7
+ | Source | Search | Track URL | Playlist | Album |
8
+ |--------|:------:|:---------:|:--------:|:-----:|
9
+ | YouTube | ✅ | ✅ | ✅ | — |
10
+ | Spotify | ✅ | ✅ | ✅ | ✅ |
11
+ | SoundCloud | ✅ | ✅ | ❌ | — |
12
+
13
+ ## YouTube
14
+
15
+ YouTube is the primary source. All audio is streamed directly from YouTube.
16
+
17
+ ```javascript
18
+ // Search
19
+ const result = await manager.search('never gonna give you up');
20
+ const result = await manager.search(query, { source: 'youtube' });
21
+
22
+ // Direct URL
23
+ const result = await manager.resolve('https://youtube.com/watch?v=dQw4w9WgXcQ');
24
+ const result = await manager.resolve('https://youtu.be/dQw4w9WgXcQ');
25
+ const result = await manager.resolve('https://music.youtube.com/watch?v=dQw4w9WgXcQ');
26
+
27
+ // Playlist
28
+ const result = await manager.loadPlaylist('https://youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf');
29
+ ```
30
+
31
+ ### Supported URL Formats
32
+
33
+ - `youtube.com/watch?v=VIDEO_ID`
34
+ - `youtu.be/VIDEO_ID`
35
+ - `youtube.com/shorts/VIDEO_ID`
36
+ - `music.youtube.com/watch?v=VIDEO_ID`
37
+ - `youtube.com/playlist?list=PLAYLIST_ID`
38
+
39
+ ### Cookies
40
+
41
+ For age-restricted or region-locked videos, provide YouTube cookies:
42
+
43
+ ```javascript
44
+ const manager = new Streamify.Manager(client, {
45
+ cookiesPath: './cookies.txt'
46
+ });
47
+ ```
48
+
49
+ See [Configuration](./configuration.md#youtube-cookies) for setup instructions.
50
+
51
+ ## Spotify
52
+
53
+ Spotify tracks are resolved to YouTube for playback. Requires API credentials.
54
+
55
+ ```javascript
56
+ const manager = new Streamify.Manager(client, {
57
+ spotify: {
58
+ clientId: process.env.SPOTIFY_CLIENT_ID,
59
+ clientSecret: process.env.SPOTIFY_CLIENT_SECRET
60
+ }
61
+ });
62
+ ```
63
+
64
+ ```javascript
65
+ // Search
66
+ const result = await manager.search('never gonna give you up', { source: 'spotify' });
67
+
68
+ // Direct URL
69
+ const result = await manager.resolve('https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8');
70
+
71
+ // Playlist
72
+ const result = await manager.loadPlaylist('https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M');
73
+
74
+ // Album
75
+ const result = await manager.loadPlaylist('https://open.spotify.com/album/4LH4d3cOWNNsVw41Gqt2kv');
76
+ ```
77
+
78
+ ### Supported URL Formats
79
+
80
+ - `open.spotify.com/track/TRACK_ID`
81
+ - `open.spotify.com/playlist/PLAYLIST_ID`
82
+ - `open.spotify.com/album/ALBUM_ID`
83
+ - `spotify:track:TRACK_ID`
84
+
85
+ ### How Resolution Works
86
+
87
+ 1. Fetch track metadata from Spotify API
88
+ 2. Search YouTube for `{artist} - {title}`
89
+ 3. Use the first result for playback
90
+
91
+ The resolved YouTube ID is cached for 5 minutes.
92
+
93
+ ## SoundCloud
94
+
95
+ SoundCloud tracks are streamed via yt-dlp.
96
+
97
+ ```javascript
98
+ // Search
99
+ const result = await manager.search('never gonna give you up', { source: 'soundcloud' });
100
+
101
+ // Direct URL
102
+ const result = await manager.resolve('https://soundcloud.com/rick-astley-official/never-gonna-give-you-up');
103
+ ```
104
+
105
+ ### Supported URL Formats
106
+
107
+ - `soundcloud.com/USER/TRACK`
108
+
109
+ ## Auto-Detection
110
+
111
+ The `resolve()` method auto-detects the source from URLs:
112
+
113
+ ```javascript
114
+ // All of these work
115
+ await manager.resolve('https://youtube.com/watch?v=dQw4w9WgXcQ');
116
+ await manager.resolve('https://open.spotify.com/track/4PTG3Z6ehGkBFwjybzWkR8');
117
+ await manager.resolve('https://soundcloud.com/rick-astley-official/never-gonna-give-you-up');
118
+
119
+ // Falls back to YouTube search
120
+ await manager.resolve('never gonna give you up');
121
+ ```
122
+
123
+ ## Track Object
124
+
125
+ All sources return the same track structure:
126
+
127
+ ```javascript
128
+ {
129
+ id: 'dQw4w9WgXcQ',
130
+ title: 'Rick Astley - Never Gonna Give You Up',
131
+ author: 'Rick Astley',
132
+ duration: 213, // seconds
133
+ thumbnail: 'https://...',
134
+ uri: 'https://...', // Original URL
135
+ source: 'youtube', // youtube, spotify, soundcloud
136
+
137
+ // Spotify only
138
+ album: 'Whenever You Need Somebody',
139
+ _resolvedId: 'dQw4w9WgXcQ' // YouTube ID
140
+ }
141
+ ```
@@ -0,0 +1,95 @@
1
+ # Sponsorblock
2
+
3
+ Streamify integrates with [SponsorBlock](https://sponsor.ajay.app/) to automatically skip sponsored segments in YouTube videos.
4
+
5
+ ## Configuration
6
+
7
+ ```javascript
8
+ const manager = new Streamify.Manager(client, {
9
+ sponsorblock: {
10
+ enabled: true,
11
+ categories: ['sponsor', 'selfpromo', 'intro', 'outro']
12
+ }
13
+ });
14
+ ```
15
+
16
+ ## Categories
17
+
18
+ | Category | Description |
19
+ |----------|-------------|
20
+ | `sponsor` | Paid promotion, sponsored content |
21
+ | `selfpromo` | Self-promotion, merchandise, Patreon |
22
+ | `intro` | Intro animation, opening sequence |
23
+ | `outro` | Outro, end cards, credits |
24
+ | `preview` | Preview of other videos |
25
+ | `filler` | Tangents, jokes, off-topic |
26
+ | `interaction` | Subscribe reminders, like requests |
27
+ | `music_offtopic` | Non-music sections in music videos |
28
+
29
+ ## Default Categories
30
+
31
+ By default, Streamify skips:
32
+ - `sponsor`
33
+ - `selfpromo`
34
+
35
+ ```javascript
36
+ // Default behavior
37
+ sponsorblock: {
38
+ enabled: true,
39
+ categories: ['sponsor', 'selfpromo']
40
+ }
41
+ ```
42
+
43
+ ## Skip Everything
44
+
45
+ ```javascript
46
+ sponsorblock: {
47
+ enabled: true,
48
+ categories: [
49
+ 'sponsor',
50
+ 'selfpromo',
51
+ 'intro',
52
+ 'outro',
53
+ 'preview',
54
+ 'filler',
55
+ 'interaction',
56
+ 'music_offtopic'
57
+ ]
58
+ }
59
+ ```
60
+
61
+ ## Music Videos
62
+
63
+ For music, you might want:
64
+
65
+ ```javascript
66
+ sponsorblock: {
67
+ enabled: true,
68
+ categories: ['sponsor', 'selfpromo', 'intro', 'outro', 'music_offtopic']
69
+ }
70
+ ```
71
+
72
+ ## Disabling
73
+
74
+ ```javascript
75
+ sponsorblock: {
76
+ enabled: false
77
+ }
78
+ ```
79
+
80
+ Or omit the `sponsorblock` config entirely.
81
+
82
+ ## How It Works
83
+
84
+ 1. When a YouTube stream starts, yt-dlp queries the SponsorBlock API
85
+ 2. Segment timestamps are fetched for the video
86
+ 3. yt-dlp removes those segments during download
87
+ 4. Audio plays seamlessly without the sponsored content
88
+
89
+ ## Notes
90
+
91
+ - Only works with YouTube (Spotify/SoundCloud unaffected)
92
+ - Segments are crowdsourced and may not exist for all videos
93
+ - Popular videos have more complete segment data
94
+ - Occasionally segments may be slightly inaccurate
95
+ - No additional latency - segments are fetched during stream initialization