Commit Graph
28 Commits
Author SHA1 Message Date
Esa Kataja 8b38986690 chore: bring MANUAL.md in line with current encoder behavior
§6 step 2: drop the codec-name allowlist, describe the bounded idet run
and the Multi-frame summary parse.

§6 step 6/7: per-stream audio.<n>.wav / audio.<n>.opus now.

§6 step 8/9: zscale is conditional and width rounds to mod-2; -vf is
omitted entirely when no filter applies. Audio language tags are indexed
by output position. TITLE/COLLECTION values are unquoted.

§6 step 11: series filename no longer requires an IMDb mapping.

§7: added a token example and notes about what the token does and does
not influence in the output filename.

§8: noted the known log-rotation limitation (filename frozen at start;
restart to rotate; structured.json does not rotate).
2026-05-16 20:20:05 +03:00
Esa Kataja 244bdce586 add: WebDL / TVRip media types and filename-token override
Source kind is now declared per-file via a `dvd` / `bluray` / `webdl` /
`tvrip` token in the basename (case-insensitive, word-bounded). Matches
the existing `tt…` / `tvm…` filename convention. When no token is
present, falls back to the pixel-count guess in DetectMediaType, which
still only chooses between DVD and Blu-ray.

The parsed media type drives both ORIGINAL_MEDIA_TYPE in the muxed
metadata and the CRF/preset profile used for encoding. EncodingConfig
gains `webdl` and `tvrip` sub-blocks with conservative defaults
(WebDL 30/3, TVRip 32/2); user can override in config.yaml.

Manual updated with the new tokens, config fields, and pipeline
description.
2026-05-16 20:17:10 +03:00
Esa Kataja 022d131cd6 fix: preserve all audio tracks and align language metadata indices
Bug #5: extractAudio invoked ffmpeg without `-map`, so default stream
selection kept only one audio track from sources with multiple audio
streams (e.g. eng/fra/jpn Blu-rays). It now enumerates audio streams
from the streamLangs already fetched by the caller and runs one
`ffmpeg -map 0🅰️<n>` per stream, writing audio.<n>.wav.

Bug #11: the audio language metadata loop in encodeVideo computed the
output index by counting source-side audio streams with a lower Index,
which drifted when some source streams lacked a language tag. It now
walks opusFiles in output order and looks up the language at the
matching source-audio position via a sorted helper.

These ship together because #11 was masked by #5: when only one audio
track survived extraction, the broken index calculation never produced
a visible misalignment. Fixing #5 alone would have caused multi-track
outputs with shuffled language tags; both fixes are required to land
correct multi-track output.
2026-05-16 20:07:59 +03:00
Esa Kataja 71f7ef7bca fix: skip no-op zscale and round SAR width to nearest even
Bug #2: calculateZscaleWidth previously emitted a zscale filter even
when no rescale was needed (SAR 1:1, N/A, empty, or computed width
equal to the source). encodeVideo then unconditionally appended it to
-vf, forcing a pointless colorspace round-trip. Return an empty filter
string in those cases and build the -vf chain conditionally; omit -vf
entirely when no filters apply.

Bug #23: the SAR-to-width math used integer truncation, producing odd
or off-by-one widths (e.g. 853 instead of 854 for 32:27 at 1920), and
the guard accepted SAR 0:N which zeroed the output width. Reject
zero-numerator SARs and round to the nearest integer then mask to an
even width for AV1/H.264 mod-2 alignment.
2026-05-16 20:07:50 +03:00
Esa Kataja 5584bbca57 fix: detect video stream by codec_type instead of codec name allowlist
GetMediaInfo previously only recognized mpeg2video/h264/hevc and silently
returned 0x0 with no error for other codecs (VC-1, MPEG-4 ASP, AV1,
ProRes), causing DetectMediaType to misclassify as DVD and feeding bogus
dimensions to the zscale filter. Pick the first stream with
codec_type=video and return an explicit error if none is found.
2026-05-16 20:07:33 +03:00
Esa Kataja 0662ee3576 fix: drop literal quotes from TITLE and COLLECTION metadata
exec.Command does not invoke a shell, so the wrapping " characters
were inserted into the muxed tag value verbatim (e.g. TITLE read as
"Snatch" instead of Snatch). Use unquoted Sprintf format strings.
2026-05-16 20:07:24 +03:00
Esa Kataja b95369168c fix: harden OMDb/TVmaze fetchers and series fallback
TVmaze: drop trailing slash from base URL (was producing //shows/), send
season/number as plain ints (TVmaze rejects zero-padding), check HTTP
status before decoding so 404 bodies stop being decoded as episodes, and
fetch /shows/{id} separately for show name + IMDb mapping —
episodebynumber does not honor embed=show despite what the docs imply.

OMDb: check HTTP status, and include a body snippet when Response is
non-True with an empty Error field so rate-limit and HTML failure modes
are diagnosable.

Both: assert that the fields we actually depend on come back non-empty
after decode. Catches silent field rename/removal without making us
fragile to TVmaze adding new optional fields.

main.processFile: split the nometadata fallback by branch. Series uses
Collection (legitimate shows can have no IMDb mapping); movies keep the
IMDBID/Title check.
2026-05-16 19:57:01 +03:00
Esa Kataja 1dab2befbd add: user manual 2026-05-16 19:42:25 +03:00
Esa Kataja 30c7d9ae27 chore: ignore BUGS.md 2026-05-16 19:42:25 +03:00
Esa Kataja 13f70195c6 chore: rename AGENTS.md to CLAUDE.md 2026-05-16 19:41:31 +03:00
Esa Kataja 07f999a338 fix: correct interlace detection and reap idet child
The previous detector substring-matched "TFF"/"BFF" against idet's own
label text, so it returned true on every source, and `cmd.Start()` was
never paired with `Wait()`, leaving a zombie ffmpeg per file.

Run idet bounded with `-frames:v 400 -an -sn -f null -` so it completes,
use CombinedOutput so the child is reaped, and parse the "Multi frame
detection" summary line — interlaced only when TFF+BFF > Progressive.
2026-05-16 19:39:33 +03:00
Esa Kataja 4783d0e0d4 fix: restore metadata tags and sanitize output filenames 2026-04-04 19:39:17 +03:00
Esa Kataja 3f3eef5d1f add: keyint=10s svtav1 parameter 2026-04-04 19:34:55 +03:00
Esa Kataja 9d8cc17e69 fix: add -preset as separate FFmpeg argument 2026-04-04 19:27:00 +03:00
Esa Kataja 832e5568f5 fix: preserve stream language metadata using ffprobe and -map_metadata -1 2026-04-04 19:20:46 +03:00
Esa Kataja 31b5f03e09 fix: use ffprobe for SAR detection and calculate zscale width 2026-04-04 19:18:43 +03:00
Esa Kataja 4eeacfe551 fix: use consistent filenames for audio extraction 2026-04-04 19:00:30 +03:00
Esa Kataja bc58017414 fix: reorder FFmpeg args to fix input option error 2026-04-04 18:58:10 +03:00
Esa Kataja 8585b5fc07 add: add AGENTS.md for agent guidance 2026-04-04 18:09:06 +03:00
Esa Kataja 935912e376 fix: improve FFmpeg output parsing for resolution detection 2026-04-04 18:08:49 +03:00
Esa Kataja 53adafbc40 add: add interlaced detection and bwdif deinterlacing 2026-04-04 18:08:25 +03:00
Esa Kataja 9356d45074 add: add gitignore and config example 2026-04-04 18:07:50 +03:00
Esa Kataja b54cf700aa add: add main CLI entrypoint 2026-04-04 18:07:38 +03:00
Esa Kataja 0f11c62c4d add: add encoder, mover, watcher, and logger packages 2026-04-04 18:07:37 +03:00
Esa Kataja 2b18f5b526 add: add metadata package for omdb and tvmaze 2026-04-04 18:07:36 +03:00
Esa Kataja 901ccc37b2 add: add types and config package 2026-04-04 18:07:26 +03:00
Esa Kataja 25ea35fc26 add: add project specification 2026-04-04 18:05:26 +03:00
Esa Kataja 3273beb574 Initial commit 2026-04-04 18:02:50 +03:00