This commit is contained in:
2026-01-11 18:56:26 -08:00
parent e70db8d8a6
commit 6076ea307b
7 changed files with 773 additions and 1476 deletions

View File

@@ -209,11 +209,8 @@ class Add_Note(Cmdlet):
note_name = str(note_name or "").strip()
note_text = str(note_text or "").strip()
if not note_name or not note_text:
log(
"[add_note] Error: -query must include title:<title> and text:<text>",
file=sys.stderr,
)
return 1
pass # We now support implicit pipeline notes if -query is missing
# But if explicit targeting (store+hash) is used, we still demand args below.
if hash_override and not store_override:
log(
@@ -224,6 +221,14 @@ class Add_Note(Cmdlet):
explicit_target = bool(hash_override and store_override)
results = normalize_result_input(result)
if explicit_target and (not note_name or not note_text):
log(
"[add_note] Error: Explicit target (store+hash) requires -query with title/text",
file=sys.stderr,
)
return 1
if results and explicit_target:
# Direct targeting mode: apply note once to the explicit target and
# pass through any piped items unchanged.
@@ -287,7 +292,36 @@ class Add_Note(Cmdlet):
ctx.emit(res)
continue
item_note_text = note_text
# Determine notes to write for this item
notes_to_write: List[Tuple[str, str]] = []
# 1. Explicit arguments always take precedence
if note_name and note_text:
notes_to_write.append((note_name, note_text))
# 2. Pipeline notes auto-ingestion
# Look for 'notes' dictionary in the item (propagated by pipeline/download-file)
# Structure: {'notes': {'lyric': '...', 'sub': '...'}}
# Check both root and nested 'extra'
# Check root 'notes' (dict or extra.notes)
pipeline_notes = res.get("notes")
if not isinstance(pipeline_notes, dict):
extra = res.get("extra")
if isinstance(extra, dict):
pipeline_notes = extra.get("notes")
if isinstance(pipeline_notes, dict):
for k, v in pipeline_notes.items():
# If arg-provided note conflicts effectively with pipeline note?
# We just append both.
if v and str(v).strip():
notes_to_write.append((str(k), str(v)))
if not notes_to_write:
# Pass through items that have nothing to add
ctx.emit(res)
continue
store_name = str(store_override or res.get("store") or "").strip()
raw_hash = res.get("hash")
@@ -298,7 +332,7 @@ class Add_Note(Cmdlet):
"[add_note] Error: Missing -store and item has no store field",
file=sys.stderr
)
return 1
continue
resolved_hash = self._resolve_hash(
raw_hash=str(raw_hash) if raw_hash else None,
@@ -312,80 +346,43 @@ class Add_Note(Cmdlet):
)
ctx.emit(res)
continue
try:
backend = store_registry[store_name]
except Exception as exc:
log(
f"[add_note] Error: Unknown store '{store_name}': {exc}",
file=sys.stderr
)
return 1
# Queue for bulk write per store. We still emit items immediately;
# the pipeline only advances after this cmdlet returns.
note_ops.setdefault(store_name,
[]).append((resolved_hash,
note_name,
item_note_text))
planned_ops += 1
# Queue operations
if store_name not in note_ops:
note_ops[store_name] = []
for (n_name, n_text) in notes_to_write:
note_ops[store_name].append((resolved_hash, n_name, n_text))
planned_ops += 1
ctx.emit(res)
# Execute bulk writes per store.
successful_writes = 0
# Execute batch operations
success_count = 0
for store_name, ops in note_ops.items():
if not ops:
continue
try:
backend = store_registry[store_name]
except Exception:
continue
if not hasattr(backend, "set_note"):
log(f"[add_note] Store '{store_name}' does not support notes", file=sys.stderr)
continue
for (h, name, text) in ops:
try:
if backend.set_note(h, name, text, config=config):
success_count += 1
except Exception as e:
log(f"[add_note] Write failed {store_name}:{h} ({name}): {e}", file=sys.stderr)
except Exception as e:
log(f"[add_note] Store access failed '{store_name}': {e}", file=sys.stderr)
store_success = 0
bulk_fn = getattr(backend, "set_note_bulk", None)
if callable(bulk_fn):
try:
ok = bool(bulk_fn(list(ops), config=config))
if ok:
store_success += len(ops)
ctx.print_if_visible(
f"✓ add-note: {len(ops)} item(s) in '{store_name}'",
file=sys.stderr
)
successful_writes += store_success
continue
log(
f"[add_note] Warning: bulk set_note returned False for '{store_name}'",
file=sys.stderr,
)
except Exception as exc:
log(
f"[add_note] Warning: bulk set_note failed for '{store_name}': {exc}; falling back",
file=sys.stderr,
)
# Fallback: per-item writes
for file_hash, name, text in ops:
try:
ok = bool(backend.set_note(file_hash, name, text, config=config))
if ok:
store_success += 1
except Exception:
continue
if store_success:
successful_writes += store_success
ctx.print_if_visible(
f"✓ add-note: {store_success} item(s) in '{store_name}'",
file=sys.stderr
)
log(
f"[add_note] Updated {successful_writes}/{planned_ops} item(s)",
file=sys.stderr
)
return 0 if successful_writes > 0 else 1
if planned_ops > 0:
msg = f"✓ add-note: Updated {success_count}/{planned_ops} notes across {len(note_ops)} stores"
ctx.print_if_visible(msg, file=sys.stderr)
return 0
CMDLET = Add_Note()