This commit is contained in:
nose
2025-12-19 02:29:42 -08:00
parent d637532237
commit 52cf3f5c9f
24 changed files with 1284 additions and 176 deletions

View File

@@ -15,6 +15,7 @@ from SYS.logger import log, debug
from SYS.utils_constant import ALL_SUPPORTED_EXTENSIONS
from Store import Store
from . import _shared as sh
from result_table import ResultTable
Cmdlet = sh.Cmdlet
CmdletArg = sh.CmdletArg
@@ -49,6 +50,13 @@ class Add_File(Cmdlet):
SharedArgs.STORE,
SharedArgs.HASH,
CmdletArg(name="provider", type="string", required=False, description="File hosting provider (e.g., 0x0)", alias="prov"),
CmdletArg(
name="room",
type="string",
required=False,
description="Matrix room_id (when -provider matrix). If omitted, a room picker table is shown.",
alias="room_id",
),
CmdletArg(name="delete", type="flag", required=False, description="Delete file after successful upload", alias="del"),
],
detail=[
@@ -70,6 +78,7 @@ class Add_File(Cmdlet):
path_arg = parsed.get("path")
location = parsed.get("store")
provider_name = parsed.get("provider")
provider_room = parsed.get("room")
delete_after = parsed.get("delete", False)
stage_ctx = ctx.get_stage_context()
@@ -250,7 +259,31 @@ class Add_File(Cmdlet):
continue
if provider_name:
code = self._handle_provider_upload(media_path, provider_name, pipe_obj, config, delete_after_item)
# Matrix provider can prompt for a room selection if one is not configured.
if str(provider_name).strip().lower() == "matrix":
room_id = None
if provider_room:
room_id = str(provider_room).strip()
if not room_id:
try:
matrix_conf = config.get("provider", {}).get("matrix", {}) if isinstance(config, dict) else {}
room_id = str(matrix_conf.get("room_id") or "").strip() or None
except Exception:
room_id = None
if not room_id:
pending = [
{
"path": str(media_path),
"pipe_obj": pipe_obj,
"delete_after": bool(delete_after_item),
}
]
return self._matrix_prompt_room_selection(pending, config, list(args))
code = self._handle_matrix_upload(media_path, pipe_obj, config, delete_after_item, room_id=room_id)
else:
code = self._handle_provider_upload(media_path, provider_name, pipe_obj, config, delete_after_item)
if code == 0:
successes += 1
else:
@@ -1496,6 +1529,134 @@ class Add_File(Cmdlet):
debug(f"[add-file] Soulseek download traceback: {e}")
return None
@staticmethod
def _handle_matrix_upload(
media_path: Path,
pipe_obj: models.PipeObject,
config: Dict[str, Any],
delete_after: bool,
*,
room_id: str,
) -> int:
"""Upload to Matrix and update the PipeObject.
Matrix needs a room_id. If you don't have one, use the interactive
room picker path which resumes via `-matrix-send`.
"""
from Provider.matrix import Matrix
log(f"Uploading via matrix: {media_path.name}", file=sys.stderr)
try:
provider = Matrix(config)
except Exception as exc:
log(f"Matrix not available: {exc}", file=sys.stderr)
return 1
try:
hoster_url = provider.upload_to_room(str(media_path), str(room_id))
log(f"File uploaded: {hoster_url}", file=sys.stderr)
# Associate URL with Hydrus if possible
f_hash = Add_File._resolve_file_hash(None, media_path, pipe_obj, None)
if f_hash:
try:
store_name = getattr(pipe_obj, "store", None)
if store_name:
store = Store(config)
backend = store[str(store_name)]
client = getattr(backend, "_client", None)
if client is not None and hasattr(client, "associate_url"):
client.associate_url(str(f_hash), hoster_url)
except Exception:
pass
except Exception as exc:
log(f"Upload failed: {exc}", file=sys.stderr)
return 1
# Update PipeObject and emit
extra_updates: Dict[str, Any] = {
"provider": "matrix",
"provider_url": hoster_url,
"room_id": str(room_id),
}
if isinstance(pipe_obj.extra, dict):
existing_known = list(pipe_obj.extra.get("url") or [])
if hoster_url and hoster_url not in existing_known:
existing_known.append(hoster_url)
extra_updates["url"] = existing_known
file_path = pipe_obj.path or (str(media_path) if media_path else None) or ""
Add_File._update_pipe_object_destination(
pipe_obj,
hash_value=f_hash or "unknown",
store="matrix",
path=file_path,
tag=pipe_obj.tag,
title=pipe_obj.title or (media_path.name if media_path else None),
extra_updates=extra_updates,
)
Add_File._emit_pipe_object(pipe_obj)
Add_File._cleanup_after_success(media_path, delete_source=bool(delete_after))
return 0
@staticmethod
def _matrix_prompt_room_selection(
pending_items: List[Dict[str, Any]],
config: Dict[str, Any],
original_args: List[str],
) -> int:
"""Show rooms table and pause pipeline for @N selection."""
from Provider.matrix import Matrix
# Stash pending uploads so @N on the matrix table can trigger Matrix.upload_to_room.
ctx.store_value("matrix_pending_uploads", pending_items)
try:
provider = Matrix(config)
except Exception as exc:
log(f"Matrix not available: {exc}", file=sys.stderr)
return 1
try:
rooms = provider.list_rooms()
except Exception as exc:
log(f"Failed to list Matrix rooms: {exc}", file=sys.stderr)
return 1
if not rooms:
log("No joined rooms found.", file=sys.stderr)
return 0
table = ResultTable("Matrix Rooms")
table.set_table("matrix")
table.set_source_command("add-file", list(original_args or []))
for room in rooms:
row = table.add_row()
name = str(room.get("name") or "").strip() if isinstance(room, dict) else ""
rid = str(room.get("room_id") or "").strip() if isinstance(room, dict) else ""
row.add_column("Name", name)
row.add_column("Room", rid)
room_items: List[Dict[str, Any]] = []
for room in rooms:
if not isinstance(room, dict):
continue
rid = str(room.get("room_id") or "").strip()
name = str(room.get("name") or "").strip()
room_items.append({**room, "store": "matrix", "provider": "matrix", "title": name or rid or "Matrix Room"})
# Overlay table: user selects @N on this Matrix rooms table to upload.
ctx.set_last_result_table_overlay(table, room_items)
ctx.set_current_stage_table(table)
print()
print(table.format_plain())
print("\nSelect room(s) with @N (e.g. @1 or @1-3) to upload the selected item(s)")
return 0
@staticmethod
def _handle_provider_upload(
media_path: Path,