-
Clean-source discovery:
Tacita.downloadPodcastgained optional
declaredEnclosureBytes/expectedDurationSecondsparams (the feed's
enclosure lengthanditunes:duration). When provided withcutAds, tacita first
probes for a serving that provably matches the feed-declared size/duration — the
pinned-tier serving, a staticfallback_urlleaked in the host's redirect chain
(Audioboom), or a bot-tier serving (Simplecast) — and downloads that copy directly,
skipping the diff. Fixes hosts that inject sticky fill on every tier, where an
immediate same-session reference is blind (see docs/ALGORITHM.md, 2026-07-04 research).
Note: callers implementingTacitathemselves must add the new params. -
Downloaderinternally supports 1-byte Range probes (final URL + Content-Length) and
per-call user-agent overrides to power the above; the pinned default UA is unchanged. -
Added an optional
log: (String) -> Unitparam toTacita.withClient— receives diagnostic
log lines (currently one per ad-cut pass, reporting its outcome); defaults to discarding them -
Added
Tacita.withLogger(log)— returns an instance with the default http-client factory but
a custom logger -
Downloadernow throws on non-2xx responses instead of saving the error body as the
episode file, and deletes the partial file when a download fails mid-stream -
Reference promotion (
overwrite+cutAdsover an existing output) now replaces an
existing stale reference file on all platforms (previously could throw on Windows) -
Removed dead internal
Downloader.fetchString(RSS fetching lives in consuming apps) -
New test coverage: direct
Downloadertests (status handling, progress with/without
Content-Length, parent dir creation, pinned user-agent),Id3ChapterShifterunit tests
(v2.3/v2.4 size encoding, bail-outs, overlapping cuts, real byte offsets), and
Mp3SegmentParserMPEG2/MPEG2.5 + truncated-frame edge cases