v0.27.0
Breaking Changes
Default paths moved to platform directories
Config, cache, and output no longer default to the current working directory. They now use standard platform directories. fdb675b
| Setting | Old Default | New Default (Linux) | Docker |
|---|---|---|---|
config |
./config.yml |
$XDG_CONFIG_HOME/caesura/config.yml |
/config.yml |
cache |
./cache |
$XDG_CACHE_HOME/caesura/ |
/cache |
output |
./output |
$XDG_DATA_HOME/caesura/output/ |
/output |
What to do
Move your config file and directories to the new locations, or pass the old paths explicitly via --config, --cache, --output. If old paths are detected at the current working directory, a migration hint will be shown.
Refer to the setup guide for the full default paths table.
content directories are now required
content no longer defaults to ["./content"]. It must be set explicitly via CLI or config file. 0dfb7cf
Docker installations still default to ["/content"].
What to do:
Docker users don't need to do anything. But if you are using a native install then, add to your config.yml:
content:
- /path/to/your/downloadsOr pass --content /path/to/your/downloads on the CLI.
Docker image now runs as non-root user
The Docker image now runs as a non-root user (uid 65532) instead of root.
The updated docker-compose.yml includes a user: "1000:1000" directive so mounted host directories remain accessible.
What to do
Determine your host UID:GID pair:
echo "$(id -u):$(id -g)"Then add it to docker-compose.yml or pass to docker via --user 1000:1000
services:
caesura:
...
# Run as host user so mounted volumes are accessible.
# Replace with your own UID:GID
user: "1000:1000"SoX_ng is now recommended
SoX_ng is now the recommended SoX binary. The original SoX repository is no longer maintained and has known issues. caesura will auto-detect which binary is available, preferring sox_ng over sox. ab70b7e aeaa6dd #185
What to do
Docker users don't need to do anything. But if you are using a native install then:
Install sox_ng and add the following to your config.yml:
sox_ng: true
sox_path: sox_ngSetting these explicitly avoids unnecessary version detection calls at startup.
Refer to the dependencies guide for install instructions.
New Features
New commands
version
Display caesura version plus versions of all external dependencies (FLAC, LAME, SoX). Useful for verifying your installation and debugging issues. bfdebfc #184
inspect
Native audio metadata inspection with ANSI color output. Prints a table of properties for each file followed by all tags and embedded images. c09c1fa #182
New options
--rename-tracks-- Standardize output filenames during transcoding.57f5c23#58--exclude-vorbis-comments-- Strip specified Vorbis comment tags from transcoded output. Defaults to strippingCOMMENT,ENCODER,RATING, andWORK.2e96540--sox-path-- Custom path to the sox binary.e9bbcd1#185--sox-ng-- Whether to usesox_ngbehavior. Auto-detected by default.e9bbcd1#185
New install methods
caesura can now be installed via Homebrew and Nix.
brew install rogueoneecho/tap/caesuranix profile install github:RogueOneEcho/nix#caesuraRefer to the install guide for all methods.
80f581e c0238bf
External dependencies
imdl, eyeD3, and ImageMagick have been replaced with native Rust implementations.
Only FLAC, LAME, and SoX are required.
Refer to the dependencies guide.
5c895db c09c1fa d405898 #140 #182 #180
Documentation
Documentation has been restructured into focused guides 07365ce
Refer to README.md as the starting point.
Docker
- Multi-arch images with native ARM64 builds
473cc3f#97 - FLAC 1.5.0 and SoX_ng 14.7.1 built from source
9752fb2b438785#161 - Smaller image:
imdl,eyeD3, andImageMagickno longer included - Runtime image hardened
297a3d7b438785 docker-compose.ymlrewritten with inline config, security hardening, and shared mount for hard-link support
Refer to the Docker guide.
Deterministic outputs
Transcoding is now deterministic. Provided the same builds of caesura, sox, flac, and lame are used the transcodes will be identical.
That has enabled us to overhaul the test suite to verify the exact files that each command produces.
caesura is now backed by an extensive suite of 300+ unit and integration tests.
Refer to the Testing guide.
Other improvements
- Error reporting now uses rich diagnostic chains. When a dependency is missing or a command fails, the full error chain is displayed including the program name and exact cause.
fd260aa#166 - Cross-tracker torrent fallback: existing torrents are duplicated with the new tracker suffix instead of re-transcoding
6bb2ba6#132 - Torrent files now only use the indexer suffix (e.g.,
.red.torrent) instead of a generic.torrent6bb2ba6#132 verifycommand checks for unnecessary subdirectories in FLAC sources68cbf9a#170- Letter-only vinyl numbering (e.g., A, B, as well as A1, B1) handled correctly
1a33796#179 - Source directories matched using libtorrent's path sanitization rules, fixing invisible character mismatches
7964c46#169 #163 - Invisible characters in API metadata (artist, album, media, remaster title) and source paths are detected and reported with human-readable names
40622c6 - Spectrogram comment updated to
caesurafbdcdde#171 - Deterministic SoX dithering via repeatable mode (
-R)c2d77cb - ANSI color styling in
inspectandconfigoutput7ffeb87889b954 - Extended version information in upload descriptions and torrent
created_byfieldc628127 - Zoom spectrograms use 50% mark for tracks shorter than 62 seconds
defa0e0
Thanks
Thanks to @vilohuhu, @finevan and @Flip7413 for their pull requests, and to everyone who submitted ideas, reported issues, and provided feedback in discussions. caesura doesn't contain any telemetry so user reports are essential feedback to encourage further improvements.
Full Changes
New Features
naming: log invisible characters found in metadata and source paths 40622c6
- Sanitize API metadata fields (artist, album, media) and warn when
invisible characters are stripped- Warn when libtorrent-unsafe characters are found in source paths
- Extract character constants into
SanitizerCharenum covering C0/C1
control and Unicode formatting characters- Replace static
Sanitizerwith rule-based builder (invisible(),
name(),libtorrent()) returningSanitizerResultwith found chars
inspect: compact multi-line headers, kHz formatting, and column reorder e2c33d8
- Add
multi_line_headers()andnewline_after_headers()toTableBuilder- Split wide column headers across rows: "Bit Rate kbps", "Sample Rate kHz",
"Bit Depth"- Format sample rate as kHz (44100 -> "44.1", 48000 -> "48")
- Reorder tag columns: item key first, native key last
- Reorder picture columns: type name first, native key last
- Add
style_info()(cyan) for native keys and headers- Rename
bitratetobit_rateonTrackInfo- Add
mock_flac()andmock_mp3()test constructors onTrackInfo- Add unit test for mixed-format properties table and 48 kHz integration test
Warning
Breaking Change: sox: replace `--no-sox-ng` boolean with `--sox-variant` enum and auto-detection aeaa6dd
- Add
SoxVariantenum (Sox/SoxNg) with serde and clap aliases - Auto-detect variant via
LazyLockby probing forsox_ng --version - Add
SoxVariant::binary()method, used bySoxFactoryand tests - Pin
SoxOptionsin config test for deterministic snapshots - Update
CONFIG.mdto match generated docs
add `--exclude-vorbis-comments` option to strip tags from transcoded output 2e96540
Add configurable Vorbis comment exclusion during transcode, defaulting
to COMMENT, ENCODER, RATING, and WORK. Tags are stripped via two paths:
in-memory ID3v2 removal for MP3 output, and on-disk Vorbis comment
removal for FLAC resamples.
inspect: add ANSI color styling to inspect output 7ffeb87
- Style keys yellow, paths green, headers and units dimmed, dividers black
- Use
DisableStyleGuard(drop-based) to produce unstyled output for upload BBCode- Reorder imports in
upload_command.rs
version: improve error formatting for missing dependencies 580e205
Use yellow
⚠instead of red?for missing dependencies and
consolidate error output into the table. Also makeTableBuilder
ANSI-aware by measuring visible terminal columns viaunicode-width
instead of byte length.
extend version information for version command, upload description, and torrent created by c628127
Use
git describeoutput captured at build time to provide richer version
strings that distinguish release builds, unmodified source builds, and
modified/development builds.
- Replace
builtcrate with a minimal build script that capturesgit describe- Add
app_infomodule withBuildStatus,app_version_or_describe(), andapp_user_agent()- Add
homepageto workspace metadata forCARGO_PKG_HOMEPAGE- Add
.git/packed-refsas a build script rerun trigger
config: add doc comments and ANSI colors to `config` command output 889b954
Render
#comment lines fromDocumentedtrait metadata above each YAML key,
with colored output (dimmed green comments, yellow keys) that auto-disables
when piping to a file. Replaceserde_jsonwithserde_yamlfor value
serialization and add missingConfigOptions/CopyOptionsto the output.
Warning
Breaking Change: replace SoX with sox-ng ab70b7e
Use sox-ng as the default sox binary, with --no-sox-ng flag to fall
back to the original sox binary when needed. A SoxFactory handles
binary selection and base flags via dependency injection.
use simple default paths in Docker containers 16459ec
Default to
/config.yml,/cache,/output, and/contentwhen
running in Docker so users only need volume mounts without explicit
CLI flags.
Warning
Breaking Change: make `content` directories required 0dfb7cf
content no longer defaults to ["./content"] — users must explicitly
set it via CLI or config. Also removes .gitignore files from the
legacy cache/, content/, and output/ directories.
Warning
Breaking Change: use platform user directories for default config, cache, and output paths fdb675b
Replace relative defaults (config.yml, ./cache, ./output) with
XDG/platform directories via the dirs crate. Legacy path migration
hints guide users who have existing files at the old locations.
add `version` command showing caesura and dependency versions bfdebfc
Replace clap's built-in
--versionflag with a customVersionCommand
that displays version info for caesura, flac, lame, and sox in a table.
Accessible viacaesura version,caesura --version, orcaesura -V.
Warning
Breaking Change: replace `imdl` CLI with native `lava_torrent` for torrent operations 5c895db
Remove the external imdl binary dependency and implement torrent
creation, reading, and verification natively using lava_torrent and
sha1.
inspect: add native audio metadata inspection command c09c1fa
Improve upload description: show properties inline, tags in collapsible.
Addinspectcommand usingloftycrate for native FLAC/MP3 metadata
reading, replacing externaleyed3andmetaflacCLI dependencies.
- Add
InspectCommandwithTrackInfo,PictureInfo, and formatting- Add
TableBuilderutility for column-aligned CLI output- Update
uploadcommand to use nativeget_details_split()- Remove
eyed3module entirely; makemetaflactest-only- Remove
eye-d3from CI, Docker, and build docs- Add
AlbumConfig::multi_disc_flat()for flat source directory tests
transcode: replace ImageMagick with native Rust image resizing d405898
Replace the
convertexternal dependency withfast_image_resizeand
imagecrates for in-process image resizing. AddFileOptionsdefault
constants and tests for RGBA, RGB16, and small-image code paths.
match source directories sanitized by libtorrent 7964c46
simplify torrent file handling with cross-tracker support 6bb2ba6
- Remove generic .torrent files; create only tracker-specific ones
(e.g., .red.torrent, .ops.torrent)- Add cross-tracker fallback to duplicate existing torrents when
switching between RED/OPS/PTH without re-transcoding- Add
SharedOptions::indexer_lowercase()for consistent case handling- Normalize all torrent filenames to lowercase indexer suffix
- Add 8 tests for torrent file creation and cross-tracker duplication
add `--rename-tracks` option for standardized output filenames 57f5c23
Adds a new CLI option that renames transcoded files from source filenames
to a standardized format:{track:0>N} {title}.{ext}. Multi-disc releases
are organized intoCD1/,CD2/subfolders.
Key changes:
- Add
--rename-tracksflag toFileOptionswith YAML config support- Add
DiscContextstruct to compute track padding and detect multi-disc- Add
Collector::get_flacs_with_context()for callers needing disc info- Cache ID3 tags on
FlacFilevia thread-safeOnceCell- Update verify command to check for missing disc_number on multi-disc
- Add snapshot tests for single-disc, multi-disc, double-digit, and vinyl
add SoX repeatable mode (`-R`) for deterministic dithering c2d77cb
Add
sox_random_ditheroption toTargetOptions(default: false).
When false, SoX runs with-Rflag which seeds the dither PRNG with
a fixed value, producing deterministic output across runs.
- Add
repeatablefield toDecodeandResamplestructs- Update
TranscodeJobFactoryto pass option through- Enable 24-bit transcode tests (previously ignored due to non-determinism)
- Add snapshots for
transcode_command_flac24_441/48/96
verify: Implement flac directory validation against unnecessary subdirs #170 68cbf9a
Bug Fixes
options: auto-detect `sox_ng` and `sox_path` in Docker 098ae50
Add
is_docker()checks to default bothsox_pathandsox_ng
when running in a Docker container.
docker: add CA certificates and update SoX_ng to 14.7.1 b438785
- Install
ca-certificates-bundlein runtime image so reqwest can
make HTTPS connections to tracker APIs- Update SoX_ng from 14.7.0.7 to 14.7.1 (old release removed from
Codeberg)
handle `Torrent.remastered` becoming optional in `gazelle_api` 0.14 2adde66
OPS API no longer returns
remastered,recordLabel, orcatalogueNumber.
Updated dependency versions and adapted the verify check to treatNone
as not-unconfirmed rather than flagging it.
torrent: cap
lava_torrentpiece-hashing thread pool to avoid exhausting OS process limit 4f98790
options: fix regression where `queue_add_path` in config.yml was ignored 0e52811
Migrate
QueueAddArgsto theOptionsderive macro for config file merging and validation.
Additional changes:
- Add
MatchPathvariant toQueueActionfor nonexistent path errors- Remove manual
validate()call fromexecute_cli()(now handled by
the options pipeline before command execution)- Add
QueueAddArgstoConfigCommandandDocsCommandoutput- Extend the docs macro to handle positional args (
#[arg(value_name)]
withoutlong) and respect explicit#[arg(long = "name")]values- Update nonexistent path test to assert error instead of
Ok(false)
options: replace clap `SetTrue` with `num_args` so bool config file values are applied 343f76a
Clap's
SetTrueaction injectsdefault_value("false")forOption<bool>
fields, making themSome(false)when absent from the CLI. This prevented
the config file merge (is_none()check) from ever applying bool values
likerename_tracks: true.
Switch tonum_args = 0..=1withdefault_missing_value = "true"which
keeps absent flags asNone, allowing the merge to work correctly.
Also updates stale macro snapshots forSharedOptionsandCacheOptions.
extract `ConfigOptions` from `SharedOptions` so `config` command loads the config file 544e7ac
The
configcommand was showing only defaults becauseSharedOptionsPartial::from_args
returnedNonefor it, preventing the config file from being read. Moving theconfig
path field to its ownConfigOptionstype letsOptionsProviderdiscover the config
file path for all commands (includingconfig) without triggeringSharedOptions
validation.
skip config file read for commands without shared options b9a79e3
read_config_filenow returnsNoneearly when the command does not
use shared options, and silently returnsNoneon read failure since
validation reports missing config errors.
upload: render full diagnostic chain for track details warning 3c57b83
docker: update `Dockerfile` for `crates/macros` workspace member a39a28a
Replace
markdown_helpwithmacroscrate and add proper proc-macro
stub that exports theOptionsderive. Clear caesura fingerprints after
dependency caching to ensure rebuild with real source.
spectrogram: use 50% mark for zoom spectrogram on short tracks defa0e0
Previously, zoom spectrograms always started at 1:00, causing truncated
output for tracks shorter than 62 seconds. Now tracks shorter than the
typical start position use the 50% mark instead, centering the 2-second
capture window.
Addduration_secsfield toSpectrogramJobandcalculate_zoom_start()
function with unit tests. AddTrackConfig.duration_secsfield and
AlbumConfig::track_30s()/track_1s()test fixtures. Refactor
spectrogram_command_helperto acceptAlbumConfigfor flexibility.
revise cli host to get services as immutable f66f1c4
Mutability was removed a while ago. Apparently, while testing is now incredibly robust, there's nothing that calls the CLI entry itself.
Build
docker: harden runtime image and `docker-compose.yml` 297a3d7
Dockerfile: remove apk, docs, and man pages from runtime image; add non-root user (65532) following the DHI convention. docker-compose.yml: use published image, Docker configs, read-only Caddy root, `no-new-privileges`, and drop all capabilities.
docker: build FLAC v1.5.0 from source and update imdl to v0.1.15 9752fb2
FLAC v1.5.0 adds multithreaded encoding support (-j/--threads flag),
though encoding defaults to single-threaded and decoding remains
single-threaded only. Caesura's semaphore-based concurrency model
continues to work correctly without changes.
Alpine packages lag behind at 1.4.3, so we now build from source in
a multi-stage build. Also updates imdl from 0.1.14 to 0.1.15.
Dependencies
update dependencies fa8a5ad
update dependencies 2d211ec
Documentation
update features and comparison table 56c7f75
add
COMPARISON.mdcomparing related transcoding and upload tools 80c4585
rename `USE.md` to `COMMANDS.md` and `CONFIG.md` to `OPTIONS.md` fac5a85
Update titles, index descriptions, inline references, and next footers
across all docs. RegenerateOPTIONS.mdfrom updated render source.
add
DEPENDENCIES.mdand GitHub Releases install method af81e44
restructure and rewrite README.md into focused guides 07365ce
- Split monolithic README into standalone guides under docs/
- Add CONTRIBUTING.md
- GIF screencasts with VHS tape sources
- Use Git LFS for GIF assets
options: improve doc comments for `rename_tracks` and `queue_add_path` 7417a3c
Clarify behavior of the
rename_tracksoption with examples and adjust documentation forqueue_add_pathto include specific paths for torrent clients (qBittorrent and Deluge).
add missing doc comments and fix stale type references b32cb1b
Add doc comments to undocumented
pubandpub(crate)methods,
structs, enums, traits, and fields across queue commands, transcode
jobs,Host,OptionsProvider,OptionRule,RegisterOptions,
andSource. Fix stale references toCommandRunner/Commandin
job subscriber docs (nowJobRunner/Job). Correct copy-paste
error inQueueSummaryCommandstruct doc.
add comprehensive documentation across codebase 4295159
- Fix incorrect docs:
Encode.outputfield,EyeD3Command::display,
TranscodeFormatStatus.format,UploadStatus.completed,EYED3constant,
ConfigCommand,BatchCommand, and SOX domain inSpectrogramJob- Add module-level docs to all modules and submodules
- Document all
pubandpub(crate)structs with their fields- Document enum variants for
Variant,Size,Status, andJob- Document
Optionstrait and helper functions- Update CLI facades (
ImdlCommand,EyeD3Command,MetaflacCommand)
to clarify subprocess invocation- Update factory docs to reference created types explicitly
Code Style
fix clippy warnings 1a4b427
Refactor
get_yearto use pattern matching instead ofis_none()with
expect(). Addclippy::doc_markdownallow for auto-generatedbuilt.rs.
Refactor
logging: add
rustls_platform_verifierexclude filter and alphabetize 2a02020
naming: improve clarity of invisible character warnings 616042a
inspect: replace global styling state with `InspectFactory` instance 04814f6
- Eliminate
AtomicBool+DisableStyleGuardin favor ofInspectFactorywith astyle: boolfield- Merge
format.rsintoinspect_factory.rs- Consolidate
format_testsintoinspect_tests
options: replace `SoxVariant` enum with `sox_path` and `sox_ng` options 0def14e
Split the single
sox_variantenum into two independent options:
sox_path: optional custom path to the sox binarysox_ng: boolean controlling--single-threadedbehavior, auto-detected fromsox --versionoutput
options: extract options framework into `caesura_options` crate a48af71
- Move traits,
OptionsProvider, registration, rules, and doc metadata
fromcrates/coreinto newcrates/optionsworkspace crate- Replace concrete
ArgumentsProviderwith genericArgsProvider<P, C>
erased behindArgsProviderContracttrait object- Move
resolve()from inherent methods intoCommandEnumContracttrait- Update macro codegen to emit
::caesura_options::paths
docs: merge
OPTIONS.mdinto a single sorted table with inline commands column 34d6c4e
macros: auto-register options via `inventory` crate faba933
The
Optionsderive macro now emits aninventory::submit!call that
registers both doc metadata and DI registration for each options type.
This eliminates three manually-maintained lists that previously required
updating in lockstep when adding new option types.
macros: add `CommandEnum` derive macro replacing manual `FromArgs` impls 78ef5a2
Replace hand-written
CommandArguments/QueueCommandArgumentsenums and all
manualFromArgsimplementations with aCommandEnumderive macro. The
Commandenum becomes the single source of truth for CLI structure via
declarative#[options(...)]attributes.
Key changes:
- New
CommandEnumderive macro generates clapSubcommandenums,Cli
parser struct,CommandEnumContracttrait impls, and argument resolution- Eliminate
FromArgstrait;OptionsProviderusesclap::FromArgMatches
withCommand::uses_options()to determine applicability- New
ArgumentsProviderreplacesArgumentsParser, stores resolved
Command+ArgMatchesin DI- Convert
SourceArg,QueueRemoveArgs,InspectArgto#[derive(Options)]
with non-optional required fields- Centralize validation in
OptionsProviderinstead of per-command checks- Docs command now renders which commands use each options type
- Reorganize macro crate into
command/andoptions/modules- Log errors when CLI argument extraction unexpectedly fails
- Add validation tests for
QueueRemoveArgsandInspectArg
docs: render `OPTIONS.md` tables via `TableBuilder` markdown mode c20da99
- Add markdown output mode to
TableBuilderwith GFM pipe-delimited
tables,<br>joined multi-line headers, and pipe/newline escaping- Right-aligned columns use
---:separator syntax- Fix last column ignoring right-alignment configuration
adapt to `rogue_logging` `InitLog` trait separating creation from initialization 39b1275
- Consolidate duplicated logger setup into shared
utils/logging.rsmodule- Explicitly call
InitLog::init()after creating the logger inhost_builder.rs- Replace
let _ = init_logger()withinit_logger()across all test files
Warning
Breaking Change: replace generic `Error` with domain-specific `miette` error types fd260aa
Use Failure<T> from rogue_logging for rich error reporting. Each
module now has its own action type defining domain-specific failure
modes with structured context.
New action types:
BatchAction,ConfigAction,QueueAction,SpectrogramActionTranscodeAction,UploadAction,VerifyActionEyed3Action,ImdlAction,MetaflacActionFsAction,TagsAction,JobAction,SourceActionProcessAction,SampleAction
New error types:BatchError,TranscodeError,UploadError,TagsError
ReplaceProcessErrorenum withFailure<ProcessAction>, making
ProcessOutputimplementErroras the source for non-zero exits.
ReplaceSampleErrorenum withFailure<SampleAction>, propagating
errors from sample generation instead of panicking.
Remove redundant path context from call sites where internal functions
already attach it.
AddDiagnosticExttrait withrender()method for fancy miette output
in warn/error log messages.
UpdateQueue::getto async to matchflat_db0.4.0 API.
clean up `libtorrent_safe_path` and add `SourceProvider` tests ce4337d
- Add doc comment with libtorrent source link
- Remove redundant
exists()check (already covered byis_dir())- Remove unnecessary
.clone()injoin()call- Replace
dedup()with explicit conditional for clarity- Add unit tests for
libtorrent_safe_path- Add integration tests for
SourceProvider::get()covering exact match,
bidi character fallback, and missing directory error- Extract
HostBuilder::with_mock_clientfromwith_mock_apifor reuse
use `LazyLock` statics instead of recompiling on each call f38323f
Replace all 7 inline
Regex::newcalls with module-levelLazyLock<Regex>
statics so patterns are compiled once. Deduplicate the shared group URL
pattern inurl_helpers.rs. Add doc comments to all modified items.
Warning
Breaking Change: clean up options derive macro with trait contracts 78c423f
Major refactoring of the options system to make the derive macro's
requirements and outputs explicit through trait contracts:
OptionsContract: you implement on resolved type withvalidate()
andtype Partial: FromArgs- defines what the macro needsOptionsPartialContract: macro generates on partial type with
resolve(),resolve_without_validation(),merge()- defines
what the macro producesFromArgs: you implement on partial type, no default impl so
compiler enforces it
This replaces the previous scattered approach where requirements
were implicit and easy to miss.
Additional improvements:- "Parse, don't validate":
resolve()returnsResult<T, Vec<OptionRule>> #[options(required)]attribute for mandatory fieldsrequiredchecks run afterdefault_fn(so both can be used together)api_key,announce_url,indexer,indexer_urlnowStringwithrequiredOptionsProvidermoved toHostBuilder, validation inbuild()- Invalid options not registered with DI container
- Docs: serde JSON for defaults,
~for null,<br>for breaks - Docs: "YAML Key" instead of "Config Key"
- Test ensuring CONFIG.md matches docs command output
- Snapshot tests for all real options structs
Conflicts:
crates/core/src/utils/testing/samples/transcode_generator.rs
consolidate process execution into `utils/process` module 03ee750
- Add
ProcessErrorenum withSpawn,Wait,Failedvariants- Add
ProcessExttrait with.run()method forCommand- Add
require_success()for spawn+wait patterns- Remove
CommandError,OutputHandlerfromutils/errors- Remove duplicate
CommandError/CommandExtfrom test utilities- Update all call sites to use new API
- Refactor
ImdlCommand::verifyto match onProcessError::Failed- Remove dead code
verify_from_buffer- Fix typo: "spawn decode" -> "spawn encode" in transcode job
add `prelude.rs` and `testing_prelude.rs` modules f3ef2e4
Consolidate common imports into prelude modules to reduce boilerplate:
prelude.rsre-exports internal modules, external crates (di, log,
colored, rogue_logging), and std types (collections, fmt, path)testing_prelude.rsextends the prelude with hosting and insta
Update ~116 files to use the new prelude imports.
options: add `Options` derive macro to reduce boilerplate a1e4d7a
Introduce
caesura_macroscrate with#[derive(Options)]proc-macro that
generates partial structs, merge/resolve methods, and documentation metadata.
Key changes:
- All option structs now use the macro instead of manual trait implementations
- Add
OptionsPartialtrait for generated partial types- Add
Documentedtrait andDocsCommandfor auto-generatingCONFIG.md- Refactor
OptionsProviderto validate only options applicable to current command- Add
Commandenum for command-specific validation- Add
SerializetoOptionRulefor snapshot testing- Replace
markdown_helpcrate with newdocscommand
Warning
Breaking Change: reorganize into Cargo workspace with `crates/core` and `crates/markdown_help` d0f934a
Move from single-package structure to workspace:
crates/core/- main library and binary (package name:caesura)crates/markdown_help/- docs generation helper
Key changes:- Root
Cargo.tomlnow workspace manifest with shared deps/lints default-membersset to core for simpler builds- Test samples now generate at workspace root
./samples/ - Updated
Dockerfile,TESTING.md,.claude/CLAUDE.mdfor new paths
BREAKING: Directory structure changed from `src/` to `crates/core/src/`use internal mutability for `GazelleClient` and `Queue` 8010d51
Update gazelle_api to v0.10.0 which uses internal mutability, allowing
removal of RefMut wrappers from DI registrations. Queue methods now
take &self instead of &mut self since flat_db::Table already handles
mutability internally.
use `#[deprecated]` attributes and add `IdProviderError::NoId` ddc6f48
Replace
/// DEPRECATEDdoc comments with proper#[deprecated]attributes
onSourceIssue::IdError,ApiResponse, andProvidervariants. Add new
IdProviderError::NoIdvariant for missing IDs and use it in batch command.
Tests
unify snapshot macros with `CAESURA_DETERMINISTIC_TESTS` env var 9267ae1
- Replace
assert_transcode_snapshot!withnormalize_snapshots!for structural verification- Replace
assert_inspect_snapshot!non-empty check with line-count assertion- Add
normalize_snapshots!for spectrogram tests (previously no cross-platform guard)- Replace
is_nix(),is_macos(),is_aarch64()withis_deterministic()- Set
CAESURA_DETERMINISTIC_TESTS=1in CI for x86_64 Linux only- Update spectrogram snapshots for SoX_ng 14.7.1
- Simplify
TESTING.mdtable
replace file-based locking with `OnceCell` caching in sample providers c54af10
The file lock behaviour depended on a timeout that was flaky in nix environments with many cores but proot bottleneck.
Replace with in-processArc<OnceCell>coordination inAlbumProviderand
TranscodeProvider. Narrow generator visibility topub(super), add
get_advanced()APIs for custom album configs, and move sample-related tests
intosamples/tests/.
replace platform-specific test skips with runtime snapshot guards 00f3e40
- Extract
is_docker,is_nix,is_macos,is_aarch64intoutils/platform.rs- Add shared
assert_transcode_snapshot!andassert_inspect_snapshot!macros- Spectrogram tests: add Nix to existing docker/macOS guard
- Transcode and inspect tests: replace
#[ignore]on aarch64 with runtime guard macros- Upload and transcode_provider tests: remove aarch64 ignores (no snapshot assertions)
- Set
CAESURA_NIX=1env var in nix derivation, removingcheckFlagsskips- Tests now run on all platforms but use simpler assertions where output differs
inspect: fix divider including style in snapshot c94c8a1
set correct API encoding for 24-bit mock sources 66a87b0
The mock API client always reported
encoding: "Lossless"regardless
of bit depth, causingExistingFormat::from_torrentto returnFlac
for 24-bit sources. This preventedTargetFormatProviderfrom including
the FLAC resample target, so the resample path was never exercised.
AddSampleFormat::encoding()to return the correct Gazelle API
encoding string based on bit depth and use it inbuild_mock_client.
The 24-bit test snapshots now include FLAC resample output.
relax `created_by` assertions to accept any version format cc6e83e
When no
v*tag is reachable (e.g. CI shallow clone or feature branch),
git describe --alwaysreturns a bare commit hash without avprefix.
The torrentcreated_bytests assumed av-prefixed version string,
causing failures on CI.
remove
build_status_is_not_releasethat fails on CI release builds 3189941
fix CI failures for version and torrent tests dba54fd
- Remove snapshot from create_produces_valid_torrent test since the
torrent file hash changes with each version bump (created_by field)- Fix sox version detection on macOS by checking stderr when stdout
is empty (some tools output version info to stderr)- Add debug output to sox test to show first_line on failure
upload: add `get_details` snapshot tests for FLAC, 320, and V0 dfac191
Extract
get_detailsfromUploadCommandto a free function so it can
be tested independently without DI setup. Add insta snapshot tests that
verify metaflac and eyeD3 output for each target format.
transcode: add
AdditionalJobFactory,AdditionalJob, andResizetests 087a0de
add RAII `LockGuard` to prevent stale `.lock` files in sample generation 6ff1980
Extract duplicated file-based locking from
AlbumGeneratorandTranscodeGenerator
intolock_guard.rswith aLockGuardthat removes the.lockfile on drop, ensuring
cleanup even on failure or panic.
add RAII auto-cleanup to `TempDirectory` and `TestDirectory` 82dd381
Test directories in
/tmp/caesura/were never cleaned up, accumulating
over time. Implement RAII pattern where directories are automatically
deleted when the struct is dropped.
- Add
TempDirectorywith automatic cleanup on drop andkeep()for debugging- Refactor
TestDirectoryto wrapTempDirectoryfor inherited cleanup- Use atomic counter + ISO timestamps for unique directory paths
- Update
AlbumConfig::single_torrent_dir()to returnTempDirectory- Remove unused
cache_dirandCacheOptionsfromTranscodeGenerator- Add comprehensive tests for both types
fix sample torrent corruption from ephemeral generation 362b3bb
AlbumGenerator: :generate_in_dir() was using config.torrent_path() which always pointed to SAMPLE_SOURCES_DIR, even when generating in a temp directory. This caused ephemeral generation to overwrite the cached sample torrent with one containing a timestamp-based name. Fix by: - Remove misleading source_dir() and torrent_path() from AlbumConfig - Compute torrent path from actual source_dir using append_extension() - Update callers to use SAMPLE_SOURCES_DIR.join() explicitly Also add samples/rm-samples helper script for clearing sample cache.
hide progress bar output during tests 1e80cfc
Use
ProgressDrawTarget::hidden()in test builds to prevent progress
bar output from cluttering test results.
fix queue add tests to use isolated torrent directories 03a7795
Tests previously read from
SAMPLE_SOURCES_DIRdirectly. Use
single_torrent_dir()to copy torrents to isolated temp directories.
Addqueue_add_test_helperto reduce setup duplication and replace
manual assertions with yaml snapshots.
add integration tests for batch, config, queue, and upload commands af7fe66
Add comprehensive test coverage for command modules:
BatchCommand: queue processing, limits, indexer filtering, upload statusConfigCommand: options serializationQueueAddCommand,QueueListCommand,QueueRemoveCommand: CRUD operationsUploadCommand: success paths, dry run, copy options, API failure handlingQueue: set/get/remove operations, filtering by status and indexerJobRunner: concurrency configuration, empty executionIdProvider: numeric ID and URL parsing, error variants
Infrastructure updates:- Add
with_upload_torrent()mock response toAlbumConfig::api()- Add
single_torrent_dir()helper for isolated torrent file tests- Add default
BatchOptionstowith_test_options()for consistent test setup
sort `DirectoryReader` paths for deterministic file selection 4e98a68
DirectoryReader::read()returns files in filesystem order which varies
across platforms. Tests using.first()got different tracks on macOS
vs Linux, causing snapshot mismatches in CI.
Sort paths before selecting to ensure consistent cross-platform behavior.
Also add snapshot assertion toeyed3_displaytest (ignored on ARM).
Split sample logic into `AlbumGenerator`, `AlbumProvider` and `TestDirectory` a0eb467
Restructure the test sample generation infrastructure for better clarity
and separation of concerns:
- Rename
SampleDataBuildertoAlbumGeneratorwithAlbumConfig- Split
SampleProviderintoAlbumProviderandTranscodeProvider- Add
TranscodeGeneratorandTranscodeConfigfor transcode samples- Add
TestDirectoryutility for test directory management- Update all dependent tests and snapshots
enable deterministic tests via mock API and sample generation a1a8744
Replace flaky live API tests with deterministic mocks:
- Abstract
GazelleClienttoGazelleClientTraitfor mock injection- Add
HostBuilder::with_mock_api()andwith_mock_samples()for testing- Delete ignored live API tests that provided little value
Add programmatic sample generation:- Add
FlacGenerator,ImageGenerator,SampleDataBuilderfor creating
reproducible test files using SOX and metaflac- Add
SampleFormatenum for type-safe audio format specifications- Add snapshot testing utilities (
AudioSnapshot,FileSnapshot, etc.)
Housekeeping:- Remove unused
TestOptionsFactory- Rename
TempDirectory::with_test_name()tofor_test()- Add
TESTING.mddocumenting test setup and required tool versions- Update CI to run determinism tests and remove
download-samplescript- Add
insta,image,sha2dev-dependencies- Update
gazelle_apito 0.11.0 for mock support
CI
publish all workspace crates to crates.io b577da7
- Use
--workspaceforset-versionandcargo publish- Include
crates/macros/Cargo.tomlandcrates/options/Cargo.tomlincargo-manifestsartifact
add
--lockedto all cargo commands in CI and Docker 435d082
fix unnecessary recompilation of caesura on every cargo invocation 2598153
Two issues caused caesura to recompile every time cargo ran:
build.rsused relativererun-if-changedpaths (.git/HEAD),
which resolved tocrates/core/.git/HEAD— a path that never
exists. Cargo treated the build script as permanently stale.- CI used
cargo auditable buildthen plaincargo test. The
cargo-auditablewrapper produces different fingerprints, so
cargo recompiled for every test step.
Fixed by using absolute paths inbuild.rsand switching CI test
steps tocargo auditable test.
run `caesura_macros` snapshot tests in CI and update stale snapshots 4a60b11
- Add macro test step to
on-push.ymlso options struct changes are caught- Update stale
expand_file_optionsandexpand_target_optionssnapshots- Document macro expansion snapshot workflow in
TESTING.md
restrict cache save and delete to main branch only 6084613
Feature branch runs were deleting main's caches and replacing them with
branch-scoped caches that main cannot access, causing cache misses.
prevent buildx cache bloat by deleting stale entries before save 395dd6c
prevent cargo cache bloat by deleting stale entries before save 0a9954a
skip tests on macOS Intel runner e63aa89
The macOS Intel runner is ~2x slower than other runners. Since macOS ARM
already runs the full test suite, Intel only needs to build the binary.
add `cargo-auditable` and `cargo-audit` to `cargo-build` bcf8ff2
Use
cargo-auditableto embed Rust dependency metadata in binaries,
then scan withcargo audit binonx86_64-unknown-linux-gnufor vulnerabilities.
add Docker security scanning and SBOM attestation 9177169
Add
docker-scanjob to CI using Syft, Grype, and cosign:
- Syft generates CycloneDX SBOM (Alpine packages + Rust crates)
- Grype scans for vulnerabilities, fails on critical
- cosign attests merged SBOM to per-arch images via keyless signing
- Manual SBOM fragment in
.github/sbom/source-deps.cdx.jsoncovers source-built FLAC
Usecargo-auditablein Dockerfile to embed Rust dependency metadata
in the binary, making crates visible to SBOM scanners in the final image.
add Nix package publishing support c0238bf
add Homebrew publishing support 80f581e
- Package release binaries as tar.xz archives instead of raw files
- Trigger
homebrew-tapworkflow after release upload
update cargo cache key to save latest version each run 46107d7
build test artifacts before caching to speed up
cargo testa5a6297
remove macOS brew caching cfd5ddd
add multi-arch Docker images with native ARM64 builds 473cc3f
- Update Dockerfile to download arch-specific imdl binary using TARGETARCH
- Split docker-build into matrix job for ubuntu-24.04 and ubuntu-24.04-arm
- Create multi-arch manifest combining both architectures in docker-release
add native ARM64 Linux builds with
ubuntu-24.04-armrunner ca41eb1
update macOS runners to macos-15 d5843d6
Replace deprecated
macos-13withmacos-15-intelfor x86_64 builds
and updatemacos-14tomacos-15for aarch64 builds.
Also remove/.githubfrom.gitignore.
Chores
use cargo-chef in `Dockerfile`, fix CI build, remove `markdown_help` crate c929628
- Refactor
Dockerfileto use cargo-chef for better dependency caching- Add
--binsflag to CI cargo build command- Delete unused
crates/markdown_helpworkspace member