| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- """Regenerate the filament-id tables from Bambu's and OrcaSlicer's own data (#3387).
- Usage:
- python scripts/generate_filament_id_tables.py [BAMBU_PUBLIC_JSON] [ORCA_IDS_JSON]
- With no arguments both sources are downloaded:
- Bambu Cloud's public preset list (no login needed). Every filament entry
- carries its setting_id and the filament_id Bambu Studio sends to the printer
- for it. For most, dropping the "S" after "GF" turns one into the other; the
- presets where it does not (beyond SUNLU, which ``derived_filament_id``
- handles by rule) go into SETTING_ID_FILAMENT_IDS, by full setting_id --
- the suffix can decide it ("GFSA05_10" is Bambu PLA Matte, every other
- "GFSA05_nn" Bambu PLA Silk).
- A bare setting_id is listed only when the rule gives an id no preset has.
- Bambuddy itself builds bare ids from filament ids ("GFA05" -> "GFSA05"), so
- where the rule leads to a real filament ("GFSA05" -> Bambu PLA Silk), it
- wins over Bambu's legacy preset of that bare id ("GFSA05" is also Bambu PLA
- Matte @BBL X1): listing it would turn every such Silk spool into Matte.
- OrcaSlicer's resources/printers/bambu_filament_ids.json, the table Orca uses
- to translate its own filament ids ("OFMUWNkp") to Bambu's at the printer.
- It becomes ORCA_FILAMENT_IDS.
- Writes backend/app/utils/filament_id_tables.py and
- frontend/src/utils/filamentIdTables.ts (the frontend needs only the first
- table). Run it by hand when Bambu or Orca add filaments, and review the diff.
- """
- import json
- import sys
- import urllib.request
- from pathlib import Path
- REPO_ROOT = Path(__file__).resolve().parent.parent
- sys.path.insert(0, str(REPO_ROOT))
- from backend.app.utils.filament_ids import derived_filament_id # noqa: E402
- BAMBU_URL = "https://api.bambulab.com/v1/iot-service/api/slicer/setting?version=2.0.0.0&public=true"
- ORCA_URL = "https://raw.githubusercontent.com/OrcaSlicer/OrcaSlicer/main/resources/printers/bambu_filament_ids.json"
- BACKEND_OUT = REPO_ROOT / "backend" / "app" / "utils" / "filament_id_tables.py"
- FRONTEND_OUT = REPO_ROOT / "frontend" / "src" / "utils" / "filamentIdTables.ts"
- def _load(arg: str | None, url: str) -> dict:
- if arg:
- return json.loads(Path(arg).read_text())
- request = urllib.request.Request(url, headers={"User-Agent": "bambuddy-filament-id-tables"})
- with urllib.request.urlopen(request, timeout=30) as response:
- return json.load(response)
- def main() -> None:
- args = sys.argv[1:]
- bambu = _load(args[0] if args else None, BAMBU_URL)
- orca = _load(args[1] if len(args) > 1 else None, ORCA_URL)
- presets = (bambu.get("filament") or {}).get("public") or []
- if not presets:
- sys.exit("Bambu's public list has no filament presets")
- real_ids = {preset.get("filament_id") for preset in presets}
- setting_ids: dict[str, str] = {}
- for preset in presets:
- setting_id, filament_id = preset.get("setting_id"), preset.get("filament_id")
- if not setting_id or not filament_id:
- continue
- derived = derived_filament_id(setting_id.split("_")[0])
- if derived == filament_id or ("_" not in setting_id and derived in real_ids):
- continue
- setting_ids[setting_id] = filament_id
- orca_ids = {
- orca_id: entry["bambu_id"]
- for orca_id, entry in (orca.get("filaments") or {}).items()
- if isinstance(entry, dict) and entry.get("bambu_id")
- }
- if not orca_ids:
- sys.exit("Orca's table has no filaments")
- header = "Generated by scripts/generate_filament_id_tables.py -- do not edit by hand."
- lines = [f'"""{header}', "", f"{len(presets)} public Bambu filament presets read.", '"""', ""]
- lines.append("# Bambu setting_id -> filament_id, where the naming rule gives another id.")
- lines.append("SETTING_ID_FILAMENT_IDS: dict[str, str] = {")
- lines += [f' "{k}": "{v}",' for k, v in sorted(setting_ids.items())]
- lines.append("}")
- lines.append("")
- commit = orca.get("bambustudio_commit", "unknown")
- lines.append(f"# OrcaSlicer filament_id -> Bambu filament_id (Orca's table, Bambu Studio {commit}).")
- lines.append("ORCA_FILAMENT_IDS: dict[str, str] = {")
- lines += [f' "{k}": "{v}",' for k, v in sorted(orca_ids.items())]
- lines.append("}")
- BACKEND_OUT.write_text("\n".join(lines) + "\n")
- ts = [f"// {header}", "// Bambu setting_id -> filament_id, where the naming rule gives another id.", ""]
- ts.append("export const SETTING_ID_FILAMENT_IDS: Readonly<Record<string, string>> = {")
- ts += [f" {k}: '{v}'," for k, v in sorted(setting_ids.items())]
- ts.append("};")
- FRONTEND_OUT.write_text("\n".join(ts) + "\n")
- print(f"{len(setting_ids)} setting_id exceptions, {len(orca_ids)} Orca ids")
- if __name__ == "__main__":
- main()
|