Files
Medios-Macina/cmdlet/get_note.py
2025-12-23 16:36:39 -08:00

149 lines
4.9 KiB
Python

from __future__ import annotations
from pathlib import Path
from typing import Any, Dict, Optional, Sequence
import sys
from SYS.logger import log
import pipeline as ctx
from . import _shared as sh
Cmdlet = sh.Cmdlet
CmdletArg = sh.CmdletArg
SharedArgs = sh.SharedArgs
normalize_hash = sh.normalize_hash
parse_cmdlet_args = sh.parse_cmdlet_args
normalize_result_input = sh.normalize_result_input
should_show_help = sh.should_show_help
from Store import Store
from SYS.utils import sha256_file
class Get_Note(Cmdlet):
def __init__(self) -> None:
super().__init__(
name="get-note",
summary="List notes on a file in a store.",
usage="get-note -store <store> [-query \"hash:<sha256>\"]",
alias=["get-notes", "get_note"],
arg=[
SharedArgs.STORE,
SharedArgs.QUERY,
],
detail=[
"- Notes are retrieved via the selected store backend.",
"- Lyrics are stored in a note named 'lyric'.",
],
exec=self.run,
)
try:
SharedArgs.STORE.choices = SharedArgs.get_store_choices(None)
except Exception:
pass
self.register()
def _resolve_hash(self, raw_hash: Optional[str], raw_path: Optional[str], override_hash: Optional[str]) -> Optional[str]:
resolved = normalize_hash(override_hash) if override_hash else normalize_hash(raw_hash)
if resolved:
return resolved
if raw_path:
try:
p = Path(str(raw_path))
stem = p.stem
if len(stem) == 64 and all(c in "0123456789abcdef" for c in stem.lower()):
return stem.lower()
if p.exists() and p.is_file():
return sha256_file(p)
except Exception:
return None
return None
def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
if should_show_help(args):
log(f"Cmdlet: {self.name}\nSummary: {self.summary}\nUsage: {self.usage}")
return 0
parsed = parse_cmdlet_args(args, self)
store_override = parsed.get("store")
query_hash = sh.parse_single_hash_query(parsed.get("query"))
if parsed.get("query") and not query_hash:
log("[get_note] Error: -query must be of the form hash:<sha256>", file=sys.stderr)
return 1
results = normalize_result_input(result)
if not results:
if store_override and query_hash:
results = [{"store": str(store_override), "hash": query_hash}]
else:
log("[get_note] Error: Requires piped item(s) or -store and -query \"hash:<sha256>\"", file=sys.stderr)
return 1
store_registry = Store(config)
any_notes = False
for res in results:
if not isinstance(res, dict):
continue
store_name = str(store_override or res.get("store") or "").strip()
raw_hash = res.get("hash")
raw_path = res.get("path")
if not store_name:
log("[get_note] Error: Missing -store and item has no store field", file=sys.stderr)
return 1
resolved_hash = self._resolve_hash(
raw_hash=str(raw_hash) if raw_hash else None,
raw_path=str(raw_path) if raw_path else None,
override_hash=str(query_hash) if query_hash else None,
)
if not resolved_hash:
continue
try:
backend = store_registry[store_name]
except Exception as exc:
log(f"[get_note] Error: Unknown store '{store_name}': {exc}", file=sys.stderr)
return 1
notes = {}
try:
notes = backend.get_note(resolved_hash, config=config) or {}
except Exception:
notes = {}
if not notes:
continue
any_notes = True
# Emit each note as its own row so CLI renders a proper note table
for k in sorted(notes.keys(), key=lambda x: str(x).lower()):
v = notes.get(k)
raw_text = str(v or "")
# Keep payload small for IPC/pipes.
raw_text = raw_text[:999]
preview = " ".join(raw_text.replace("\r", "").split("\n"))
ctx.emit(
{
"store": store_name,
"hash": resolved_hash,
"note_name": str(k),
"note_text": raw_text,
"columns": [
("Name", str(k)),
("Text", preview.strip()),
],
}
)
if not any_notes:
ctx.emit("No notes found.")
return 0
CMDLET = Get_Note()