diff --git a/identity/device-auth.json b/identity/device-auth.json index 367303e..06db909 100644 --- a/identity/device-auth.json +++ b/identity/device-auth.json @@ -12,7 +12,7 @@ "operator.read", "operator.write" ], - "updatedAtMs": 1782957219692 + "updatedAtMs": 1783328657006 } } } diff --git a/skill-workshop/proposals.json b/skill-workshop/proposals.json index 5e589a2..b47c977 100644 --- a/skill-workshop/proposals.json +++ b/skill-workshop/proposals.json @@ -1 +1 @@ -{"schema":"openclaw.skill-workshop.proposals-manifest.v1","updatedAt":"2026-07-01T23:52:24.428Z","proposals":[{"id":"jellyfin-nfo-builder-20260701-6434352e0d","kind":"create","status":"pending","title":"Create jellyfin-nfo-builder","description":"为剧集整理统一文件名、生成缺失的 Jellyfin .nfo 剧集元数据","skillName":"jellyfin-nfo-builder","skillKey":"jellyfin-nfo-builder","createdAt":"2026-07-01T23:52:24.406Z","updatedAt":"2026-07-01T23:52:24.406Z","scanState":"clean"},{"id":"weekly-report-g5-20260626-7595273f1d","kind":"create","status":"applied","title":"Create weekly-report-g5","description":"维云智造G5周报生成:整理每日工作→多段邮件(纯文本+HTML含签名图)→存入钉邮草稿箱","skillName":"weekly-report-g5","skillKey":"weekly-report-g5","createdAt":"2026-06-26T00:46:22.478Z","updatedAt":"2026-06-26T00:46:35.812Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-0fc374efd7","kind":"update","status":"pending","title":"Update calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T03:23:27.062Z","updatedAt":"2026-06-24T03:23:27.062Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-cdbeb219a3","kind":"update","status":"applied","title":"Update calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T03:03:28.166Z","updatedAt":"2026-06-24T03:03:30.915Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-a441798af9","kind":"create","status":"applied","title":"Create calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T02:29:02.278Z","updatedAt":"2026-06-24T02:29:27.227Z","scanState":"clean"},{"id":"calibre-title-cleaner-20260624-3760b64e8b","kind":"create","status":"applied","title":"Create calibre-title-cleaner","description":"清洗 Calibre 书库中损坏的 txt 文档书名(HTML标签/长文本/乱码/路径超限修复)","skillName":"calibre-title-cleaner","skillKey":"calibre-title-cleaner","createdAt":"2026-06-24T01:10:56.296Z","updatedAt":"2026-06-24T01:13:39.670Z","scanState":"clean"},{"id":"dianping-review-20260611-d402abec10","kind":"create","status":"pending","title":"Create dianping-review","description":"通过大众点评搜索查询餐厅、老店、美食推荐和评论","skillName":"dianping-review","skillKey":"dianping-review","createdAt":"2026-06-11T23:50:15.731Z","updatedAt":"2026-06-11T23:50:15.731Z","scanState":"clean"}]} +{"schema":"openclaw.skill-workshop.proposals-manifest.v1","updatedAt":"2026-07-06T09:04:18.526Z","proposals":[{"id":"f-download-sorter-20260706-902cc0d5aa","kind":"create","status":"applied","title":"Create f-download-sorter","description":"整理 /mnt/f 下下载的视频文件:扫描→清垃圾→按规则归档到7个大类目录","skillName":"f-download-sorter","skillKey":"f-download-sorter","createdAt":"2026-07-06T09:03:54.941Z","updatedAt":"2026-07-06T09:04:18.513Z","scanState":"clean"},{"id":"jellyfin-nfo-builder-20260701-6434352e0d","kind":"create","status":"pending","title":"Create jellyfin-nfo-builder","description":"为剧集整理统一文件名、生成缺失的 Jellyfin .nfo 剧集元数据","skillName":"jellyfin-nfo-builder","skillKey":"jellyfin-nfo-builder","createdAt":"2026-07-01T23:52:24.406Z","updatedAt":"2026-07-01T23:52:24.406Z","scanState":"clean"},{"id":"weekly-report-g5-20260626-7595273f1d","kind":"create","status":"applied","title":"Create weekly-report-g5","description":"维云智造G5周报生成:整理每日工作→多段邮件(纯文本+HTML含签名图)→存入钉邮草稿箱","skillName":"weekly-report-g5","skillKey":"weekly-report-g5","createdAt":"2026-06-26T00:46:22.478Z","updatedAt":"2026-06-26T00:46:35.812Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-0fc374efd7","kind":"update","status":"pending","title":"Update calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T03:23:27.062Z","updatedAt":"2026-06-24T03:23:27.062Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-cdbeb219a3","kind":"update","status":"applied","title":"Update calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T03:03:28.166Z","updatedAt":"2026-06-24T03:03:30.915Z","scanState":"clean"},{"id":"calibre-cleaner-20260624-a441798af9","kind":"create","status":"applied","title":"Create calibre-cleaner","description":"清洗 Calibre 书库:修复损坏书名/提取作者/检测编码损坏、小文件的批量删除","skillName":"calibre-cleaner","skillKey":"calibre-cleaner","createdAt":"2026-06-24T02:29:02.278Z","updatedAt":"2026-06-24T02:29:27.227Z","scanState":"clean"},{"id":"calibre-title-cleaner-20260624-3760b64e8b","kind":"create","status":"applied","title":"Create calibre-title-cleaner","description":"清洗 Calibre 书库中损坏的 txt 文档书名(HTML标签/长文本/乱码/路径超限修复)","skillName":"calibre-title-cleaner","skillKey":"calibre-title-cleaner","createdAt":"2026-06-24T01:10:56.296Z","updatedAt":"2026-06-24T01:13:39.670Z","scanState":"clean"},{"id":"dianping-review-20260611-d402abec10","kind":"create","status":"pending","title":"Create dianping-review","description":"通过大众点评搜索查询餐厅、老店、美食推荐和评论","skillName":"dianping-review","skillKey":"dianping-review","createdAt":"2026-06-11T23:50:15.731Z","updatedAt":"2026-06-11T23:50:15.731Z","scanState":"clean"}]} diff --git a/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/PROPOSAL.md b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/PROPOSAL.md new file mode 100644 index 0000000..3277090 --- /dev/null +++ b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/PROPOSAL.md @@ -0,0 +1,64 @@ +--- +name: "f-download-sorter" +description: "整理 /mnt/f 下下载的视频文件:扫描→清垃圾→按规则归档到7个大类目录" +status: proposal +version: "v1" +date: "2026-07-06T09:03:54.941Z" +--- + +# /mnt/f 下载文件批量归档整理 + +## 用途 +当 `/mnt/f/collections` 和 `/mnt/f/video` 里堆了大量下载的视频文件时,用此 Skill 批量整理:**清理垃圾 → 按内容类型归档到 `/mnt/f` 下的大类目录**。 + +## 触发条件 +- 用户说"整理 /mnt/f 的视频"、"归档 collections"、"下载文件太多了帮忙理一下"等 +- 或者用户显式调用此 skill + +## 流程 + +### Step 1: 扫描并统计 +运行 `/home/yangxuan/.nvm/versions/node/v25.2.0/lib/node_modules/openclaw/skills/f-download-sorter/scripts/scan_and_clean.py` +- 遍历 `/mnt/f/collections` 和 `/mnt/f/video` 下所有条目 +- 输出每个条目的:名称、大小、视频文件数 + +### Step 2: 清理垃圾 +同上脚本自动清理以下两类: +- **空壳目录**:目录总大小 < 1MB 且无视频文件(通常是推广 HTML/URL 文件) +- **小视频残片**:整条目录总大小 < 50MB 且视频内容极少 + +### Step 3: 按规则归类归档 +运行 `/home/yangxuan/.nvm/versions/node/v25.2.0/lib/node_modules/openclaw/skills/f-download-sorter/scripts/classify_and_move.py` + +分类规则(按文件名关键词匹配,优先级从上到下): + +| 规则 | 关键词 | 目标目录 | +|------|--------|----------| +| 过那条巷子 | "过那条巷子" | `/mnt/f/过那条巷子/` | +| 2048合集 | "2048" | `/mnt/f/2048合集/` | +| AI短剧 | "AI短剧"/"AI自制"/"AI视频"/"美丽新世界"/"少年阿宾"/"NTR寝取"/"嫂子"/"魔女小姨子"/"桃运圣医"/"我和老师的约定" | `/mnt/f/AI短剧/` | +| FC2福利姬 | "FC2"/"Comatozze"/"Dainty"/"KAKAE"/"lananlanan"/"P站" | `/mnt/f/FC2福利姬/` | +| 种子合集 | "BT-btt" | `/mnt/f/合集种子/` | +| 国产露脸 | "19岁"/"冯帆"/"momocats"/"露脸才是王道"/"香蕉" | `/mnt/f/国产露脸/` | +| 自拍泄漏 | 剩余所有含"泄密"/"自拍"/"露脸"/"自慰"/"原相机"/"情侣"/"校花"/"嫩妹"/"福利姬"/"裸聊"/"绿帽"/"良家"/"约炮"/"狗哥"/"土豪"/"原档"/"维度"/"桃子"/"娇娇"/"学妹"/"反差"等关键词 | `/mnt/f/自拍泄漏/` | +| 其他无法归类 | 以上都不匹配 | `/mnt/f/AI短剧/`(兜底) | + +**特殊规则:** +- `重生之征服郭伯母`(`/mnt/f/video/重生之征服郭伯母`)已有 Jellyfin NFO 元数据,**不动** + +### Step 4: 清理空目录 +移动完毕后,删除 `/mnt/f/collections` 和 `/mnt/f/video` 目录(如已为空)。 + +### Step 5: 报告结果 +输出最终 `/mnt/f` 下 7 个大类目录的结构和各目录大小。 + +## 注意事项 +- **WSL `/mnt/` 跨文件系统扫描很慢**,如果条目数极大(>500),优先在 Windows 原生 Python 中执行扫描/移动 +- 所有操作都是**同一分区内重命名(mv)**,不复制数据,瞬间完成 +- 不会打开/预览视频内容,仅基于文件名关键词分类 +- 删除前会经用户确认 + +## 脚本 +两个脚本位于 skill 目录的 `scripts/` 下: +- `scripts/scan_and_clean.py` — 扫描+清理垃圾 +- `scripts/classify_and_move.py` — 分类归档移动 \ No newline at end of file diff --git a/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/proposal.json b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/proposal.json new file mode 100644 index 0000000..789f0c7 --- /dev/null +++ b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/proposal.json @@ -0,0 +1 @@ +{"schema":"openclaw.skill-workshop.proposal.v1","id":"f-download-sorter-20260706-902cc0d5aa","kind":"create","status":"applied","title":"Create f-download-sorter","description":"整理 /mnt/f 下下载的视频文件:扫描→清垃圾→按规则归档到7个大类目录","createdAt":"2026-07-06T09:03:54.941Z","updatedAt":"2026-07-06T09:04:18.513Z","createdBy":"skill-workshop","origin":{"agentId":"storage","sessionKey":"agent:storage:main","runId":"ead41134-1fbd-4c3a-92b3-6ac9ff66c881","messageId":"ead41134-1fbd-4c3a-92b3-6ac9ff66c881"},"proposedVersion":"v1","draftFile":"PROPOSAL.md","draftHash":"6bb936a1321fbabce7a95b719c325be86c0a50005faa4e56bce40a058bdc9360","target":{"skillName":"f-download-sorter","skillKey":"f-download-sorter","skillDir":"/home/yangxuan/.openclaw/workspace/storage/skills/f-download-sorter","skillFile":"/home/yangxuan/.openclaw/workspace/storage/skills/f-download-sorter/SKILL.md","source":"openclaw-workspace"},"scan":{"state":"clean","scannedAt":"2026-07-06T09:04:18.504Z","critical":0,"warn":0,"info":0,"findings":[]},"appliedAt":"2026-07-06T09:04:18.513Z"} diff --git a/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/rollback.json b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/rollback.json new file mode 100644 index 0000000..f90b202 --- /dev/null +++ b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/rollback.json @@ -0,0 +1 @@ +{"schema":"openclaw.skill-workshop.rollback.v1","proposalId":"f-download-sorter-20260706-902cc0d5aa","writtenAt":"2026-07-06T09:04:18.505Z","targetSkillFile":"/home/yangxuan/.openclaw/workspace/storage/skills/f-download-sorter/SKILL.md","action":"create"} diff --git a/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/classify_and_move.py b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/classify_and_move.py new file mode 100644 index 0000000..c68720e --- /dev/null +++ b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/classify_and_move.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +""" +按关键词规则分类归档 /mnt/f/collections + /mnt/f/video 到 /mnt/f 下的大类目录 +""" +import os, shutil, json + +SRC = ["/mnt/f/collections", "/mnt/f/video"] +BASE = "/mnt/f" + +# 目标大类目录(自动创建) +CATEGORIES = { + "过那条巷子": ("过那条巷子", ["过那条巷子"]), + "2048合集": ("2048合集", ["2048"]), + "AI短剧": ("AI短剧", ["AI短剧","AI自制","AI视频","美丽新世界","少年阿宾","NTR寝取", + "嫂子","魔女小姨子","桃运圣医","我和老师的约定"]), + "FC2福利姬": ("FC2福利姬", ["FC2","Comatozze","Dainty","KAKAE","lananlanan","P站"]), + "合集种子": ("合集种子", ["BT-btt"]), + "国产露脸": ("国产露脸", ["19岁","冯帆","momocats","露脸才是王道","香蕉"]), + "自拍泄漏": ("自拍泄漏", ["泄密","自拍","自慰","原相机","情侣","校花","嫩妹","福利姬", + "裸聊","绿帽","良家","约炮","狗哥","土豪","原档","维度", + "桃子","娇娇","学妹","反差"]), +} + +KEEP_AS_IS = {"重生之征服郭伯母"} + +def classify(name): + """返回目标目录名或 None""" + if name in KEEP_AS_IS: + return None + for cat_name, (dir_name, keywords) in CATEGORIES.items(): + if any(k in name for k in keywords): + return os.path.join(BASE, dir_name) + return os.path.join(BASE, "AI短剧") # 兜底 + +moves = [] +for base in SRC: + if not os.path.isdir(base): + continue + for entry in sorted(os.listdir(base)): + full = os.path.join(base, entry) + if not os.path.isdir(full): + continue + dst_base = classify(entry) + if dst_base is None: + print(f" ○ 不动: {entry}") + continue + dst = os.path.join(dst_base, entry) + if os.path.exists(dst): + i = 1 + while os.path.exists(f"{dst}_{i}"): i += 1 + dst = f"{dst}_{i}" + moves.append((full, dst)) + +# 创建目录 +all_dirs = set(os.path.dirname(d) for _, d in moves) +for d in all_dirs: + os.makedirs(d, exist_ok=True) + +# 执行移动 +print(f"开始移动 {len(moves)} 个条目...") +for src, dst in moves: + try: + shutil.move(src, dst) + print(f" ✓ {os.path.basename(src)}") + except Exception as e: + print(f" ✗ {os.path.basename(src)} -> {e}") + +# 清理空目录 +for d in SRC: + if os.path.isdir(d) and not os.listdir(d): + os.rmdir(d) + print(f" ✓ 已删空目录: {d}") + +# 报告 +print("\n=== /mnt/f 最终结构 ===") +for d in sorted(os.listdir(BASE)): + full = os.path.join(BASE, d) + if os.path.isdir(full): + sz = 0 + cnt = 0 + for dp, dn, fn in os.walk(full): + for f in fn: + cnt += 1 + try: sz += os.path.getsize(os.path.join(dp, f)) + except: pass + print(f" {d}/ ({cnt} 文件, {sz/1024**3:.1f}GB)") diff --git a/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/scan_and_clean.py b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/scan_and_clean.py new file mode 100644 index 0000000..f07a954 --- /dev/null +++ b/skill-workshop/proposals/f-download-sorter-20260706-902cc0d5aa/scripts/scan_and_clean.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +扫一扫 + 清垃圾 +遍历 /mnt/f/collections 和 /mnt/f/video,输出清单并清理空壳/小文件残片 +""" +import os, shutil + +SRC = ["/mnt/f/collections", "/mnt/f/video"] +MINSIZE = 50 * 1024 * 1024 # 50MB +video_exts = {'.mp4','.mkv','.avi','.mov','.wmv','.flv','.webm','.ts','.m4v','.rmvb'} + +targets = [] +print("=== 扫描 ===") +for base in SRC: + if not os.path.isdir(base): + continue + for entry in sorted(os.listdir(base)): + full = os.path.join(base, entry) + if not os.path.isdir(full): + continue + total_sz = 0 + real_video = 0 + try: + for dp, dn, fn in os.walk(full): + for f in fn: + fp = os.path.join(dp, f) + try: + total_sz += os.path.getsize(fp) + except: pass + if os.path.splitext(f)[1].lower() in video_exts: + real_video += 1 + except: pass + + action = "" + if total_sz < MINSIZE and real_video == 0: + action = "DELETE" + elif total_sz < MINSIZE and real_video > 0: + action = "DELETE" + else: + action = "KEEP" + + print(f" [{action:>6}] {entry} ({total_sz/1024**2:.0f}MB, {real_video}视频)") + + if action == "DELETE": + targets.append(full) + +if targets: + print(f"\n待删除: {len(targets)} 个") + print("开始删除...") + for d in targets: + shutil.rmtree(d) + print(f" ✓ 已删: {os.path.basename(d)}") +else: + print("\n无需清理。") diff --git a/workspace-attestations/b7bc825f1ed54245663ac357564ad4f39678451d147525a2c689c68dd0bb7882.attested b/workspace-attestations/b7bc825f1ed54245663ac357564ad4f39678451d147525a2c689c68dd0bb7882.attested index 1bab727..a755cf3 100644 --- a/workspace-attestations/b7bc825f1ed54245663ac357564ad4f39678451d147525a2c689c68dd0bb7882.attested +++ b/workspace-attestations/b7bc825f1ed54245663ac357564ad4f39678451d147525a2c689c68dd0bb7882.attested @@ -1,2 +1,2 @@ openclaw-workspace-attestation:v1 -2026-07-06T08:49:46.214Z +2026-07-06T09:51:32.683Z