dfdsf
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Get tags from Hydrus or local sidecar metadata.
|
||||
|
||||
This cmdlet retrieves tags for a selected result, supporting both:
|
||||
- Hydrus Network (for files with hash_hex)
|
||||
- Hydrus Network (for files with hash)
|
||||
- Local sidecar files (.tags)
|
||||
|
||||
In interactive mode: navigate with numbers, add/delete tags
|
||||
@@ -12,15 +12,15 @@ from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
from helper.logger import log, debug
|
||||
from helper.metadata_search import get_metadata_provider, list_metadata_providers
|
||||
from SYS.logger import log, debug
|
||||
from Provider.metadata_provider import get_metadata_provider, list_metadata_providers
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
import pipeline as ctx
|
||||
from helper import hydrus
|
||||
from helper.folder_store import read_sidecar, write_sidecar, find_sidecar, FolderDB
|
||||
from API import HydrusNetwork
|
||||
from API.folder import read_sidecar, write_sidecar, find_sidecar, API_folder_store
|
||||
from ._shared import normalize_hash, looks_like_hash, Cmdlet, CmdletArg, SharedArgs, parse_cmdlet_args, get_field
|
||||
from config import get_local_storage_path
|
||||
|
||||
@@ -47,15 +47,14 @@ class TagItem:
|
||||
"""
|
||||
tag_name: str
|
||||
tag_index: int # 1-based index for user reference
|
||||
hash_hex: Optional[str] = None
|
||||
source: str = "hydrus"
|
||||
hash: Optional[str] = None
|
||||
store: str = "hydrus"
|
||||
service_name: Optional[str] = None
|
||||
file_path: Optional[str] = None
|
||||
path: Optional[str] = None
|
||||
|
||||
def __post_init__(self):
|
||||
# Make ResultTable happy by adding standard fields
|
||||
# NOTE: Don't set 'title' - we want only the tag column in ResultTable
|
||||
self.origin = self.source
|
||||
self.detail = f"Tag #{self.tag_index}"
|
||||
self.target = self.tag_name
|
||||
self.media_kind = "tag"
|
||||
@@ -65,20 +64,21 @@ class TagItem:
|
||||
return {
|
||||
"tag_name": self.tag_name,
|
||||
"tag_index": self.tag_index,
|
||||
"hash_hex": self.hash_hex,
|
||||
"source": self.source,
|
||||
"hash": self.hash,
|
||||
"store": self.store,
|
||||
"path": self.path,
|
||||
"service_name": self.service_name,
|
||||
}
|
||||
|
||||
|
||||
def _emit_tags_as_table(
|
||||
tags_list: List[str],
|
||||
hash_hex: Optional[str],
|
||||
source: str = "hydrus",
|
||||
file_hash: Optional[str],
|
||||
store: str = "hydrus",
|
||||
service_name: Optional[str] = None,
|
||||
config: Dict[str, Any] = None,
|
||||
item_title: Optional[str] = None,
|
||||
file_path: Optional[str] = None,
|
||||
path: Optional[str] = None,
|
||||
subject: Optional[Any] = None,
|
||||
) -> None:
|
||||
"""Emit tags as TagItem objects and display via ResultTable.
|
||||
@@ -92,8 +92,8 @@ def _emit_tags_as_table(
|
||||
table_title = "Tags"
|
||||
if item_title:
|
||||
table_title = f"Tags: {item_title}"
|
||||
if hash_hex:
|
||||
table_title += f" [{hash_hex[:8]}]"
|
||||
if file_hash:
|
||||
table_title += f" [{file_hash[:8]}]"
|
||||
|
||||
table = ResultTable(table_title, max_columns=1)
|
||||
table.set_source_command("get-tag", [])
|
||||
@@ -104,10 +104,10 @@ def _emit_tags_as_table(
|
||||
tag_item = TagItem(
|
||||
tag_name=tag_name,
|
||||
tag_index=idx,
|
||||
hash_hex=hash_hex,
|
||||
source=source,
|
||||
hash=file_hash,
|
||||
store=store,
|
||||
service_name=service_name,
|
||||
file_path=file_path,
|
||||
path=path,
|
||||
)
|
||||
tag_items.append(tag_item)
|
||||
table.add_result(tag_item)
|
||||
@@ -401,8 +401,8 @@ def _emit_tag_payload(source: str, tags_list: List[str], *, hash_value: Optional
|
||||
tag_item = TagItem(
|
||||
tag_name=tag_name,
|
||||
tag_index=idx,
|
||||
hash_hex=hash_value,
|
||||
source=source,
|
||||
hash=hash_value,
|
||||
store=source,
|
||||
service_name=None
|
||||
)
|
||||
ctx.emit(tag_item)
|
||||
@@ -698,7 +698,7 @@ def _scrape_isbn_metadata(isbn: str) -> List[str]:
|
||||
"""Scrape metadata for an ISBN using Open Library API."""
|
||||
new_tags = []
|
||||
try:
|
||||
from ..helper.http_client import HTTPClient
|
||||
from ..API.HTTP import HTTPClient
|
||||
import json as json_module
|
||||
|
||||
isbn_clean = isbn.replace('-', '').strip()
|
||||
@@ -822,7 +822,7 @@ def _scrape_openlibrary_metadata(olid: str) -> List[str]:
|
||||
"""
|
||||
new_tags = []
|
||||
try:
|
||||
from ..helper.http_client import HTTPClient
|
||||
from ..API.HTTP import HTTPClient
|
||||
import json as json_module
|
||||
|
||||
# Format: OL9674499M or just 9674499M
|
||||
@@ -995,7 +995,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
get-tag -scrape <url|provider>
|
||||
|
||||
Options:
|
||||
-hash <sha256>: Override hash to use instead of result's hash_hex
|
||||
-hash <sha256>: Override hash to use instead of result's hash
|
||||
--store <key>: Store result to this key for pipeline
|
||||
--emit: Emit result without interactive prompt (quiet mode)
|
||||
-scrape <url|provider>: Scrape metadata from URL or provider name (itunes, openlibrary, googlebooks)
|
||||
@@ -1150,7 +1150,8 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
table = ResultTable(f"Metadata: {provider.name}")
|
||||
table.set_source_command("get-tag", [])
|
||||
selection_payload = []
|
||||
hash_for_payload = normalize_hash(hash_override) or normalize_hash(get_field(result, "hash_hex", None))
|
||||
hash_for_payload = normalize_hash(hash_override) or normalize_hash(get_field(result, "hash", None))
|
||||
store_for_payload = get_field(result, "store", None)
|
||||
for idx, item in enumerate(items):
|
||||
tags = provider.to_tags(item)
|
||||
row = table.add_row()
|
||||
@@ -1165,13 +1166,12 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
"artist": item.get("artist"),
|
||||
"album": item.get("album"),
|
||||
"year": item.get("year"),
|
||||
"hash": hash_for_payload,
|
||||
"store": store_for_payload,
|
||||
"extra": {
|
||||
"tags": tags,
|
||||
"provider": provider.name,
|
||||
"hydrus_hash": hash_for_payload,
|
||||
"storage_source": get_field(result, "source", None) or get_field(result, "origin", None),
|
||||
},
|
||||
"file_hash": hash_for_payload,
|
||||
}
|
||||
selection_payload.append(payload)
|
||||
table.set_row_selection_args(idx, [str(idx + 1)])
|
||||
@@ -1192,30 +1192,29 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
if isinstance(result, list) and len(result) > 0:
|
||||
result = result[0]
|
||||
|
||||
hash_from_result = normalize_hash(get_field(result, "hash_hex", None))
|
||||
hash_hex = hash_override or hash_from_result
|
||||
hash_from_result = normalize_hash(get_field(result, "hash", None))
|
||||
file_hash = hash_override or hash_from_result
|
||||
# Only use emit mode if explicitly requested with --emit flag, not just because we're in a pipeline
|
||||
# This allows interactive REPL to work even in pipelines
|
||||
emit_mode = emit_requested or bool(store_key)
|
||||
store_label = (store_key.strip() if store_key and store_key.strip() else None)
|
||||
|
||||
# Get hash and store from result
|
||||
file_hash = hash_hex
|
||||
storage_source = get_field(result, "store") or get_field(result, "storage") or get_field(result, "origin")
|
||||
store_name = get_field(result, "store")
|
||||
|
||||
if not file_hash:
|
||||
log("No hash available in result", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not storage_source:
|
||||
log("No storage backend specified in result", file=sys.stderr)
|
||||
if not store_name:
|
||||
log("No store specified in result", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Get tags using storage backend
|
||||
try:
|
||||
from helper.store import FileStorage
|
||||
storage = FileStorage(config)
|
||||
backend = storage[storage_source]
|
||||
from Store import Store
|
||||
storage = Store(config)
|
||||
backend = storage[store_name]
|
||||
current, source = backend.get_tag(file_hash, config=config)
|
||||
|
||||
if not current:
|
||||
@@ -1224,7 +1223,7 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
|
||||
service_name = ""
|
||||
except KeyError:
|
||||
log(f"Storage backend '{storage_source}' not found", file=sys.stderr)
|
||||
log(f"Store '{store_name}' not found", file=sys.stderr)
|
||||
return 1
|
||||
except Exception as exc:
|
||||
log(f"Failed to get tags: {exc}", file=sys.stderr)
|
||||
@@ -1235,48 +1234,42 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
item_title = get_field(result, "title", None) or get_field(result, "name", None) or get_field(result, "filename", None)
|
||||
|
||||
# Build a subject payload representing the file whose tags are being shown
|
||||
subject_origin = get_field(result, "origin", None) or get_field(result, "source", None) or source
|
||||
subject_store = get_field(result, "store", None) or store_name
|
||||
subject_payload: Dict[str, Any] = {
|
||||
"tags": list(current),
|
||||
"title": item_title,
|
||||
"name": item_title,
|
||||
"origin": subject_origin,
|
||||
"source": subject_origin,
|
||||
"storage_source": subject_origin,
|
||||
"store": subject_store,
|
||||
"service_name": service_name,
|
||||
"extra": {
|
||||
"tags": list(current),
|
||||
"storage_source": subject_origin,
|
||||
"hydrus_hash": hash_hex,
|
||||
},
|
||||
}
|
||||
if hash_hex:
|
||||
subject_payload.update({
|
||||
"hash": hash_hex,
|
||||
"hash_hex": hash_hex,
|
||||
"file_hash": hash_hex,
|
||||
"hydrus_hash": hash_hex,
|
||||
})
|
||||
if file_hash:
|
||||
subject_payload["hash"] = file_hash
|
||||
if local_path:
|
||||
try:
|
||||
path_text = str(local_path)
|
||||
subject_payload.update({
|
||||
"file_path": path_text,
|
||||
"path": path_text,
|
||||
"target": path_text,
|
||||
})
|
||||
subject_payload["extra"]["file_path"] = path_text
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if source == "hydrus":
|
||||
_emit_tags_as_table(current, hash_hex=hash_hex, source="hydrus", service_name=service_name, config=config, item_title=item_title, subject=subject_payload)
|
||||
else:
|
||||
_emit_tags_as_table(current, hash_hex=hash_hex, source="local", service_name=None, config=config, item_title=item_title, file_path=str(local_path) if local_path else None, subject=subject_payload)
|
||||
_emit_tags_as_table(
|
||||
current,
|
||||
file_hash=file_hash,
|
||||
store=subject_store,
|
||||
service_name=service_name if source == "hydrus" else None,
|
||||
config=config,
|
||||
item_title=item_title,
|
||||
path=str(local_path) if local_path else None,
|
||||
subject=subject_payload,
|
||||
)
|
||||
|
||||
# If emit requested or store key provided, emit payload
|
||||
if emit_mode:
|
||||
_emit_tag_payload(source, current, hash_value=hash_hex, store_label=store_label)
|
||||
_emit_tag_payload(source, current, hash_value=file_hash, store_label=store_label)
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1341,22 +1334,22 @@ class Get_Tag(Cmdlet):
|
||||
|
||||
# Get hash and store from parsed args or result
|
||||
hash_override = parsed.get("hash")
|
||||
file_hash = hash_override or get_field(result, "hash") or get_field(result, "file_hash") or get_field(result, "hash_hex")
|
||||
storage_source = parsed.get("store") or get_field(result, "store") or get_field(result, "storage") or get_field(result, "origin")
|
||||
file_hash = normalize_hash(hash_override) or normalize_hash(get_field(result, "hash"))
|
||||
store_name = parsed.get("store") or get_field(result, "store")
|
||||
|
||||
if not file_hash:
|
||||
log("No hash available in result", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not storage_source:
|
||||
log("No storage backend specified in result", file=sys.stderr)
|
||||
if not store_name:
|
||||
log("No store specified in result", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Get tags using storage backend
|
||||
try:
|
||||
from helper.store import FileStorage
|
||||
storage_obj = FileStorage(config)
|
||||
backend = storage_obj[storage_source]
|
||||
from Store import Store
|
||||
storage_obj = Store(config)
|
||||
backend = storage_obj[store_name]
|
||||
current, source = backend.get_tag(file_hash, config=config)
|
||||
|
||||
if not current:
|
||||
@@ -1367,18 +1360,18 @@ class Get_Tag(Cmdlet):
|
||||
item_title = get_field(result, "title") or file_hash[:16]
|
||||
_emit_tags_as_table(
|
||||
tags_list=current,
|
||||
hash_hex=file_hash,
|
||||
source=source,
|
||||
file_hash=file_hash,
|
||||
store=store_name,
|
||||
service_name="",
|
||||
config=config,
|
||||
item_title=item_title,
|
||||
file_path=None,
|
||||
path=None,
|
||||
subject=result,
|
||||
)
|
||||
return 0
|
||||
|
||||
except KeyError:
|
||||
log(f"Storage backend '{storage_source}' not found", file=sys.stderr)
|
||||
log(f"Store '{store_name}' not found", file=sys.stderr)
|
||||
return 1
|
||||
except Exception as exc:
|
||||
log(f"Failed to get tags: {exc}", file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user