peertube-plugin-video-published-webhook
v1.4.1
Published
PeerTube 8+ plugin that sends an HMAC-signed webhook when a local video or audio finishes transcoding and reaches the PUBLISHED state. Uses a DB watcher, so it works even though PeerTube fires no publish hook.
Downloads
312
Maintainers
Readme
peertube-plugin-video-published-webhook
A PeerTube 8+ plugin that sends an HMAC-signed webhook when a local video or audio finishes transcoding and reaches the PUBLISHED state.
Why a watcher?
PeerTube fires no server hook when transcoding completes and a video auto-publishes (action:api.video.updated only fires on explicit API edits). So relying on hooks alone misses normal uploads. This plugin instead runs a lightweight database watcher that detects the transition to state = 1 (PUBLISHED) and sends the webhook the moment it happens — typically within a few seconds.
Features
- Fires reliably on auto-publish after transcoding (via the DB watcher), not just on edits
- HMAC-SHA256 signature for secure payload verification
- Retry logic with exponential backoff (configurable 1–5 attempts)
- Request timeout (10s) to prevent hanging
- Deduplication so each video is notified once per publish
- Cursor on
publishedAt, so later metadata edits do not re-fire - Fully configurable via the PeerTube admin UI
How it works
- On startup the plugin starts an interval (default 8s) that queries the DB for local videos whose
publishedAtis newer than the last check and whosestate = 1 (PUBLISHED). - For each newly published video it POSTs the webhook payload (below) to your configured URL, signed with HMAC-SHA256.
- The cursor only moves forward, so a restart never re-notifies old videos, and edits never re-trigger.
Installation
From the PeerTube admin UI
- Go to Administration → Plugins/Themes → Search
- Search for
peertube-plugin-video-published-webhook - Click Install
Note: PeerTube's plugin search index can lag npm by hours after a new publish. If it doesn't appear yet, install by exact name instead (below).
By exact npm name (CLI — works immediately)
cd /var/www/peertube/peertube-latest
sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production \
npm run plugin:install -- --npm-name peertube-plugin-video-published-webhookBy exact npm name (REST API — no shell needed)
curl -X POST "https://your-peertube/api/v1/plugins/install" \
-H "Authorization: Bearer <ADMIN_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"npmName":"peertube-plugin-video-published-webhook"}'Configuration
Administration → Plugins → Video Published Webhook → Settings
| Setting | Description | Default |
|----------------------------|-----------------------------------------------------------------------------|---------|
| Webhook URL | The endpoint that receives the notification | – |
| Webhook Secret | Secret for the HMAC-SHA256 signature (must match your receiver) | – |
| Enable Webhook | Master on/off toggle | true |
| Retry Attempts | Retries for failed requests (clamped 1–5) | 3 |
| Enable publish watcher | The DB watcher that catches auto-publish. Leave ON to catch normal uploads. | true |
| Watcher interval (seconds) | How often the watcher checks the DB (clamped 3–120s) | 8 |
| Debug: log every hook | Logs uuid + state on each lifecycle hook; for diagnostics | false |
Webhook Payload
{
"event": "video.published",
"videoId": "uuid-of-the-video",
"peertubeId": 42,
"videoName": "Video Title",
"channelId": 1,
"publishedAt": "2024-01-15T10:30:00.000Z",
"duration": 120,
"state": 1,
"category": 1,
"hook": "watcher:db-poll",
"sentAt": "2024-01-15T10:30:05.000Z"
}videoId is the PeerTube UUID; peertubeId is the numeric id.
Request Headers
| Header | Value |
|---------------------|-------------------------------------------|
| Content-Type | application/json |
| X-Webhook-Signature | HMAC-SHA256 hex signature (if secret set) |
Signature Verification
If a secret is configured, verify the signature over the raw request body:
const crypto = require('crypto');
function isValid(rawBody, signature, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signature, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}PeerTube Video States
The webhook fires only when state = 1 (PUBLISHED).
| State ID | Name | |----------|-----------------------------| | 1 | PUBLISHED | | 2 | TO_TRANSCODE | | 3 | TO_IMPORT | | 4 | WAITING_FOR_LIVE | | 5 | LIVE_ENDED | | 6 | TO_MOVE_TO_EXTERNAL_STORAGE | | 7 | TRANSCODING_FAILED | | 8 | TO_EDIT |
Testing
- Install the plugin and set the Webhook URL (use webhook.site for a quick test).
- Upload an audio/video and let transcoding finish.
- Within a few seconds the watcher sends the webhook — check your receiver and the PeerTube logs.
Logs
[Video Published Webhook] DB publish watcher started (every 8s)
[Video Published Webhook] Sending webhook for video <uuid> (<name>) ... via watcher:db-poll
[Video Published Webhook] Webhook sent successfully for video <uuid>, status: 200Requirements
- PeerTube >= 8.0.0 (verified against 8.2.2)
