@mr-quin/dango-manifests 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -34
- package/catalog.json +96 -0
- package/package.json +5 -2
- package/src/manifests/{builtin-aiyifan.json → aiyifan.json} +2 -2
- package/src/manifests/{builtin-bahamut.json → bahamut.json} +2 -2
- package/src/manifests/{builtin-bilibili.json → bilibili.json} +2 -2
- package/src/manifests/{builtin-dandanplay.json → dandanplay.json} +2 -2
- package/src/manifests/{builtin-hanjutv.json → hanjutv.json} +2 -2
- package/src/manifests/{builtin-iqiyi.json → iqiyi.json} +2 -2
- package/src/manifests/{builtin-maiduidui.json → maiduidui.json} +2 -2
- package/src/manifests/{builtin-mango.json → mango.json} +2 -2
- package/src/manifests/{builtin-migu.json → migu.json} +2 -2
- package/src/manifests/{builtin-renren.json → renren.json} +2 -2
- package/src/manifests/{builtin-sohu.json → sohu.json} +2 -2
- package/src/manifests/{builtin-tencent.json → tencent.json} +2 -2
- package/src/manifests/{builtin-youku.json → youku.json} +12 -7
package/README.md
CHANGED
|
@@ -6,42 +6,42 @@ This package is data, not code. There is no `index.ts`: consumers import each ma
|
|
|
6
6
|
|
|
7
7
|
## Shipped manifests
|
|
8
8
|
|
|
9
|
-
| Id
|
|
10
|
-
|
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
9
|
+
| Id | Endpoint | Notes |
|
|
10
|
+
| ------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `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). |
|
|
12
|
+
| `bilibili` | `api.bilibili.com` | Parallel media_bangumi + media_ft search; xml + protobuf danmaku variants. |
|
|
13
|
+
| `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). |
|
|
14
|
+
| `hanjutv` | `hxqapi.hiyun.tv` + `hxqapi.zmdcq.com` | Korean-drama source; search, detail-driven episodes, per-segment danmaku. |
|
|
15
|
+
| `mango` | `*.mgtv.com` + `*.hitv.com` | Mango TV; source=imgo search, two-stage showlist episodes, per-minute CDN danmaku shards. |
|
|
16
|
+
| `migu` | `*.migu.cn` + `*.miguvideo.com` | Migu Video; content-info lookup, episodes list, segmented danmaku. |
|
|
17
|
+
| `youku` | `*.youku.com` + `log.mmstat.com` | Youku; HTML-stripped search, openapi episodes, signed per-minute danmaku POSTs (cna guid + \_m_h5_tk token). |
|
|
18
|
+
| `iqiyi` | `*.iqiyi.com` + `mesh.if.iqiyi.com` | iQIYI; /v\_ watch-page search, signed base_info episodes, zlib-deflated XML bullet shards. |
|
|
19
|
+
| `aiyifan` | `yfsp.tv` + `rankv21.tripdata.app` | Aiyifan; homepage-scraped pub/priv keys sign each JSON request; getBarrage danmaku. |
|
|
20
|
+
| `bahamut` | `api.gamer.com.tw` | Bahamut Anime (Traditional Chinese); single danmu.php fetch, time in tenths of a second. |
|
|
21
|
+
| `maiduidui` | `mob.mddcloud.com.cn` | Maiduidui; nested search, listVodSactions episodes, per-minute vodBarrage shards. |
|
|
22
|
+
| `renren` | `api.gorafie.com` + `static-dm.qwdjapp.com` | Renren (foreign drama); array-rooted danmaku with CSV `p` strings. |
|
|
23
|
+
| `sohu` | `*.sohu.com` | Sohu TV; site=1 search, album episodes, paginated dmListAll danmaku (decimal/hex color handling). |
|
|
24
24
|
|
|
25
25
|
## Layout
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
src/
|
|
29
29
|
manifests/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
aiyifan.json
|
|
31
|
+
bahamut.json
|
|
32
|
+
bilibili.json
|
|
33
|
+
dandanplay.json
|
|
34
|
+
hanjutv.json
|
|
35
|
+
iqiyi.json
|
|
36
|
+
maiduidui.json
|
|
37
|
+
mango.json
|
|
38
|
+
migu.json
|
|
39
|
+
renren.json
|
|
40
|
+
sohu.json
|
|
41
|
+
tencent.json
|
|
42
|
+
youku.json
|
|
43
43
|
__tests__/
|
|
44
|
-
|
|
44
|
+
*.test.ts # per-manifest pipeline tests
|
|
45
45
|
fixtures/ # captured representative responses
|
|
46
46
|
mockFetcher.ts # shared test fetcher (string + Uint8Array bodies)
|
|
47
47
|
scripts/
|
|
@@ -52,7 +52,7 @@ scripts/
|
|
|
52
52
|
|
|
53
53
|
```ts
|
|
54
54
|
import { ManifestRunner, zManifest } from '@mr-quin/dango'
|
|
55
|
-
import builtinDandanplay from '@mr-quin/dango-manifests/manifests/
|
|
55
|
+
import builtinDandanplay from '@mr-quin/dango-manifests/manifests/dandanplay.json' with { type: 'json' }
|
|
56
56
|
|
|
57
57
|
const manifest = zManifest.parse(builtinDandanplay)
|
|
58
58
|
const runner = new ManifestRunner(manifest, { fetcher })
|
|
@@ -66,9 +66,46 @@ const danmaku = await runner.runDanmaku({
|
|
|
66
66
|
})
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
## CDN consumption
|
|
70
|
+
|
|
71
|
+
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.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
https://cdn.jsdelivr.net/npm/@mr-quin/dango-manifests@<version>/catalog.json
|
|
75
|
+
https://cdn.jsdelivr.net/npm/@mr-quin/dango-manifests@<version>/<file>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`catalog.json` is generated from the manifests on disk and ships with the package:
|
|
79
|
+
|
|
80
|
+
```jsonc
|
|
81
|
+
{
|
|
82
|
+
"packageVersion": "0.3.0",
|
|
83
|
+
"manifests": [
|
|
84
|
+
{
|
|
85
|
+
"id": "bilibili",
|
|
86
|
+
"name": "Bilibili",
|
|
87
|
+
"version": "0.3.0",
|
|
88
|
+
"apiVersion": 1,
|
|
89
|
+
"file": "src/manifests/bilibili.json",
|
|
90
|
+
},
|
|
91
|
+
// ...
|
|
92
|
+
],
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Each `file` is the in-package path to fetch, e.g.:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
https://cdn.jsdelivr.net/npm/@mr-quin/dango-manifests@0.3.0/src/manifests/bilibili.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
unpkg 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.
|
|
103
|
+
|
|
104
|
+
`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).
|
|
105
|
+
|
|
69
106
|
## Routing notes
|
|
70
107
|
|
|
71
|
-
**DanDanPlay** (`
|
|
108
|
+
**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.
|
|
72
109
|
|
|
73
110
|
**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.
|
|
74
111
|
|
|
@@ -86,7 +123,7 @@ The smoke fetcher keeps a per-host cookie jar so bilibili's anti-bot wall lets u
|
|
|
86
123
|
|
|
87
124
|
## Adding a new manifest
|
|
88
125
|
|
|
89
|
-
1. Drop the JSON file in `src/manifests/`. Use `id: '
|
|
126
|
+
1. Drop the JSON file in `src/manifests/`. Use `id: '<source>'`.
|
|
90
127
|
2. Capture representative responses from the source's API to `src/__tests__/fixtures/`.
|
|
91
128
|
3. Write a per-manifest test that:
|
|
92
129
|
- Parses the manifest against `zManifest` (catches schema drift)
|
|
@@ -107,5 +144,5 @@ Manifests in this package are vetted at PR review time and shipped as built-ins.
|
|
|
107
144
|
| `bun test` | bun test, fixture-backed pipeline tests |
|
|
108
145
|
| `bun run smoke <source>` | Live end-to-end test against the real API (manual, **not CI**) |
|
|
109
146
|
| `bun run type-check` | tsc --noEmit |
|
|
110
|
-
| `bun run
|
|
111
|
-
| `bun run
|
|
147
|
+
| `bun run catalog` | Regenerate `catalog.json` from the manifests on disk |
|
|
148
|
+
| `bun run catalog:check` | Fail if the committed `catalog.json` is stale |
|
package/catalog.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packageVersion": "0.3.0",
|
|
3
|
+
"manifests": [
|
|
4
|
+
{
|
|
5
|
+
"id": "aiyifan",
|
|
6
|
+
"name": "Aiyifan",
|
|
7
|
+
"version": "0.3.0",
|
|
8
|
+
"apiVersion": 1,
|
|
9
|
+
"file": "src/manifests/aiyifan.json"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "bahamut",
|
|
13
|
+
"name": "Bahamut",
|
|
14
|
+
"version": "0.3.0",
|
|
15
|
+
"apiVersion": 1,
|
|
16
|
+
"file": "src/manifests/bahamut.json"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "bilibili",
|
|
20
|
+
"name": "Bilibili",
|
|
21
|
+
"version": "0.3.0",
|
|
22
|
+
"apiVersion": 1,
|
|
23
|
+
"file": "src/manifests/bilibili.json"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "dandanplay",
|
|
27
|
+
"name": "DanDanPlay",
|
|
28
|
+
"version": "0.3.0",
|
|
29
|
+
"apiVersion": 1,
|
|
30
|
+
"file": "src/manifests/dandanplay.json"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "hanjutv",
|
|
34
|
+
"name": "Hanjutv",
|
|
35
|
+
"version": "0.3.0",
|
|
36
|
+
"apiVersion": 1,
|
|
37
|
+
"file": "src/manifests/hanjutv.json"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "iqiyi",
|
|
41
|
+
"name": "iQIYI",
|
|
42
|
+
"version": "0.3.0",
|
|
43
|
+
"apiVersion": 1,
|
|
44
|
+
"file": "src/manifests/iqiyi.json"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "maiduidui",
|
|
48
|
+
"name": "Maiduidui",
|
|
49
|
+
"version": "0.3.0",
|
|
50
|
+
"apiVersion": 1,
|
|
51
|
+
"file": "src/manifests/maiduidui.json"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "mango",
|
|
55
|
+
"name": "Mango TV",
|
|
56
|
+
"version": "0.3.0",
|
|
57
|
+
"apiVersion": 1,
|
|
58
|
+
"file": "src/manifests/mango.json"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "migu",
|
|
62
|
+
"name": "Migu Video",
|
|
63
|
+
"version": "0.3.0",
|
|
64
|
+
"apiVersion": 1,
|
|
65
|
+
"file": "src/manifests/migu.json"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "renren",
|
|
69
|
+
"name": "Renren",
|
|
70
|
+
"version": "0.3.0",
|
|
71
|
+
"apiVersion": 1,
|
|
72
|
+
"file": "src/manifests/renren.json"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "sohu",
|
|
76
|
+
"name": "Sohu",
|
|
77
|
+
"version": "0.3.0",
|
|
78
|
+
"apiVersion": 1,
|
|
79
|
+
"file": "src/manifests/sohu.json"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "tencent",
|
|
83
|
+
"name": "Tencent Video",
|
|
84
|
+
"version": "0.3.0",
|
|
85
|
+
"apiVersion": 1,
|
|
86
|
+
"file": "src/manifests/tencent.json"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "youku",
|
|
90
|
+
"name": "Youku",
|
|
91
|
+
"version": "0.3.0",
|
|
92
|
+
"apiVersion": 1,
|
|
93
|
+
"file": "src/manifests/youku.json"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mr-quin/dango-manifests",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Built-in dango manifests for danmaku sources",
|
|
5
5
|
"author": "Mr-Quin",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
"./manifests/*.json": "./src/manifests/*.json"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"src/manifests"
|
|
20
|
+
"src/manifests",
|
|
21
|
+
"catalog.json"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"type-check": "tsc -p tsconfig.json",
|
|
24
25
|
"test": "bun test",
|
|
26
|
+
"catalog": "bun run scripts/gen-catalog.ts",
|
|
27
|
+
"catalog:check": "bun run scripts/gen-catalog.ts --check",
|
|
25
28
|
"smoke": "bun run scripts/smoke-test.ts"
|
|
26
29
|
},
|
|
27
30
|
"devDependencies": {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"apiVersion": 1,
|
|
3
|
-
"id": "
|
|
3
|
+
"id": "youku",
|
|
4
4
|
"name": "Youku",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.0",
|
|
6
6
|
"hosts": [
|
|
7
7
|
"search.youku.com",
|
|
8
8
|
"openapi.youku.com",
|
|
@@ -29,16 +29,21 @@
|
|
|
29
29
|
"inputs": ["showId"],
|
|
30
30
|
"steps": [
|
|
31
31
|
{
|
|
32
|
-
"type": "
|
|
33
|
-
"id": "
|
|
32
|
+
"type": "forEach",
|
|
33
|
+
"id": "pages",
|
|
34
|
+
"in": "$range(1, 51)",
|
|
35
|
+
"as": "page",
|
|
34
36
|
"request": {
|
|
35
37
|
"method": "GET",
|
|
36
38
|
"url": "'https://openapi.youku.com/v2/shows/videos.json'",
|
|
37
|
-
"query": "{ 'client_id': '53e6cc67237fc59a', 'package': 'com.huawei.hwvplayer.youku', 'ext': 'show', 'show_id': showId, 'page':
|
|
38
|
-
}
|
|
39
|
+
"query": "{ 'client_id': '53e6cc67237fc59a', 'package': 'com.huawei.hwvplayer.youku', 'ext': 'show', 'show_id': showId, 'page': $string(page), 'count': '100' }"
|
|
40
|
+
},
|
|
41
|
+
"collect": "videos",
|
|
42
|
+
"breakOn": "$count($) < 100",
|
|
43
|
+
"throttleMs": 100
|
|
39
44
|
}
|
|
40
45
|
],
|
|
41
|
-
"output": "[
|
|
46
|
+
"output": "[pages.{ 'providerIds': { 'vid': id }, 'indexedId': id, 'title': title, 'episodeNumber': $number(stage), 'imageUrl': thumbnail_v2 }]"
|
|
42
47
|
},
|
|
43
48
|
"danmaku": {
|
|
44
49
|
"inputs": ["vid"],
|