Tecnología · GUÍA PRÁCTICA
¿Desaparecieron los perfiles de Bambu Studio? Audita los archivos antes de reinstalar
Que no aparezcan en el menú no demuestra que se borró el JSON. Conserva el árbol, calcula hashes y resuelve la herencia antes de reparar.

Si desaparecen perfiles personalizados de filamento en Bambu Studio, no empieces copiando JSON sueltos al perfil activo ni reinstalando encima. Los informes actuales muestran al menos dos casos distintos: perfiles heredados que siguen en disco pero quedan ocultos y un paquete de perfiles del sistema que queda vacío tras una actualización. El mismo síntoma puede ser visibilidad, falta del padre, datos dañados o ausencia real del archivo.
Esta guía genera un informe de evidencia de solo lectura desde una copia preservada del árbol de configuración de Bambu Studio. Registra para cada perfil su ámbito de cuenta, ruta relativa, bytes exactos, SHA-256, nombre, inherits, impresoras compatibles y uno de cuatro estados: root-preset, parent-found, parent-missing o unreadable. No inicia sesión en la nube, no modifica el perfil activo ni promete recuperar archivos borrados.
Congela la evidencia antes de cambiar Studio
Cierra Bambu Studio por completo, identifica la raíz que usa esa instalación y crea una copia completa con nombre independiente. No copies solo filament; conserva fechas y permisos cuando sea posible. No limpies, sincronices, importes, restablezcas ni reinstales primero, porque esas acciones pueden cambiar la evidencia que distingue un perfil oculto de un archivo ausente.
Anota la versión de Bambu Studio, sistema operativo, impresora y boquilla seleccionadas, y la hora de la copia. Si los perfiles siguen visibles en algún perfil, exporta también el paquete documentado antes de cerrar esa sesión. La exportación visible y el inventario en disco responden preguntas distintas.
Separa los perfiles de usuario de sus padres
Bambu Studio puede guardar perfiles de filamento en varios ámbitos, incluidos default y carpetas por cuenta. Un perfil también puede guardar solo diferencias y apuntar a un padre mediante inherits. Encontrar el JSON es necesario, pero no basta para demostrar que Studio puede cargarlo.
La auditoría indexa perfiles con nombre bajo system/BBL/filament y compara cada inherits. No supone que dos nombres de archivo son el mismo perfil: registra el nombre JSON y los bytes exactos, y rechaza claves JSON duplicadas en vez de aceptar silenciosamente la última.
Ejecuta la auditoría solo en la copia
Guarda el siguiente script como bambu_preset_audit.py. Con Python 3.12 o un Python 3 compatible, pasa la raíz preservada y una ruta CSV nueva fuera de ella. El informe se crea en exclusiva, por lo que no sobrescribe otro; omite enlaces simbólicos y no escribe en el árbol de entrada.
Run this exact reviewed script from a copy of the configuration tree, not the live tree: ```python #!/usr/bin/env python3 """Read-only inventory for Bambu Studio user filament preset JSON files.""" from __future__ import annotations import argparse import csv import hashlib import json from pathlib import Path def object_no_duplicates(pairs): result = {} for key, value in pairs: if key in result: raise ValueError(f"duplicate JSON key: {key}") result[key] = value return result def load_json(path: Path): raw = path.read_bytes() value = json.loads(raw.decode("utf-8-sig"), object_pairs_hook=object_no_duplicates) if not isinstance(value, dict): raise ValueError("top-level JSON value is not an object") return raw, value def text_list(value): if value is None: return [] if isinstance(value, str): return [value] if isinstance(value, list) and all(isinstance(item, str) for item in value): return value raise ValueError("compatible_printers is not a string list") def system_names(root: Path): names = {} system_root = root / "system" / "BBL" / "filament" if not system_root.is_dir(): return names for path in sorted(system_root.rglob("*.json")): if path.is_symlink() or not path.is_file(): continue try: _, data = load_json(path) name = data.get("name") if isinstance(name, str) and name: names.setdefault(name, []).append(path.relative_to(root).as_posix()) except (OSError, UnicodeError, ValueError, json.JSONDecodeError): continue return names def audit(root: Path): parents = system_names(root) user_root = root / "user" rows = [] if not user_root.is_dir(): return rows for scope in sorted(user_root.iterdir()): filament = scope / "filament" if scope.is_symlink() or not scope.is_dir() or not filament.is_dir(): continue for path in sorted(filament.rglob("*.json")): if path.is_symlink() or not path.is_file(): continue row = { "account_scope": scope.name, "relative_path": path.relative_to(root).as_posix(), "bytes": path.stat().st_size, "sha256": "", "preset_name": "", "inherits": "", "parent_status": "unreadable", "parent_paths": "", "compatible_printers": "", "error": "", } try: raw, data = load_json(path) row["sha256"] = hashlib.sha256(raw).hexdigest() name = data.get("name", path.stem) if not isinstance(name, str): raise ValueError("name is not a string") inherits = data.get("inherits", "") if not isinstance(inherits, str): raise ValueError("inherits is not a string") printers = text_list(data.get("compatible_printers")) row["preset_name"] = name row["inherits"] = inherits row["compatible_printers"] = " | ".join(printers) if not inherits: row["parent_status"] = "root-preset" elif inherits in parents: row["parent_status"] = "parent-found" row["parent_paths"] = " | ".join(parents[inherits]) else: row["parent_status"] = "parent-missing" except (OSError, UnicodeError, ValueError, json.JSONDecodeError) as exc: row["error"] = str(exc) rows.append(row) return rows def main(): parser = argparse.ArgumentParser() parser.add_argument("config_root", type=Path) parser.add_argument("report_csv", type=Path) args = parser.parse_args() root = args.config_root.resolve(strict=True) report = args.report_csv.resolve() if not root.is_dir(): raise SystemExit("config_root is not a directory") if report == root or root in report.parents: raise SystemExit("report_csv must be outside config_root") rows = audit(root) fields = [ "account_scope", "relative_path", "bytes", "sha256", "preset_name", "inherits", "parent_status", "parent_paths", "compatible_printers", "error", ] with report.open("x", encoding="utf-8-sig", newline="") as handle: writer = csv.DictWriter(handle, fieldnames=fields) writer.writeheader() writer.writerows(rows) print(json.dumps({"config_root": str(root), "report_csv": str(report), "rows": len(rows)})) if __name__ == "__main__": main() ```
Verifica el comando y el límite del informe
Ejemplo: python3 bambu_preset_audit.py '/evidence/BambuStudio-copy' '/evidence/bambu-preset-report.csv'. La segunda ruta debe estar fuera de la copia. El script imprime solo rutas resueltas y número de filas; el detalle queda en el CSV. Conserva hashes del script y del informe junto con la copia.
El ayudante revisado mide 4.697 bytes y su SHA-256 es 4711e9c5db94afee575fc6dbbc2a206a29178eeae4ce17387db8a6159a21cf0. Pasó una prueba en CPython 3.12.14 con raíz, padre encontrado, padre ausente y JSON con clave duplicada. La prueba demuestra el clasificador acotado, no compatibilidad con una cuenta, impresora o nube real.
Lee cada fila antes de reparar
root-preset indica que no declara padre. parent-found indica al menos un perfil de sistema con el nombre heredado; revisa parent_paths y compatible_printers juntos. parent-missing significa que existe el archivo de usuario pero no el padre en la copia. unreadable conserva ruta y error sin tratar JSON dañado como válido.
Compara account_scope antes de unir. Dos perfiles con igual nombre pueden tener bytes distintos. SHA-256 demuestra identidad exacta, no calidad ni compatibilidad. Mantén filas separadas salvo que rutas y hashes justifiquen una unión deliberada.
Deja que la evidencia elija la rama
Si existen archivos y padres, comprueba primero impresora/boquilla seleccionadas y si Studio oculta un perfil incompatible; exporta mientras sea visible en vez de editar JSON activo. Si falta el padre, conserva archivos de usuario y repara solo la capa de sistema correspondiente desde una fuente fiable y específica de esa versión.
Para JSON unreadable, revisa una copia y compárala con una copia de seguridad conocida; no reescribas la única evidencia. Si no existe el archivo de usuario, la auditoría no puede recrearlo. La recuperación depende de un respaldo, exportación aún visible o restauración admitida por el proveedor.
Define finalización y límites
La fase de evidencia termina cuando cada JSON de filamento de cada ámbito tiene una fila, el CSV está fuera de la copia y se revisaron parent-missing y unreadable. Reparar es aparte: conserva primero, abre Studio después, selecciona la impresora/boquilla y confirma valores o importa un paquete verificado.
El procedimiento no decide seguridad del material, compatibilidad, sincronización en la nube ni diagnostica todos los informes históricos. Se detiene antes de escribir el árbol activo. Si el CSV contradice la interfaz, conserva ambos y entrega a soporte ruta, hash, estado del padre y versión.
