Files
fn_registry/python/functions/obsidian/open_obsidian_vault.py
T
2026-06-15 01:33:35 +02:00

108 lines
3.9 KiB
Python

"""Abre un vault en la app de escritorio Obsidian via el esquema obsidian://.
Construye el URI `obsidian://open?vault=<name>` y lanza la app para abrir ese vault.
Opcionalmente lo registra antes en la config de la app si recibe una ruta existente
no registrada (compone register_obsidian_vault del grupo obsidian).
Funcion impura: puede escribir la config de la app (al registrar) y lanza un proceso
externo (xdg-open) de forma desacoplada para abrir el URI en Obsidian.
"""
import os
import subprocess
import urllib.parse
from obsidian import register_obsidian_vault
def open_obsidian_vault(
vault: str,
register_if_missing: bool = True,
launch: bool = True,
config_path: str = "",
) -> dict:
"""Abre un vault en la app Obsidian construyendo y lanzando un URI obsidian://.
Args:
vault: ruta absoluta a un vault o su nombre (basename). Si es una ruta
existente, el nombre del URI es su basename; si no parece una ruta
existente se trata como nombre tal cual.
register_if_missing: si True (default) y vault es una ruta existente no
registrada en la app, la registra (open=True) antes de abrir.
launch: si True (default) lanza la app via `xdg-open <uri>` desacoplado.
Si False (util en tests) NO lanza nada, solo construye el URI.
config_path: ruta al obsidian.json de la app. Vacio -> default
~/.config/obsidian/obsidian.json. Se pasa a register_obsidian_vault.
Returns:
dict con:
- vault: el argumento original recibido.
- uri: el URI obsidian://open?vault=<name> construido.
- name: nombre del vault usado en el URI (basename o el propio vault).
- launched: True si se lanzo xdg-open.
- registered_now: True si se registro el vault en esta llamada.
Raises:
OSError: si el lanzamiento del proceso o el registro fallan por I/O.
"""
registered_now = False
is_path = os.path.sep in vault or vault.startswith("~")
abs_path = os.path.abspath(os.path.expanduser(vault)) if is_path else ""
# Si es una ruta existente, opcionalmente registrarla y usar su basename.
if abs_path and os.path.isdir(abs_path):
name = os.path.basename(abs_path.rstrip(os.path.sep))
if register_if_missing:
res = register_obsidian_vault(abs_path, open=True, config_path=config_path)
registered_now = bool(res.get("registered"))
elif is_path:
# Parece ruta pero no existe: usar su basename como nombre.
name = os.path.basename(abs_path.rstrip(os.path.sep))
else:
# Es un nombre, no una ruta.
name = vault
uri = "obsidian://open?vault=" + urllib.parse.quote(name)
launched = False
if launch:
env = dict(os.environ)
subprocess.Popen(
["xdg-open", uri],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True,
env=env,
)
launched = True
return {
"vault": vault,
"uri": uri,
"name": name,
"launched": launched,
"registered_now": registered_now,
}
if __name__ == "__main__":
import tempfile
tmp = tempfile.mkdtemp()
cfg = os.path.join(tmp, "obsidian.json")
vault = os.path.join(tmp, "Mi Vault")
os.makedirs(vault, exist_ok=True)
r = open_obsidian_vault(vault, launch=False, config_path=cfg)
assert r["launched"] is False, r
assert r["registered_now"] is True, r
assert r["name"] == "Mi Vault", r
assert r["uri"] == "obsidian://open?vault=Mi%20Vault", r
# Por nombre, sin lanzar ni registrar.
r2 = open_obsidian_vault("MiVaultPorNombre", launch=False, config_path=cfg)
assert r2["uri"] == "obsidian://open?vault=MiVaultPorNombre", r2
assert r2["registered_now"] is False, r2
print("open_obsidian_vault smoke OK")