huge refactor of the entire codebase, with the goal of improving maintainability, readability, and extensibility. This commit includes changes to almost every file in the project, including:
This commit is contained in:
+79
-62
@@ -176,14 +176,14 @@ class Add_File(Cmdlet):
|
||||
super().__init__(
|
||||
name="add-file",
|
||||
summary=
|
||||
"Ingest a local media file to a store backend, file provider, or local directory.",
|
||||
"Ingest a local media file to a store backend, upload plugin, or local directory.",
|
||||
usage=
|
||||
"add-file (-path <filepath> | <piped>) (-storage <location> | -provider <fileprovider>) [-delete]",
|
||||
"add-file (-path <filepath> | <piped>) (-storage <location> | -plugin <upload-plugin>) [-delete]",
|
||||
arg=[
|
||||
SharedArgs.PATH,
|
||||
SharedArgs.STORE,
|
||||
SharedArgs.URL,
|
||||
SharedArgs.PROVIDER,
|
||||
SharedArgs.PLUGIN,
|
||||
CmdletArg(
|
||||
name="delete",
|
||||
type="flag",
|
||||
@@ -198,7 +198,7 @@ class Add_File(Cmdlet):
|
||||
" hydrus: Upload to Hydrus database with metadata tagging",
|
||||
" local: Copy file to local directory",
|
||||
" <path>: Copy file to specified directory",
|
||||
"- File provider options (use -provider):",
|
||||
"- Upload plugin options (use -plugin):",
|
||||
" 0x0: Upload to 0x0.st for temporary hosting",
|
||||
" file.io: Upload to file.io for temporary hosting",
|
||||
" internetarchive: Upload to archive.org (optional tag: ia:<identifier> to upload into an existing item)",
|
||||
@@ -224,13 +224,13 @@ class Add_File(Cmdlet):
|
||||
path_arg = parsed.get("path")
|
||||
location = parsed.get("store")
|
||||
source_url_arg = parsed.get("url")
|
||||
provider_name = parsed.get("provider")
|
||||
plugin_name = parsed.get("plugin")
|
||||
delete_after = parsed.get("delete", False)
|
||||
|
||||
# Convenience: when piping a file into add-file, allow `-path <existing dir>`
|
||||
# to act as the destination export directory.
|
||||
# Example: screen-shot "https://..." | add-file -path "C:\Users\Admin\Desktop"
|
||||
if path_arg and not location and not provider_name:
|
||||
if path_arg and not location and not plugin_name:
|
||||
try:
|
||||
candidate_dir = Path(str(path_arg))
|
||||
if candidate_dir.exists() and candidate_dir.is_dir():
|
||||
@@ -263,7 +263,7 @@ class Add_File(Cmdlet):
|
||||
dir_scan_results: Optional[List[Dict[str, Any]]] = None
|
||||
explicit_path_list_results: Optional[List[Dict[str, Any]]] = None
|
||||
|
||||
if path_arg and location and not provider_name:
|
||||
if path_arg and location and not plugin_name:
|
||||
# Support comma-separated path lists: -path "file1,file2,file3"
|
||||
# This is the mechanism used by @N expansion for directory tables.
|
||||
try:
|
||||
@@ -403,7 +403,7 @@ class Add_File(Cmdlet):
|
||||
("result_type", type(result).__name__),
|
||||
("items", total_items),
|
||||
("location", location),
|
||||
("provider", provider_name),
|
||||
("plugin", plugin_name),
|
||||
("delete", delete_after),
|
||||
],
|
||||
border_style="cyan",
|
||||
@@ -599,8 +599,8 @@ class Add_File(Cmdlet):
|
||||
export_destination=(Path(location) if location and not is_storage_backend_location else None),
|
||||
store_instance=storage_registry,
|
||||
)
|
||||
if not media_path and provider_name:
|
||||
media_path, file_hash, temp_dir_to_cleanup = Add_File._download_provider_source(
|
||||
if not media_path and plugin_name:
|
||||
media_path, file_hash, temp_dir_to_cleanup = Add_File._download_piped_source(
|
||||
pipe_obj, config, storage_registry
|
||||
)
|
||||
if media_path:
|
||||
@@ -610,7 +610,7 @@ class Add_File(Cmdlet):
|
||||
[
|
||||
("path", media_path),
|
||||
("hash", file_hash or "N/A"),
|
||||
("provider", provider_name or "local"),
|
||||
("plugin", plugin_name or "local"),
|
||||
],
|
||||
border_style="green",
|
||||
)
|
||||
@@ -635,10 +635,10 @@ class Add_File(Cmdlet):
|
||||
progress.step("hashing file")
|
||||
progress.step("ingesting file")
|
||||
|
||||
if provider_name:
|
||||
code = self._handle_provider_upload(
|
||||
if plugin_name:
|
||||
code = self._handle_plugin_upload(
|
||||
media_path,
|
||||
provider_name,
|
||||
plugin_name,
|
||||
pipe_obj,
|
||||
config,
|
||||
delete_after_item
|
||||
@@ -1365,7 +1365,7 @@ class Add_File(Cmdlet):
|
||||
hash_hint = get_field(result, "hash") or get_field(result, "file_hash") or getattr(pipe_obj, "hash", None)
|
||||
return candidate, hash_hint, None
|
||||
|
||||
downloaded_path, hash_hint, tmp_dir = Add_File._maybe_download_provider_result(
|
||||
downloaded_path, hash_hint, tmp_dir = Add_File._maybe_download_plugin_result(
|
||||
result,
|
||||
pipe_obj,
|
||||
config,
|
||||
@@ -1393,45 +1393,41 @@ class Add_File(Cmdlet):
|
||||
return normalized
|
||||
|
||||
@staticmethod
|
||||
def _maybe_download_provider_result(
|
||||
def _maybe_download_plugin_result(
|
||||
result: Any,
|
||||
pipe_obj: models.PipeObject,
|
||||
config: Dict[str, Any],
|
||||
) -> Tuple[Optional[Path], Optional[str], Optional[Path]]:
|
||||
provider_key = None
|
||||
plugin_key = None
|
||||
for source in (
|
||||
pipe_obj.provider,
|
||||
get_field(result, "plugin"),
|
||||
get_field(result, "provider"),
|
||||
get_field(result, "table"),
|
||||
):
|
||||
candidate = Add_File._normalize_provider_key(source)
|
||||
if candidate:
|
||||
provider_key = candidate
|
||||
plugin_key = candidate
|
||||
break
|
||||
|
||||
if not provider_key:
|
||||
if not plugin_key:
|
||||
return None, None, None
|
||||
|
||||
provider = get_search_provider(provider_key, config)
|
||||
if provider is None:
|
||||
from ProviderCore.registry import get_search_plugin
|
||||
|
||||
plugin = get_search_plugin(plugin_key, config)
|
||||
if plugin is None:
|
||||
return None, None, None
|
||||
|
||||
# Check for specialized download helper (used by AllDebrid and potentially others)
|
||||
handler = getattr(provider, "download_for_pipe_result", None)
|
||||
if not callable(handler):
|
||||
# Fallback: check class if it's a classmethod and instance didn't have it (unlikely but safe)
|
||||
handler = getattr(type(provider), "download_for_pipe_result", None)
|
||||
|
||||
if callable(handler):
|
||||
try:
|
||||
return handler(result, pipe_obj, config)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] Provider '{provider_key}' download helper failed: {exc}")
|
||||
try:
|
||||
return plugin.resolve_pipe_result_download(result, pipe_obj)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] Plugin '{plugin_key}' download helper failed: {exc}")
|
||||
|
||||
return None, None, None
|
||||
|
||||
@staticmethod
|
||||
def _download_provider_source(
|
||||
def _download_piped_source(
|
||||
pipe_obj: models.PipeObject,
|
||||
config: Dict[str, Any],
|
||||
store_instance: Optional[Any],
|
||||
@@ -2152,23 +2148,23 @@ class Add_File(Cmdlet):
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def _handle_provider_upload(
|
||||
def _handle_plugin_upload(
|
||||
media_path: Path,
|
||||
provider_name: str,
|
||||
plugin_name: str,
|
||||
pipe_obj: models.PipeObject,
|
||||
config: Dict[str,
|
||||
Any],
|
||||
delete_after: bool,
|
||||
) -> int:
|
||||
"""Handle uploading to a file provider (e.g. 0x0)."""
|
||||
from ProviderCore.registry import get_file_provider
|
||||
"""Handle uploading via an upload plugin (e.g. 0x0)."""
|
||||
from ProviderCore.registry import get_upload_plugin
|
||||
|
||||
log(f"Uploading via {provider_name}: {media_path.name}", file=sys.stderr)
|
||||
log(f"Uploading via {plugin_name}: {media_path.name}", file=sys.stderr)
|
||||
|
||||
try:
|
||||
file_provider = get_file_provider(provider_name, config)
|
||||
file_provider = get_upload_plugin(plugin_name, config)
|
||||
if not file_provider:
|
||||
log(f"File provider '{provider_name}' not available", file=sys.stderr)
|
||||
log(f"Upload plugin '{plugin_name}' not available", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
hoster_url = file_provider.upload(str(media_path), pipe_obj=pipe_obj)
|
||||
@@ -2183,8 +2179,8 @@ class Add_File(Cmdlet):
|
||||
# Update PipeObject and emit
|
||||
extra_updates: Dict[str,
|
||||
Any] = {
|
||||
"provider": provider_name,
|
||||
"provider_url": hoster_url,
|
||||
"plugin": plugin_name,
|
||||
"plugin_url": hoster_url,
|
||||
}
|
||||
if isinstance(pipe_obj.extra, dict):
|
||||
# Also track hoster URL as a url for downstream steps
|
||||
@@ -2197,7 +2193,7 @@ class Add_File(Cmdlet):
|
||||
Add_File._update_pipe_object_destination(
|
||||
pipe_obj,
|
||||
hash_value=f_hash or "unknown",
|
||||
store=provider_name or "provider",
|
||||
store=plugin_name or "plugin",
|
||||
path=file_path,
|
||||
tag=pipe_obj.tag,
|
||||
title=pipe_obj.title or (media_path.name if media_path else None),
|
||||
@@ -2445,9 +2441,6 @@ class Add_File(Cmdlet):
|
||||
try:
|
||||
adder = getattr(backend, "add_tag", None)
|
||||
if callable(adder):
|
||||
debug(
|
||||
f"[add-file] Applying {len(tags)} tag(s) post-upload to {backend_name}"
|
||||
)
|
||||
adder(resolved_hash, list(tags))
|
||||
except Exception as exc:
|
||||
log(f"[add-file] Post-upload tagging failed for {backend_name}: {exc}", file=sys.stderr)
|
||||
@@ -2479,48 +2472,72 @@ class Add_File(Cmdlet):
|
||||
try:
|
||||
setter = getattr(backend, "set_note", None)
|
||||
if callable(setter):
|
||||
debug(
|
||||
f"[add-file] Writing sub note (len={len(str(sub_note))}) to {backend_name}:{resolved_hash}"
|
||||
)
|
||||
setter(resolved_hash, "sub", sub_note)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] sub note write failed: {exc}")
|
||||
debug_panel(
|
||||
"add-file note write failed",
|
||||
[
|
||||
("store", backend_name),
|
||||
("hash", resolved_hash),
|
||||
("note", "sub"),
|
||||
("error", exc),
|
||||
],
|
||||
border_style="yellow",
|
||||
)
|
||||
|
||||
lyric_note = Add_File._get_note_text(result, pipe_obj, "lyric")
|
||||
if lyric_note:
|
||||
try:
|
||||
setter = getattr(backend, "set_note", None)
|
||||
if callable(setter):
|
||||
debug(
|
||||
f"[add-file] Writing lyric note (len={len(str(lyric_note))}) to {backend_name}:{resolved_hash}"
|
||||
)
|
||||
setter(resolved_hash, "lyric", lyric_note)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] lyric note write failed: {exc}")
|
||||
debug_panel(
|
||||
"add-file note write failed",
|
||||
[
|
||||
("store", backend_name),
|
||||
("hash", resolved_hash),
|
||||
("note", "lyric"),
|
||||
("error", exc),
|
||||
],
|
||||
border_style="yellow",
|
||||
)
|
||||
|
||||
chapters_note = Add_File._get_note_text(result, pipe_obj, "chapters")
|
||||
if chapters_note:
|
||||
try:
|
||||
setter = getattr(backend, "set_note", None)
|
||||
if callable(setter):
|
||||
debug(
|
||||
f"[add-file] Writing chapters note (len={len(str(chapters_note))}) to {backend_name}:{resolved_hash}"
|
||||
)
|
||||
setter(resolved_hash, "chapters", chapters_note)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] chapters note write failed: {exc}")
|
||||
debug_panel(
|
||||
"add-file note write failed",
|
||||
[
|
||||
("store", backend_name),
|
||||
("hash", resolved_hash),
|
||||
("note", "chapters"),
|
||||
("error", exc),
|
||||
],
|
||||
border_style="yellow",
|
||||
)
|
||||
|
||||
caption_note = Add_File._get_note_text(result, pipe_obj, "caption")
|
||||
if caption_note:
|
||||
try:
|
||||
setter = getattr(backend, "set_note", None)
|
||||
if callable(setter):
|
||||
debug(
|
||||
f"[add-file] Writing caption note (len={len(str(caption_note))}) to {backend_name}:{resolved_hash}"
|
||||
)
|
||||
setter(resolved_hash, "caption", caption_note)
|
||||
except Exception as exc:
|
||||
debug(f"[add-file] caption note write failed: {exc}")
|
||||
debug_panel(
|
||||
"add-file note write failed",
|
||||
[
|
||||
("store", backend_name),
|
||||
("hash", resolved_hash),
|
||||
("note", "caption"),
|
||||
("error", exc),
|
||||
],
|
||||
border_style="yellow",
|
||||
)
|
||||
|
||||
meta: Dict[str,
|
||||
Any] = {}
|
||||
|
||||
Reference in New Issue
Block a user