diff --git a/API-Reference.-.md b/API-Reference.-.md new file mode 100644 index 0000000..df48ab7 --- /dev/null +++ b/API-Reference.-.md @@ -0,0 +1,457 @@ +# API Reference + +| Meta | Value | +|------|-------| +| **Repo** | `xpltdco/tubearr` | +| **Page** | `API-Reference` | +| **Audience** | developers, agents | +| **Last Updated** | 2026-04-04 | +| **Status** | current | + +## Base URL + +``` +https://tubearr.xpltd.co/api/v1 +``` + +Local development: `http://localhost:8989/api/v1` + +## Authentication + +All API endpoints (except `/ping`) require authentication via one of: + +| Method | Details | +|--------|---------| +| **Same-origin** | Requests from the Tubearr UI (matching Origin/Referer header) are authenticated automatically | +| **API Key header** | `X-Api-Key: ` | +| **API Key query** | `?apikey=` | + +The API key is a UUID auto-generated on first startup. Retrieve or regenerate it via the System endpoints. + +**Unauthorized response:** +```json +{ + "statusCode": 401, + "error": "Unauthorized", + "message": "Invalid or missing API key" +} +``` + +## Error Format + +All errors return a consistent JSON structure: + +```json +{ + "statusCode": 404, + "error": "Not Found", + "message": "Channel not found" +} +``` + +In development mode, a `stack` field may be included. API keys are always redacted from error responses. + +--- + +## Health & System + +### `GET /ping` + +Liveness probe. **No authentication required.** + +``` +200 OK +``` + +### `GET /api/v1/health` + +Full health check with component status (database, yt-dlp, disk space, scheduler). + +### `GET /api/v1/system/status` + +Runtime info: version, uptime, memory usage. + +### `GET /api/v1/system/apikey` + +Returns the current API key. + +### `POST /api/v1/system/apikey/regenerate` + +Generate a new API key. Returns the new key. The old key is immediately invalidated. + +### `GET /api/v1/system/settings` + +Global settings (check interval, concurrent downloads). + +### `PUT /api/v1/system/settings` + +Update global settings. + +```json +{ + "checkInterval": 360, + "concurrentDownloads": 2 +} +``` + +### `GET /api/v1/system/ytdlp/status` + +yt-dlp version and last update timestamp. + +### `POST /api/v1/system/ytdlp/update` + +Force yt-dlp to self-update. Returns the new version string. + +--- + +## Channels + +### `GET /api/v1/channel` + +List all monitored channels with content counts. + +**Response:** +```json +[ + { + "id": 1, + "name": "Example Channel", + "platform": "youtube", + "platformId": "UCxxxxxxx", + "url": "https://youtube.com/@example", + "monitoringEnabled": true, + "monitoringMode": "all", + "checkInterval": 360, + "imageUrl": "https://...", + "lastCheckedAt": "2026-04-04T10:00:00Z", + "lastCheckStatus": "success", + "contentCount": 42, + "downloadedCount": 15 + } +] +``` + +### `POST /api/v1/channel` + +Add a channel by URL. Tubearr resolves metadata (name, image, subscriber count) via yt-dlp. + +**Request:** +```json +{ + "url": "https://youtube.com/@example", + "monitoringMode": "future", + "formatProfileId": 1 +} +``` + +### `GET /api/v1/channel/:id` + +Get single channel with full metadata. + +### `PUT /api/v1/channel/:id` + +Update channel settings. + +```json +{ + "name": "Updated Name", + "checkInterval": 120, + "formatProfileId": 2, + "monitoringEnabled": true +} +``` + +### `PUT /api/v1/channel/:id/monitoring-mode` + +Change monitoring mode. + +```json +{ + "monitoringMode": "future" +} +``` + +**Modes:** `all` (grab everything), `future` (new content only), `existing` (backlog only), `none` (pause monitoring) + +### `DELETE /api/v1/channel/:id` + +Delete channel. Cascades to all content items and queue items. + +### `POST /api/v1/channel/scan-all` + +Manually trigger monitoring scan for all enabled channels. Returns immediately (202 Accepted); scans run in background. + +### `POST /api/v1/channel/collect-all` + +Trigger back-catalog import for all channels with `grabAllEnabled`. + +--- + +## Content Items + +### `GET /api/v1/content` + +Paginated content listing with filters. + +**Query parameters:** + +| Param | Type | Description | +|-------|------|-------------| +| `page` | number | Page number (default: 1) | +| `limit` | number | Items per page (default: 20) | +| `status` | string | Filter by status | +| `contentType` | string | Filter by type (`video`, `audio`, `livestream`) | +| `search` | string | Search by title | +| `channelId` | number | Filter by channel | + +### `GET /api/v1/channel/:id/content` + +Content items for a specific channel. Same pagination and filter params as above. + +### `PATCH /api/v1/content/:id/monitored` + +Toggle monitoring state for a single content item. + +```json +{ + "monitored": false +} +``` + +### `PATCH /api/v1/content/bulk/monitored` + +Bulk toggle monitoring state. + +```json +{ + "ids": [1, 2, 3], + "monitored": true +} +``` + +--- + +## Download Queue + +### `POST /api/v1/download/:contentItemId` + +Enqueue a content item for download. Returns **202 Accepted**. + +```json +{ + "priority": 10 +} +``` + +### `GET /api/v1/queue` + +List queue items. Optional `?status=pending|downloading|completed|failed|cancelled` filter. + +**Response:** +```json +[ + { + "id": 1, + "contentItemId": 42, + "status": "downloading", + "priority": 0, + "attempts": 1, + "maxAttempts": 3, + "error": null, + "startedAt": "2026-04-04T10:05:00Z", + "contentItem": { + "title": "Example Video", + "channelName": "Example Channel" + } + } +] +``` + +### `GET /api/v1/queue/:id` + +Get single queue item with content details. + +### `POST /api/v1/queue` + +Alternative enqueue endpoint (accepts `contentItemId` in body). + +### `DELETE /api/v1/queue/:id` + +Cancel a queue item (sets status to `cancelled`). + +### `POST /api/v1/queue/:id/retry` + +Retry a failed queue item (resets to `pending`, increments attempts). + +--- + +## Format Profiles + +### `GET /api/v1/format-profile` + +List all format profiles. + +**Response:** +```json +[ + { + "id": 1, + "name": "High Quality", + "videoResolution": "1080p", + "audioCodec": "opus", + "audioBitrate": "192k", + "containerFormat": "mkv", + "isDefault": true, + "embedSubtitles": true, + "sponsorBlockRemove": "sponsor,selfpromo" + } +] +``` + +### `POST /api/v1/format-profile` + +Create a format profile. + +```json +{ + "name": "Mobile Friendly", + "videoResolution": "720p", + "audioCodec": "aac", + "audioBitrate": "128k", + "containerFormat": "mp4", + "embedSubtitles": false, + "embedThumbnail": true +} +``` + +### `PUT /api/v1/format-profile/:id` + +Update a format profile. + +### `DELETE /api/v1/format-profile/:id` + +Delete a format profile. Channels using it will have their `formatProfileId` set to NULL. + +--- + +## Notifications + +### `GET /api/v1/notification` + +List notification channel configurations. + +### `POST /api/v1/notification` + +Create a notification channel. + +```json +{ + "type": "discord", + "name": "My Discord Server", + "enabled": true, + "config": { + "webhookUrl": "" + }, + "onGrab": true, + "onDownload": true, + "onFailure": true +} +``` + +### `PUT /api/v1/notification/:id` + +Update notification settings. + +### `DELETE /api/v1/notification/:id` + +Delete a notification channel. + +### `POST /api/v1/notification/:id/test` + +Send a test notification to verify configuration. + +--- + +## Platform Settings + +### `GET /api/v1/platform-settings` + +Get per-platform settings for all platforms. + +### `PUT /api/v1/platform-settings/:platform` + +Update settings for a specific platform (`youtube`, `soundcloud`, `generic`). + +```json +{ + "checkInterval": 240, + "concurrencyLimit": 3, + "rateLimitDelay": 2000, + "defaultMonitoringMode": "future", + "grabAllEnabled": false +} +``` + +--- + +## Scan & Collect + +### `POST /api/v1/scan/:channelId` + +Manually trigger a monitoring scan for a specific channel. Checks for new content and inserts it. + +### `POST /api/v1/collect/:channelId` + +Trigger back-catalog import for a specific channel. + +--- + +## History + +### `GET /api/v1/history` + +Download activity log with pagination. + +**Query parameters:** `page`, `limit`, `eventType` + +**Event types:** `grabbed`, `downloaded`, `failed`, `imported`, `deleted` + +--- + +## Playlists + +### `GET /api/v1/playlist` + +List playlists discovered from monitored channels. + +--- + +## WebSocket + +### `GET /ws` + +Upgrade to WebSocket connection for real-time events. + +**Events pushed to clients:** + +| Event | Description | +|-------|-------------| +| `download:progress` | Download percentage, speed, ETA for an active download | +| `download:complete` | Download finished successfully | +| `download:failed` | Download failed (includes error) | +| `scan:start` | Channel monitoring scan started | +| `scan:complete` | Channel monitoring scan finished | +| `scan:new-content` | New content discovered during scan | + +**Message format:** +```json +{ + "event": "download:progress", + "data": { + "contentItemId": 42, + "percent": 45.2, + "speed": "5.2MiB/s", + "eta": "00:01:23" + } +} +``` \ No newline at end of file