v0.0.1
Pre-release
Pre-release
Changelog
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.
[0.0.1] - 2026-08-28
First public release. Matchora is a Go service that ingests title rows or scans a
video library, searches YAML-defined metadata APIs, and ranks candidates with a
local llama.cpp embedder or instruct model.
Added
Matching and providers
- Generic GET + JSON-path provider engine. Provider names are not hardcoded in Go.
- Shipped providers: TVMaze, Jikan v4, OMDb (movies, keyed), TMDB movie and TMDB TV (keyed).
- Type allowlists so a typed job only calls providers that list that type.
- Fast pass plus deferred providers (
defer: true) when hit count or best score is too low. - Parallel provider GETs per title; per-job HTTP clocks so a slow deferred call does not stall the batch.
- Per-provider pacing (
min_interval_ms), retries, per-attempt timeouts, capped exponential backoff, andRetry-After. - Provider cooldown after consecutive GET failures (jittered skip, reset on success).
- Ranking: MiniLM embeddings (cosine) or instruct chat; lexical token overlap + year bonus if the embed server is down.
- Auto-
matchedvsmanualvsunmatchedfrommin_score/min_margin; user confirm via select. - Season/episode catalog fetch for TV providers (TVMaze, TMDB TV), including a catalog-only request that does not change the match.
- Optional provider
detailGET (OMDb plot) and poster downloads. skip_episode_posterson ingest, scan, rematch, retry, select, and catalog.
Ingest and scan
POST /v1/ingestfor CSV (header) or JSON arrays:title,year,type,season,episode,imdb.- CSV alias map (
ingest.aliases) and type rewrite (episode/season→tv). - Instruct fallback to map unknown CSV columns using
config/ingest.md. POST /v1/scanlists videos underbrowse_root, groups dirty names with a local instruct model (config/prompt.md), then matches in the worker.- Scan grouping progress via
GET /v1/scan/status. - Expected Plex / Jellyfin / Infuse trees (movies vs series roots, optional
{tmdb-…}/{imdb-tt…}ids).
Catalog
- Matched, selected, and cataloged titles written under
{data_dir}/catalogas[uniqueid-id] Title (Year)/trees. tvshow.nfo/movie.nfo, season folders, episode.nfo, and downloaded posters.- Distinct
uniqueidslugs so TMDB movie vs TV ids cannot collide (tmdb-movie,tmdb-tv, OMDbimdb). GET /v1/catalogandGET /v1/catalog/{provider}/{id}; posters at/poster.jpg(and season/episode variants).- Clearing jobs does not delete the catalog tree.
Runtime and llama.cpp
- HTTP admin server on
:7680(User-Agent: matchora/{version}). - Writable
{exeDir}/data:jobs.json, optionalconfig.yamloverlay,secrets(YAML map of API keys). GET/POST /v1/secretsreport which key slots are set and merge the secrets file (values never returned). Slots are provider API keys only.GET/POST /v1/configread and deep-merge{data_dir}/config.yaml(same shape asdefault.yaml). Never includes secrets.- Listen address is
llama.host/llama.port(defaults127.0.0.1/8080);llama.base_urlis derived ashttp://{host}:{port}/v1. - On start, probe that URL. A healthy listener is left alone. If it is down, install llama.cpp + GGUFs into
{exeDir}/vendor/llama.cppand spawn one llama-server on127.0.0.1at that port (embed + optional instruct). Distinctllm_base_url(e.g. a stub) is left alone. - After a successful secrets or config POST, return the JSON body, stop a spawned llama-server, and re-exec so the next
Load/llama.Startapplies the files. Setters write files only. --prepareruns that install, verifies models, stops the spawned server, and exits.- Dist is binary +
config/+public/only; llama.cpp is not in the slim tree.
Admin console
- Verification UI at
/(folder picker viaGET /v1/fs, ingest upload, scan, job cards). - Secrets panel for provider keys and llama panel for host/port; both wait for
/healthafter the process restart. - Live match wait log, sticky status chips, score heatmap, retry errors/unmatched, clear jobs.
- Manual candidate select and per-candidate seasons catalog.
- Skip-episode-posters checkbox persisted in
localStorage.
HTTP API
GET /,/health,/v1/fs,/v1/jobs,/v1/match/log,/v1/scan/status,/v1/catalog,/v1/catalog/{provider}/{id}GET/POST /v1/secrets,GET/POST /v1/configPOST /v1/ingest,/v1/scan,/v1/match,/v1/retry,/v1/jobs/{id}/select,/v1/jobs/{id}/catalogDELETE /v1/jobs(empty list and abort in-flight scan grouping)
Build, package, and tests
- Podman linux/amd64 dist builder (
./build/run: run, rebuild, prepare, package). - Slim tarball
matchora-*-linux-amd64.tar.gz(binary, config, public, LICENSE). - Bundled tarball
matchora-*-linux-amd64-llama.tar.gz(same plus llama.cpp, GGUFs, and fetched third-party licenses). - Podman-only unit, smoke (stub metadata + stub chat; waits for
/healthafter secrets POST), and optional live (MATCHORA_LIVE=1) harness. - BSD 3-Clause license.