Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Clears the open FabledCurator todo list. All CI-green on dev (run 615).
Tags / normalization
find_or_create/renamekeep original casing (ML/booru vocabulary) but gain case-insensitive lookup + clash detection so case variants dedup instead of forking.TagService._do_merge(FK repoints + protective ML aliases). dry-run projection + long-running maintenance task; "Standardize tag casing" section in the Cleanup tab behind a back-up-first warning.Downloads / ingester
Maintenance / archives (#713)
UI / modal bug-fixes
🤖 Generated with Claude Code
Patreon attachment downloads land with sanitized URL-blob filenames (01_https___www.patreon.com_media-u_v3_<id>) whose Path.suffix is junk, never .zip — so the extension-only is_archive() filed them as opaque PostAttachments and never extracted them ("No images attached to this post"). Add archive_extractor.detect_archive_format() — extension first, then magic-byte sniff (zipfile.is_zipfile + RAR/7z signatures). is_archive(), extract_archive(), and safe_probe._inspect_archive() (the bomb-guard) all route through it, so a mis-named/extension-less archive is now detected, bomb-guarded, integrity-tested, AND extracted regardless of filename. Stops new ones; part 2 re-extracts the already-imported backlog. Tests: mis-named zip detected + extracted; non-archive dotted name not misdetected; _inspect_archive on a mis-named zip; signature updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Tags now normalize to Title Case + collapsed whitespace at the central TagService.find_or_create (and rename) — so manual entry, the create API, and anything routed through find_or_create produce the canonical form. The lookup is case-insensitive, so a differently-cased entry finds the existing tag instead of forking a case-variant duplicate ('hatsune miku' / 'HATSUNE MIKU' → one tag). normalize_tag_name uses per-word capitalize (not str.title(), which mangles apostrophes) and folds ALL-CAPS input. Existing tags keep their current casing until touched — a retro-normalize maintenance pass (Title-Case + merge case-collisions) is the follow-up to convert the back-catalog. Test: create title-cases + collapses whitespace; case/whitespace variants dedupe to one tag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>TABLESAMPLE SYSTEM_ROWS reads CONTIGUOUS rows from each sampled page, so sequentially-imported near-duplicates (multi-image posts, variant sets) came back adjacent and clustered in the showcase ("three near-identical in a row"). Sample limit*5 rows (spanning more pages) then ORDER BY random() before taking limit — breaks the physical adjacency for much better spread, still cheap (random() over a few hundred rows, not the whole table). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Now that we own the walk, surface live counts on the in-flight download in the Downloads view. ingest_core.run takes an event_id and does a TIME-THROTTLED write (~5s, decoupled from page boundaries so it ticks steadily regardless of how big/slow a page is) of {downloaded, skipped, errors, quarantined, posts} to the running download_event's metadata.live (jsonb_set; short session; status guard so a finalized event isn't clobbered). download_backends threads event_id from ctx; the /api/downloads list surfaces `live`; ActiveDownloadsPanel renders it beside the elapsed timer. Native (Patreon) only — gallery-dl is an opaque subprocess; the row only shows when `live` is present. Phase 3 overwrites metadata with run_stats on finish, dropping `live`. Test: _write_live_progress updates a running event's metadata.live and leaves a finalized (status != running) event alone. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>