104 lines
2.8 KiB
Python
104 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Copy meaningful metadata from one file to another.
|
|
|
|
Run without files to type source/destination paths, or drag exactly two files
|
|
onto the script and choose which is the source.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from tools.console import pause_if_interactive, prompt_input
|
|
from tools.exiftool import require_exiftool
|
|
from tools.metadata_copy import copy_meaningful_metadata
|
|
|
|
|
|
def prompt_path(prompt: str) -> Path:
|
|
while True:
|
|
value = prompt_input(prompt).strip().strip('"')
|
|
path = Path(value).expanduser()
|
|
if path.is_file():
|
|
return path.resolve()
|
|
print("File not found. Enter a single file path.")
|
|
|
|
|
|
def choose_from_two(path_a: Path, path_b: Path) -> tuple[Path, Path] | None:
|
|
print("Choose metadata source:")
|
|
print(f"1: {path_a}")
|
|
print(f"2: {path_b}")
|
|
while True:
|
|
answer = prompt_input("Source file [1/2, Enter=1]: ").strip()
|
|
if answer == "" or answer == "1":
|
|
return path_a, path_b
|
|
if answer == "2":
|
|
return path_b, path_a
|
|
print("Please choose 1 or 2.")
|
|
|
|
|
|
def resolve_files(argv: list[str]) -> tuple[Path, Path] | None:
|
|
args = argv[1:]
|
|
if not args:
|
|
source = prompt_path("Source file: ")
|
|
destination = prompt_path("Destination file: ")
|
|
return source, destination
|
|
|
|
if len(args) != 2:
|
|
print("Error: provide exactly two files, or run without files to type paths.")
|
|
return None
|
|
|
|
paths = [Path(arg).expanduser().resolve() for arg in args]
|
|
missing = [path for path in paths if not path.is_file()]
|
|
if missing:
|
|
for path in missing:
|
|
print(f"File not found: {path}")
|
|
return None
|
|
|
|
return choose_from_two(paths[0], paths[1])
|
|
|
|
|
|
def copy_metadata(exiftool: str, source: Path, destination: Path) -> int:
|
|
print(f"Source: {source}")
|
|
print(f"Destination: {destination}", flush=True)
|
|
copy_meaningful_metadata(exiftool, source, destination)
|
|
return 0
|
|
|
|
|
|
def run(argv: list[str]) -> int:
|
|
try:
|
|
exiftool = require_exiftool()
|
|
except RuntimeError as exc:
|
|
print(exc)
|
|
return 1
|
|
|
|
try:
|
|
resolved = resolve_files(argv)
|
|
if resolved is None:
|
|
return 1
|
|
except RuntimeError as exc:
|
|
print(exc)
|
|
return 1
|
|
|
|
source, destination = resolved
|
|
if source == destination:
|
|
print("Source and destination must be different files.")
|
|
return 1
|
|
|
|
return_code = copy_metadata(exiftool, source, destination)
|
|
if return_code == 0:
|
|
print("Metadata copy complete.")
|
|
return return_code
|
|
|
|
|
|
def main(argv: list[str]) -> int:
|
|
try:
|
|
return run(argv)
|
|
finally:
|
|
pause_if_interactive()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv))
|