continuing refactor

This commit is contained in:
2026-05-03 21:20:05 -07:00
parent 77cab1bd27
commit 5534812426
50 changed files with 1004 additions and 428 deletions
+28 -30
View File
@@ -224,12 +224,11 @@ class Add_File(Cmdlet):
super().__init__(
name="add-file",
summary=
"Ingest a local media file to a store backend, upload plugin, or local directory.",
"Ingest a local media file to a configured instance, upload plugin, or local directory.",
usage=
"add-file (-path <filepath> | <piped>) (-store <backend|path> | -plugin <upload-plugin>) [-instance NAME] [-delete]",
"add-file (-path <filepath> | <piped>) (-instance <name|path> | -plugin <upload-plugin>) [-delete]",
arg=[
SharedArgs.PATH,
SharedArgs.STORE,
SharedArgs.INSTANCE,
SharedArgs.URL,
SharedArgs.PLUGIN,
@@ -243,7 +242,7 @@ class Add_File(Cmdlet):
],
detail=[
"Note: add-file ingests local files. To fetch remote sources, use download-file and pipe into add-file.",
"- Storage location options (use -store):",
"- Instance/location options (use -instance):",
" hydrus: Upload to Hydrus database with metadata tagging",
" local: Copy file to local directory",
" <path>: Copy file to specified directory",
@@ -252,10 +251,9 @@ class Add_File(Cmdlet):
" file.io: Upload to file.io for temporary hosting",
" internetarchive: Upload to archive.org (optional tag: ia:<identifier> to upload into an existing item)",
"- Use -instance with -plugin to target a named provider config: add-file -plugin ftp -instance archive -path C:\\Media\\file.pdf",
"- In plugin mode, -store <name> is still accepted as a compatibility alias for -instance <name>.",
],
examples=[
'download-file "https://themathesontrust.org/papers/christianity/alcock-alphabet1.pdf" | add-file -store tutorial',
'download-file "https://themathesontrust.org/papers/christianity/alcock-alphabet1.pdf" | add-file -instance tutorial',
'add-file -plugin ftp -instance archive -path C:\\Media\\report.pdf',
],
exec=self.run,
@@ -272,7 +270,7 @@ class Add_File(Cmdlet):
storage_registry = deps.get_store()
path_arg = parsed.get("path")
location = parsed.get("store")
location = parsed.get("instance")
plugin_instance = parsed.get("instance")
source_url_arg = parsed.get("url")
plugin_name = parsed.get("plugin")
@@ -308,8 +306,8 @@ class Add_File(Cmdlet):
has_downstream_stage = bool(stage_ctx is not None and not is_last_stage)
# Directory-mode selector:
# - Terminal use: `add-file -store X -path <DIR>` shows a selectable table.
# - Pipelined use: `add-file -store X -path <DIR> | ...` processes the full batch
# - Terminal use: `add-file -instance X -path <DIR>` shows a selectable table.
# - Pipelined use: `add-file -instance X -path <DIR> | ...` processes the full batch
# immediately so downstream stages receive the uploaded items.
# - Selection replay: `@N` re-runs add-file with `-path file1,file2,...`.
dir_scan_mode = False
@@ -389,7 +387,7 @@ class Add_File(Cmdlet):
except Exception:
pass
# Determine if -store targets a registered backend (vs a filesystem export path).
# Determine if -instance targets a registered backend (vs a filesystem export path).
is_storage_backend_location = False
if location:
try:
@@ -598,7 +596,7 @@ class Add_File(Cmdlet):
successes = 0
failures = 0
# When add-file -store is the last stage, always show a final search-file table.
# When add-file -instance is the last stage, always show a final search-file table.
# This is especially important for multi-item ingests (e.g., multi-clip downloads)
# so the user always gets a selectable ResultTable.
live_progress = None
@@ -702,7 +700,7 @@ class Add_File(Cmdlet):
pipe_obj.path = str(media_path)
# When using -path (filesystem export), allow all file types.
# When using -store (backend), restrict to SUPPORTED_MEDIA_EXTENSIONS.
# When using -instance (backend), restrict to SUPPORTED_MEDIA_EXTENSIONS.
allow_all_files = not bool(effective_storage_backend_name)
if not self._validate_source(media_path, allow_all_extensions=allow_all_files):
failures += 1
@@ -828,7 +826,7 @@ class Add_File(Cmdlet):
except Exception:
pass
# Always end add-file -store (when last stage) by showing item detail panels.
# Always end add-file -instance (when last stage) by showing item detail panels.
# Legacy search-file refresh is no longer used for final display.
if want_final_search_file and collected_payloads:
try:
@@ -898,7 +896,7 @@ class Add_File(Cmdlet):
@staticmethod
def _try_emit_search_file_by_hashes(
*,
store: str,
instance: str,
hash_values: List[str],
config: Dict[str,
Any],
@@ -909,15 +907,15 @@ class Add_File(Cmdlet):
Returns the emitted search-file payload items on success, else None.
"""
hashes = [h for h in (hash_values or []) if isinstance(h, str) and len(h) == 64]
if not store or not hashes:
if not instance or not hashes:
return None
try:
from cmdlet.search_file import CMDLET as search_file_cmdlet
query = "hash:" + ",".join(hashes)
args = ["-store", str(store), "-internal-refresh", query]
debug(f'[add-file] Refresh: search-file -store {store} "{query}"')
args = ["-instance", str(instance), "-internal-refresh", query]
debug(f'[add-file] Refresh: search-file -instance {instance} "{query}"')
# Run search-file under a temporary stage context so its ctx.emit() calls
# don't interfere with the outer add-file pipeline stage.
@@ -967,7 +965,7 @@ class Add_File(Cmdlet):
table,
items,
subject={
"store": store,
"store": instance,
"hash": hashes
},
overlay=True,
@@ -1344,21 +1342,21 @@ class Add_File(Cmdlet):
return safe_name or "download"
@staticmethod
def _resolve_backend_by_name(store: Any, backend_name: str) -> Optional[Any]:
if not store or not backend_name:
def _resolve_backend_by_name(instance: Any, backend_name: str) -> Optional[Any]:
if not instance or not backend_name:
return None
try:
return store[backend_name]
return instance[backend_name]
except Exception:
pass
target = str(backend_name or "").strip().lower()
if not target:
return None
try:
for candidate in store.list_backends():
for candidate in instance.list_backends():
if isinstance(candidate, str) and candidate.strip().lower() == target:
try:
return store[candidate]
return instance[candidate]
except Exception:
continue
except Exception:
@@ -1739,7 +1737,7 @@ class Add_File(Cmdlet):
Args:
media_path: Path to the file to validate
allow_all_extensions: If True, skip file type filtering (used for -path exports).
If False, only allow SUPPORTED_MEDIA_EXTENSIONS (used for -store).
If False, only allow SUPPORTED_MEDIA_EXTENSIONS (used for -instance).
"""
if media_path is None:
return False
@@ -1748,7 +1746,7 @@ class Add_File(Cmdlet):
log(f"File not found: {media_path}")
return False
# Validate file type: only when adding to -store backend, not for -path exports
# Validate file type: only when adding to -instance backend, not for -path exports
if not allow_all_extensions:
file_extension = media_path.suffix.lower()
if file_extension not in SUPPORTED_MEDIA_EXTENSIONS:
@@ -2004,7 +2002,7 @@ class Add_File(Cmdlet):
@staticmethod
def _try_emit_search_file_by_hash(
*,
store: str,
instance: str,
hash_value: str,
config: Dict[str,
Any]
@@ -2021,7 +2019,7 @@ class Add_File(Cmdlet):
try:
from cmdlet.search_file import CMDLET as search_file_cmdlet
args = ["-store", str(store), f"hash:{str(hash_value)}"]
args = ["-instance", str(instance), f"hash:{str(hash_value)}"]
# Run search-file under a temporary stage context so its ctx.emit() calls
# don't interfere with the outer add-file pipeline stage.
@@ -2057,7 +2055,7 @@ class Add_File(Cmdlet):
overlay_existing_result_table(
ctx,
subject={
"store": store,
"store": instance,
"hash": hash_value
},
)
@@ -2815,7 +2813,7 @@ class Add_File(Cmdlet):
)
refreshed_items = Add_File._try_emit_search_file_by_hash(
store=backend_name,
instance=backend_name,
hash_value=resolved_hash,
config=config,
)
@@ -2930,7 +2928,7 @@ class Add_File(Cmdlet):
@staticmethod
def _load_sidecar_bundle(
media_path: Path,
store: Optional[str],
instance: Optional[str],
config: Dict[str,
Any],
) -> Tuple[Optional[Path],