This document explains how to develop and test the PeerTube SponsorBlock plugin.
- Node.js >= 16
- A development PeerTube instance (>= 6.0.0)
- PostgreSQL (used by PeerTube)
- FFmpeg and ffprobe (required for permanent removal mode)
git clone https://github.com/jblemee/peertube-plugin-sponsorblock.git
cd peertube-plugin-sponsorblocknpm install# From the PeerTube directory
cd /var/www/peertube
# Install the plugin
sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run plugin:install -- --plugin-path /path/to/peertube-plugin-sponsorblock# Create a symlink in the PeerTube plugins directory
ln -s /path/to/peertube-plugin-sponsorblock /var/www/peertube/storage/plugins/node_modules/peertube-plugin-sponsorblock
# Restart PeerTube
sudo systemctl restart peertube- Go to the PeerTube admin interface
- Navigate to Administration > Plugins/Themes
- Enable the SponsorBlock plugin
- Configure the settings as needed
peertube-plugin-sponsorblock/
├── main.js # Server entry point (settings, hooks, worker, sync timer)
├── package.json # Plugin metadata
├── client/ # Client-side code (browser)
│ ├── common.js # Common code
│ ├── video-watch.js # Video player (skip logic)
│ └── admin.js # Admin dashboard (admin-plugin scope)
├── server/ # Server-side code
│ ├── routes.js # REST API (segments, mapping, scan, sync, process, admin)
│ └── ffmpeg.js # FFmpeg/ffprobe wrapper (cut, concat, file discovery)
├── assets/ # Static resources
│ ├── style.css # CSS styles
│ └── images/ # Images
├── languages/ # Translations
│ ├── en.json # English
│ └── fr.json # French
└── scripts/ # Build scripts
YouTube Import → Post-import hook → YouTube ID extraction → SponsorBlock API
↓
Cache in DB
↓ ↓
(remove mode) (always)
Auto-queue Client skip via API /segments/:uuid
↓
Manual Process → Processing queue ← Process button (any mode)
↓
Worker (30s)
↓
FFmpeg cut + concat → File replacement
The plugin creates 3 tables:
plugin_sponsorblock_mapping: YouTube ID to PeerTube UUID mappingplugin_sponsorblock_segments: SponsorBlock segments cacheplugin_sponsorblock_processing_queue: Queue for FFmpeg processing (auto in remove mode, manual via Process button in any mode)
# Via the web interface or CLI
cd /var/www/peertube
sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run import-videos -- \
--target-url "https://www.youtube.com/watch?v=dQw4w9WgXcQ"sudo -u postgres psql peertube_prod
SELECT * FROM plugin_sponsorblock_mapping;
SELECT * FROM plugin_sponsorblock_segments;- Open the imported video
- Observe the colored markers on the progress bar
- Let the video play: segments should be skipped automatically
- A notification should appear on each skip
BASE=http://localhost:9000/plugins/sponsorblock/router
# Fetch segments for a video
curl $BASE/segments/{VIDEO_UUID}
# Fetch the YouTube mapping
curl $BASE/mapping/{VIDEO_UUID}
# Force a sync
curl -X POST $BASE/sync/{VIDEO_UUID}
# Queue a video for FFmpeg processing (admin auth required)
curl -X POST $BASE/process/{VIDEO_UUID} -H "Authorization: Bearer TOKEN"
# Queue all unprocessed videos (admin auth required)
curl -X POST $BASE/process-all -H "Authorization: Bearer TOKEN"
# Get admin dashboard stats (admin auth required)
curl $BASE/admin/stats -H "Authorization: Bearer TOKEN"
# Get all mappings with details (admin auth required)
curl $BASE/admin/mappings -H "Authorization: Bearer TOKEN"
# Sync all mappings (admin auth required)
curl -X POST $BASE/sync-all -H "Authorization: Bearer TOKEN"
# Delete a mapping (admin auth required)
curl -X DELETE $BASE/mapping/{VIDEO_UUID} -H "Authorization: Bearer TOKEN"- Verify that
storage_pathpoints to the correct directory - Verify FFmpeg:
ffmpeg -version && ffprobe -version - Import a YouTube video with known segments
- Either set mode to
removefor auto-queue, or click Process in the dashboard - Check the queue in the database:
sudo -u postgres psql peertube_prod -c "SELECT id, video_uuid, status, priority FROM plugin_sponsorblock_processing_queue;" - The worker processes jobs every 30s — check the logs for progress
Plugin logs are visible in the PeerTube logs:
# Follow logs in real time
sudo journalctl -u peertube -f
# Or from the log files
tail -f /var/www/peertube/storage/logs/peertube.logOpen the browser developer console (F12):
// Plugin logs start with [SponsorBlock]
console.log('[SponsorBlock] Video loaded')# Restart PeerTube
sudo systemctl restart peertube
# Or reload plugins only (if available)
# Via the admin interface: Plugins > ReloadEdit main.js:
registerHook({
target: 'action:api.video.updated',
handler: async (params) => {
// Your code here
}
})Full list of hooks: https://docs.joinpeertube.org/api/plugins
Edit server/routes.js:
router.get('/my-endpoint', async (req, res) => {
// Your code here
res.json({ success: true })
})Edit client/video-watch.js:
// Your code to interact with the video player
player.on('play', () => {
console.log('Video started playing')
})npm testnpm run test:integration- Update the version in
package.json - Update
CHANGELOG.md - Create a git tag:
git tag -a v0.1.0 -m "Release v0.1.0"
git push origin v0.1.0npm publishThe plugin will be automatically indexed by PeerTube if published on NPM with the peertube-plugin- prefix.
- PeerTube Documentation: https://docs.joinpeertube.org/contribute/plugins
- SponsorBlock API: https://wiki.sponsor.ajay.app/w/API_Docs
- Plugin Example: https://github.com/samlich/peertube-plugin-chapters
- Check the logs:
sudo journalctl -u peertube -f - Verify that
engine.peertubeinpackage.jsonmatches your version - Check the plugin directory permissions
- Open the developer console (F12)
- Verify that segments are fetched:
[SponsorBlock] Found X segments to skip - Verify that the API returns segments:
/plugins/sponsorblock/router/segments/{UUID}
- Verify the tables exist:
\dt plugin_sponsorblock*in psql - Drop and recreate the tables if needed (warning: data loss)
To report a bug or request a feature: https://github.com/jblemee/peertube-plugin-sponsorblock/issues