92 lines
3.5 KiB
Python
92 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
resource-watchdog.py — 文件资源管理看门狗(2026-09-05 牧尘要求:避免文件乱放)
|
||
|
||
管理规则(科学分类,遵循已有约定,不重复造轮子):
|
||
✅ 脚本统一 → ~/.hermes/scripts/(140+ 脚本库,不新建 scripts 目录)
|
||
✅ 知识/文档 → ~/mc/ 知识库(Obsidian,可检索进织忆图谱)
|
||
✅ 应用目录不动 → ComfyUI/models/ocr_v6_env/projects/mc/Downloads/Pictures/Videos
|
||
⚠️ 根目录(~)只允许 dotfile 配置 + 目录,不允许散落文件
|
||
|
||
看门狗动作:
|
||
1. 扫描 ~ 根目录非 dotfile 文件
|
||
2. 按扩展名分类:报告类→mc/06-Raw、临时→提示、未知→列出待处理
|
||
3. 磁盘>85% 或日志/备份异常附带提醒
|
||
|
||
用法: python3 resource-watchdog.py [--dry-run|--apply]
|
||
输出: 默认静默(watchdog 语义);有散落文件才报警
|
||
"""
|
||
import os, sys, shutil
|
||
from pathlib import Path
|
||
|
||
HOME = Path.home()
|
||
RAW_DIR = HOME / "mc/小唯/06-Raw"
|
||
|
||
# 文件类型 → 目标子目录(在 06-Raw 下按年月分)
|
||
EXT_MAP = {
|
||
# 报告/文档 → 06-Raw 按年份
|
||
".md": "reports", ".json": "reports", ".txt": "reports", ".log": "logs",
|
||
".pdf": "reports", ".docx": "reports", ".xlsx": "reports", ".csv": "reports",
|
||
# 图片(根目录不该有,应已在 Pictures/media)
|
||
".png": "images", ".jpg": "images", ".jpeg": "images", ".webp": "images", ".gif": "images",
|
||
# 视频
|
||
".mp4": "videos", ".mkv": "videos", ".mov": "videos", ".avi": "videos",
|
||
# 压缩包 → 提示人工(通常是待处理下载)
|
||
".zip": "archives", ".tar": "archives", ".gz": "archives", ".7z": "archives", ".rar": "archives",
|
||
}
|
||
|
||
# 明确忽略的(根目录正常存在的非 dotfile)
|
||
IGNORE = {"Desktop", "Documents", "Downloads", "Pictures", "Videos"}
|
||
|
||
def main():
|
||
apply = "--apply" in sys.argv
|
||
mode = "APPLY" if apply else "DRY-RUN"
|
||
stray = []
|
||
for f in HOME.iterdir():
|
||
if not f.is_file():
|
||
continue
|
||
if f.name.startswith("."):
|
||
continue
|
||
if f.name in IGNORE:
|
||
continue
|
||
stray.append(f)
|
||
|
||
if not stray:
|
||
# 干净,watchdog 静默
|
||
return 0
|
||
|
||
print(f"[{mode}] ⚠️ 根目录发现 {len(stray)} 个散落文件:")
|
||
moved = 0
|
||
for f in sorted(stray):
|
||
ext = f.suffix.lower()
|
||
kind = EXT_MAP.get(ext, "unknown")
|
||
if kind == "unknown":
|
||
print(f" ❓ {f.name} ({ext or '无扩展名'}, {f.stat().st_size//1024}K) — 需人工判断")
|
||
continue
|
||
# 目标: 06-Raw/YYYY/kind/(保文件名)
|
||
year = "2026" # 简化,实际可按 mtime
|
||
dest_dir = RAW_DIR / year / kind
|
||
if apply:
|
||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||
dest = dest_dir / f.name
|
||
if not dest.exists():
|
||
shutil.move(str(f), str(dest))
|
||
print(f" 📦 {f.name} → mc/小唯/06-Raw/{year}/{kind}/")
|
||
moved += 1
|
||
else:
|
||
# 同名冲突 → 加时间戳
|
||
ts = f.name.rsplit(".", 1)
|
||
dest = dest_dir / f"{ts[0]}-dup.{ts[1]}" if len(ts) > 1 else dest_dir / f"{f.name}-dup"
|
||
shutil.move(str(f), str(dest))
|
||
print(f" 📦 {f.name} → {dest.name}(同名避免)")
|
||
moved += 1
|
||
else:
|
||
print(f" [dry] {f.name} → {kind}/")
|
||
|
||
if not apply:
|
||
print("(dry-run;加 --apply 实际归档)")
|
||
return 0 if (moved or not apply) else 0
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|