sdimport — 检测视频 SD 卡自动导入

插入记录仪 SD 卡 → 自动按拍摄日期归类 → 落盘 → 清空卡内副本 → 延时自动弹出。

macOS 与 Windows 共用同一套核心逻辑,系统差异全部收敛在 src/sdimport/platforms/。

插卡 → 认卡 → 按日期分组 → 对账 → 倒计时确认 → 拷贝 → 校验 → 清卡 → 完成提示 → 延时弹卡
环节 规则
认卡 不认卷名,认卡内有没有 VID-YYYYMMDD-HHMMSS.AVI。换卡、换记录仪、卡被改名都不受影响
分组 日期只取文件名里的八位数,不看卡上目录名(实测过目录名与拍摄日期错位)
范围 只扫 scan_roots 指定的目录,绝不进 VIDEO/ 的子目录 —— 那里面是历史归档
对账 已落盘的跳过;同名但体积不符的另起名字,绝不覆盖
校验 体积 + 头尾各 64KB 指纹一致才算成功
清卡 校验通过才删卡内源文件;单文件失败即整批中止,不删任何源文件
弹卡 完成后弹提示,N 分钟后自动弹出;期间可点「暂不弹出」,或执行 sdimport keep 取消

安装

macOS(已实测)

cd ~/WorkBuddy/检测视频自动导入
./bin/sdimport selftest     # 环境自检
./bin/sdimport install      # 装后台服务(launchd)

若 install 提示「未能在本次会话中加载」,双击项目根目录的 安装后台服务.command, 或在终端粘贴 launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.sdimport.agent.plist。 什么都不做也行 —— 注销或重启后 macOS 会自动加载。

触发方式:WatchPaths 监视 /Volumes(插卡即响应)+ 每 120 秒兜底检查一次。

Windows(尚未在真机实测)

  1. 装 Python 3.9+(https://www.python.org/downloads/),安装时勾选 Add python.exe to PATH。
  2. 把本项目整个目录拷到那台 Windows 机器上,路径不要含空格最省事。
  3. 先自检,再演练,最后安装:
bin\sdimport.cmd selftest
bin\sdimport.cmd scan
bin\sdimport.cmd once --no-delete
bin\sdimport.cmd install

或直接双击 install-service.cmd。

触发方式:常驻进程 sdimport daemon 订阅 WMI 卷插入事件(秒级响应)+ 每 30 秒轮询兜底, 由任务计划 sdimport 在登录时自动拉起。

可选提速:pip install wmi 之后插卡是秒级响应;不装也能用,只是最坏延迟 30 秒。


命令

命令 作用
sdimport scan 演练:只显示会导入什么,不做任何写入
sdimport once 立即执行一次导入
sdimport once --no-delete 导入但保留卡内文件
sdimport status 服务状态、待弹出的任务、最近导入记录
sdimport log 查看最近日志
sdimport keep 取消待执行的自动弹出(卡继续挂着)
sdimport eject 立刻弹出 SD 卡
sdimport selftest 环境自检
sdimport install / uninstall 安装 / 卸载后台服务
sdimport daemon 常驻进程(Windows 用,一般无需手动跑)

macOS 用 ./bin/sdimport,Windows 用 bin\sdimport.cmd,参数完全一致。


配置(config.json)

改动前请先读 .workbuddy/memory/MEMORY.md 的「铁律」一节。

键 默认 说明
target_root ~/Downloads/检测视频 落盘根目录,按 <root>/<YYYYMMDD>/ 组织
filename_regex ^VID-(\d{8})-(\d{6})\.(AVI|MP4|…)$ 只碰匹配此模式的文件,其余一律不动
scan_roots ["", "VIDEO", "DCIM:2", "MOVIE", "PRIVATE"] 扫描根。"" 是卷根;:N 是该根下最多再进几层子目录
scan_max_depth 0 未写 :N 时的默认下潜层数
min_video_bytes 1024 只挡 0 字节 / 畸形残片
tiny_video_bytes 1048576 小于此值的只标注、照样导入,不丢数据
delete_source_after_verify true 校验通过后是否清卡
notify_countdown_seconds 60 开始导入前的倒计时,期间可取消
eject_after_import true 导入完成后是否自动弹出
eject_delay_seconds 300 延时多久弹出
completion_dialog_seconds 30 完成提示框停留秒数;设 0 则只发通知不弹框
eject_finder_fallback false macOS:改走「访达推出」通道。需先授予「自动化」权限,否则会弹框阻塞
windows_only_removable true Windows:只把可移动磁盘当候选卷(硬安全线,别轻易关)

调试用环境变量:SDIMPORT_TARGET_ROOT、SDIMPORT_COUNTDOWN、SDIMPORT_EJECT_DELAY、 SDIMPORT_COMPLETION_DIALOG。


目录结构

install-service.cmd       Windows:双击安装后台服务
uninstall-service.cmd     Windows:双击卸载
bin/sdimport              macOS / Linux 入口
bin/sdimport.cmd          Windows 入口
bin/on-volume-change.sh   launchd 触发入口
src/sdimport/
  planner.py              按日期分组与落盘规划      (跨平台)
  transfer.py             拷贝 → 校验 → 删源        (跨平台)
  pipeline.py             主流程编排                  (跨平台)
  scanner.py              卷内录像扫描规则            (跨平台)
  runner.py               auto 一轮流程               (跨平台)
  daemon.py               常驻进程(Windows 触发用)  (跨平台)
  journal.py              日志、状态、单实例锁        (跨平台)
  paths.py                路径与配置                  (跨平台)
  volumes.py / notify.py / ejector.py   薄门面,委托平台
  platforms/
    base.py               接口与 Volume 模型
    macos.py              /Volumes + diskutil + osascript + launchd
    windows.py            盘符 + kernel32 + PowerShell + 任务计划
    generic.py            兜底(Linux 等)
runtime/logs/             import-YYYYMMDD.log、launchd.err.log、eject.log
runtime/state/            state.json、pending-eject.json

故障排查

现象 处置
插卡没反应 sdimport status 看服务在不在;sdimport log 看最近日志
说「判定为非记录仪卡」 卡上确实没有符合 filename_regex 的文件;或卡上文件都在子目录里(按设计不纳入)
说「另有 N 个录像不纳入」 那些在扫描根的子目录里,属归档范围,按设计不动。真要处理就改 scan_roots
macOS 卡弹不出来 多半是访达窗口开着这张卡。关掉窗口,或在访达侧边栏点「推出」
Windows 卡弹不出来 关掉资源管理器里该盘的窗口;或右键该盘选「弹出」
想临时保住卡不弹 sdimport keep

排查第一站永远是 runtime/logs/ 下的日志,每次导入的每个文件都留了痕。


边界声明

  • 本程序只做「SD 卡 → <target_root>/<YYYYMMDD>/ → 清卡」这一段。 电梯编号识别由 elevator-video-classifier skill 负责,那一步需要人工校对,两者不重叠。
  • Windows 侧代码未在真机实测(开发机是 macOS)。写法上已尽量保守 (纯标准库优先、依赖缺失自动降级、无 GUI 会话也能工作),但仍建议先跑 selftest 与 scan。
S
Description
检测视频自动导入 —— SD 卡自动导入工具(macOS/Windows 跨平台)
Readme
86 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 96.8%
Shell 2.4%
Batchfile 0.8%