feat(worker): auto-tag packages with the slicer(s) their files target

Indexes 86k+ Lychee Slicer (.lys/.lyt), 23k+ ChituBox (.chitubox/.ctb/
.cbddlp), 1k+ Anycubic (.photon/.pwmo/.pwmx), and Bambu (.3mf)
slicer-specific files. Until now they were just generic extensions in
PackageFile.

After this commit:
  - Newly-ingested packages get tags derived from their file list
    ("lychee", "chitubox", "anycubic", "bambu", "fdm", "mango")
  - The `backfill_filelists` listener also applies tags to re-indexed
    packages
  - A new pure-DB listener `backfill_slicer_tags` walks existing
    Packages with file lists and applies tags retroactively — no
    downloads, no TDLib, takes seconds for thousands of rows.

Trigger the one-shot retroactive backfill with:
  SELECT pg_notify('backfill_slicer_tags', '{"limit":5000}');

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-24 08:53:18 +02:00
co-authored by Claude Opus 4.7
parent 7d39a13310
commit c4d9be83bd
4 changed files with 164 additions and 4 deletions
+58
View File
@@ -0,0 +1,58 @@
import type { FileEntry } from "./zip-reader.js";
/**
* Mapping from file extensions to slicer tags. Each tag groups a family of
* extensions that mean the same thing for end users — "this archive contains
* files I can open in <slicer>".
*
* Extensions are matched case-insensitively without the leading dot.
*/
const SLICER_EXTENSION_MAP: Record<string, string> = {
// Lychee Slicer
lys: "lychee",
lyt: "lychee",
lyc: "lychee",
// ChituBox / Anycubic / Phrozen / Elegoo (resin printers)
chitubox: "chitubox",
ctb: "chitubox",
cbddlp: "chitubox",
// Anycubic Photon family
photon: "anycubic",
pwmo: "anycubic",
pwmx: "anycubic",
pwmb: "anycubic",
pwma: "anycubic",
pws: "anycubic",
pwsq: "anycubic",
phz: "anycubic",
// Bambu / Prusa
"3mf": "bambu",
bgcode: "bambu",
// FDM gcode (generic)
gcode: "fdm",
// Mango / generic resin formats sometimes seen in releases
mfp: "mango",
mfpv: "mango",
osla: "mango",
};
/**
* Derive a deduplicated list of slicer tags from an archive's file listing.
* Returns an empty array if no recognised slicer-specific files are present
* (e.g., the archive is just STLs without pre-supports).
*/
export function extractSlicerTags(entries: FileEntry[]): string[] {
const tags = new Set<string>();
for (const entry of entries) {
if (!entry.extension) continue;
const ext = entry.extension.toLowerCase();
const tag = SLICER_EXTENSION_MAP[ext];
if (tag) tags.add(tag);
}
return [...tags].sort();
}