mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-21 08:36:33 +03:00
Research-driven rebuild of the peertube skill (docs.joinpeertube.org REST reference 8.1.0 + SepiaSearch + server source + live anonymous probes): - SKILL.md rewritten to the lastfm model: intent-grouped commands, pipeline recipes, jq guidance, researched gotchas, When-to-use/When-not-to-use, reference routing table. New negative boundary in the description (YouTube/Vimeo uploads, video editing, server administration). - scripts/peertube-cli -> scripts/peertube, rewritten and extended: offset (start/count) pagination replaces the nonexistent page param, comments fixed to the hyphenated /comment-threads route, server command now composes /config/about + /server/stats (canonical paths), search gains --search-target with searchTarget=local default and help text stating its instance-local scope, new video/comments/channel/account/ my-videos/logout commands, --server hoisted before or after the subcommand, OAuth2 password grant hardened for 2FA (x-peertube-otp) and the production client_secret masking behavior, per-instance owner-only token file with refresh-before-expiry and revocation. - references/: auth-and-tokens, search-and-discovery, endpoint-catalog, gotchas-field-guide, worked-recipes - all cited to official docs with Sources footers (URLs verified live at authoring time). - scripts/test_peertube.py: 54 offline tests (help, argument errors, dry-run plans, mocked OAuth2 persistence/refresh/revocation, handler contracts, documented pipeline chains) passing pytest strict-markers, unittest discovery, and the proxy-trap zero-egress rerun; one env-guarded anonymous live probe (PEERTUBE_LIVE_TESTS=1). - evals/evals.json: six schema-v1 cases incl. SepiaSearch-scope and masked-secret cases plus a should-not-trigger YouTube negative probe. - README refreshed for humans; root README blurb and skill-triggers row synced; marketplace.json/llms.txt regenerated (codex artifacts unchanged); test-results/ gitignored (pytest runner artifact). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
263 lines
12 KiB
Markdown
263 lines
12 KiB
Markdown
---
|
|
name: peertube
|
|
description: Browse PeerTube federated video from the terminal — instance stats, latest
|
|
videos, video detail, comment threads, channels, accounts, instance-local search, and
|
|
OAuth2 login with per-instance token persistence. Set PEERTUBE_SERVER to any instance;
|
|
point it at sepiasearch.org for fediverse-wide search. Use when the user mentions
|
|
PeerTube, federated video, SepiaSearch, or browsing a specific PeerTube instance.
|
|
Do not use this skill for YouTube/Vimeo uploads, video editing, or installing and
|
|
administering a PeerTube server.
|
|
license: MIT
|
|
compatibility: Requires Python 3.8+ and `requests`. Reads are anonymous; authenticated
|
|
commands (`me`, `my-videos`) need a token from `scripts/peertube login`. Tokens persist
|
|
per-instance to ~/.config/peertube/token.json (owner-only).
|
|
metadata:
|
|
tags: peertube, federated-video, activitypub, video-platform, sepiasearch, api-client
|
|
sources: https://docs.joinpeertube.org/api-rest-reference.html, https://sepiasearch.org/
|
|
---
|
|
|
|
# peertube — PeerTube federated video from the terminal
|
|
|
|
Browse any PeerTube instance — a federated deployment, not a single API — from the
|
|
terminal: instance stats, latest videos, full video detail, comment threads, channels,
|
|
accounts, and instance-local search. Authenticate with OAuth2 only for your own account
|
|
commands. Every command is read-only except `login`/`logout`.
|
|
|
|
## Setup
|
|
|
|
1. Choose the instance to talk to. Every command is per-instance; the API shape is
|
|
identical everywhere, but accounts, tokens, rules, and catalogs are not:
|
|
|
|
```bash
|
|
export PEERTUBE_SERVER="https://<INSTANCE_HOST>" # e.g. https://tilvids.com
|
|
```
|
|
|
|
To search the whole fediverse instead of one instance, point the same variable at the
|
|
public search index: `PEERTUBE_SERVER=https://sepiasearch.org` (same API shape — see
|
|
[references/search-and-discovery.md](references/search-and-discovery.md)).
|
|
|
|
2. Nothing else is required to browse: videos, search, channels, comments, and instance
|
|
info are anonymous reads.
|
|
|
|
3. (Optional) Log in only for your own account commands (`me`, `my-videos`):
|
|
|
|
```bash
|
|
scripts/peertube login --username <NAME> --prompt
|
|
```
|
|
|
|
### How authentication works
|
|
|
|
PeerTube uses plain OAuth2 with per-instance client credentials: the CLI anonymously
|
|
fetches the client pair from `GET /api/v1/oauth-clients/local` (singular `local`), then
|
|
exchanges your username/password for a bearer token at `POST /api/v1/users/token`
|
|
(`grant_type=password`, form-encoded). The token rides `Authorization: Bearer <token>`,
|
|
lives for the instance's configured lifetime (read `expires_in` from the response — do not
|
|
assume a fixed number), and is refreshed automatically when it expires. The token file is
|
|
written owner-only to `~/.config/peertube/token.json` keyed by server URL.
|
|
**Do not commit tokens** — they are account credentials; revoke with `scripts/peertube
|
|
logout` (`POST /users/revoke-token`) when done. Current production instances mask
|
|
`client_secret` in the API response; the CLI detects this and explains the workaround.
|
|
Details and wire-level error signatures:
|
|
[references/auth-and-tokens.md](references/auth-and-tokens.md).
|
|
|
|
## Essential Commands
|
|
|
|
### server — instance stats and identity (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube server # name, description, user/video/view counters
|
|
scripts/peertube server --json
|
|
```
|
|
|
|
Composes `GET /config/about` + `GET /server/stats` (canonical paths — there is no
|
|
`/instance/stats`).
|
|
|
|
### videos — browse the instance's uploads (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube videos # latest 15, offset pagination
|
|
scripts/peertube videos --limit 50 --offset 50
|
|
scripts/peertube videos --sort -views --json # popular first
|
|
```
|
|
|
|
Pagination is `start`/`count` offsets (max count 100) — the API has **no `page`
|
|
parameter**.
|
|
|
|
### search — find videos on THIS instance (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube search --query "linux" # instance-local (searchTarget=local)
|
|
scripts/peertube search -q "docker" --limit 20 --json
|
|
PEERTUBE_SERVER="https://sepiasearch.org" scripts/peertube search -q "linux" # fediverse-wide
|
|
```
|
|
|
|
The bundled CLI performs **instance-local** search only (`searchTarget=local`). For
|
|
fediverse-wide search, point `PEERTUBE_SERVER` at SepiaSearch — same commands, wider
|
|
index. Search results carry `channel.host`/`url`, the origin instance of federated hits.
|
|
|
|
### video — full detail for one video (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube video --id <UUID> # numeric id, UUID, or shortUUID all work
|
|
scripts/peertube video --id <UUID> --json | jq '{name, description, views, url}'
|
|
```
|
|
|
|
### comments — top-level comment threads (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube comments --id <UUID> # GET /videos/{id}/comment-threads
|
|
scripts/peertube comments --id <UUID> --limit 30 --json
|
|
```
|
|
|
|
### channels / channel / account — creators (anonymous)
|
|
|
|
```bash
|
|
scripts/peertube channels --limit 20 --json # instance channel list
|
|
scripts/peertube channel --handle framasoft@framatube.org # name or name@host
|
|
scripts/peertube account --name chocobozzz@framatube.org
|
|
```
|
|
|
|
`channel` shows metadata plus the channel's uploads (offset-paginated).
|
|
|
|
### me / my-videos — your account (requires login)
|
|
|
|
```bash
|
|
scripts/peertube me --json | jq '.role.label'
|
|
scripts/peertube my-videos --limit 50 --json
|
|
```
|
|
|
|
### login / logout — OAuth2 session management
|
|
|
|
```bash
|
|
scripts/peertube login --username <NAME> --prompt # hidden prompt
|
|
echo "<PASSWORD>" | scripts/peertube login --username <NAME> --password-stdin
|
|
scripts/peertube login --username <NAME> --otp <CODE> # 2FA-enabled accounts
|
|
scripts/peertube logout # revoke server-side + delete file
|
|
```
|
|
|
|
## Global flags
|
|
|
|
```bash
|
|
scripts/peertube --json videos # flag before or after the subcommand
|
|
scripts/peertube videos --json
|
|
scripts/peertube --dry-run search --query test # request plan, zero network
|
|
scripts/peertube --verbose videos --limit 2 # trace requests on stderr
|
|
scripts/peertube --server https://tilvids.com server # per-invocation instance override
|
|
```
|
|
|
|
`--dry-run` emits `{"dry_run": true, "method", "path", "params"}` (login adds
|
|
`form_fields` names only, never values) — use it to verify a jq chain before running it
|
|
live. `--help` and `--dry-run` never require credentials.
|
|
|
|
## Pipeline recipes
|
|
|
|
### Search, then inspect the top hit
|
|
|
|
```bash
|
|
scripts/peertube search --query "linux" --limit 5 --json | jq -r '.videos[0].uuid'
|
|
scripts/peertube video --id "$(scripts/peertube search -q linux --limit 1 --json | jq -r '.videos[0].uuid')" --json
|
|
```
|
|
|
|
### Page through a channel's uploads
|
|
|
|
```bash
|
|
scripts/peertube channel --handle framasoft@framatube.org --limit 100 --offset 0 --json | jq -r '.videos[].name'
|
|
# loop: advance --offset by the returned count until you reach .total (no page param exists)
|
|
```
|
|
|
|
### Instance report card
|
|
|
|
```bash
|
|
scripts/peertube server --json | jq '{name: .instance.name, videos: .stats.totalLocalVideos, users: .stats.totalUsers, views: .stats.totalLocalVideoViews}'
|
|
```
|
|
|
|
### Log in, check quota, log out
|
|
|
|
```bash
|
|
scripts/peertube login --username <NAME> --prompt
|
|
scripts/peertube me --json | jq '{username, role: .role.label, quota_bytes: .videoQuota}'
|
|
scripts/peertube logout
|
|
```
|
|
|
|
## JSON and jq
|
|
|
|
`--json` output keys are stable snake_case wrappers around raw API objects: `videos`
|
|
(the API's `{total, data}` list objects), `channels`, `threads` (+ `total_not_deleted`),
|
|
`instance` + `stats`, `channel`, `dry_run`/`method`/`path`/`params` for plans. Video
|
|
objects keep PeerTube's own field names — `uuid`, `shortUUID`, `name`, `duration`
|
|
(seconds), `views`, `publishedAt`, `account{name,displayName,host}`,
|
|
`channel{name,displayName,host}` — so jq selectors transfer directly to raw `curl`
|
|
against `/api/v1`. Example: `jq -r '.videos[] | [.name, .views, .channel.displayName] | @tsv'`.
|
|
|
|
## Known Gotchas
|
|
|
|
- **Instances are independent (federated, not one API)** — accounts, tokens, rules,
|
|
enabled features, and catalogs differ per instance. A token from instance A 401s on
|
|
instance B; the CLI keys the token file by server URL. Content federated *onto* an
|
|
instance still belongs to its origin (`channel.host`, video `url`).
|
|
- **Search scope is two different things** — `searchTarget=local` searches the
|
|
instance's own catalog; `search-index` (or SepiaSearch's base URL) searches the
|
|
fediverse via an external index. Omitting `searchTarget` gives the instance's own
|
|
scope on current servers, not the fediverse. The bundled CLI is instance-local unless
|
|
you point it at sepiasearch.org.
|
|
- **`page` does not exist** — collections paginate with `start`/`count` (max 100).
|
|
Clients sending `page=` silently re-read the first page forever.
|
|
- **The comments route is `/comment-threads`** (hyphenated) — `/comments` and
|
|
`/commentthreads` are not routes (they 400 on current servers).
|
|
- **Instance metadata paths are mixed** — stats at `/server/stats` (operation titled
|
|
"instance stats"), about at `/config/about`, config at `/config`. No
|
|
`/instance/*` metadata paths exist.
|
|
- **Production masks `client_secret`** — `oauth-clients/local` answers
|
|
`"********************************"` on current production instances; a token request
|
|
with the masked value 400s. The CLI detects it and explains the front-end-asset
|
|
workaround. `response_type=code` appears in old quick-start curls but is not part of
|
|
the current token schema — the CLI omits it.
|
|
- **Token lifetimes are instance-configurable** — read `expires_in` per response; the
|
|
CLI persists the absolute `expires_at` and refreshes automatically. Store tokens
|
|
owner-only, never commit them, revoke on logout (deleting the file alone leaves the
|
|
session live).
|
|
- **2FA needs an OTP header** — `x-peertube-otp` on the token request; the CLI maps a
|
|
bare 401 to "pass --otp".
|
|
- **Rate limits** — default 50 calls/10 s per IP (token endpoint tighter); on 429 read
|
|
`Retry-After` and back off. Errors use RFC7807 `application/problem+json` bodies, and
|
|
unknown routes answer 400 (not 404) — read the body.
|
|
- **`duration` is seconds**; ids are triple (`id`, `uuid`, `shortUUID` — all accepted by
|
|
detail endpoints); `role` is an object `{id, label}`; `videoQuota` is bytes.
|
|
- **Anonymous vs authed** — browsing/search/comments/instance-info need no token;
|
|
`/users/me*` and mutations always do.
|
|
|
|
## When to use
|
|
|
|
Use this skill for read-only interaction with PeerTube instances: browsing and filtering
|
|
videos, instance-local or fediverse-wide search (via SepiaSearch), video detail and
|
|
comments, channel/account exploration, instance stats, and managing your own account
|
|
session with OAuth2 (login, profile, my videos, logout).
|
|
|
|
## When not to use
|
|
|
|
Do not use this skill for YouTube, Vimeo, or other platform uploads or any video
|
|
editing/transcoding (route to those platforms' own tooling and ffmpeg); for installing,
|
|
hosting, or administering a PeerTube server (instance administration is out of scope —
|
|
the bundled CLI is read-only plus login/logout); or for generic ActivityPub/Mastodon
|
|
federation questions (use a Mastodon or ActivityPub skill).
|
|
|
|
## Reference Files
|
|
|
|
| File | Use it for |
|
|
| ---- | ---------- |
|
|
| [references/auth-and-tokens.md](references/auth-and-tokens.md) | OAuth2 flow (oauth-clients/local, password grant), secret masking, refresh/revocation, token-file hygiene, wire error signatures |
|
|
| [references/search-and-discovery.md](references/search-and-discovery.md) | searchTarget local vs search-index, SepiaSearch semantics, search parameters and sorts |
|
|
| [references/endpoint-catalog.md](references/endpoint-catalog.md) | Every read endpoint's parameters, response shapes, pagination, rate limits |
|
|
| [references/gotchas-field-guide.md](references/gotchas-field-guide.md) | Symptom → cause → fix table for every failure signature and version drift |
|
|
| [references/worked-recipes.md](references/worked-recipes.md) | Multi-step CLI/jq workflows, raw curl auth chain, jq processing patterns |
|
|
|
|
## Available Scripts and Prerequisites
|
|
|
|
- `scripts/peertube` — the bundled Python CLI (`--json`, `--dry-run`, `--verbose`,
|
|
`--server` override). Imports only the standard library and `requests`.
|
|
- `scripts/test_peertube.py` — offline test suite (pytest + unittest compatible); all
|
|
HTTP is mocked, zero network egress.
|
|
- Requires Python 3.8+ and `requests`. Any reachable PeerTube instance (or SepiaSearch)
|
|
works; no credentials exist or are required by default. No service is started by this
|
|
skill.
|