@mr-quin/dango-manifests
v0.6.0
Published
Built-in dango manifests for danmaku sources
Downloads
149
Readme
@mr-quin/dango-manifests
Built-in dango manifests for a curated set of danmaku sources. Each manifest is a JSON file declaring the search/episodes/danmaku pipelines a @mr-quin/dango ManifestRunner interprets at runtime, with no per-source TypeScript fetching code.
This package is data, not code. There is no index.ts: consumers import each manifest JSON directly via the ./manifests/* subpath export.
Shipped manifests
| Id | Endpoint | Notes |
| ------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| dandanplay | baseUrl (default api.dandanplay.net) | Unified DDP source. Default official; optional appId/appSecret signing, auth headers, or none (proxy). baseUrl overrides the endpoint (proxy / self-hosted). |
| bilibili | api.bilibili.com | Parallel media_bangumi + media_ft search; xml + protobuf danmaku variants. |
| tencent | pbaccess.video.qq.com + dm.video.qq.com | POST bodies, page-cursor episode pagination via forEach breakOn, two-phase danmaku (segment index then per-segment fetch). |
| hanjutv | hxqapi.hiyun.tv + hxqapi.zmdcq.com | Korean-drama source; search, detail-driven episodes, per-segment danmaku. |
| mango | *.mgtv.com + *.hitv.com | Mango TV; source=imgo search, two-stage showlist episodes, per-minute CDN danmaku shards. |
| migu | *.migu.cn + *.miguvideo.com | Migu Video; content-info lookup, episodes list, segmented danmaku. |
| youku | *.youku.com + log.mmstat.com | Youku; HTML-stripped search, openapi episodes, signed per-minute danmaku POSTs (cna guid + _m_h5_tk token). |
| iqiyi | *.iqiyi.com + mesh.if.iqiyi.com | iQIYI; /v_ watch-page search, signed base_info episodes, zlib-deflated XML bullet shards. |
| aiyifan | yfsp.tv + rankv21.tripdata.app | Aiyifan; homepage-scraped pub/priv keys sign each JSON request; getBarrage danmaku. |
| bahamut | api.gamer.com.tw | Bahamut Anime (Traditional Chinese); single danmu.php fetch, time in tenths of a second. |
| maiduidui | mob.mddcloud.com.cn | Maiduidui; nested search, listVodSactions episodes, per-minute vodBarrage shards. |
| renren | api.gorafie.com + static-dm.qwdjapp.com | Renren (foreign drama); array-rooted danmaku with CSV p strings. |
| sohu | *.sohu.com | Sohu TV; site=1 search, album episodes, paginated dmListAll danmaku (decimal/hex color handling). |
Layout
src/
manifests/
aiyifan.json
bahamut.json
bilibili.json
dandanplay.json
hanjutv.json
iqiyi.json
maiduidui.json
mango.json
migu.json
renren.json
sohu.json
tencent.json
youku.json
__tests__/
*.test.ts # per-manifest pipeline tests
fixtures/ # captured representative responses
mockFetcher.ts # shared test fetcher (string + Uint8Array bodies)
scripts/
smoke-test.ts # manual end-to-end test against the real APIUsage
import { ManifestRunner, zManifest } from '@mr-quin/dango'
import builtinDandanplay from '@mr-quin/dango-manifests/manifests/dandanplay.json' with { type: 'json' }
const manifest = zManifest.parse(builtinDandanplay)
const runner = new ManifestRunner(manifest, { fetcher })
const results = await runner.runSearch({ q: 'frieren' })
const episodes = await runner.runEpisodes({
bangumiId: results[0].providerIds.bangumiId,
})
const danmaku = await runner.runDanmaku({
episodeId: episodes[0].providerIds.episodeId,
})CDN consumption
A host can discover and fetch manifests over a CDN without bundling this package at build time. jsDelivr and unpkg serve the published package files, so a host reads catalog.json for the index, then fetches each entry's file path.
https://cdn.jsdelivr.net/npm/@mr-quin/dango-manifests@<version>/catalog.json
https://cdn.jsdelivr.net/npm/@mr-quin/dango-manifests@<version>/<file>catalog.json is generated from the manifests on disk and ships with the package:
{
"packageVersion": "0.4.0",
"manifests": [
{
"id": "bilibili",
"name": "Bilibili",
"version": "0.4.0",
"apiVersion": 1,
"file": "src/manifests/bilibili.json",
},
// ...
],
}Each file is the in-package path to fetch, e.g.:
https://cdn.jsdelivr.net/npm/@mr-quin/[email protected]/src/manifests/bilibili.jsonunpkg works the same way (https://unpkg.com/@mr-quin/dango-manifests@<version>/...). Pin a <version> for reproducibility; omit it to track the latest published release.
catalog.json is regenerated as part of bun run build; bun run check fails if the committed copy is stale (run bun run catalog and commit the result).
Routing notes
DanDanPlay (dandanplay) is one manifest for every DDP endpoint over the /api/v2 paths. baseUrl (config) defaults to the official api.dandanplay.net; point it at a proxy or self-hosted server to override. Auth is picked by config: appId + appSecret sign each request (X-Signature: Base64(SHA256(appId + timestamp + path + appSecret)), secret never sent); else auth.enabled + auth.headers attach custom headers; else no auth (for a proxy that signs server-side). The official API is just the case with no baseUrl and credentials set.
Bilibili and Tencent call their public APIs directly. Both rely on rewriteHeaders for Origin / Referer, which a browser host's FetchLike applies via a request-header rewrite mechanism such as chrome.declarativeNetRequest. The smoke script merges those headers in directly since Node fetch lets you set them.
Smoke testing
bun run smoke <source> [keyword] walks search → first result → episodes → first episode → danmaku against the real API. Not in CI; useful when adding a manifest or verifying after an upstream change.
| Source | Command | Status |
| -------- | ------------------------------- | -------------------------------------------------------- |
| ddp | bun run smoke ddp Frieren | needs DDP_APP_ID / DDP_APP_SECRET env (official API) |
| bilibili | bun run smoke bilibili Naruto | works (after a cookie warm-up via www.bilibili.com) |
| tencent | bun run smoke tencent 庆余年 | works |
The smoke fetcher keeps a per-host cookie jar so bilibili's anti-bot wall lets us through, and it merges rewriteHeaders into the outgoing request (Node has no Origin/Referer restriction). The default ddp smoke hits the official API and needs DDP_APP_ID / DDP_APP_SECRET.
Adding a new manifest
- Drop the JSON file in
src/manifests/. Useid: '<source>'. - Capture representative responses from the source's API to
src/__tests__/fixtures/. - Write a per-manifest test that:
- Parses the manifest against
zManifest(catches schema drift) - Runs each pipeline with a mocked
FetchLikeagainst the captured fixtures - Asserts the canonical shape the engine emits
- Parses the manifest against
- (Optional) Add a section to
scripts/smoke-test.tsto exercise the new manifest against a live endpoint.
Each manifest's tests own their own fixtures, don't share fixtures across manifests.
Trust model
Manifests in this package are vetted at PR review time and shipped as built-ins. They are not user-installable. User-installed manifests are a separate concern a host may add with explicit consent UX. See dango's trust model for the engine-level invariants that apply regardless of where a manifest comes from.
Scripts
| Command | Description |
| ------------------------ | -------------------------------------------------------------- |
| bun test | bun test, fixture-backed pipeline tests |
| bun run smoke <source> | Live end-to-end test against the real API (manual, not CI) |
| bun run type-check | tsc --noEmit |
| bun run catalog | Regenerate catalog.json from the manifests on disk |
| bun run catalog:check | Fail if the committed catalog.json is stale |
