Communitygithub.com

zimodzh/hls-dot0-to-mp4-skill

Agent Skill:华为浏览器 sniff-download / 资源嗅探 的 HLS `.0` cache(aq.m3u8.0 · *.ts.0 · *.key.0)→ desktop-playable MP4. 手机能播、电脑打不开 — local remux only, no URL scrape, no DRM.

hls-dot0-to-mp4-skill 是什么?

hls-dot0-to-mp4-skill is a Cursor agent skill that agent Skill:华为浏览器 sniff-download / 资源嗅探 的 HLS `.0` cache(aq.m3u8.0 · *.ts.0 · *.key.0)→ desktop-playable MP4. 手机能播、电脑打不开 — local remux only, no URL scrape, no DRM.

兼容平台~Claude Code~Codex CLICursor
npx skills add zimodzh/hls-dot0-to-mp4-skill

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

HLS .0 cache → MP4

Huawei Browser sniff-download stores each video as a UUID folder of encrypted HLS, then appends .0 to every filename. The phone player reads its own DB + these names. PC players and FFmpeg do not.

This skill converts that cache by hardlinking .ts.0.ts and .key.0.key, feeding the original playlist to FFmpeg (-c copy), then deleting only the temp names. Verified on Huawei Browser caches. Other vendors are untested.

When to use

Activate if any of these are true:

  • Folder names look like 64f1723d-421b-495c-8a10-85ab7d74ddab
  • Files named aq.m3u8.0, *.ts.0, *.key.0
  • User says 嗅探下载 / 华为浏览器 / VideoData / 手机能播电脑不能
  • Log lines mention DLEngine, DLSegMgr, download_content_

Do not use for: downloading an m3u8 URL (that is N_m3u8DL-RE / 猫抓), Widevine/PSSH DRM, or remuxing already-plain .mp4.

Layout (do not trust workspace search)

Cursor/ripgrep omit binary *.0 files. Glob **/*.ts.0 returns 0 even when 73 segments exist. Prove files with a directory listing (Get-ChildItem / dir / Path.iterdir), or by reading a playlist-named path (binary read error = file exists).

Each video folder:

<uuid>/
  aq.m3u8.0          # playlist; references foo.ts and foo.key (no .0)
  <digits>.ts.0      # AES-128 MPEG-TS, ~10s each
  <digits>.key.0     # 16-byte HLS key

Optional sibling log/<uuid>.txt is DLEngine text, not media.

Read references/layout.md if the tree differs (missing key, nested dirs, no aq.m3u8.0).

Workflow

Hard gate — do this before any convert or download.

0. Find ffmpeg, or stop and ask

Bounded search only (never recurse a whole drive). scripts/convert.py uses the same order:

  1. --ffmpeg / env HLS_DOT0_FFMPEG
  2. <cache-root>/ffmpeg.exe or <cache-root>/ffmpeg
  3. PATH (where.exe ffmpeg / command -v ffmpeg)
  4. A few common dirs if still missing: %LOCALAPPDATA%\Microsoft\WinGet\Links\ffmpeg.exe, %USERPROFILE%\scoop\shims\ffmpeg.exe, C:\ffmpeg\bin\ffmpeg.exe, /opt/homebrew/bin/ffmpeg, /usr/local/bin/ffmpeg

Run ffmpeg -version (or that absolute path). Success → go to step 1.

If not found, stop. Ask the user exactly these two options; do not install or convert until they answer:

  • A. They install or drop ffmpeg themselves, then tell you when ready — re-run this search + -version.
  • B. You install it — detect OS and arch first (win32 + PROCESSOR_ARCHITECTURE / uname -s + uname -m). Then follow only the matching default in references/ffmpeg-install.md.

Install rules: one default command, one fallback if it fails, then ask again. Do not install Homebrew / Chocolatey / Scoop just to get ffmpeg unless the user agrees. Do not commit a downloaded binary into this skill repo. After a successful install, verify -version in a new shell or via the installer path (Windows PATH often stale).

1. Plan (print, then convert)

List UUID directories (8-4-4-4-12 hex). For each, count *.ts.0, *.key.0, and whether aq.m3u8.0 exists. Skip folders with 0 segments or no key.

Default order: folder name A–Z. Number outputs 01.mp4, 02.mp4, … in --out-dir (default <cache-root>/mp4) from --start (default 1). The script skips a name when that mp4 already exists (JSON skipped: true) unless --force. Re-run the same command after a partial batch — already-done numbers stay, the rest convert. Do not invent a second numbering scheme.

2. Run the bundled script (do not reinvent)

From this skill root:

python scripts/convert.py --root <cache-root> --dry-run
python scripts/convert.py --root <cache-root> --out-dir <cache-root>/mp4 --start 1
python scripts/convert.py --root <cache-root> --folder <uuid> --name 01 --force

Always pass --dry-run first on a new tree. Script stdout is JSON; progress goes to stderr.

Do not rewrite the playlist to *.ts.0. FFmpeg rejects that extension even with -allowed_extensions ALL (not in allowed_segment_extensions). Hardlink/copy to the names already in aq.m3u8.0.

Do not probe outputs with PowerShell $ErrorActionPreference = "Stop" plus ffmpeg -i file -f null -. FFmpeg writes banner to stderr; PowerShell treats it as a terminating error and a catch that deletes the mp4 will wipe a successful convert.

Exact FFmpeg flags (fragile — do not drop):

ffmpeg -y -hide_banner -loglevel warning -stats -allowed_extensions ALL -protocol_whitelist file,crypto,data -i play.m3u8 -c copy out.mp4

3. Cleanup and report

The script removes only temp names it created this run (plus leftover hardlinks that already point at the .0 files) and always removes play.m3u8. Original *.ts.0 / *.key.0 / aq.m3u8.0 stay. It does not delete a pre-existing .ts / .key that is not a hardlink to the .0 file.

Report a table: number, size, duration if known, sps_warning. See references/troubleshooting.md for SPS and other failures.

If the user asks to re-encode a SPS-warning file: ffmpeg -i 04.mp4 -c:v libx264 -crf 18 -c:a copy 04_fixed.mp4 — only those files, not the whole batch.

Checklist

  • Directory listing shows .ts.0 and .key.0 (search tools may lie)
  • ffmpeg found (bounded search) or user chose A/B; -version ok; no full-disk scan
  • If installing: OS/arch detected; only the matching commands in references/ffmpeg-install.md
  • --dry-run plan looks right (counts, output names, SKIP on existing mp4s)
  • One folder converted and user can play it (unless they said convert all)
  • Batch JSON ok / skipped / per-item errors; temp links gone
  • Mention SPS-warning numbers so the user can spot-check

Output format

Converted N/M videos → <out-dir>
01.mp4  101 MB  (~12:10)  ok
04.mp4  251 MB  (~23:59)  SPS warning — check start and ~10s cuts
FAIL  <uuid>  missing key.0

Gotchas

  • .0 is the real media. Glob/index skipping binaries is not “files missing.”
  • Playlist URI="….key" and ….ts — on disk they are ….key.0 / ….ts.0.
  • Hardlinks must stay on the same volume; if os.link fails, copy (slow, extra disk).
  • non-existing SPS 0 referenced in buffering period is usually cosmetic on -c copy. Check 10s boundaries; re-encode only if playback is broken.
  • GUI tools (N_m3u8DL-RE, m3u8-to-mp4) expect standard extensions. They work after rename/hardlink, not on raw Huawei names.
  • This is standard HLS AES-128 with a local key (no pssh in DLEngine logs), not Widevine circumvention.
  • No ffmpeg → ask A/B first. Do not silently winget/brew/apt or download an exe.
  • Existing 01.mp4… are skipped, not errors. Use --force only when the user wants those files overwritten.

相关技能