Changes
New Features
http: Remove MP3 files from cache after download cd9ecbe
download: Add `--replace` flag to re-download existing episodes 8c02679
- Add
replace: booltoDownloadRequestand--replaceCLI flag toDownloadOptions- Add
delete_existing_stepto remove old files before re-downloading- Deletion is best-effort (warns on failure) since the pipeline will overwrite or fail anyway
- Handles naming convention changes by deleting at old path and writing to current path
dioxus: Add podcast from UI with form and server function #20 859aa74
- Add form with slug and feed URL fields to AddPodcastPage
- Add server function to trigger add command via AddHandler
- Refactor Field component: remove Copy bound, make unit optional, replace use_effect with direct validation in oninput
- Add e2e tests for add podcast page including full integration test
- Pass typed Slug and UrlWrapper directly to server function instead of raw strings
- Use #[expect] with reasons for lint suppression attributes
- Remove unnecessary waitForTimeout calls in e2e tests
Bug Fixes
Use miette `.render()` for `Report` error logging instead of `Debug` 743f77f
- Enable
studiole-report/renderfeature behind theserverfeature gate- Replace
{error:?}witherror.render()in CLI and server error logging- Non-
Reporterrors (DbErr,io::Error, channel errors) left unchanged
Performance
metadata: Enable SQLite WAL journal mode to reduce write contention c9cd8a5
Concurrent episode downloads were blocking on SQLite's default rollback
journal, causing UPDATE statements to take 2-4 seconds. WAL mode allows
concurrent writes without file-level lock contention.
Dependencies
Upgrade workspace dependencies and fix breaking changes d11b1a0
- Upgrade
lofty0.22 to 0.23 (replaceset_yearwithset_dateusingTimestamp)- Upgrade
fast_image_resize,sea-orm,dioxus, and other dependencies- Bump
DX_VERSIONindocker/dioxus/Dockerfileto 0.7.3- Fix clippy
if_then_some_else_nonewarning inactions.rs
Refactor
di: Migrate to `studiole-di` v0.3, `studiole-command` v0.2, `studiole-report` v0.4 90ae72f
- Replace
Servicetrait withFromServices/FromServicesAsyncsplit- Replace
ServiceProvider::new()withServiceBuilder::new().with_core().build()- Replace
get_service::<T>()withget::<T>()(sync) orget_async::<T>()(async)- Replace
ServiceErrorvariants withResolveErrorequivalents- Add
with_core.rsfor explicitServiceBuilderregistration of all core services- Remove
attach_pathfromCustomReportExt(now provided bystudiole-reportv0.4)- Pin
studiole-*dependency versions to exact semver
Replace `error-stack` with `studiole-report` and extract `command`, `di`, `di-macros` to separate crates 6144f5e
- Remove in-tree
packages/command,packages/di,packages/di-macros- Add
studiole-command,studiole-di,studiole-reportas workspace dependencies- Migrate
attach(format!("Key: {val}"))to structuredattach("Key", val)- Replace
bail!with explicitreturn Err(Report::new(...))- Replace
downcast_refwithcurrent_contextinEmulateCommand- Split
CustomResultExtintoCustomReportExtandCustomResultExtforReportandResultrespectively
Tests
e2e: Centralise timeouts and fix flaky `podcast.spec.ts` test 88ae7b2
- Add shared
TIMEOUTSconfig inplaywright.config.tsfor hydration and UI waits- Replace magic number timeouts in
add.spec.tswith named constants- Remove
waitForLoadState("networkidle")frompodcast.spec.tswhich times out when the podcast has many episodes- Remove unreachable 120s
webServer.timeoutand always reuse existing server
Other
core: Use mock RSS feed for add/fetch handler tests #4 4dc0d29
- Add
MockServices::with_rss_feed()to prime HTTP cache with mock data
- Generate RSS XML from MockFeeds using PodcastToRss
- Export PodcastToRss from emulate module
- Remove example_rss_url constant (replaced by MockServices::rss_url())
- Update add_handler, fetch_feed_rss, and fetch_handler tests
- Add snapshot test for fetch_feed_rss