f
This commit is contained in:
217
cmdnat/matrix.py
217
cmdnat/matrix.py
@@ -223,6 +223,191 @@ def _room_id_matches_filter(room_id: str, allowed_ids_canon: set[str]) -> bool:
|
||||
return bool(base) and base in allowed_ids_canon
|
||||
|
||||
|
||||
def _extract_room_arg(args: Sequence[str]) -> Optional[str]:
|
||||
"""Extract the `-room <value>` argument from a cmdnat args list."""
|
||||
if not args:
|
||||
return None
|
||||
try:
|
||||
tokens = list(args)
|
||||
except Exception:
|
||||
return None
|
||||
for i, tok in enumerate(tokens):
|
||||
try:
|
||||
low = str(tok or "").strip()
|
||||
if not low:
|
||||
continue
|
||||
low_lower = low.lower()
|
||||
if low_lower in ("-room", "--room") and i + 1 < len(tokens):
|
||||
return str(tokens[i + 1] or "").strip()
|
||||
if low_lower.startswith("-room=") or low_lower.startswith("--room="):
|
||||
parts = low.split("=", 1)
|
||||
if len(parts) > 1:
|
||||
return parts[1].strip()
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def _resolve_room_identifier(value: str, config: Dict[str, Any]) -> Optional[str]:
|
||||
"""Resolve a user-provided room identifier (display name or id) to a Matrix room_id.
|
||||
|
||||
Returns the canonical room_id string on success, otherwise None.
|
||||
"""
|
||||
try:
|
||||
cand = str(value or "").strip()
|
||||
if not cand:
|
||||
return None
|
||||
|
||||
# If looks like an id already (starts with '!'), accept it as-is
|
||||
if cand.startswith("!"):
|
||||
return cand
|
||||
|
||||
# First try to resolve against configured default rooms (fast, local)
|
||||
conf_ids = _parse_config_room_filter_ids(config)
|
||||
if conf_ids:
|
||||
# Attempt to fetch names for the configured IDs
|
||||
try:
|
||||
from Provider.matrix import Matrix
|
||||
# Avoid __init__ network failures by requiring homeserver+token to exist
|
||||
block = config.get("provider", {}).get("matrix", {})
|
||||
if block and block.get("homeserver") and block.get("access_token"):
|
||||
try:
|
||||
m = Matrix(config)
|
||||
rooms = m.list_rooms(room_ids=conf_ids)
|
||||
for room in rooms or []:
|
||||
name = str(room.get("name") or "").strip()
|
||||
rid = str(room.get("room_id") or "").strip()
|
||||
if name and name.lower() == cand.lower():
|
||||
return rid
|
||||
if name and cand.lower() in name.lower():
|
||||
return rid
|
||||
except Exception:
|
||||
# Best-effort; fallback below
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Last resort: attempt to ask the server for matching rooms (if possible)
|
||||
try:
|
||||
from Provider.matrix import Matrix
|
||||
block = config.get("provider", {}).get("matrix", {})
|
||||
if block and block.get("homeserver") and block.get("access_token"):
|
||||
try:
|
||||
m = Matrix(config)
|
||||
rooms = m.list_rooms()
|
||||
for room in rooms or []:
|
||||
name = str(room.get("name") or "").strip()
|
||||
rid = str(room.get("room_id") or "").strip()
|
||||
if name and name.lower() == cand.lower():
|
||||
return rid
|
||||
if name and cand.lower() in name.lower():
|
||||
return rid
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _send_pending_to_rooms(config: Dict[str, Any], room_ids: List[str], args: Sequence[str]) -> int:
|
||||
"""Send currently pending items to the specified list of room_ids.
|
||||
|
||||
This function mirrors the existing -send behavior but accepts explicit
|
||||
room_ids so the same logic can be reused for -room direct invocation.
|
||||
"""
|
||||
pending_items = ctx.load_value(_MATRIX_PENDING_ITEMS_KEY, default=[])
|
||||
items = _normalize_to_list(pending_items)
|
||||
if not items:
|
||||
log("No pending items to upload (use: @N | .matrix)", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
from Provider.matrix import Matrix
|
||||
|
||||
try:
|
||||
provider = Matrix(config)
|
||||
except Exception as exc:
|
||||
log(f"Matrix not available: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
text_value = _extract_text_arg(args)
|
||||
if not text_value:
|
||||
try:
|
||||
text_value = str(ctx.load_value(_MATRIX_PENDING_TEXT_KEY, default="") or "").strip()
|
||||
except Exception:
|
||||
text_value = ""
|
||||
|
||||
size_limit_bytes = _get_matrix_size_limit_bytes(config)
|
||||
size_limit_mb = (size_limit_bytes / (1024 * 1024)) if size_limit_bytes else None
|
||||
|
||||
# Resolve upload paths once
|
||||
upload_jobs: List[Dict[str, Any]] = []
|
||||
any_failed = False
|
||||
for item in items:
|
||||
file_path = _resolve_upload_path(item, config)
|
||||
if not file_path:
|
||||
any_failed = True
|
||||
log("Matrix upload requires a local file (path) or a direct URL on the selected item", file=sys.stderr)
|
||||
continue
|
||||
|
||||
media_path = Path(file_path)
|
||||
if not media_path.exists():
|
||||
any_failed = True
|
||||
log(f"Matrix upload file missing: {file_path}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
if size_limit_bytes is not None:
|
||||
try:
|
||||
byte_size = int(media_path.stat().st_size)
|
||||
except Exception:
|
||||
byte_size = -1
|
||||
if byte_size >= 0 and byte_size > size_limit_bytes:
|
||||
any_failed = True
|
||||
actual_mb = byte_size / (1024 * 1024)
|
||||
lim = float(size_limit_mb or 0)
|
||||
log(f"ERROR: file is too big, skipping: {media_path.name} ({actual_mb:.1f} MB > {lim:.1f} MB)", file=sys.stderr)
|
||||
continue
|
||||
|
||||
upload_jobs.append({
|
||||
"path": str(media_path),
|
||||
"pipe_obj": item
|
||||
})
|
||||
|
||||
for rid in room_ids:
|
||||
sent_any_for_room = False
|
||||
for job in upload_jobs:
|
||||
file_path = str(job.get("path") or "")
|
||||
if not file_path:
|
||||
continue
|
||||
try:
|
||||
link = provider.upload_to_room(file_path, rid, pipe_obj=job.get("pipe_obj"))
|
||||
debug(f"✓ Sent {Path(file_path).name} -> {rid}")
|
||||
if link:
|
||||
log(link)
|
||||
sent_any_for_room = True
|
||||
except Exception as exc:
|
||||
any_failed = True
|
||||
log(f"Matrix send failed for {Path(file_path).name}: {exc}", file=sys.stderr)
|
||||
|
||||
if text_value and sent_any_for_room:
|
||||
try:
|
||||
provider.send_text_to_room(text_value, rid)
|
||||
except Exception as exc:
|
||||
any_failed = True
|
||||
log(f"Matrix text send failed: {exc}", file=sys.stderr)
|
||||
|
||||
# Clear pending items once attempted
|
||||
ctx.store_value(_MATRIX_PENDING_ITEMS_KEY, [])
|
||||
try:
|
||||
ctx.store_value(_MATRIX_PENDING_TEXT_KEY, "")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return 1 if any_failed else 0
|
||||
|
||||
|
||||
def _extract_text_arg(args: Sequence[str]) -> str:
|
||||
"""Extract a `-text <value>` argument from a cmdnat args list."""
|
||||
if not args:
|
||||
@@ -1128,9 +1313,31 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# When piped (result has data), show rooms directly.
|
||||
# When not piped (first command), show main menu.
|
||||
# When piped (result has data), either send directly (if -room given)
|
||||
# or show rooms for interactive selection.
|
||||
if selected_items:
|
||||
# If user provided a -room argument, resolve it and send to the target(s)
|
||||
room_arg = _extract_room_arg(args)
|
||||
if room_arg:
|
||||
# Support comma-separated list of room names/ids
|
||||
requested = [r.strip() for r in room_arg.split(",") if r.strip()]
|
||||
resolved_ids: List[str] = []
|
||||
for req in requested:
|
||||
try:
|
||||
rid = _resolve_room_identifier(req, config)
|
||||
if rid:
|
||||
resolved_ids.append(rid)
|
||||
except Exception:
|
||||
# Ignore unresolved entries
|
||||
continue
|
||||
|
||||
if not resolved_ids:
|
||||
log("Could not resolve specified room(s). Opening room selection table instead.", file=sys.stderr)
|
||||
return _show_rooms_table(config)
|
||||
|
||||
# Proceed to send the pending items directly
|
||||
return _send_pending_to_rooms(config, resolved_ids, args)
|
||||
|
||||
return _show_rooms_table(config)
|
||||
else:
|
||||
return _show_main_menu()
|
||||
@@ -1185,6 +1392,12 @@ CMDLET = Cmdlet(
|
||||
description="Ignore config room filter and show all joined rooms",
|
||||
required=False,
|
||||
),
|
||||
CmdletArg(
|
||||
name="room",
|
||||
type="string",
|
||||
description="Target room (name or id). Comma-separated values supported. Autocomplete uses configured defaults.",
|
||||
required=False,
|
||||
),
|
||||
CmdletArg(
|
||||
name="text",
|
||||
type="string",
|
||||
|
||||
Reference in New Issue
Block a user