All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
reeln initcommand — guided first-time setup with interactive sport selection, directory configuration, and config creation- Non-interactive mode:
reeln init --sport hockey --source-dir ~/replays --output-dir ~/games
- Plugin install/uninstall now finds
uvin common paths (~/.local/bin,~/.cargo/bin,/opt/homebrew/bin) when shell PATH is minimal (fixes "No module named pip" in Tauri/GUI apps)
reeln queuecommand group for staged render-then-publish workflow: list, show, edit, publish, publish-all, remove, targets--queue/-qflag onrender shortandrender 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_QUEUEandON_PUBLISHlifecycle hooks for plugin integration with the queue workflow- Centralized metadata generation (
core/metadata.py) — auto-generates title and description from game/event context QueueItemstores config profile name —queue publishloads 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 QueueErrorexception 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 authcommand — test authentication for plugins (--jsonfor machine output,--refreshto force reauthentication)reeln plugins uninstallcommand — uninstall a plugin and remove from config (--forceto skip confirmation,--dry-runto preview)Authenticatorcapability protocol — plugins implementauth_check()andauth_refresh()for credential verification and token renewalAuthCheckResult,AuthStatus,PluginAuthReportmodels (reeln/models/auth.py) for structured auth status reporting
reeln game list— list games in output directory with status badges (finished/in progress)reeln game info— show detailed game information (teams, venue, progress, livestreams)reeln game delete— delete a game directory with confirmation prompt (--forceto skip)- Colored CLI output:
--version,plugins list,plugins search,plugins info,plugins inputs,game list,game info,game deleteall use consistent styled output (bold names, green/red/yellow badges, dim labels) - Shared
reeln.commands.stylemodule for consistent CLI formatting - Plugin Input Contributions: plugins declare additional user inputs via
input_schemaclass attribute (PluginInputSchema,InputField) --plugin-input KEY=VALUE(-I) repeatable option ongame init,render short, andrender preview- Interactive prompts for plugin-contributed inputs (questionary-based, preset-first pattern)
- Conditional prompting:
thumbnailandtournamentonly prompted when a plugin declares them InputCollectorwith conflict resolution (same-type dedup, cross-type namespacing)get_input_schema()method support: plugins can conditionally declare inputs based on feature flags (e.g., only prompt for thumbnail whencreate_livestreamis enabled)- Registry fallback: plugins without
input_schema/get_input_schema()get inputs fromui_contributions.input_fieldsin registry JSON reeln plugins inputsintrospection command (text + JSON output for reeln-dock)input_contributionsfield onRegistryEntrymodel, parsed fromui_contributions.input_fields- Google plugin registry entry updated with
thumbnail_imageinput field forgame_init
init_game()acceptsplugin_inputskwarg, included inON_GAME_INIT/ON_GAME_READYhook dataPRE_RENDER/POST_RENDERhook data includesplugin_inputswhen presentactivate_plugins()now registers plugin input schemas with theInputCollectorsingletongame initchecks for unfinished games before interactive prompts (fail fast instead of prompting then failing)_resolve_game_dirnow sorts bycreated_atfromgame.jsoninstead of filesystem mtime (which is unreliable due to Spotlight/Time Machine)_resolve_game_dirprefers unfinished games over finished ones, soreeln game finishfinds the right game
- Read the Docs example page links now navigate correctly (renamed wrapper files to match example filenames)
examples/directory with 10 step-by-step walkthrough pages covering install, OBS setup, game lifecycle, rendering, profiles, plugins, and smart zoom- Examples integrated into Read the Docs via
docs/examples/section - Video demo talking points (gitignored, presenter-only)
- README.md rewritten: prominent ffmpeg dependency callout, updated CLI reference (removed stale "coming soon" section), added examples link
- Docs index updated with ffmpeg admonition, current feature list, and examples toctree entry
reeln hooks runandreeln hooks listCLI commands for non-interactive hook execution (JSON-in/JSON-out, designed for reeln-dock integration)reeln-nativev0.2.0 as a required dependency (Rust-powered acceleration)native-devandpluginsMakefile targets for local development
- Goal overlay layout: dynamic box height when assists are present, adjusted assist Y-coordinates for better spacing
probe_duration()now accepts single-arg form with auto-discovery (probe_duration(path))- Overlay template documentation now covers ASS templates only (JSON templates deferred to native migration)
- Dead PNG overlay pipeline (
ResolvedOverlay,resolve_overlay_for_profile,composite_video_overlay) — unreachable code from incomplete JSON template integration goal_overlay.jsontemplate (nothing loaded it)- Shell completion Makefile targets (replaced by symlink install)
- Branding overlay on rendered shorts: shows "reeln v{version} by https://streamn.dad" with a black-bordered white text at the top of the video for the first ~5 seconds with a smooth fade-out — enabled by default, configurable via
brandingconfig section, disable with--no-brandingCLI flag BrandingConfigmodel (enabled,template,duration) for per-user branding customization- Bundled
branding.assASS template with\fad(300,800)animation and black outline for visibility over any background --no-brandingflag onrender shortandrender previewcommands- Branding renders only on the first iteration in multi-iteration mode
- Cross-fade transitions between iterations: uses ffmpeg
xfade+acrossfadefilters for smooth 0.5s fade transitions instead of hard cuts, with automatic fallback to concat demuxer if xfade fails - Smart zoom support in the iteration pipeline:
--smart --iteratenow extracts frames once upfront and passes the zoom path through to each iteration'splan_short()call speed_segmentsin render profiles for variable speed within a single clip — e.g., normal speed → slow motion → normal speed, using the proven split/trim/concat ffmpeg pattern--player-numbers(-n) flag onrender short,render preview, andrender applyfor roster-based player lookup: accepts comma-separated jersey numbers (e.g.,--player-numbers 48,24,2), looks up names from the team roster CSV, and populates goal scorer and assist overlays automatically--event-typeflag on render commands for scoring team resolution:HOME_GOAL/AWAY_GOALdetermines which team's roster to look upRosterEntrydata model andload_roster()/lookup_players()/resolve_scoring_team()core functions for roster managementGameInfonow persistslevel,home_slug, andaway_slugwhengame init --levelis used, enabling roster lookup during renderingbuild_overlay_context()accepts optionalscoring_teamparameter to override the default (home team)- Smart target zoom (
--crop smart): extracts frames from clips, emitsON_FRAMES_EXTRACTEDhook for vision plugins (e.g. reeln-plugin-openai) to detect action targets, then builds dynamic ffmpeg crop expressions that smoothly pan across detected targets ZoomPoint,ZoomPath, andExtractedFramesdata models for smart zoom contractsON_FRAMES_EXTRACTEDlifecycle hook for plugins to analyze extracted video framesextract_frames()method on the Renderer protocol and FFmpegRenderer for frame extractionbuild_piecewise_lerp()andbuild_smart_crop_filter()for dynamic ffmpeg crop expressions--zoom-framesoption onrender shortandrender preview(default 5, range 1-20)- Zoom debug output:
debug/zoom/zoom_path.jsonand frame symlinks when--debugis used with smart crop - Smart pad mode (
--crop smart_pad): follows action vertically like smart zoom but keeps black bars instead of filling the entire frame — falls back to static pad when no vision plugin provides data build_smart_pad_filter()for dynamic vertical pad positioning based on zoom path center_y- Debug crosshair annotations: extracted frames in
debug/zoom/now include annotated copies with green crop box and red crosshair overlays showing detected center points --scaleoption onrender shortandrender preview(0.5-3.0, default 1.0): zooms in by scaling up the intermediate frame before crop/pad — works with all crop modes including smart tracking--smartflag onrender shortandrender preview: enables smart tracking via vision plugin as an orthogonal option, composable with--crop pad|cropand--scalebuild_overflow_crop_filter()for pad + scale > 1.0: crops overflow after scale-up before padding- Automatic fallback from smart crop to center crop (or smart_pad to static pad) when no vision plugin provides zoom data
--no-enforce-hooksglobal CLI flag to temporarily disable registry-based hook enforcement for pluginsgame finishnow relocates segment and highlights outputs from the shared output directory intogame_dir/outputs/, preventing file collisions across multiple games per daygame initnow blocks with a clear error if an unfinished game exists — runreeln game finishfirstGameStatetrackssegment_outputsandhighlights_outputfor file relocationfind_unfinished_games()helper scans for active game directoriesrelocate_outputs()helper moves output files into the game directoryreeln doctornow collects and runs health checks from plugins that implementdoctor_checks()doctorcapability added to plugin duck-type detection--tournamentCLI flag ongame initfor optional tournament name/context — flows through to plugins via hook context and overlay templatestournamentandlevelfields now included in template context (build_base_context()), available as{{tournament}}and{{level}}in ASS subtitle templates
- Scale, framing (crop/pad), and smart tracking are now orthogonal axes — any combination works without dedicated enum values
- Short/preview renders now output to a
shorts/subdirectory by default (e.g.,period-2/shorts/clip_short.mp4) to prevent segment merges from picking up rendered files
--crop smart— use--crop crop --smartinstead (still works, shows deprecation warning)--crop smart_pad— use--crop pad --smartinstead (still works, shows deprecation warning)
team_levelin overlay context now uses the actual team level (e.g., "2016", "bantam") instead of the sport name — previously showed "hockey" instead of the level- Segment merge and highlights merge output extension now matches input files instead of being hardcoded to
.mkv - Highlights merge now discovers segment files with any video extension (
.mp4,.mkv,.mov, etc.), not just.mkv
--profilenow resolves relative to the active config directory (parent ofREELN_CONFIG) instead of the platform default, so profiles stored alongside a custom config file are found correctly--profileand--pathCLI arguments now take strict priority overREELN_CONFIGandREELN_PROFILEenvironment variables
ON_POST_GAME_FINISHhook — fires afterON_GAME_FINISHwith shared context, enabling cross-plugin data consumption at game finish (mirrorsON_GAME_INIT→ON_GAME_READYpattern)--log-levelCLI option andREELN_LOG_LEVELenv var to control log verbosity (default: WARNING)enforce_hooksplugin config option — restricts plugins to hooks declared in the registry; setfalsefor local plugin development- Registry capability enforcement — plugins can only register hooks declared in their
registry/plugins.jsonentry
- Explicit
--profileor--pathto a nonexistent config file now fails immediately instead of silently using defaults
- Default log level changed from INFO to WARNING (reduces noise during normal operation)
ON_GAME_READYhook — fires afterON_GAME_INITwith shared context, enabling cross-plugin data consumption (e.g. OpenAI generates thumbnail during init, Google updates livestream during ready)config shownow displays the full resolved configuration including all default values and plugin schema defaults- Plugin registry entries for
meta(Facebook Live/Instagram/Threads) andopenai(LLM-powered metadata/thumbnails/translation)
- PyPI Documentation link now points to correct URL (
reeln-cli.readthedocs.io)
- Plugins that are not installed log at debug level instead of warning with traceback
--version/-Vflag onreeln plugins installandreeln plugins updateto pin a specific version (git tag or PyPI release)- Logo on Read the Docs site (sidebar and favicon)
--description/-dflag ongame initfor broadcast description--thumbnailflag ongame initfor thumbnail image pathGameInfo.descriptionandGameInfo.thumbnailfields- Interactive prompts for description and thumbnail (both optional)
- PyPI logo: restore absolute URL for README image (lost during merge)
HookContext.shareddict for plugins to pass data back (e.g. livestream URLs)GameState.livestreamsfield — persists livestream URLs written by hook pluginsresolve_config_path()— extracted config path resolution for reuse
- Plugin install now uses
git+{homepage}for GitHub/GitLab plugins instead of PyPI lookup - Post-install verification catches silent
uv pip installno-ops save_config()now respectsREELN_CONFIG/REELN_PROFILEenv vars (previously always wrote to default path)detect_installer()passes--python sys.executableto uv so plugins install into the correct environment- Hardcoded version strings removed from tests (use
__version__dynamically)
- Logo image on PyPI (use absolute URL for
assets/logo.jpg) - Add project URLs to PyPI sidebar (Homepage, Docs, Repo, Changelog, Issues)
- Registry URL casing —
raw.githubusercontent.comis case-sensitive (StreamnDadnotstreamn-dad) - mypy errors in
prompts.py(renamed shadowed variables) - CI workflows use
uv syncinstead ofuv pip install --system(PEP 668) - Plugin registry: correct homepage URL and metadata for
streamn-scoreboard
First feature-complete release of reeln — platform-agnostic CLI toolkit for livestreamers.
reeln --version— show version, ffmpeg info, and installed plugin versionsreeln doctor— comprehensive health check: ffmpeg, codecs, hardware acceleration, config, permissionsreeln config show— display current configuration as JSONreeln config doctor— validate config, warn on issuesreeln game init— initialize game workspace with sport-specific segment subdirectoriesreeln game segment <N>— merge replays in a segment directory into a highlight videoreeln game highlights— merge all segment highlights into a full-game highlight reelreeln game finish— mark a game as finished with summaryreeln game prune— remove generated artifacts from a finished game directoryreeln game event list— list events with filters (--segment,--type,--untagged)reeln game event tag— tag an event with type, player, and metadatareeln game event tag-all— bulk-tag all events in a segmentreeln game compile— compile raw event clips into a single video by criteriareeln render short— render a 9:16 short from a clipreeln render preview— fast low-res preview renderreeln render apply— apply a named render profile to a clip (full-frame, no crop/scale)reeln render reel— assemble rendered shorts into a concatenated reelreeln media prune— scan and prune all finished game directoriesreeln plugins list— list installed plugins with version inforeeln plugins search— search the plugin registryreeln plugins info <name>— show detailed plugin informationreeln plugins install <name>— install a plugin from the registry with auto-enablereeln plugins update [name]— update a plugin or all installed pluginsreeln plugins enable <name>/reeln plugins disable <name>— enable/disable plugins
- Package skeleton:
pyproject.toml, Makefile,.coveragerc,pytest.ini,python -m reelnsupport - Structured logging module with JSON and human formatters
- Error hierarchy:
ReelnErrorbase with typed subclasses - FFmpeg discovery with cross-platform support (PATH, brew, apt, choco), version checking (5.0+ minimum)
- Media probe helpers: duration, fps, resolution via ffprobe
- Deterministic ffmpeg command builders (concat, render) with golden test assertions
FFmpegRendererimplementation withrender()andpreview()methods- Config system: JSON loading, schema validation,
config_version, XDG-compliant paths, env var overrides (REELN_<SECTION>_<KEY>), deep merge, atomic writes, named profiles - Segment model: generic time division abstraction with sport alias registry (hockey, basketball, soccer, football, baseball, lacrosse, generic) and custom sport registration
- Game lifecycle:
GameInfo,GameState,GameEventmodels with JSON serialization, double-header auto-detection,game.jsonstate tracking GameEventmodel for first-class event tracking with UUID-based IDs, prefix matching, extensible metadata, and idempotent creation- Render state tracking in
game.jsonviaRenderEntrywith event auto-linking - ShortConfig model with crop modes (pad, crop), output formats (vertical, square), anchor positions
- Filter graph builders: scale, pad, crop, speed, LUT, subtitle — composable and golden-tested
- Render profiles: named configuration sets for reusable rendering parameter overrides (speed, LUT, subtitle template, encoding)
- Multi-iteration rendering: run a clip through N render profiles sequentially and concatenate results
- Template engine:
{{key}}placeholder substitution for.asssubtitle files TemplateContext,TemplateProviderprotocol,build_base_context()for game/event context- ASS subtitle helpers:
rgb_to_ass(),format_ass_time() - Bundled
goal_overlayASS subtitle template with dynamic font sizing and team-colored background builtin:prefix forsubtitle_templatein render profiles (e.g."builtin:goal_overlay")build_overlay_context()for computing overlay-specific template variables from event metadata--playerand--assistsCLI flags onrender short,render preview, andrender apply— populate overlay template variables without game event tagging; override event data when both are present- Default
player-overlayrender profile andgoaliteration mapping in bundled config TeamProfilemodel with metadata (logo, roster, colors, jersey colors, period length)- Team profile management: load, save, list, delete with atomic writes
- Interactive team selection and game time prompting in
game init --game-time,--level,--period-length,--venueoptions ongame init--debugflag on game and render commands — writes pipeline debug artifacts with ffmpeg commands, filter chains, and metadata- HTML debug index (
debug/index.html) with summary table and per-operation sections --dry-runsupport across all destructive and render commandsPruneResultmodel,format_bytes(),find_game_dirs()helpersCompilationResultmodel for compilation output trackingquestionaryas optional dependency (pip install reeln[interactive])
- Plugin system foundation: lifecycle hooks, capability protocols, hook registry
Hookenum with 11 lifecycle hooks:PRE_RENDER,POST_RENDER,ON_CLIP_AVAILABLE,ON_EVENT_CREATED,ON_EVENT_TAGGED,ON_GAME_INIT,ON_GAME_FINISH,ON_HIGHLIGHTS_MERGED,ON_ERROR,ON_SEGMENT_START,ON_SEGMENT_COMPLETEHookRegistrywith safe emission — handler exceptions are caught and logged- Capability protocols:
Uploader,MetadataEnricher,Notifier,Generator - Plugin orchestrator: sequential pipeline (Generator -> MetadataEnricher -> Uploader -> Notifier)
- Plugin loader:
discover_plugins(),load_plugin(),load_enabled_plugins(),activate_plugins() - Plugin config schema declaration with
ConfigFieldandPluginConfigSchema - Remote plugin registry with cache, search, install, update, and auto-enable
authorandlicensefields on plugin registry entriesThrottledReaderfor upload throughput limiting,upload_lock()for serializationfilelock>=3.0dependency
- GitHub Actions CI workflow (Python 3.11/3.12/3.13 matrix, lint, type check, tests, docs build)
- GitHub Actions release workflow (tag-based PyPI publish via trusted publisher)
- CI and docs badges in README
- Documentation infrastructure: Sphinx + MyST, Furo theme, Read the Docs config
- Full docs site: install guide, quickstart tutorial, CLI reference, configuration guide, sports guide
render short --render-profilenow correctly resolvessubtitle_templatefrom the profile — previously the template was silently dropped in the single-profile path
--rinkCLI flag renamed to--venuefor sport-agnostic terminology- Segment merge and highlights merge output written to
paths.output_dirfor discoverability period_lengthmoved fromTeamProfiletoGameInfo- Full test suite with 100% line + branch coverage