Expired Cleaner: rename the safety toggle to dry_run (default ON), matching Re-tag

The destructive job's findings-vs-auto toggle was 'auto_delete: False'. Renamed
to 'dry_run: True' to match the Re-tag job's convention and make the safe
default unmistakable: dry run ON (default) = findings only, deletes nothing;
dry run OFF = hands-off auto-delete. Behaviour-identical to the previous
default — just clearer + consistent. Help text + tests updated.
This commit is contained in:
BoulderBadgeDad 2026-06-07 22:13:30 -07:00
parent 696119d5ac
commit 46730d1661
2 changed files with 19 additions and 10 deletions

View file

@ -69,12 +69,13 @@ class ExpiredDownloadCleanerJob(RepairJob):
'fewer than the keep-threshold (default: played more than once is kept). ' 'fewer than the keep-threshold (default: played more than once is kept). '
'It only touches downloads recorded from the Download Origins feature ' 'It only touches downloads recorded from the Download Origins feature '
'forward — never your pre-existing or manually-added library.\n\n' 'forward — never your pre-existing or manually-added library.\n\n'
'By default it creates findings for you to review and delete. Set ' 'Dry run is ON by default: it only creates findings for you to review '
'Auto-delete to true for hands-off cleanup.\n\n' 'and delete — nothing is deleted automatically. Turn Dry run OFF for '
'hands-off auto-cleanup.\n\n'
'Settings:\n' 'Settings:\n'
'- Watchlist retention / Playlist retention: off, or a window\n' '- Watchlist retention / Playlist retention: off, or a window\n'
'- Keep if played at least: play count that protects a track (default 2)\n' '- Keep if played at least: play count that protects a track (default 2)\n'
'- Auto-delete: delete automatically instead of creating findings' '- Dry run: ON = findings only (default); OFF = delete automatically'
) )
icon = 'repair-icon-cleanup' icon = 'repair-icon-cleanup'
default_enabled = False default_enabled = False
@ -83,12 +84,12 @@ class ExpiredDownloadCleanerJob(RepairJob):
'watchlist_retention': 'off', 'watchlist_retention': 'off',
'playlist_retention': 'off', 'playlist_retention': 'off',
'keep_if_played_at_least': 2, 'keep_if_played_at_least': 2,
'auto_delete': False, 'dry_run': True,
} }
setting_options = { setting_options = {
'watchlist_retention': RETENTION_OPTIONS, 'watchlist_retention': RETENTION_OPTIONS,
'playlist_retention': RETENTION_OPTIONS, 'playlist_retention': RETENTION_OPTIONS,
'auto_delete': [False, True], 'dry_run': [True, False],
} }
auto_fix = False auto_fix = False
@ -110,7 +111,7 @@ class ExpiredDownloadCleanerJob(RepairJob):
min_plays = int(settings.get('keep_if_played_at_least', 2)) min_plays = int(settings.get('keep_if_played_at_least', 2))
except (TypeError, ValueError): except (TypeError, ValueError):
min_plays = 2 min_plays = 2
auto_delete = bool(settings.get('auto_delete', False)) dry_run = bool(settings.get('dry_run', True))
candidates = context.db.get_origin_cleanup_candidates() candidates = context.db.get_origin_cleanup_candidates()
if not candidates: if not candidates:
@ -150,7 +151,7 @@ class ExpiredDownloadCleanerJob(RepairJob):
for i, entry in enumerate(expired): for i, entry in enumerate(expired):
if context.check_stop(): if context.check_stop():
return result return result
if auto_delete: if not dry_run:
try: try:
res = delete_origin_download(context.db, entry, context.config_manager) res = delete_origin_download(context.db, entry, context.config_manager)
if res.get('removed') or res.get('file_deleted'): if res.get('removed') or res.get('file_deleted'):
@ -191,7 +192,7 @@ class ExpiredDownloadCleanerJob(RepairJob):
logger.info("[Expired Cleaner] %d candidates, %d expired (%s)", logger.info("[Expired Cleaner] %d candidates, %d expired (%s)",
len(candidates), len(expired), len(candidates), len(expired),
"auto-deleted" if auto_delete else "findings created") "findings created (dry run)" if dry_run else "auto-deleted")
return result return result
def estimate_scope(self, context: JobContext) -> int: def estimate_scope(self, context: JobContext) -> int:

View file

@ -104,11 +104,19 @@ def test_scan_protects_watched_artist():
assert findings == [] # still watched → protected assert findings == [] # still watched → protected
def test_scan_auto_delete_mode(): def test_scan_dry_run_default_is_findings_only():
# No dry_run in settings → defaults to True → findings, never deletes.
db = _DB([_cand(1, created=OLD, path="/music/x.flac")])
findings = []
res = ExpiredDownloadCleanerJob().scan(_ctx(db, {'playlist_retention': '2mo'}, findings))
assert res.findings_created == 1 and db.deleted_history == [] # nothing deleted
def test_scan_auto_delete_when_dry_run_off():
db = _DB([_cand(1, created=OLD, path="/music/x.flac")]) db = _DB([_cand(1, created=OLD, path="/music/x.flac")])
findings = [] findings = []
res = ExpiredDownloadCleanerJob().scan(_ctx( res = ExpiredDownloadCleanerJob().scan(_ctx(
db, {'playlist_retention': '2mo', 'auto_delete': True}, findings)) db, {'playlist_retention': '2mo', 'dry_run': False}, findings))
assert findings == [] # no findings in auto mode assert findings == [] # no findings in auto mode
assert res.auto_fixed == 1 assert res.auto_fixed == 1
assert 1 in db.deleted_history # history row removed assert 1 in db.deleted_history # history row removed