dfdf
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
"""Delete-file cmdlet: Delete files from local storage and/or Hydrus."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Sequence
|
||||
from typing import Any, Dict, List, Sequence
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from SYS.logger import debug, log
|
||||
from SYS.utils import format_bytes
|
||||
from Store.Folder import Folder
|
||||
from Store import Store
|
||||
from . import _shared as sh
|
||||
from API import HydrusNetwork as hydrus_wrapper
|
||||
import pipeline as ctx
|
||||
from result_table import ResultTable, _format_size
|
||||
from rich_display import stdout_console
|
||||
|
||||
|
||||
class Delete_File(sh.Cmdlet):
|
||||
@@ -38,9 +41,20 @@ class Delete_File(sh.Cmdlet):
|
||||
)
|
||||
self.register()
|
||||
|
||||
def _process_single_item(self, item: Any, override_hash: str | None, conserve: str | None,
|
||||
lib_root: str | None, reason: str, config: Dict[str, Any]) -> bool:
|
||||
"""Process deletion for a single item."""
|
||||
def _process_single_item(
|
||||
self,
|
||||
item: Any,
|
||||
override_hash: str | None,
|
||||
conserve: str | None,
|
||||
lib_root: str | None,
|
||||
reason: str,
|
||||
config: Dict[str, Any],
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Process deletion for a single item.
|
||||
|
||||
Returns display rows (for the final Rich table). Returning an empty list
|
||||
indicates no delete occurred.
|
||||
"""
|
||||
# Handle item as either dict or object
|
||||
if isinstance(item, dict):
|
||||
hash_hex_raw = item.get("hash_hex") or item.get("hash")
|
||||
@@ -50,6 +64,44 @@ class Delete_File(sh.Cmdlet):
|
||||
hash_hex_raw = sh.get_field(item, "hash_hex") or sh.get_field(item, "hash")
|
||||
target = sh.get_field(item, "target") or sh.get_field(item, "file_path") or sh.get_field(item, "path")
|
||||
title_val = sh.get_field(item, "title") or sh.get_field(item, "name")
|
||||
|
||||
def _get_ext_from_item() -> str:
|
||||
try:
|
||||
if isinstance(item, dict):
|
||||
ext_val = item.get("ext")
|
||||
if ext_val:
|
||||
return str(ext_val)
|
||||
extra = item.get("extra")
|
||||
if isinstance(extra, dict) and extra.get("ext"):
|
||||
return str(extra.get("ext"))
|
||||
else:
|
||||
ext_val = sh.get_field(item, "ext")
|
||||
if ext_val:
|
||||
return str(ext_val)
|
||||
extra = sh.get_field(item, "extra")
|
||||
if isinstance(extra, dict) and extra.get("ext"):
|
||||
return str(extra.get("ext"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback: infer from target path or title if it looks like a filename
|
||||
try:
|
||||
if isinstance(target, str) and target:
|
||||
suffix = Path(target).suffix
|
||||
if suffix:
|
||||
return suffix.lstrip(".")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
if title_val:
|
||||
suffix = Path(str(title_val)).suffix
|
||||
if suffix:
|
||||
return suffix.lstrip(".")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return ""
|
||||
|
||||
store = None
|
||||
if isinstance(item, dict):
|
||||
@@ -70,9 +122,16 @@ class Delete_File(sh.Cmdlet):
|
||||
|
||||
local_deleted = False
|
||||
local_target = isinstance(target, str) and target.strip() and not str(target).lower().startswith(("http://", "https://"))
|
||||
deleted_rows: List[Dict[str, Any]] = []
|
||||
|
||||
if conserve != "local" and local_target:
|
||||
path = Path(str(target))
|
||||
size_bytes: int | None = None
|
||||
try:
|
||||
if path.exists() and path.is_file():
|
||||
size_bytes = int(path.stat().st_size)
|
||||
except Exception:
|
||||
size_bytes = None
|
||||
|
||||
# If lib_root is provided and this is from a folder store, use the Folder class
|
||||
if lib_root:
|
||||
@@ -80,8 +139,15 @@ class Delete_File(sh.Cmdlet):
|
||||
folder = Folder(Path(lib_root), name=store or "local")
|
||||
if folder.delete_file(str(path)):
|
||||
local_deleted = True
|
||||
ctx.emit(f"Removed file: {path.name}")
|
||||
log(f"Deleted: {path.name}", file=sys.stderr)
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"size_bytes": size_bytes,
|
||||
"ext": _get_ext_from_item() or path.suffix.lstrip("."),
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
debug(f"Folder.delete_file failed: {exc}", file=sys.stderr)
|
||||
# Fallback to manual deletion
|
||||
@@ -89,8 +155,15 @@ class Delete_File(sh.Cmdlet):
|
||||
if path.exists() and path.is_file():
|
||||
path.unlink()
|
||||
local_deleted = True
|
||||
ctx.emit(f"Removed local file: {path}")
|
||||
log(f"Deleted: {path.name}", file=sys.stderr)
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"size_bytes": size_bytes,
|
||||
"ext": _get_ext_from_item() or path.suffix.lstrip("."),
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
log(f"Local delete failed: {exc}", file=sys.stderr)
|
||||
else:
|
||||
@@ -99,8 +172,15 @@ class Delete_File(sh.Cmdlet):
|
||||
if path.exists() and path.is_file():
|
||||
path.unlink()
|
||||
local_deleted = True
|
||||
ctx.emit(f"Removed local file: {path}")
|
||||
log(f"Deleted: {path.name}", file=sys.stderr)
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else path.name,
|
||||
"store": store_label,
|
||||
"hash": hash_hex or sh.normalize_hash(path.stem) or "",
|
||||
"size_bytes": size_bytes,
|
||||
"ext": _get_ext_from_item() or path.suffix.lstrip("."),
|
||||
}
|
||||
)
|
||||
except Exception as exc:
|
||||
log(f"Local delete failed: {exc}", file=sys.stderr)
|
||||
|
||||
@@ -168,26 +248,32 @@ class Delete_File(sh.Cmdlet):
|
||||
except Exception:
|
||||
# If it's not in Hydrus (e.g. 404 or similar), that's fine
|
||||
if not local_deleted:
|
||||
return False
|
||||
return []
|
||||
|
||||
if hydrus_deleted and hash_hex:
|
||||
title_str = str(title_val).strip() if title_val else ""
|
||||
if reason:
|
||||
if title_str:
|
||||
ctx.emit(f"{hydrus_prefix} Deleted title:{title_str} hash:{hash_hex} (reason: {reason}).")
|
||||
size_hint = None
|
||||
try:
|
||||
if isinstance(item, dict):
|
||||
size_hint = item.get("size_bytes") or item.get("size")
|
||||
else:
|
||||
ctx.emit(f"{hydrus_prefix} Deleted hash:{hash_hex} (reason: {reason}).")
|
||||
else:
|
||||
if title_str:
|
||||
ctx.emit(f"{hydrus_prefix} Deleted title:{title_str} hash:{hash_hex}.")
|
||||
else:
|
||||
ctx.emit(f"{hydrus_prefix} Deleted hash:{hash_hex}.")
|
||||
size_hint = sh.get_field(item, "size_bytes") or sh.get_field(item, "size")
|
||||
except Exception:
|
||||
size_hint = None
|
||||
deleted_rows.append(
|
||||
{
|
||||
"title": str(title_val).strip() if title_val else "",
|
||||
"store": store_label,
|
||||
"hash": hash_hex,
|
||||
"size_bytes": size_hint,
|
||||
"ext": _get_ext_from_item(),
|
||||
}
|
||||
)
|
||||
|
||||
if hydrus_deleted or local_deleted:
|
||||
return True
|
||||
return deleted_rows
|
||||
|
||||
log("Selected result has neither Hydrus hash nor local file target")
|
||||
return False
|
||||
return []
|
||||
|
||||
def run(self, result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
"""Execute delete-file command."""
|
||||
@@ -257,15 +343,34 @@ class Delete_File(sh.Cmdlet):
|
||||
return 1
|
||||
|
||||
success_count = 0
|
||||
deleted_rows: List[Dict[str, Any]] = []
|
||||
for item in items:
|
||||
if self._process_single_item(item, override_hash, conserve, lib_root, reason, config):
|
||||
rows = self._process_single_item(item, override_hash, conserve, lib_root, reason, config)
|
||||
if rows:
|
||||
success_count += 1
|
||||
deleted_rows.extend(rows)
|
||||
|
||||
if success_count > 0:
|
||||
# Clear cached tables/items so deleted entries are not redisplayed
|
||||
if deleted_rows:
|
||||
table = ResultTable("Deleted")
|
||||
table.set_no_choice(True).set_preserve_order(True)
|
||||
for row in deleted_rows:
|
||||
result_row = table.add_row()
|
||||
result_row.add_column("Title", row.get("title", ""))
|
||||
result_row.add_column("Store", row.get("store", ""))
|
||||
result_row.add_column("Hash", row.get("hash", ""))
|
||||
result_row.add_column("Size", _format_size(row.get("size_bytes"), integer_only=False))
|
||||
result_row.add_column("Ext", row.get("ext", ""))
|
||||
|
||||
# Display-only: print directly and do not affect selection/history.
|
||||
try:
|
||||
stdout_console().print()
|
||||
stdout_console().print(table)
|
||||
setattr(table, "_rendered_by_cmdlet", True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Ensure no stale overlay/selection carries forward.
|
||||
try:
|
||||
ctx.set_last_result_table_overlay(None, None, None)
|
||||
ctx.set_last_result_table(None, [])
|
||||
ctx.set_last_result_items_only([])
|
||||
ctx.set_current_stage_table(None)
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user