Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .claude/rules/plugin-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,25 @@ class MyPlugin:

## Hook System

**Hook enum** (`reeln.plugins.hooks.Hook`) — 13 lifecycle hooks:
**Hook enum** (`reeln.plugins.hooks.Hook`) — 16 lifecycle hooks:

| Hook | Emitted when |
|------|-------------|
| `PRE_RENDER` | Before a render operation starts |
| `POST_RENDER` | After a render completes |
| `POST_RENDER` | After a render completes (fast-track publish) |
| `ON_CLIP_AVAILABLE` | A new clip file is ready |
| `ON_EVENT_CREATED` | A new event is created |
| `ON_EVENT_TAGGED` | An event is tagged/categorized |
| `ON_GAME_INIT` | `reeln game init` sets up a new game |
| `ON_GAME_READY` | After all `ON_GAME_INIT` handlers complete — plugins read shared context from init phase |
| `ON_GAME_FINISH` | `reeln game finish` finalizes a game |
| `ON_POST_GAME_FINISH` | After all `ON_GAME_FINISH` handlers complete |
| `ON_HIGHLIGHTS_MERGED` | Segment highlights are merged into a reel |
| `ON_SEGMENT_START` | A new segment begins |
| `ON_SEGMENT_COMPLETE` | A segment finishes |
| `ON_FRAMES_EXTRACTED` | Frames extracted from a clip for smart zoom analysis |
| `ON_QUEUE` | A render result is added to the queue (`--queue` flag) |
| `ON_PUBLISH` | A queued item is published to an external target |
| `ON_ERROR` | An error occurs during any operation |

**HookContext** — frozen dataclass passed to every handler:
Expand Down Expand Up @@ -92,6 +95,7 @@ Plugins can implement typed protocols for specific capabilities (`reeln.plugins.
| `MetadataEnricher` | `enrich(event_data) -> dict` | Enrich event metadata |
| `Notifier` | `notify(message, *, metadata) -> None` | Send notifications |
| `Generator` | `generate(context) -> GeneratorResult` | Generate media assets |
| `Authenticator` | `auth_check() -> list[AuthCheckResult]`, `auth_refresh() -> list[AuthCheckResult]` | Test credentials and refresh tokens |

## Config Schema

Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [0.0.38] - 2026-04-07

### Added
- `reeln queue` command group for staged render-then-publish workflow: list, show, edit, publish, publish-all, remove, targets
- `--queue` / `-q` flag on `render short` and `render apply` — renders but queues for review instead of publishing immediately
- Per-target publish tracking — publish to YouTube, review, then selectively push to Instagram/TikTok without re-rendering
- `ON_QUEUE` and `ON_PUBLISH` lifecycle hooks for plugin integration with the queue workflow
- Centralized metadata generation (`core/metadata.py`) — auto-generates title and description from game/event context
- `QueueItem` stores config profile name — `queue publish` loads the same plugin settings used at queue time
- Queue persistence via `render_queue.json` (per-game directory) with advisory central index for cross-game listing
- `QueueError` exception class for queue operation errors
- Team logo overlay on goal shorts — resolves logo from `TeamProfile.logo_path`, scales to 80% of box height, right-aligned with text clipping. Supports all four filter chain paths (simple pad/crop, smart pad, speed segments, speed segments + smart pad)
- `reeln plugins auth` command — test authentication for plugins (`--json` for machine output, `--refresh` to force reauthentication)
- `reeln plugins uninstall` command — uninstall a plugin and remove from config (`--force` to skip confirmation, `--dry-run` to preview)
- `Authenticator` capability protocol — plugins implement `auth_check()` and `auth_refresh()` for credential verification and token renewal
- `AuthCheckResult`, `AuthStatus`, `PluginAuthReport` models (`reeln/models/auth.py`) for structured auth status reporting

## [0.0.37] - 2026-04-03

### Added
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ reeln doctor # checks ffmpeg, codecs, config, permissions, plugins
- **Render profiles** — save and reuse rendering settings, chain them with iterations
- **Smart zoom** — AI-powered tracking that follows the action (via plugin)
- **Player overlays** — roster-aware goal overlays with jersey number lookup
- **Render queue** — stage renders for review, then selectively publish to YouTube, Instagram, TikTok
- **Team logo overlays** — automatic logo placement on goal shorts from team profiles
- **Plugin architecture** — lifecycle hooks for YouTube, Instagram, cloud uploads, and more
- **Flexible configuration** — JSON config, XDG paths, env var overrides, named profiles
- **Cross-platform** — macOS, Linux, Windows
Expand Down Expand Up @@ -85,6 +87,8 @@ reeln game finish

See the [examples](examples/) for detailed walkthroughs of every workflow.

> Looking for a GUI? [reeln dock](https://github.com/StreamnDad/reeln-dock) is a cross-platform desktop companion for reeln — visual render profiles, clip review, and game management without touching the terminal. Coming soon.

## Supported sports

| Sport | Segment name | Count | Example directories |
Expand Down Expand Up @@ -128,6 +132,18 @@ See the [examples](examples/) for detailed walkthroughs of every workflow.
| `reeln render apply` | Apply a render profile (full-frame, no crop) |
| `reeln render reel` | Assemble rendered shorts into a reel |

### Queue

| Command | Description |
|---|---|
| `reeln queue list` | List queued render items |
| `reeln queue show <ID>` | Show detailed queue item info |
| `reeln queue edit <ID>` | Edit title/description before publishing |
| `reeln queue publish <ID>` | Publish to one or all targets (`--target <name>`) |
| `reeln queue publish-all` | Publish all rendered items |
| `reeln queue remove <ID>` | Soft-delete queue item |
| `reeln queue targets` | List available publish targets |

### Configuration

| Command | Description |
Expand All @@ -147,6 +163,8 @@ See the [examples](examples/) for detailed walkthroughs of every workflow.
| `reeln plugins list` | List installed plugins |
| `reeln plugins enable <name>` | Enable a plugin |
| `reeln plugins disable <name>` | Disable a plugin |
| `reeln plugins uninstall <name>` | Uninstall a plugin |
| `reeln plugins auth` | Test plugin authentication |

## Configuration

Expand All @@ -161,6 +179,20 @@ reeln uses a layered JSON config system:
reeln config show
```

## Smart zoom — AI-powered action tracking

`reeln render short --smart` uses the [OpenAI plugin](https://github.com/StreamnDad/reeln-plugin-openai) to analyse extracted frames and track the action — dynamically cropping and panning the camera to follow the play in your 9:16 short. Read [What happened when I let AI edit my youth hockey videos](https://streamn-dad.medium.com/what-happened-when-i-let-ai-edit-my-youth-hockey-videos-d7ece1883905) for the full story.

Add `--debug` to see exactly what the AI sees: annotated frames with crosshair tracking, crop regions, the full zoom path, and every ffmpeg filter chain.

[Live debug example](https://streamn.dad/examples/reeln-debug/) — real game clip with 16-frame smart zoom tracking.

<p align="center">
<a href="https://streamn.dad/examples/reeln-debug/">
<img src="https://raw.githubusercontent.com/StreamnDad/reeln-cli/main/assets/debug-preview.png" alt="Smart zoom debug — annotated frame showing crosshair tracking and crop region" width="600">
</a>
</p>

## Documentation

- [Full documentation](https://reeln-cli.readthedocs.io) — install, guides, CLI reference
Expand Down
Binary file added assets/debug-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ reeln provides a hierarchical command structure organized by domain.
| `reeln render` | Video rendering: short, preview, reel | Available | {doc}`render` |
| `reeln media` | Media management: prune | Available | {doc}`media` |
| `reeln plugins` | Plugin management: list, enable, disable | Available | {doc}`plugins` |
| `reeln queue` | Render queue: list, show, edit, publish, remove, targets | Available | {doc}`queue` |

## Global options

Expand Down
62 changes: 62 additions & 0 deletions docs/cli/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,64 @@ reeln plugins disable <NAME>

Adds the plugin to the `plugins.disabled` list and removes it from `plugins.enabled` in your config file.

### `reeln plugins uninstall`

Uninstall a plugin and remove it from config.

```bash
reeln plugins uninstall <NAME>
reeln plugins uninstall <NAME> --force
reeln plugins uninstall <NAME> --dry-run
```

| Argument | Description |
|---|---|
| `NAME` | Plugin name to uninstall |

| Option | Description |
|---|---|
| `--force`, `-f` | Skip confirmation prompt |
| `--dry-run` | Preview the uninstall command without executing |
| `--installer` | Force a specific installer (`pip` or `uv`) |

Prompts for confirmation before uninstalling. Removes the plugin from `plugins.enabled` and adds it to `plugins.disabled` in your config.

### `reeln plugins auth`

Test authentication for plugins, or force reauthentication.

```bash
reeln plugins auth
reeln plugins auth google
reeln plugins auth google --refresh
reeln plugins auth --json
```

| Argument | Description |
|---|---|
| `NAME` | Plugin name (empty = test all plugins with auth support) |

| Option | Description |
|---|---|
| `--refresh`, `-r` | Force reauthentication (requires a plugin name) |
| `--json` | Output as JSON |
| `--profile` | Named config profile |
| `--config` | Explicit config file path |

Checks each plugin that implements the `Authenticator` protocol. Reports per-service status:

| Status | Badge | Meaning |
|---|---|---|
| `ok` | `authenticated` | Credentials are valid |
| `warn` | `warning` | Credentials work but with caveats (e.g., missing scopes) |
| `expired` | `expired` | Token has expired |
| `not_configured` | `not configured` | No credentials found |
| `fail` | `failed` | Authentication check failed |

With `--refresh`, the plugin's `auth_refresh()` method is called to force token renewal (e.g., OAuth refresh flow).

Exits with code 1 if any result is `fail` or `expired`.

## Plugin registry

reeln maintains a remote plugin registry that lists available plugins, their packages, and capabilities. The registry is fetched from GitHub and cached locally for 1 hour.
Expand Down Expand Up @@ -189,6 +247,9 @@ reeln exposes lifecycle hooks that plugins can subscribe to:
| `ON_HIGHLIGHTS_MERGED` | After game highlights are merged |
| `ON_SEGMENT_START` | Before segment file I/O begins |
| `ON_SEGMENT_COMPLETE` | After segment merge and state update |
| `ON_FRAMES_EXTRACTED` | After frames are extracted for smart zoom analysis |
| `ON_QUEUE` | After a render result is added to the queue (`--queue` flag) |
| `ON_PUBLISH` | After a queued item is published to an external target |
| `ON_ERROR` | When an error occurs in core operations |

Hooks receive a `HookContext` with three fields:
Expand All @@ -212,6 +273,7 @@ Plugins can implement typed capability interfaces:
- **Uploader** — upload rendered media to external services (YouTube, social media, cloud storage)
- **MetadataEnricher** — enrich event metadata with additional information (LLM descriptions, statistics)
- **Notifier** — send notifications when events occur (Slack, Discord, email)
- **Authenticator** — test credentials and refresh tokens (`auth_check()` returns `list[AuthCheckResult]`, `auth_refresh()` forces token renewal)

## Orchestration pipeline

Expand Down
173 changes: 173 additions & 0 deletions docs/cli/queue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# reeln queue

Render queue management for staged render-then-publish workflows.

## Overview

The render queue decouples rendering from publishing. Instead of `POST_RENDER`
plugin hooks firing immediately after a render, the `--queue` flag on
`render short` or `render apply` saves the rendered output to a queue for
review. You can then edit metadata (title, description), selectively publish
to specific platforms, and track per-target publish status.

Queue files are stored per-game as `render_queue.json` alongside `game.json`.

## Commands

### `reeln queue list`

List queued render items.

```bash
reeln queue list [OPTIONS]
```

| Option | Description |
|---|---|
| `--game-dir`, `-g` | Game directory (default: cwd) |
| `--all`, `-a` | List across all games (uses central index) |
| `--status`, `-s` | Filter by status: rendered, published, partial, failed |

Removed items are hidden by default.

### `reeln queue show`

Show detailed info for a queue item.

```bash
reeln queue show <ID> [OPTIONS]
```

| Option | Description |
|---|---|
| `--game-dir`, `-g` | Game directory (default: cwd) |

Displays output path, duration, file size, game context, player info, render
profile, publish targets with status and URLs.

ID supports prefix matching (e.g., `abc` matches `abc123def456`).

### `reeln queue edit`

Edit title or description before publishing.

```bash
reeln queue edit <ID> [OPTIONS]
```

| Option | Description |
|---|---|
| `--title`, `-t` | New title |
| `--description`, `-d` | New description |
| `--game-dir`, `-g` | Game directory (default: cwd) |

At least one of `--title` or `--description` is required.

### `reeln queue publish`

Publish a queue item to one or all targets.

```bash
reeln queue publish <ID> [OPTIONS]
```

| Option | Description |
|---|---|
| `--target`, `-t` | Publish to specific target only (e.g., `google`, `meta`) |
| `--game-dir`, `-g` | Game directory (default: cwd) |
| `--profile` | Override config profile (default: profile stored at queue time) |
| `--config` | Explicit config file path |

Without `--target`, publishes to all pending targets. Each target is tracked
independently — you can publish to YouTube first, review, then push to
Instagram later.

The config profile stored in the queue item is used by default, ensuring the
same plugin settings (API keys, channel IDs, etc.) apply. Use `--profile` to
override.

### `reeln queue publish-all`

Publish all rendered items in the queue.

```bash
reeln queue publish-all [OPTIONS]
```

| Option | Description |
|---|---|
| `--game-dir`, `-g` | Game directory (default: cwd) |
| `--profile` | Named config profile |
| `--config` | Explicit config file path |

Only items with status `rendered` are published. Items already published,
failed, or removed are skipped.

### `reeln queue remove`

Soft-delete a queue item.

```bash
reeln queue remove <ID> [OPTIONS]
```

| Option | Description |
|---|---|
| `--game-dir`, `-g` | Game directory (default: cwd) |

Marks the item as removed. Does not delete the rendered file.

### `reeln queue targets`

List available publish targets from loaded uploader plugins.

```bash
reeln queue targets [OPTIONS]
```

| Option | Description |
|---|---|
| `--profile` | Named config profile |
| `--config` | Explicit config file path |

Targets are discovered from installed plugins that implement the `Uploader`
capability protocol.

## Status lifecycle

Queue items progress through these statuses:

| Status | Meaning |
|---|---|
| `rendered` | Render complete, not yet published |
| `publishing` | Publish in progress |
| `published` | All targets published successfully |
| `partial` | Some targets published, others pending or failed |
| `failed` | All target publishes failed |
| `removed` | Soft-deleted |

Each publish target has its own status: `pending`, `published`, `failed`, or
`skipped`.

## Examples

```bash
# Render and queue
reeln render short clip.mkv --queue --profile tournament-stream

# Review what's queued
reeln queue list
reeln queue show abc123

# Fix the title
reeln queue edit abc123 --title "Smith Goal - North vs South"

# Publish to YouTube first
reeln queue publish abc123 --target google

# Review the YouTube upload, then push to Instagram
reeln queue publish abc123 --target meta

# See all available targets
reeln queue targets
```
Loading
Loading