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.
- package/LICENSE +21 -0
- package/README.md +430 -0
- package/bin/streamify.js +84 -0
- package/docs/README.md +31 -0
- package/docs/automation.md +186 -0
- package/docs/configuration.md +169 -0
- package/docs/discord/events.md +206 -0
- package/docs/discord/manager.md +180 -0
- package/docs/discord/player.md +180 -0
- package/docs/discord/queue.md +197 -0
- package/docs/examples/advanced-bot.md +391 -0
- package/docs/examples/basic-bot.md +182 -0
- package/docs/examples/lavalink.md +156 -0
- package/docs/filters.md +309 -0
- package/docs/http/endpoints.md +199 -0
- package/docs/http/server.md +172 -0
- package/docs/quick-start.md +92 -0
- package/docs/sources.md +141 -0
- package/docs/sponsorblock.md +95 -0
- package/index.d.ts +350 -0
- package/index.js +252 -0
- package/package.json +57 -0
- package/silence.ogg +0 -0
- package/src/cache/index.js +61 -0
- package/src/config.js +133 -0
- package/src/discord/Manager.js +453 -0
- package/src/discord/Player.js +658 -0
- package/src/discord/Queue.js +129 -0
- package/src/discord/Stream.js +252 -0
- package/src/filters/ffmpeg.js +270 -0
- package/src/providers/soundcloud.js +166 -0
- package/src/providers/spotify.js +216 -0
- package/src/providers/youtube.js +320 -0
- package/src/server.js +318 -0
- package/src/utils/logger.js +139 -0
- package/src/utils/stream.js +108 -0
|
@@ -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
|
package/docs/sources.md
ADDED
|
@@ -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
|