d
This commit is contained in:
@@ -2,10 +2,12 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Dict, Sequence
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
import webbrowser
|
||||
|
||||
from . import register
|
||||
import pipeline as ctx
|
||||
from ._shared import Cmdlet, CmdletArg, SharedArgs, parse_cmdlet_args, get_field, normalize_hash
|
||||
from SYS.logger import log, debug
|
||||
@@ -25,8 +27,8 @@ class Get_File(Cmdlet):
|
||||
arg=[
|
||||
SharedArgs.HASH,
|
||||
SharedArgs.STORE,
|
||||
CmdletArg("-path", description="Output directory path (default: from config)"),
|
||||
CmdletArg("-name", description="Output filename (default: from metadata title)"),
|
||||
SharedArgs.PATH,
|
||||
CmdletArg("name", description="Output filename (default: from metadata title)"),
|
||||
],
|
||||
detail=[
|
||||
"- Exports file from storage backend to local path",
|
||||
@@ -79,32 +81,23 @@ class Get_File(Cmdlet):
|
||||
log(f"Error: File metadata not found for hash {file_hash[:12]}...")
|
||||
return 1
|
||||
debug(f"[get-file] Metadata retrieved: title={metadata.get('title')}, ext={metadata.get('ext')}")
|
||||
|
||||
# Determine output filename
|
||||
if output_name:
|
||||
filename = output_name
|
||||
else:
|
||||
# Use title from metadata, sanitize it
|
||||
title = metadata.get("title", "export")
|
||||
filename = self._sanitize_filename(title)
|
||||
|
||||
# Add extension if metadata has it
|
||||
ext = metadata.get("ext")
|
||||
if ext and not filename.endswith(ext):
|
||||
if not ext.startswith('.'):
|
||||
ext = '.' + ext
|
||||
filename += ext
|
||||
|
||||
# Determine output directory
|
||||
if output_path:
|
||||
output_dir = Path(output_path).expanduser()
|
||||
else:
|
||||
output_dir = resolve_output_dir(config)
|
||||
|
||||
debug(f"[get-file] Output dir: {output_dir}")
|
||||
|
||||
# Create output directory
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def resolve_display_title() -> str:
|
||||
candidates = [
|
||||
get_field(result, "title"),
|
||||
get_field(result, "name"),
|
||||
get_field(result, "filename"),
|
||||
(metadata.get("title") if isinstance(metadata, dict) else None),
|
||||
(metadata.get("name") if isinstance(metadata, dict) else None),
|
||||
(metadata.get("filename") if isinstance(metadata, dict) else None),
|
||||
]
|
||||
for candidate in candidates:
|
||||
if candidate is None:
|
||||
continue
|
||||
text = str(candidate).strip()
|
||||
if text:
|
||||
return text
|
||||
return ""
|
||||
|
||||
debug(f"[get-file] Calling backend.get_file({file_hash[:12]}...)")
|
||||
|
||||
@@ -115,15 +108,20 @@ class Get_File(Cmdlet):
|
||||
|
||||
# Check if backend returned a URL (HydrusNetwork case)
|
||||
if isinstance(source_path, str) and (source_path.startswith("http://") or source_path.startswith("https://")):
|
||||
log(f"File opened in browser: {source_path}", file=sys.stderr)
|
||||
ctx.emit(f"Opened in browser: {source_path}")
|
||||
# Hydrus backend returns a URL; open it only for this explicit user action.
|
||||
try:
|
||||
webbrowser.open(source_path)
|
||||
except Exception as exc:
|
||||
log(f"Error opening browser: {exc}", file=sys.stderr)
|
||||
else:
|
||||
log(f"Opened in browser: {source_path}", file=sys.stderr)
|
||||
|
||||
# Emit result for pipeline
|
||||
ctx.emit({
|
||||
"hash": file_hash,
|
||||
"store": store_name,
|
||||
"url": source_path,
|
||||
"title": filename,
|
||||
"title": resolve_display_title() or "Opened",
|
||||
})
|
||||
return 0
|
||||
|
||||
@@ -131,32 +129,58 @@ class Get_File(Cmdlet):
|
||||
if isinstance(source_path, str):
|
||||
source_path = Path(source_path)
|
||||
|
||||
# Determine output directory
|
||||
if not source_path or not source_path.exists():
|
||||
log(f"Error: Backend could not retrieve file for hash {file_hash[:12]}...")
|
||||
return 1
|
||||
|
||||
# Folder store UX: without -path, just open the file in the default app.
|
||||
# Only export/copy when -path is explicitly provided.
|
||||
backend_name = type(backend).__name__
|
||||
is_folder_backend = backend_name.lower() == "folder"
|
||||
if is_folder_backend and not output_path:
|
||||
display_title = resolve_display_title() or source_path.stem or "Opened"
|
||||
ext_for_emit = metadata.get("ext") or source_path.suffix.lstrip(".")
|
||||
self._open_file_default(source_path)
|
||||
log(f"Opened: {source_path}", file=sys.stderr)
|
||||
ctx.emit({
|
||||
"hash": file_hash,
|
||||
"store": store_name,
|
||||
"path": str(source_path),
|
||||
"title": str(display_title),
|
||||
"ext": str(ext_for_emit or ""),
|
||||
})
|
||||
debug("[get-file] Completed successfully")
|
||||
return 0
|
||||
|
||||
# Otherwise: export/copy to output_dir.
|
||||
if output_path:
|
||||
output_dir = Path(output_path).expanduser()
|
||||
else:
|
||||
output_dir = resolve_output_dir(config)
|
||||
|
||||
|
||||
debug(f"[get-file] Output dir: {output_dir}")
|
||||
|
||||
# Create output directory
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Build full output path
|
||||
dest_path = output_dir / filename
|
||||
|
||||
# Make path unique if file exists
|
||||
dest_path = self._unique_path(dest_path)
|
||||
|
||||
if not source_path or not source_path.exists():
|
||||
log(f"Error: Backend could not retrieve file for hash {file_hash[:12]}...")
|
||||
return 1
|
||||
|
||||
# Determine output filename (only when exporting)
|
||||
if output_name:
|
||||
filename = output_name
|
||||
else:
|
||||
title = (metadata.get("title") if isinstance(metadata, dict) else None) or resolve_display_title() or "export"
|
||||
filename = self._sanitize_filename(title)
|
||||
|
||||
# Add extension if metadata has it
|
||||
ext = metadata.get("ext")
|
||||
if ext and not filename.endswith(ext):
|
||||
if not ext.startswith('.'):
|
||||
ext = '.' + ext
|
||||
filename += ext
|
||||
|
||||
dest_path = self._unique_path(output_dir / filename)
|
||||
|
||||
# Copy file to destination
|
||||
debug(f"[get-file] Copying {source_path} -> {dest_path}", file=sys.stderr)
|
||||
shutil.copy2(source_path, dest_path)
|
||||
|
||||
ctx.emit(f"Exported to: {dest_path}")
|
||||
|
||||
log(f"Exported: {dest_path}", file=sys.stderr)
|
||||
|
||||
# Emit result for pipeline
|
||||
@@ -169,6 +193,19 @@ class Get_File(Cmdlet):
|
||||
|
||||
debug(f"[get-file] Completed successfully")
|
||||
return 0
|
||||
|
||||
def _open_file_default(self, path: Path) -> None:
|
||||
"""Open a local file in the OS default application."""
|
||||
try:
|
||||
if sys.platform.startswith("win"):
|
||||
os.startfile(str(path)) # type: ignore[attr-defined]
|
||||
return
|
||||
if sys.platform == "darwin":
|
||||
subprocess.Popen(["open", str(path)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
return
|
||||
subprocess.Popen(["xdg-open", str(path)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
except Exception as exc:
|
||||
log(f"Error opening file: {exc}", file=sys.stderr)
|
||||
|
||||
def _sanitize_filename(self, name: str) -> str:
|
||||
"""Sanitize filename by removing invalid characters."""
|
||||
|
||||
Reference in New Issue
Block a user