wjs-mining-voicedrop
This Claude Code skill processes voice memos from a VoiceDrop iOS app by retrieving unprocessed M4A files from an R2 cloud inbox, transcribing them using the wjs-transcribing-audio skill, and mining them into WeChat article drafts via the wjs-mining-articles skill. Use it when a user requests processing of their voice recordings with Chinese phrases like "处理 VoiceDrop 录音" or commands like "/wjs-mining-voicedrop", ensuring files are locally archived before deletion and only removed after successful article generation to prevent data loss.
git clone --depth 1 https://github.com/jianshuo/claude-skills /tmp/wjs-mining-voicedrop && cp -r /tmp/wjs-mining-voicedrop/wjs-mining-voicedrop ~/.claude/skills/wjs-mining-voicedropSKILL.md
# wjs-mining-voicedrop VoiceDrop 收件箱(`jianshuo.dev/files` 上的 `VoiceDrop-*.m4a`)→ 逐条转写 → 交给 `wjs-mining-articles` 出公众号草稿。这是 VoiceDrop iOS app(开口即录、停即上传)的 Mac 端闭环。 ## Core Principle **复用,不重写。** 本 skill 只做两件本身没有的事:**收件箱的进出**(列/下载/删)和**逐条编排**。转写交 `wjs-transcribing-audio`,成文交 `wjs-mining-articles`,一行都不重写。 **R2 当收件箱。** 「未处理」= 桶里现有的所有 `VoiceDrop-*.m4a`。一条**成功**跑完文章后,音频已存档到本地,再从 R2 删——桶里永远只剩还没处理的。**没成功就不删**,留着下次再来。 ## When This Skill Fires - 用户说「处理 VoiceDrop 录音」「把新录音挖成文章」「处理一下我的口述」 - 用户跑 `/wjs-mining-voicedrop` ## When NOT to use - **已经有 SRT** → 直接 `wjs-mining-articles` - **音频不在 R2 收件箱**(本地散文件)→ 直接 `wjs-transcribing-audio` 出 SRT,再 `wjs-mining-articles` - **桶里是别的机器传的非录音文件** → 本 skill 只认 `VoiceDrop-*.m4a` 前缀,其余不碰 ## 前置 - `~/code/.env` 里有 `FILES_TOKEN`(收件箱鉴权)和火山 ASR creds(`VOLC_ASR_*` / `VOLC_TTS_*`,转写用)。`set -a; source ~/code/.env; set +a`。 ## Workflow 唯一的新增代码:`scripts/voicedrop-inbox.sh`(`list` / `download` / `delete`,token 运行时从 `~/code/.env` 读,绝不落代码)。从 skill 根目录跑。 ### Step 1 · 列收件箱 ```bash scripts/voicedrop-inbox.sh list # 打印未处理的 VoiceDrop-*.m4a,一行一个 ``` 空 → 报「收件箱没有新录音」结束。非空 → 拿到这一批文件名。 ### Step 2 · 逐条闭环(串行,一条跑完再下一条) **串行**,因为删除安全依赖「这一条彻底成功」。对每个 `<name>`: 1. **先下载存档**(绝不先删 R2): ```bash scripts/voicedrop-inbox.sh download <name> ~/code/voicedrop/archive ``` 音频落 `~/code/voicedrop/archive/<name>`。**这一步就是存档**——之后即使删了 R2,本地也有。 2. **快速看一眼是不是真录音**:`ffprobe` 查时长。≈0 秒 / 几字节的误传/测试文件 → 跳过、向用户报告,**不删**(让用户自己决定清不清)。 3. **转写** → SRT:载入 **`wjs-transcribing-audio`**(中文走火山豆包 `volc_asr_stream.py` + `build_srt_from_asr.py` + 在 session 内做 AI 润色改错别字)。SRT 落 `~/code/voicedrop/archive/<stem>.srt`。 4. **挖文章**:把这个 SRT 交给 **`wjs-mining-articles`** 跑它的完整流程——出选题清单(**它的人工闸,照走别跳**)、成文、建微信草稿。语音备忘多是短独白单主题,清单常只有 1 条,照常让用户确认。 5. **只有上面都成功**(出了至少一篇草稿、用户没中止)**才删 R2**: ```bash scripts/voicedrop-inbox.sh delete <name> ``` 转写失败 / 用户没勾任何选题 / 挖不出文章 → **不删**,留收件箱,报告原因。 ### Step 3 · 汇报 处理了几条、各挖出几篇草稿(落在 `~/code/wechat-publish/`)、本地存档路径、R2 收件箱现在还剩几条。 ## 删除安全红线 ``` download(存档) → transcribe → mine → 出了草稿 → 才 delete ``` 任何一步失败、用户没勾选、没产出草稿 → **不 delete**。删除是「这一条彻底处理完」的最后一步,不是中途动作。先存档后删,音频永不丢。 ## 复用边界 | 复用 | 用法 | |---|---| | `wjs-transcribing-audio` | 每条音频 → SRT(中文火山豆包,含润色改错别字) | | `wjs-mining-articles` | 每个 SRT → 选题清单 → 成文 → 微信草稿(含它自己的人工闸) | | `~/code/.env` | `FILES_TOKEN` + 火山 ASR creds | | VoiceDrop app | 上游:文件名形如 `VoiceDrop-<时间戳>-<时长>-<星期>-<时段>[-<城市-城区>].m4a`(全 ASCII)。本 skill 靠 `VoiceDrop-` 前缀 + `.m4a` 后缀认领;中间的时长/星期/时段/地点是上下文,成文时可借来判断这条录音是何时何地的口述 | **本 skill 唯一新增代码**:`scripts/voicedrop-inbox.sh`。 ## Common Mistakes - **先删 R2 再处理** —— 红线倒置。必须先 download 存档、彻底成功后才 delete。 - **转写失败/没成文却把文件删了** —— 永久丢录音。没产出草稿绝不 delete。 - **跳过 `wjs-mining-articles` 的选题闸自己硬写** —— 那个闸是它的设计,照走。 - **并行处理多条还各自删** —— 串行逐条闭环,避免中途失败时收件箱状态混乱。 - **把桶里非 VoiceDrop 文件也当源** —— 只认 `VoiceDrop-*.m4a` 前缀。 - **误传/0 秒测试文件当真录音去转写** —— 先 ffprobe 看时长,可疑的报给用户、不删。
Repo-wide drift detector for the wjs-* Claude Code skills in this marketplace. Sweeps every SKILL.md, scores it against the repo's own conventions (V-ing naming, trigger-phrase density, companion files, description shape), and returns a grouped punch list ordered by severity. Read-only — never edits files. Use before pushing a batch of skill changes, or whenever you wonder "are these skills still internally consistent?
|
Use when the user asks to audit what's wrong with a project, "make it right", "看看项目出了什么问题", "为什么用户的需求还没上线", "为什么没提交App Store", "为什么没新build", or wants a holistic state-of-the-project check covering unmerged branches, stalled PRs, failed GitHub Actions, stale builds, plan drift (TODOS.md / ROADMAP), unreleased commits, and log errors. Runs read-only investigation, presents a grouped checklist, fixes only after explicit user confirmation. Aware of the Cathier iOS app workflow (Xcode + fastlane + auto-merge @claude PRs from in-app feedback).
Use when the user has a video + an SRT and wants the subtitles either burned into the pixels (libass, always-visible) or soft-muxed as a togglable track. Also handles the final composite step for the localization pipeline — burn subs, mix a dub track, and keep the original audio as a low-volume bed, all in ONE ffmpeg encode (no cascade). Verifies libass availability and auto-downloads a static evermeet ffmpeg build when Homebrew's stripped binary lacks it. Triggers — "烧字幕", "硬字幕", "burn subtitles", "burn-in subs", "embed subtitle", "soft mux SRT", "把字幕烧进视频", "做最终合成".
Use when the user complains about spam on his X/Twitter posts — 同城面付 / 寻固炮 / 线下上门 / 免费破处 这类引流号在他推文下刷的 emoji 垃圾回复 — and wants them removed. Covers the last 7 days (X recent-search window). Triggers — "把这些spam删掉", "清理X垃圾回复", "推文下面好多引流号", "clean spam replies", "/wjs-cleaning-spam".
Use when the user wants a 王建硕-style WeChat article (article.md) turned into a narrated short MP4 video — TTS voiceover via 火山引擎 Volcano TTS, HyperFrames CSS/GSAP animation per scene, subtle SFX, abstract watercolor background, full pipeline rendering to 1080×1920 portrait MP4 (30-90s). Triggers — "把这篇文章做成视频", "做一个解说视频", "讲解视频", "/wjs-converting-text-to-video".
Use when migrating a WordPress site to a Hugo static site on GitHub Pages from a WXR export (.xml) plus the wp-content/uploads folder — preserving /archives/<id>/ URLs, localizing images, and deploying via GitHub Actions. Triggers — "把 WordPress 迁成 Hugo", "wordpress 转静态站", "migrate WordPress to Hugo", "WXR to Hugo", "publish WordPress to GitHub Pages", "/wjs-converting-wp-to-hugo".
Use when the user has a video + a target-language SRT and wants the video to actually speak that language — generates a time-aligned TTS voice dub. Routes by voice ID — Volcano (豆包) TTS for Chinese, edge-tts neural for any language. Defaults to one voice (single-speaker); opt-in multi-speaker via visual diarization. Outputs `*_<lang>_dub.mp4` with the dub audio in place of the original. Final mixing (audio bed + burn-in) is handed off to `/wjs-burning-subtitles`. Triggers — "配音", "中文配音", "Chinese dub", "voice over this", "dub the video", "TTS this SRT", "different voice for each speaker".