2025-11-25 20:09:33 -08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from typing import Any, Dict, Sequence
|
2025-12-01 01:10:16 -08:00
|
|
|
import sys
|
2025-11-25 20:09:33 -08:00
|
|
|
|
|
|
|
|
import pipeline as ctx
|
2025-12-16 23:23:43 -08:00
|
|
|
from . import _shared as sh
|
2025-12-11 19:04:02 -08:00
|
|
|
from SYS.logger import log
|
|
|
|
|
from Store import Store
|
2025-11-25 20:09:33 -08:00
|
|
|
|
|
|
|
|
|
2025-12-16 23:23:43 -08:00
|
|
|
class Add_Url(sh.Cmdlet):
|
2025-12-11 12:47:30 -08:00
|
|
|
"""Add URL associations to files via hash+store."""
|
2025-12-14 00:53:52 -08:00
|
|
|
|
|
|
|
|
def __init__(self) -> None:
|
|
|
|
|
super().__init__(
|
|
|
|
|
name="add-url",
|
|
|
|
|
summary="Associate a URL with a file",
|
|
|
|
|
usage="@1 | add-url <url>",
|
|
|
|
|
arg=[
|
2025-12-20 02:12:45 -08:00
|
|
|
sh.SharedArgs.QUERY,
|
2025-12-16 23:23:43 -08:00
|
|
|
sh.SharedArgs.STORE,
|
|
|
|
|
sh.CmdletArg("url", required=True, description="URL to associate"),
|
2025-12-14 00:53:52 -08:00
|
|
|
],
|
|
|
|
|
detail=[
|
|
|
|
|
"- Associates URL with file identified by hash+store",
|
|
|
|
|
"- Multiple url can be comma-separated",
|
|
|
|
|
],
|
|
|
|
|
exec=self.run,
|
|
|
|
|
)
|
|
|
|
|
self.register()
|
2025-11-25 20:09:33 -08:00
|
|
|
|
2025-12-11 12:47:30 -08:00
|
|
|
def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
|
|
|
|
"""Add URL to file via hash+store backend."""
|
2025-12-16 23:23:43 -08:00
|
|
|
parsed = sh.parse_cmdlet_args(args, self)
|
2025-12-20 02:12:45 -08:00
|
|
|
|
|
|
|
|
query_hash = sh.parse_single_hash_query(parsed.get("query"))
|
|
|
|
|
if parsed.get("query") and not query_hash:
|
|
|
|
|
log("Error: -query must be of the form hash:<sha256>")
|
|
|
|
|
return 1
|
2025-12-01 01:10:16 -08:00
|
|
|
|
2025-12-11 12:47:30 -08:00
|
|
|
# Extract hash and store from result or args
|
2025-12-20 02:12:45 -08:00
|
|
|
file_hash = query_hash or sh.get_field(result, "hash")
|
2025-12-16 23:23:43 -08:00
|
|
|
store_name = parsed.get("store") or sh.get_field(result, "store")
|
2025-12-11 12:47:30 -08:00
|
|
|
url_arg = parsed.get("url")
|
|
|
|
|
|
|
|
|
|
if not file_hash:
|
2025-12-20 02:12:45 -08:00
|
|
|
log("Error: No file hash provided (pipe an item or use -query \"hash:<sha256>\")")
|
2025-12-11 12:47:30 -08:00
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
if not store_name:
|
|
|
|
|
log("Error: No store name provided")
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
if not url_arg:
|
|
|
|
|
log("Error: No URL provided")
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
# Normalize hash
|
2025-12-16 23:23:43 -08:00
|
|
|
file_hash = sh.normalize_hash(file_hash)
|
2025-12-11 12:47:30 -08:00
|
|
|
if not file_hash:
|
|
|
|
|
log("Error: Invalid hash format")
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
# Parse url (comma-separated)
|
2025-12-11 19:04:02 -08:00
|
|
|
urls = [u.strip() for u in str(url_arg).split(',') if u.strip()]
|
|
|
|
|
if not urls:
|
2025-12-11 12:47:30 -08:00
|
|
|
log("Error: No valid url provided")
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
# Get backend and add url
|
2025-12-01 01:10:16 -08:00
|
|
|
try:
|
2025-12-11 19:04:02 -08:00
|
|
|
storage = Store(config)
|
2025-12-11 12:47:30 -08:00
|
|
|
backend = storage[store_name]
|
2025-12-11 19:04:02 -08:00
|
|
|
|
|
|
|
|
backend.add_url(file_hash, urls)
|
|
|
|
|
for u in urls:
|
|
|
|
|
ctx.emit(f"Added URL: {u}")
|
2025-12-11 12:47:30 -08:00
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
except KeyError:
|
|
|
|
|
log(f"Error: Storage backend '{store_name}' not configured")
|
|
|
|
|
return 1
|
2025-12-01 01:10:16 -08:00
|
|
|
except Exception as exc:
|
2025-12-11 12:47:30 -08:00
|
|
|
log(f"Error adding URL: {exc}", file=sys.stderr)
|
|
|
|
|
return 1
|
2025-12-01 01:10:16 -08:00
|
|
|
|
2025-12-11 12:47:30 -08:00
|
|
|
|
2025-12-14 00:53:52 -08:00
|
|
|
CMDLET = Add_Url()
|
2025-11-25 20:09:33 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|