df
This commit is contained in:
@@ -27,6 +27,8 @@ class UrlItem:
|
||||
hash: str
|
||||
store: str
|
||||
title: str = ""
|
||||
size: int | None = None
|
||||
ext: str = ""
|
||||
|
||||
|
||||
class Get_Url(Cmdlet):
|
||||
@@ -183,6 +185,58 @@ class Get_Url(Cmdlet):
|
||||
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _resolve_size_ext_for_hash(backend: Any, file_hash: str, hit: Any = None) -> tuple[int | None, str]:
|
||||
"""Best-effort (size, ext) resolution for a found hash."""
|
||||
# First: see if the hit already includes these fields.
|
||||
try:
|
||||
size_val = get_field(hit, "size")
|
||||
if size_val is None:
|
||||
size_val = get_field(hit, "file_size")
|
||||
if size_val is None:
|
||||
size_val = get_field(hit, "filesize")
|
||||
if size_val is None:
|
||||
size_val = get_field(hit, "size_bytes")
|
||||
size_int = int(size_val) if isinstance(size_val, (int, float)) else None
|
||||
except Exception:
|
||||
size_int = None
|
||||
|
||||
try:
|
||||
ext_val = get_field(hit, "ext")
|
||||
if ext_val is None:
|
||||
ext_val = get_field(hit, "extension")
|
||||
ext = str(ext_val).strip().lstrip(".") if isinstance(ext_val, str) else ""
|
||||
except Exception:
|
||||
ext = ""
|
||||
|
||||
if size_int is not None or ext:
|
||||
return size_int, ext
|
||||
|
||||
# Next: backend.get_metadata(hash) when available.
|
||||
try:
|
||||
if hasattr(backend, "get_metadata"):
|
||||
meta = backend.get_metadata(file_hash)
|
||||
if isinstance(meta, dict):
|
||||
size_val2 = meta.get("size")
|
||||
if size_val2 is None:
|
||||
size_val2 = meta.get("file_size")
|
||||
if size_val2 is None:
|
||||
size_val2 = meta.get("filesize")
|
||||
if size_val2 is None:
|
||||
size_val2 = meta.get("size_bytes")
|
||||
if isinstance(size_val2, (int, float)):
|
||||
size_int = int(size_val2)
|
||||
|
||||
ext_val2 = meta.get("ext")
|
||||
if ext_val2 is None:
|
||||
ext_val2 = meta.get("extension")
|
||||
if isinstance(ext_val2, str) and ext_val2.strip():
|
||||
ext = ext_val2.strip().lstrip(".")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return size_int, ext
|
||||
|
||||
def _search_urls_across_stores(self,
|
||||
pattern: str,
|
||||
config: Dict[str,
|
||||
@@ -210,6 +264,7 @@ class Get_Url(Cmdlet):
|
||||
backend = storage[store_name]
|
||||
|
||||
title_cache: Dict[str, str] = {}
|
||||
meta_cache: Dict[str, tuple[int | None, str]] = {}
|
||||
|
||||
# Search only URL-bearing records using the backend's URL search capability.
|
||||
# This avoids the expensive/incorrect "search('*')" scan.
|
||||
@@ -250,6 +305,11 @@ class Get_Url(Cmdlet):
|
||||
title = self._resolve_title_for_hash(backend, file_hash, hit)
|
||||
title_cache[file_hash] = title
|
||||
|
||||
size, ext = meta_cache.get(file_hash, (None, ""))
|
||||
if size is None and not ext:
|
||||
size, ext = self._resolve_size_ext_for_hash(backend, file_hash, hit)
|
||||
meta_cache[file_hash] = (size, ext)
|
||||
|
||||
try:
|
||||
urls = backend.get_url(file_hash)
|
||||
except Exception:
|
||||
@@ -264,6 +324,8 @@ class Get_Url(Cmdlet):
|
||||
hash=str(file_hash),
|
||||
store=str(store_name),
|
||||
title=str(title or ""),
|
||||
size=size,
|
||||
ext=str(ext or ""),
|
||||
)
|
||||
)
|
||||
found_stores.add(str(store_name))
|
||||
@@ -308,22 +370,44 @@ class Get_Url(Cmdlet):
|
||||
log(f"No urls matching pattern: {search_pattern}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# NOTE: The CLI can auto-render tables from emitted items. When emitting
|
||||
# dataclass objects, the generic-object renderer will include `hash` as a
|
||||
# visible column. To keep HASH available for chaining but hidden from the
|
||||
# table, emit dicts (dict rendering hides `hash`) and provide an explicit
|
||||
# `columns` list to force display order and size formatting.
|
||||
display_items: List[Dict[str, Any]] = []
|
||||
|
||||
table = (
|
||||
ResultTable(
|
||||
"URL Search Results",
|
||||
max_columns=3
|
||||
).set_preserve_order(True).set_table("urls").set_value_case("preserve")
|
||||
"url",
|
||||
max_columns=5
|
||||
).set_preserve_order(True).set_table("url").set_value_case("preserve")
|
||||
)
|
||||
table.set_source_command("get-url", ["-url", search_pattern])
|
||||
|
||||
for item in items:
|
||||
row = table.add_row()
|
||||
row.add_column("Title", item.title)
|
||||
row.add_column("Url", item.url)
|
||||
row.add_column("Store", item.store)
|
||||
ctx.emit(item)
|
||||
payload: Dict[str, Any] = {
|
||||
# Keep fields for downstream cmdlets.
|
||||
"hash": item.hash,
|
||||
"store": item.store,
|
||||
"url": item.url,
|
||||
"title": item.title,
|
||||
"size": item.size,
|
||||
"ext": item.ext,
|
||||
# Force the visible table columns + ordering.
|
||||
"columns": [
|
||||
("Title", item.title),
|
||||
("Url", item.url),
|
||||
("Size", item.size),
|
||||
("Ext", item.ext),
|
||||
("Store", item.store),
|
||||
],
|
||||
}
|
||||
display_items.append(payload)
|
||||
table.add_result(payload)
|
||||
ctx.emit(payload)
|
||||
|
||||
ctx.set_last_result_table(table if items else None, items, subject=result)
|
||||
ctx.set_last_result_table(table if display_items else None, display_items, subject=result)
|
||||
log(
|
||||
f"Found {len(items)} matching url(s) in {len(stores_searched)} store(s)"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user