Skip to content

Releases: AlyShmahell/matchora

v0.0.4

Choose a tag to compare

@AlyShmahell AlyShmahell released this 31 Aug 12:41

Changelog

Matchora 0.0.4

  • No local LLM, embedder, or llama.cpp. 🎉
  • Scan grouping and candidate ranking are SequenceMatcher plus YAML.
  • The release tarball is binary, config/, public/, and LICENSE.

Scan grouping

Scan no longer calls an instruct model (prompt.md is gone). Each library child is classified from disk: seasons and extras fold into the walk-root title; named sibling folders become their own titles; leftover loose videos cluster with SequenceMatcher.

Word lists live under group: in config/default.yaml (video_ext, extras, release, kinds, seq_threshold). Years are taken only from a (YYYY) suffix or a trailing year token already on the name.

Ranking

Jobs record ranker: seq. Score is SequenceMatcher on normalized titles only:

  • Exact title match is 1.0.
  • Otherwise title ratio, with a second try against title + year (helps Girls (2012) vs Girls).
  • Matching year still adds 0.15.
  • Synopsis is not used. A one-word query whose word appeared in a synopsis no longer scores 1.0 (Wednesday vs Wednesday Club, Limitless vs Limitless with Chris Hemsworth, and similar).

True same-name collisions with no job year (Dark Matter 2015 vs 2024) stay manual.

Ingest

Unknown CSV headers are mapped with ingest.aliases, then SequenceMatcher against canonical fields when the ratio is at least group.seq_threshold. The instruct ingest.md path is gone.

Config

version: in config/default.yaml is the only version string (0.0.4). There is no root VERSION file and no compile-time version.

Grouping lists and match/http numbers come only from YAML. Missing or invalid required keys fail start. POST /v1/config that would clear a required list is 400 and is not written.

Removed: llama: block, ranker: embed, GGUF URLs, --prepare, and the llama admin form.

Packaging and docs

  • One archive: matchora-<version>-linux-amd64.tar.gz (no -llama tarball, no vendored llama.cpp).
  • Packaging fails if version is missing from the shipped YAML.
  • README is written for the release tarball: unpack, ./matchora, listen on http.addr.

Upgrade notes

  • Delete any leftover vendor/llama.cpp tree; it is unused.
  • Overlay data/config.yaml must not rely on llama: keys.
  • Rematch existing sessions if you want title-only ranking on old jobs.
  • Scan jobs still have empty type. Jikan (types: [anime]) does not run on untyped scan unless the TVMaze pass is empty. English folder titles that TVMaze stores under a Japanese name (e.g. Erased → Boku Dake ga Inai Machi) can sit below other exact-title hits; the admin UI shows the top 5 candidates.

v0.0.3

v0.0.3 Pre-release
Pre-release

Choose a tag to compare

@AlyShmahell AlyShmahell released this 29 Aug 13:17

Changelog

0.0.3 - 2026-08-29

Scan/ingest are isolated per request. Title-finding is back to the August 17 loop (one child, one instruct call, match kicked immediately), plus a title folder path.

Breaking

  • POST /v1/scan returns 202 {"session","files"}. POST /v1/ingest returns 202 {"session","jobs"} (jobs are no longer a bare array).
  • GET/DELETE /v1/jobs, GET /v1/scan/status, GET /v1/match/log, POST /v1/match, POST /v1/retry, select/catalog-on-job, and catalog reads require ?session=. Missing id is 400; unknown or expired is 404.
  • Jobs persist as {data_dir}/jobs-{session}.json, not jobs.json.
  • Scan no longer attaches video files to jobs or maps them onto catalog episodes (that 0.0.2 experiment is reverted).

Changed (title-finding realignment)

Restored the August 17 grouping engine (bb1cdb1 / 0692b2d), not the later Units / batched Group / LLM SxxExx experiments.

  • Immediate children only (scan.Children). One match.Group per child. Compact listing, ~5 filename samples, max_tokens: 256.
  • Append + Kick inside the child loop so matching overlaps later grouping.
  • Prompt is the August 17 rules again (folder as title, one object per series, no SxxExx, extras are not shows).
  • Added Path: on the listing and {title,year,path} so a mixed folder can use {Path}/{child} (movie/OVA next to seasons).
  • Parent: on folder listings; fallback title prefers Parent when Folder: is Season N.
  • Same title from two children is still two jobs (no end-of-scan merge).

Added

  • Server-minted session ids: <UTC 20060102T150405Z>-<16 hex>.
  • GET /v1/sessions — unexpired ids, newest first.
  • session.ttl_ms (default and max 24h). Expired job files are purged; catalog on disk is not.
  • GET /v1/catalog?session= lists only titles that session matched.
  • DELETE /v1/catalog and DELETE /v1/catalog/{provider}/{id} — no session; 409 if any live session still has that match.
  • Admin UI stores the last session and sends ?session= on job/scan/catalog calls.

Fixed

  • Image Fetch no longer shares the provider API pacer (tvmaze/poster no longer queues for minutes behind search).
  • Admin scan poller no longer dies on the previous session while POST /v1/scan is in flight; poller restarts after setSession.
  • POST /v1/scan does not walk the whole tree before 202; files is the sum of each child’s video count.
  • ListVideos / samples follow symlink library roots.

Removed

  • Units / FolderClass / batched GroupUnit / LLM file S/E labels.
  • Unused MergeJobs / empty Grouped.Files leftovers.

v0.0.2

v0.0.2 Pre-release
Pre-release

Choose a tag to compare

@AlyShmahell AlyShmahell released this 28 Aug 23:49

0.0.2

Scan jobs now carry video files and map them onto catalog episodes. Grouping stays one instruct call per library child (prompt.md); season/episode labels are only taken from explicit SxxExx in the filename.

Added

  • Job files (path, optional season / episode) filled during scan from videos under each child.
  • Catalog episodes get path / paths when file S/E matches the catalog numbers (01 = 1).
  • Same title+year in one scan merge into one job (Season 1 + Season 2 of one show), with path set to the show folder.
  • Season-folder listings include Parent: so a failed group falls back to the show name, not Season 1.
  • Vendored llama-server is started with PR_SET_PDEATHSIG SIGTERM so it exits if Matchora’s PID disappears. Clean Stop() still SIGTERMs the process group.

Changed

  • prompt.md may return files on each show. Paths must be copied from the listing; do not guess S/E from 01.mkv or a Season N folder.
  • browse_root: / treats absolute paths as inside the root.

Notes

  • Ingest is unchanged (ingest.md). Catalog join is still numeric, not a second LLM call.
  • share/config/default.yaml version is still 0.0.1; bump it if the shipped YAML should match VERSION.

v0.0.1

v0.0.1 Pre-release
Pre-release

Choose a tag to compare

@AlyShmahell AlyShmahell released this 28 Aug 13:02

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, and Retry-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-matched vs manual vs unmatched from min_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 detail GET (OMDb plot) and poster downloads.
  • skip_episode_posters on ingest, scan, rematch, retry, select, and catalog.

Ingest and scan

  • POST /v1/ingest for CSV (header) or JSON arrays: title, year, type, season, episode, imdb.
  • CSV alias map (ingest.aliases) and type rewrite (episode/seasontv).
  • Instruct fallback to map unknown CSV columns using config/ingest.md.
  • POST /v1/scan lists videos under browse_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}/catalog as [uniqueid-id] Title (Year)/ trees.
  • tvshow.nfo / movie.nfo, season folders, episode .nfo, and downloaded posters.
  • Distinct uniqueid slugs so TMDB movie vs TV ids cannot collide (tmdb-movie, tmdb-tv, OMDb imdb).
  • GET /v1/catalog and GET /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, optional config.yaml overlay, secrets (YAML map of API keys).
  • GET/POST /v1/secrets report which key slots are set and merge the secrets file (values never returned). Slots are provider API keys only.
  • GET/POST /v1/config read and deep-merge {data_dir}/config.yaml (same shape as default.yaml). Never includes secrets.
  • Listen address is llama.host / llama.port (defaults 127.0.0.1 / 8080); llama.base_url is derived as http://{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.cpp and spawn one llama-server on 127.0.0.1 at that port (embed + optional instruct). Distinct llm_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.Start applies the files. Setters write files only.
  • --prepare runs 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 via GET /v1/fs, ingest upload, scan, job cards).
  • Secrets panel for provider keys and llama panel for host/port; both wait for /health after 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/config
  • POST /v1/ingest, /v1/scan, /v1/match, /v1/retry, /v1/jobs/{id}/select, /v1/jobs/{id}/catalog
  • DELETE /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 /health after secrets POST), and optional live (MATCHORA_LIVE=1) harness.
  • BSD 3-Clause license.