---
name: media-library-organization
description: "Use when organizing media downloads into 待处理/已完成 folders."
version: 1.0.0
author: Hermes Agent
license: MIT
platforms: [linux, macos]
metadata:
  hermes:
    tags: [media, files, organization, funscript, mp4, library, data-disk]
---

# Media Library Organization

Organize a downloaded media library where videos ship with optional companion
script files (`.funscript`, used by interactive toys). The library uses a
pending/completed split with a strict per-video folder convention.

## When to Use

- User asks to check/organize `/mnt/DataDisk` (or mentions 待处理 / 已完成).
- Loose `.mp4` files need folding into per-video folders.
- Folders containing both an mp4 and its `.funscript` companion need archiving
  to the completed area.
- The user may ask to run this repeatedly or as a cron job — the rules are stable.

## Library Layout (user's environment)

```
/mnt/DataDisk/
├── 待处理/          # PENDING: incoming downloads
│   ├── <Video Title>/<Video Title>.mp4      # already-organized videos (normal state)
│   └── loose.mp4                             # rule-1 target: needs a folder
└── 已完成/          # COMPLETED: folders with mp4 + funscript pairs
    └── <Video Title>/  # contains <Title>.mp4 + <Title>.funscript (+ .multi/.r1 variants)
```

## The Two Rules

1. **Loose mp4 → own folder.** A `.mp4` sitting directly in 待处理 with **no
   same-name `.aria2` file** (aria2 = download in progress) gets a folder named
   after the mp4 basename *without* extension, and the mp4 moves inside.
2. **Completed folder → 已完成.** A subfolder of 待处理 containing **both** a
   same-name `.mp4` and a `.funscript` file moves wholesale to 已完成.
   `.multi.funscript` / `.r1.funscript` variants count as the funscript presence.

## Workflow: Survey → Act → Verify

The user deliberately tests reliability — never trust the state from a previous
run. State changes between runs (files get moved in by downloads or by the user
to test you).

1. **Survey.** `ls -la` both folders; `find "$PENDING" -mindepth 1` for the full
   tree; scan the whole disk for `*.aria2` and `*.funscript` to establish the
   baseline. Note the naming convention of existing folders before creating new
   ones (folder = mp4 basename without extension).
2. **Pre-check conflicts.** Before any `mv` into 已完成, test whether a
   same-name folder already exists there — plain `mv` would merge/overwrite.
3. **Act.** `mkdir -p` the target folder then `mv` (same filesystem = instant
   rename, even for multi-GB files). Quote all paths — they contain spaces,
   CJK, and special characters (`&`, `~`, `[ ]`, `♡`).
4. **Verify after every move.** Destination contains the expected files with
   matching sizes; source path no longer exists. Finish with a full re-scan:
   no loose mp4s left, no pending subfolder still holding mp4+funscript pairs,
   zero `.aria2` files, target folder present in 已完成.

## Event-Driven Automation (file watcher + webhook)

Since 2026-08-11 there is a live event-driven pipeline — new files trigger
organizing **immediately** (no cron):

- `~/.hermes/scripts/media_watcher.py` — Python watchdog script watching
  `/mnt/DataDisk/待处理` recursively, debounces 5s, HMAC-SHA256 V2-signed POST
  to the `media-library-watch` webhook route on the local gateway.
- Runs as systemd user service `media-watcher.service` (restarts on failure,
  enabled at boot; linger already on). Uses venv `~/.hermes/watcher-venv`.
- Gateway (`hermes-gateway.service`, port 8644) hosts the webhook platform;
  subscription in `~/.hermes/webhook_subscriptions.json` (deliver=`log`,
  skills=`media-library-organization`, prompt directs agent to append a
  timestamped summary line to `~/.hermes/media-organize-report.md`).
- Prompt template placeholders must NOT carry a `payload.` prefix — write
  `{file}` / `{event}`, not `{payload.file}`. `_render_prompt` (in
  gateway/platforms/webhook.py) resolves the FIRST dotted segment as a literal
  key lookup into the payload dict, so `{payload.file}` silently stays as the
  literal placeholder text and the agent reports seeing "placeholder values".
- `deliver: origin` is NOT a valid webhook deliver type — only `log`,
  `github_comment`, or a real enabled platform adapter work. Use `log` +
  a report file (as configured above) so results are inspectable.
- Webhook agent toolset is configured via `platform_toolsets.webhook` in
  config.yaml (YAML list, e.g. terminal/file/skills/todo/clarify/web).
  ⚠️ Set it with `hermes tools enable --platform webhook <name> ...` — a plain
  `hermes config set` writes the list as a STRING, which `_get_platform_tools`
  ignores and silently falls back to the intentionally-minimal webhook-safe
  toolset (web_search/web_extract/vision_analyze/clarify).
- Verification evidence for a fire: `~/.hermes/logs/media-watcher.log`
  (queued → POST 202), gateway.log `Response for ...`, and the report file.
- Test end-to-end by dropping a dummy mp4 into 待处理, waiting ~10-15s, then
  checking the report file; clean up the test folder afterwards.

## Scripts

- `scripts/organize_pending.sh` — repeatable survey (dry-run) + apply mover.
  Run `bash organize_pending.sh` to report what needs doing, add `--apply` to
  perform the moves.

## Pitfalls

- `.aria2` file next to an mp4 means the download is **incomplete** — skip it.
- `.funscript` matching must be case-insensitive (`-iname`) and must catch
  variants: `Title.funscript`, `Title.multi.funscript`, `Title.r1.funscript`.
- Use `find -maxdepth 1 -name "*.mp4"` for loose files only — mp4s already
  inside per-video folders must NOT be re-foldered.
- Folder naming must follow the existing convention exactly (basename, no
  `.mp4` extension) or the library ends up inconsistent.
- When offering automation (cron), ask first — the user may prefer to keep it
  manual and move things in to test.
- Report per-rule results explicitly (rule 1: N files folded; rule 2: N folders
  moved) with verification evidence — the user checks that you actually did it.
