from __future__ import annotations from typing import Any, Dict, Sequence import json import sys from pathlib import Path from . import register from helper import hydrus as hydrus_wrapper from ._shared import Cmdlet, CmdletArg, normalize_hash from helper.logger import log from config import get_local_storage_path from helper.local_library import LocalLibraryDB import pipeline as ctx CMDLET = Cmdlet( name="delete-url", summary="Remove a URL association from a file (Hydrus or Local).", usage="delete-url [-hash ] ", args=[ CmdletArg("-hash", description="Override the Hydrus file hash (SHA256) to target instead of the selected result."), CmdletArg("url", required=True, description="The URL to remove from the file."), ], details=[ "- Removes the URL from the file's known URL list.", ], ) def _parse_hash_and_rest(args: Sequence[str]) -> tuple[str | None, list[str]]: override_hash: str | None = None rest: list[str] = [] i = 0 while i < len(args): a = args[i] low = str(a).lower() if low in {"-hash", "--hash", "hash"} and i + 1 < len(args): override_hash = str(args[i + 1]).strip() i += 2 continue rest.append(a) i += 1 return override_hash, rest @register(["del-url", "delete-url", "delete_url"]) # aliases def delete(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int: # Help try: if any(str(a).lower() in {"-?", "/?", "--help", "-h", "help", "--cmdlet"} for a in args): log(json.dumps(CMDLET, ensure_ascii=False, indent=2)) return 0 except Exception: pass override_hash, rest = _parse_hash_and_rest(args) url_arg = None if rest: url_arg = str(rest[0] or '').strip() # Normalize result to a list items = result if isinstance(result, list) else [result] if not items: log("No input provided.") return 1 success_count = 0 for item in items: target_url = url_arg target_file = item # Check for rich URL object from get-url if isinstance(item, dict) and "url" in item and "source_file" in item: if not target_url: target_url = item["url"] target_file = item["source_file"] if not target_url: continue if _delete_single(target_file, target_url, override_hash, config): success_count += 1 if success_count == 0: if not url_arg: log("Requires a URL argument or valid selection.") else: log("Failed to delete URL(s).") return 1 return 0 def _delete_single(result: Any, url: str, override_hash: str | None, config: Dict[str, Any]) -> bool: # Helper to get field from both dict and object def get_field(obj: Any, field: str, default: Any = None) -> Any: if isinstance(obj, dict): return obj.get(field, default) else: return getattr(obj, field, default) success = False # 1. Try Local Library file_path = get_field(result, "file_path") or get_field(result, "path") if file_path and not override_hash: try: path_obj = Path(file_path) if path_obj.exists(): storage_path = get_local_storage_path(config) if storage_path: with LocalLibraryDB(storage_path) as db: metadata = db.get_metadata(path_obj) or {} known_urls = metadata.get("known_urls") or [] # Handle comma-separated URLs if passed as arg # But first check if the exact url string exists (e.g. if it contains commas itself) urls_to_process = [] if url in known_urls: urls_to_process = [url] else: urls_to_process = [u.strip() for u in url.split(',') if u.strip()] local_changed = False for u in urls_to_process: if u in known_urls: known_urls.remove(u) local_changed = True ctx.emit(f"Deleted URL from local file {path_obj.name}: {u}") if local_changed: metadata["known_urls"] = known_urls db.save_metadata(path_obj, metadata) success = True except Exception as e: log(f"Error updating local library: {e}", file=sys.stderr) # 2. Try Hydrus hash_hex = normalize_hash(override_hash) if override_hash else normalize_hash(get_field(result, "hash_hex", None)) if hash_hex: try: client = hydrus_wrapper.get_client(config) if client: urls_to_delete = [u.strip() for u in url.split(',') if u.strip()] for u in urls_to_delete: client.delete_url(hash_hex, u) preview = hash_hex[:12] + ('…' if len(hash_hex) > 12 else '') ctx.emit(f"Deleted URL from Hydrus file {preview}: {u}") success = True except Exception as exc: log(f"Hydrus del-url failed: {exc}", file=sys.stderr) return success