feat: copy+verify+delete, --limit flag, fix exfat compat

This commit is contained in:
Eddy de Vink 2026-05-29 19:54:02 +02:00
commit 4b4179e01c

View file

@ -1,19 +1,21 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Transfer dashcam MP4 files from SD card to USB-SSD with date/camera structure.""" """Transfer dashcam MP4 files from SD card to USB-SSD with date/camera structure."""
import argparse
import fcntl import fcntl
import logging import logging
import os import os
import re import re
import shutil import shutil
import subprocess
import sys import sys
SD_CARD = "/mnt/sdcard" SD_CARD = "/mnt/sdcard"
SOURCE_DIR = os.path.join(SD_CARD, "Novatek", "Movie") SOURCE_DIR = os.path.join(SD_CARD, "Novatek", "Movie")
SSD = "/mnt/ultratouch" SSD = "/mnt/ultratouch"
TARGET_BASE = os.path.join(SSD, "dashcam") TARGET_BASE = os.path.join(SSD, "dashcam")
LOG_FILE = "/var/log/dashcam-transfer.log" LOG_FILE = "/tmp/dashcam-transfer.log"
LOCK_FILE = "/var/run/dashcam-transfer.lock" LOCK_FILE = "/tmp/dashcam-transfer.lock"
CAMERA_MAP = {"F": "front", "B": "back"} CAMERA_MAP = {"F": "front", "B": "back"}
FILE_PATTERN = re.compile(r"^(\d{8})\d{6}_\d+([FB])\.MP4$") FILE_PATTERN = re.compile(r"^(\d{8})\d{6}_\d+([FB])\.MP4$")
@ -101,7 +103,17 @@ def ensure_free_space(needed_bytes, target_base):
logging.info("Ruimte vrijgemaakt: %d bytes door %d mappen", freed, len(removed)) logging.info("Ruimte vrijgemaakt: %d bytes door %d mappen", freed, len(removed))
def parse_args():
parser = argparse.ArgumentParser(description="Dashcam transfer tool")
parser.add_argument(
"--limit", "-n", type=int, default=0,
help="Maximum aantal bestanden om over te zetten (0 = alle)"
)
return parser.parse_args()
def main(): def main():
args = parse_args()
setup_logging() setup_logging()
lock_fd = acquire_lock() lock_fd = acquire_lock()
@ -113,6 +125,9 @@ def main():
logging.info("Geen MP4 bestanden gevonden in %s", SOURCE_DIR) logging.info("Geen MP4 bestanden gevonden in %s", SOURCE_DIR)
return return
if args.limit > 0:
files = files[:args.limit]
total_size = sum( total_size = sum(
os.path.getsize(os.path.join(SOURCE_DIR, fname)) for fname, _, _ in files os.path.getsize(os.path.join(SOURCE_DIR, fname)) for fname, _, _ in files
) )
@ -129,18 +144,50 @@ def main():
os.makedirs(target_dir, exist_ok=True) os.makedirs(target_dir, exist_ok=True)
src = os.path.join(SOURCE_DIR, fname) src = os.path.join(SOURCE_DIR, fname)
dst = os.path.join(target_dir, fname) dst = os.path.join(target_dir, fname)
if os.path.exists(dst):
src_size = os.path.getsize(src)
dst_size = os.path.getsize(dst)
if src_size == dst_size:
logging.info(
"Bestaat al en klopt: %s → %s/%s/", fname, date_str, CAMERA_MAP[cam]
)
os.remove(src)
ok += 1
continue
else:
logging.warning(
"Doel %s bestaat maar is anders (%d vs %d bytes) — overschrijf",
dst, dst_size, src_size,
)
os.remove(dst)
try: try:
shutil.move(src, dst) subprocess.run(
logging.info( ["cp", src, dst], check=True, capture_output=True, timeout=600
"Verplaatst: %s → %s/%s/", fname, date_str, CAMERA_MAP[cam]
) )
ok += 1 except (subprocess.CalledProcessError, OSError) as e:
except OSError as e: logging.error("Fout bij kopiëren %s: %s", fname, e)
logging.error("Fout bij verplaatsen %s: %s", fname, e)
errors += 1 errors += 1
continue
dst_size = os.path.getsize(dst)
src_size = os.path.getsize(src)
if dst_size != src_size:
logging.error(
"Verificatie mislukt %s: %d vs %d bytes", fname, src_size, dst_size
)
errors += 1
continue
os.remove(src)
logging.info(
"Overgezet: %s → %s/%s/ (%d bytes)", fname, date_str, CAMERA_MAP[cam], src_size
)
ok += 1
logging.info( logging.info(
"Transfer voltooid: %d ok, %d fouten, %d bytes", ok, errors, total_size "Transfer voltooid: %d ok, %d fouten", ok, errors
) )