a90b7443e4
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
"""Desregistra un vault de la app de escritorio Obsidian.
|
|
|
|
Quita la entrada del vault de la clave "vaults" del archivo de configuracion de la
|
|
app (~/.config/obsidian/obsidian.json). NO borra la carpeta del vault en disco: solo
|
|
hace que la app Obsidian deje de conocerlo. Preserva el resto del JSON intacto.
|
|
|
|
Funcion impura: lee y escribe la config de la app y hace backup .bak antes de
|
|
sobreescribir.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import shutil
|
|
|
|
|
|
def _default_config_path() -> str:
|
|
"""Ruta por defecto del obsidian.json de la app de escritorio Obsidian."""
|
|
return os.path.expanduser("~/.config/obsidian/obsidian.json")
|
|
|
|
|
|
def _load_config(config_path: str) -> dict:
|
|
"""Carga obsidian.json. Si no existe devuelve la estructura vacia base."""
|
|
if not os.path.exists(config_path):
|
|
return {"vaults": {}}
|
|
with open(config_path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
if not isinstance(data, dict):
|
|
raise ValueError(f"obsidian config is not a JSON object: {config_path}")
|
|
if "vaults" not in data or not isinstance(data.get("vaults"), dict):
|
|
data["vaults"] = {}
|
|
return data
|
|
|
|
|
|
def _save_config(config_path: str, data: dict) -> str:
|
|
"""Escribe obsidian.json haciendo backup .bak previo si ya existia.
|
|
|
|
Devuelve la ruta del backup creado (cadena vacia si no habia archivo previo).
|
|
"""
|
|
parent = os.path.dirname(config_path)
|
|
if parent:
|
|
os.makedirs(parent, exist_ok=True)
|
|
|
|
backup_path = ""
|
|
if os.path.exists(config_path):
|
|
backup_path = config_path + ".bak"
|
|
shutil.copy2(config_path, backup_path)
|
|
|
|
with open(config_path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
|
|
return backup_path
|
|
|
|
|
|
def unregister_obsidian_vault(vault_ref: str, config_path: str = "") -> dict:
|
|
"""Quita un vault de la lista de vaults conocidos por la app Obsidian.
|
|
|
|
Args:
|
|
vault_ref: id exacto de la entrada (hex de 16 chars) O una ruta al vault.
|
|
Si parece una ruta se normaliza a absoluta y se compara con "path".
|
|
Primero se intenta match por id; si no hay, por path.
|
|
config_path: ruta al obsidian.json de la app. Vacio -> default
|
|
~/.config/obsidian/obsidian.json.
|
|
|
|
Returns:
|
|
dict con:
|
|
- removed: True si se quito una entrada, False si no se encontro.
|
|
- id: id de la entrada quitada ("" si no se encontro).
|
|
- path: path de la entrada quitada ("" si no se encontro).
|
|
- config_path: ruta del obsidian.json usado.
|
|
- backup_path: ruta del backup .bak escrito ("" si no se escribio nada).
|
|
|
|
Raises:
|
|
ValueError: si el obsidian.json existente no es un objeto JSON valido.
|
|
OSError: si la lectura/escritura del archivo falla por I/O.
|
|
"""
|
|
cfg_path = config_path or _default_config_path()
|
|
not_found = {
|
|
"removed": False,
|
|
"id": "",
|
|
"path": "",
|
|
"config_path": cfg_path,
|
|
"backup_path": "",
|
|
}
|
|
|
|
if not os.path.exists(cfg_path):
|
|
return not_found
|
|
|
|
data = _load_config(cfg_path)
|
|
vaults = data["vaults"]
|
|
|
|
target_id = None
|
|
|
|
# 1) Match directo por id.
|
|
if vault_ref in vaults:
|
|
target_id = vault_ref
|
|
else:
|
|
# 2) Match por path normalizado.
|
|
abs_ref = os.path.abspath(os.path.expanduser(vault_ref))
|
|
for vid, entry in vaults.items():
|
|
if isinstance(entry, dict) and entry.get("path") == abs_ref:
|
|
target_id = vid
|
|
break
|
|
|
|
if target_id is None:
|
|
return not_found
|
|
|
|
removed_path = ""
|
|
entry = vaults.get(target_id)
|
|
if isinstance(entry, dict):
|
|
removed_path = entry.get("path", "")
|
|
del vaults[target_id]
|
|
|
|
backup_path = _save_config(cfg_path, data)
|
|
return {
|
|
"removed": True,
|
|
"id": target_id,
|
|
"path": removed_path,
|
|
"config_path": cfg_path,
|
|
"backup_path": backup_path,
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import tempfile
|
|
import time
|
|
|
|
tmp = tempfile.mkdtemp()
|
|
cfg = os.path.join(tmp, "obsidian.json")
|
|
payload = {
|
|
"extra": "preservar",
|
|
"vaults": {
|
|
"aaaaaaaaaaaaaaaa": {"path": "/a/Alpha", "ts": int(time.time() * 1000), "open": True},
|
|
"bbbbbbbbbbbbbbbb": {"path": "/b/Beta", "ts": int(time.time() * 1000), "open": False},
|
|
},
|
|
}
|
|
with open(cfg, "w", encoding="utf-8") as f:
|
|
json.dump(payload, f)
|
|
|
|
r = unregister_obsidian_vault("/a/Alpha", config_path=cfg)
|
|
assert r["removed"] is True and r["id"] == "aaaaaaaaaaaaaaaa", r
|
|
|
|
r2 = unregister_obsidian_vault("bbbbbbbbbbbbbbbb", config_path=cfg)
|
|
assert r2["removed"] is True and r2["path"] == "/b/Beta", r2
|
|
|
|
with open(cfg, "r", encoding="utf-8") as f:
|
|
final = json.load(f)
|
|
assert final["extra"] == "preservar", final
|
|
assert final["vaults"] == {}, final
|
|
|
|
assert unregister_obsidian_vault("nope", config_path=cfg)["removed"] is False
|
|
print("unregister_obsidian_vault smoke OK")
|