mirror of
https://github.com/daydreamer-json/ak-endfield-api-archive.git
synced 2026-03-27 17:52:35 +01:00
feat: implement china region launcher api support
This commit is contained in:
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -20,6 +20,12 @@ jobs:
|
|||||||
uses: oven-sh/setup-bun@v2
|
uses: oven-sh/setup-bun@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install
|
run: bun install
|
||||||
|
- name: Create config auth
|
||||||
|
env:
|
||||||
|
CONFIG_AUTH_TXT_CTX: ${{ secrets.CONFIG_AUTH_TXT }}
|
||||||
|
run: |
|
||||||
|
mkdir -p config
|
||||||
|
echo "$CONFIG_AUTH_TXT_CTX" > config/config_auth.txt
|
||||||
- name: Run script
|
- name: Run script
|
||||||
uses: nick-fields/retry@v3
|
uses: nick-fields/retry@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
config/config.yaml
|
config/config.yaml
|
||||||
|
config/config_auth.txt
|
||||||
memo/
|
memo/
|
||||||
|
|
||||||
# dependencies (bun install)
|
# dependencies (bun install)
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -7,9 +7,9 @@ API outputs are stored in the [`output`](/output/) directory.
|
|||||||
|
|
||||||
The APIs currently being monitored are as follows:
|
The APIs currently being monitored are as follows:
|
||||||
- Launcher
|
- Launcher
|
||||||
- Get latest game
|
- Get latest game (Global)
|
||||||
- Get latest game resources
|
- Get latest game resources
|
||||||
- Get latest launcher
|
- Get latest launcher (Global, China)
|
||||||
|
|
||||||
## Download Library
|
## Download Library
|
||||||
|
|
||||||
@@ -23,9 +23,15 @@ To easily view information about past versions of game packages and other items,
|
|||||||
- [Windows Official](/output/akEndfield/launcher/game/6/list_patch.md)
|
- [Windows Official](/output/akEndfield/launcher/game/6/list_patch.md)
|
||||||
- [Windows Epic](/output/akEndfield/launcher/game/801/list_patch.md.md)
|
- [Windows Epic](/output/akEndfield/launcher/game/801/list_patch.md.md)
|
||||||
- [**Game resources**](/output/akEndfield/launcher/game_resources/6/list.md) (Windows, Android, iOS, PlayStation)
|
- [**Game resources**](/output/akEndfield/launcher/game_resources/6/list.md) (Windows, Android, iOS, PlayStation)
|
||||||
|
- **Launcher packages**
|
||||||
|
- [Launcher (zip)](/output/akEndfield/launcher/launcher/list.md)
|
||||||
|
- [Launcher (installer)](/output/akEndfield/launcher/launcherExe/list.md)
|
||||||
|
|
||||||
|
Some packages requiring `auth_key` are available via the Wayback Machine mirror.
|
||||||
|
|
||||||
All dates and times specified in Markdown files are in Asia server time (China Standard Time, UTC+8).
|
All dates and times specified in Markdown files are in Asia server time (China Standard Time, UTC+8).
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Since I can only run the game on platforms and operating systems that are available to me, there may be inaccuracies. If you have information -particularly regarding **Chinese regional game data**, beta versions, encrypted binaries such as `game_files` or `package_files`- or if you're able to help improve the code, or if you encounter any other issues, feel free to submit an issue or a pull request.
|
Since I can only run the game on platforms and operating systems that are available to me, there may be inaccuracies. If you have information -particularly regarding **Chinese regional game data**, beta versions, encrypted binaries such as `game_files` or `package_files`- or if you're able to help improve the code, or if you encounter any other issues, feel free to submit an issue or a pull request.
|
||||||
|
|||||||
3
bun.lock
3
bun.lock
@@ -7,6 +7,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"cli-table3": "^0.6.5",
|
"cli-table3": "^0.6.5",
|
||||||
|
"cookie": "^1.1.1",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"ky": "^1.14.2",
|
"ky": "^1.14.2",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
@@ -139,6 +140,8 @@
|
|||||||
|
|
||||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
||||||
|
|
||||||
"date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="],
|
"date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|||||||
21
output/akEndfield/launcher/launcher/Arknights/1/all.json
Normal file
21
output/akEndfield/launcher/launcher/Arknights/1/all.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:45.284+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805425-b97874bbf29b4747a0aba81165580890-0-3d4e79aa6cd654b814cc71189103aa83",
|
||||||
|
"md5": "013d7e900c46b2324c8a749a06b84768",
|
||||||
|
"package_size": "125456996",
|
||||||
|
"total_size": "389401989",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
18
output/akEndfield/launcher/launcher/Arknights/1/latest.json
Normal file
18
output/akEndfield/launcher/launcher/Arknights/1/latest.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805425-b97874bbf29b4747a0aba81165580890-0-3d4e79aa6cd654b814cc71189103aa83",
|
||||||
|
"md5": "013d7e900c46b2324c8a749a06b84768",
|
||||||
|
"package_size": "125456996",
|
||||||
|
"total_size": "389401989",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcher/Arknights/1/v1.1.1.json
Normal file
18
output/akEndfield/launcher/launcher/Arknights/1/v1.1.1.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805425-b97874bbf29b4747a0aba81165580890-0-3d4e79aa6cd654b814cc71189103aa83",
|
||||||
|
"md5": "013d7e900c46b2324c8a749a06b84768",
|
||||||
|
"package_size": "125456996",
|
||||||
|
"total_size": "389401989",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
21
output/akEndfield/launcher/launcher/EndField/1/all.json
Normal file
21
output/akEndfield/launcher/launcher/EndField/1/all.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:44.678+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "EndField"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805424-b340c15e0d964370803a4e25b35dfae7-0-c4db269999383a19f59306d6cbef99a0",
|
||||||
|
"md5": "0200ac146e854fc7692361d5f02e7727",
|
||||||
|
"package_size": "125818123",
|
||||||
|
"total_size": "390124155",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
18
output/akEndfield/launcher/launcher/EndField/1/latest.json
Normal file
18
output/akEndfield/launcher/launcher/EndField/1/latest.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "EndField"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805424-b340c15e0d964370803a4e25b35dfae7-0-c4db269999383a19f59306d6cbef99a0",
|
||||||
|
"md5": "0200ac146e854fc7692361d5f02e7727",
|
||||||
|
"package_size": "125818123",
|
||||||
|
"total_size": "390124155",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcher/EndField/1/v1.1.1.json
Normal file
18
output/akEndfield/launcher/launcher/EndField/1/v1.1.1.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "EndField"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805424-b340c15e0d964370803a4e25b35dfae7-0-c4db269999383a19f59306d6cbef99a0",
|
||||||
|
"md5": "0200ac146e854fc7692361d5f02e7727",
|
||||||
|
"package_size": "125818123",
|
||||||
|
"total_size": "390124155",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
40
output/akEndfield/launcher/launcher/list.md
Normal file
40
output/akEndfield/launcher/launcher/list.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Launcher Packages (zip)
|
||||||
|
|
||||||
|
- [OS EndField](#launcher-os-endfield)
|
||||||
|
- [OS Official](#launcher-os-official)
|
||||||
|
- [CN EndField](#launcher-cn-endfield)
|
||||||
|
- [CN Arknights](#launcher-cn-arknights)
|
||||||
|
- [CN Official](#launcher-cn-official)
|
||||||
|
|
||||||
|
<h2 id="launcher-os-endfield">OS EndField</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | MD5 Checksum | Unpacked | Packed |
|
||||||
|
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------: | ---------: |
|
||||||
|
| 2026/01/22 17:44:29 | 1.0.0 | [GRYPHLINK_1.0.0_6_6_official.zip](https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip) | `fe71ba125d1b1c30d4bf1c05d7af4be6` | 238.08 MiB | 106.04 MiB |
|
||||||
|
| 2026/01/29 18:30:23 | 1.0.2 | [GRYPHLINK_1.0.2_6_6_endfield.zip](https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.2/6/6/FCLRoWw78h2SQCYy/GRYPHLINK_1.0.2_6_6_endfield.zip) | `154d73bd32b34e9e3429a1b4fda44a0c` | 252.01 MiB | 119.97 MiB |
|
||||||
|
| 2026/02/09 10:00:29 | 1.1.0 | [GRYPHLINK_v1.1.0.1107_6_6_endfield.zip](https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/NVX60B0FgrIAIWH2/GRYPHLINK_v1.1.0.1107_6_6_endfield.zip) | `b099efdca62ba3a86e1160487b8c0589` | 412.06 MiB | 279.70 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-os-official">OS Official</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | MD5 Checksum | Unpacked | Packed |
|
||||||
|
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------: | ---------: |
|
||||||
|
| 2026/01/22 17:44:47 | 1.0.0 | [GRYPHLINK_1.0.0_6_6_official.zip](https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip) | `fe71ba125d1b1c30d4bf1c05d7af4be6` | 238.08 MiB | 106.04 MiB |
|
||||||
|
| 2026/02/09 10:00:29 | 1.1.0 | [GRYPHLINK_v1.1.0.1112_6_6_official.zip](https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/oL3UfvgkscD1onKF/GRYPHLINK_v1.1.0.1112_6_6_official.zip) | `dd92acd3fd5217992a64cb4b22729740` | 238.13 MiB | 106.06 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-endfield">CN EndField</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | MD5 Checksum | Unpacked | Packed |
|
||||||
|
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------: | ---------: |
|
||||||
|
| 2026/02/11 18:23:44 | 1.1.1 | HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip [Orig](https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805424-b340c15e0d964370803a4e25b35dfae7-0-c4db269999383a19f59306d6cbef99a0) / [Mirror](https://web.archive.org/web/20260211102702/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805594-f034be52dc1c4149b8e5863d81942bc5-0-ebc04db7ac1c356da84cbd05abb7dc8a) | `0200ac146e854fc7692361d5f02e7727` | 252.06 MiB | 119.99 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-arknights">CN Arknights</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | MD5 Checksum | Unpacked | Packed |
|
||||||
|
| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------: | ---------: |
|
||||||
|
| 2026/02/11 18:23:45 | 1.1.1 | HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip [Orig](https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805425-b97874bbf29b4747a0aba81165580890-0-3d4e79aa6cd654b814cc71189103aa83) / [Mirror](https://web.archive.org/web/20260211103331/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805996-d0cbf63e930148b0911850e320f016f1-0-5cfcf50e25770622c3c1bd2ab32b3165) | `013d7e900c46b2324c8a749a06b84768` | 251.72 MiB | 119.65 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-official">CN Official</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | MD5 Checksum | Unpacked | Packed |
|
||||||
|
| ------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------: | ---------: |
|
||||||
|
| 2026/02/11 18:23:46 | 1.1.0 | HypergryphLauncher_v1.1.0.1111_1_1_official.zip [Orig](https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770805425-4767f09255e04759acec76fee5709419-0-704e6c4ef290a9ed54699fa50d25896f) / [Mirror](https://web.archive.org/web/20260211075808/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770796678-5a2fff9d792c4621b62bf9b541e36f4c-0-e9484399f81f6163d5ffea3ea3d0772f) | `ac840b12eeeee1e09be228e767300cc5` | 238.14 MiB | 106.06 MiB |
|
||||||
21
output/akEndfield/launcher/launcher/official/1/all.json
Normal file
21
output/akEndfield/launcher/launcher/official/1/all.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:46.357+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770805425-4767f09255e04759acec76fee5709419-0-704e6c4ef290a9ed54699fa50d25896f",
|
||||||
|
"md5": "ac840b12eeeee1e09be228e767300cc5",
|
||||||
|
"package_size": "111213036",
|
||||||
|
"total_size": "360918444",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
18
output/akEndfield/launcher/launcher/official/1/latest.json
Normal file
18
output/akEndfield/launcher/launcher/official/1/latest.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770805425-4767f09255e04759acec76fee5709419-0-704e6c4ef290a9ed54699fa50d25896f",
|
||||||
|
"md5": "ac840b12eeeee1e09be228e767300cc5",
|
||||||
|
"package_size": "111213036",
|
||||||
|
"total_size": "360918444",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcher/official/1/v1.1.0.json
Normal file
18
output/akEndfield/launcher/launcher/official/1/v1.1.0.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"targetApp": "Official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"zip_package_url": "https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770805425-4767f09255e04759acec76fee5709419-0-704e6c4ef290a9ed54699fa50d25896f",
|
||||||
|
"md5": "ac840b12eeeee1e09be228e767300cc5",
|
||||||
|
"package_size": "111213036",
|
||||||
|
"total_size": "360918444",
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
"appCode": "TiaytKBUIEdoEwRT",
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
"channel": 6,
|
"channel": 6,
|
||||||
"subChannel": 6,
|
"subChannel": 6,
|
||||||
"targetApp": null
|
"targetApp": "Official"
|
||||||
},
|
},
|
||||||
"rsp": {
|
"rsp": {
|
||||||
"action": 1,
|
"action": 1,
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
"appCode": "TiaytKBUIEdoEwRT",
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
"channel": 6,
|
"channel": 6,
|
||||||
"subChannel": 6,
|
"subChannel": 6,
|
||||||
"targetApp": null
|
"targetApp": "Official"
|
||||||
},
|
},
|
||||||
"rsp": {
|
"rsp": {
|
||||||
"action": 1,
|
"action": 1,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"appCode": "TiaytKBUIEdoEwRT",
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
"channel": 6,
|
"channel": 6,
|
||||||
"subChannel": 6,
|
"subChannel": 6,
|
||||||
"targetApp": null
|
"targetApp": "Official"
|
||||||
},
|
},
|
||||||
"rsp": {
|
"rsp": {
|
||||||
"action": 1,
|
"action": 1,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"appCode": "TiaytKBUIEdoEwRT",
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
"channel": 6,
|
"channel": 6,
|
||||||
"subChannel": 6,
|
"subChannel": 6,
|
||||||
"targetApp": null
|
"targetApp": "Official"
|
||||||
},
|
},
|
||||||
"rsp": {
|
"rsp": {
|
||||||
"action": 1,
|
"action": 1,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"appCode": "TiaytKBUIEdoEwRT",
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
"channel": 6,
|
"channel": 6,
|
||||||
"subChannel": 6,
|
"subChannel": 6,
|
||||||
"targetApp": null
|
"targetApp": "Official"
|
||||||
},
|
},
|
||||||
"rsp": {
|
"rsp": {
|
||||||
"action": 1,
|
"action": 1,
|
||||||
|
|||||||
18
output/akEndfield/launcher/launcherExe/Arknights/1/all.json
Normal file
18
output/akEndfield/launcher/launcherExe/Arknights/1/all.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:45.295+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770805425-172992522f484813a1114b3495dbf372-0-08a2616d5eb0731a005ece3fd6e606a9&tracking=Hypergryph",
|
||||||
|
"exe_size": "166524160"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770805425-172992522f484813a1114b3495dbf372-0-08a2616d5eb0731a005ece3fd6e606a9&tracking=Hypergryph",
|
||||||
|
"exe_size": "166524160"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "arknights"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770805425-172992522f484813a1114b3495dbf372-0-08a2616d5eb0731a005ece3fd6e606a9&tracking=Hypergryph",
|
||||||
|
"exe_size": "166524160"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcherExe/EndField/1/all.json
Normal file
18
output/akEndfield/launcher/launcherExe/EndField/1/all.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:44.682+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770805424-20054abefba5462089be18ccc722a216-0-ea895a486266c0d352a65e21d49127d5&tracking=Hypergryph",
|
||||||
|
"exe_size": "167777352"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770805424-20054abefba5462089be18ccc722a216-0-ea895a486266c0d352a65e21d49127d5&tracking=Hypergryph",
|
||||||
|
"exe_size": "167777352"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.1",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770805424-20054abefba5462089be18ccc722a216-0-ea895a486266c0d352a65e21d49127d5&tracking=Hypergryph",
|
||||||
|
"exe_size": "167777352"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcherExe/EndField/6/all.json
Normal file
18
output/akEndfield/launcher/launcherExe/EndField/6/all.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:41.749+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/NVX60B0FgrIAIWH2/GRYPHLINK_v1.1.0.1107_6_6_endfield.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "167774552"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/NVX60B0FgrIAIWH2/GRYPHLINK_v1.1.0.1107_6_6_endfield.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "167774552"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "endfield"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/NVX60B0FgrIAIWH2/GRYPHLINK_v1.1.0.1107_6_6_endfield.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "167774552"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcherExe/Official/1/all.json
Normal file
18
output/akEndfield/launcher/launcherExe/Official/1/all.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:46.359+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770805426-482b692452694284b22c17c22bfb41ca-0-3a0e71c35f55d5c438e0b88d2a134d6e&tracking=Hypergryph",
|
||||||
|
"exe_size": "124329856"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770805426-482b692452694284b22c17c22bfb41ca-0-3a0e71c35f55d5c438e0b88d2a134d6e&tracking=Hypergryph",
|
||||||
|
"exe_size": "124329856"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "abYeZZ16BPluCFyT",
|
||||||
|
"channel": 1,
|
||||||
|
"subChannel": 1,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770805426-482b692452694284b22c17c22bfb41ca-0-3a0e71c35f55d5c438e0b88d2a134d6e&tracking=Hypergryph",
|
||||||
|
"exe_size": "124329856"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
output/akEndfield/launcher/launcherExe/Official/6/all.json
Normal file
18
output/akEndfield/launcher/launcherExe/Official/6/all.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"updatedAt": "2026-02-11T19:23:42.081+09:00",
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/oL3UfvgkscD1onKF/GRYPHLINK_v1.1.0.1112_6_6_official.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "124325992"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/oL3UfvgkscD1onKF/GRYPHLINK_v1.1.0.1112_6_6_official.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "124325992"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"req": {
|
||||||
|
"appCode": "TiaytKBUIEdoEwRT",
|
||||||
|
"channel": 6,
|
||||||
|
"subChannel": 6,
|
||||||
|
"ta": "official"
|
||||||
|
},
|
||||||
|
"rsp": {
|
||||||
|
"action": 1,
|
||||||
|
"version": "1.1.0",
|
||||||
|
"request_version": "",
|
||||||
|
"exe_url": "https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/oL3UfvgkscD1onKF/GRYPHLINK_v1.1.0.1112_6_6_official.exe?tracking=GRYPHLINK",
|
||||||
|
"exe_size": "124325992"
|
||||||
|
}
|
||||||
|
}
|
||||||
37
output/akEndfield/launcher/launcherExe/list.md
Normal file
37
output/akEndfield/launcher/launcherExe/list.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Launcher Packages (Installer)
|
||||||
|
|
||||||
|
- [OS EndField](#launcher-os-endfield)
|
||||||
|
- [OS Official](#launcher-os-official)
|
||||||
|
- [CN EndField](#launcher-cn-endfield)
|
||||||
|
- [CN Arknights](#launcher-cn-arknights)
|
||||||
|
- [CN Official](#launcher-cn-official)
|
||||||
|
|
||||||
|
<h2 id="launcher-os-endfield">OS EndField</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | Size |
|
||||||
|
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------: |
|
||||||
|
| 2026/02/11 18:23:41 | 1.1.0 | [GRYPHLINK_v1.1.0.1107_6_6_endfield.exe](https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/NVX60B0FgrIAIWH2/GRYPHLINK_v1.1.0.1107_6_6_endfield.exe?tracking=GRYPHLINK) | 160.00 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-os-official">OS Official</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | Size |
|
||||||
|
| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------: |
|
||||||
|
| 2026/02/11 18:23:42 | 1.1.0 | [GRYPHLINK_v1.1.0.1112_6_6_official.exe](https://launcher-rule.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.1.0/6/6/oL3UfvgkscD1onKF/GRYPHLINK_v1.1.0.1112_6_6_official.exe?tracking=GRYPHLINK) | 118.57 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-endfield">CN EndField</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | Size |
|
||||||
|
| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------: |
|
||||||
|
| 2026/02/11 18:23:44 | 1.1.1 | HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe [Orig](https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770805424-20054abefba5462089be18ccc722a216-0-ea895a486266c0d352a65e21d49127d5&tracking=Hypergryph) / [Mirror](https://web.archive.org/web/20260211080403/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770796924-4c08f546f40f471885825225162e3acd-0-051b324e1cee0bb6f261f16999d72abb) | 160.00 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-arknights">CN Arknights</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | Size |
|
||||||
|
| ------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------: |
|
||||||
|
| 2026/02/11 18:23:45 | 1.1.1 | HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe [Orig](https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770805425-172992522f484813a1114b3495dbf372-0-08a2616d5eb0731a005ece3fd6e606a9&tracking=Hypergryph) / [Mirror](https://web.archive.org/web/20260211104513/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770806682-d158e31170ce4841ad36c2f52ad9e818-0-aa7b23946d4c2499383620ea525a8792) | 158.81 MiB |
|
||||||
|
|
||||||
|
<h2 id="launcher-cn-official">CN Official</h2>
|
||||||
|
|
||||||
|
| Date | Version | File | Size |
|
||||||
|
| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------: |
|
||||||
|
| 2026/02/11 18:23:46 | 1.1.0 | HypergryphLauncher_v1.1.0.1111_1_1_official.exe [Orig](https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770805426-482b692452694284b22c17c22bfb41ca-0-3a0e71c35f55d5c438e0b88d2a134d6e&tracking=Hypergryph) / [Mirror](https://web.archive.org/web/20260211112144/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770808883-5e39f01f0f6244e8a94f354e98f4e12d-0-7b8f1742c7d1646b9c3d618f2dd58f0c) | 118.57 MiB |
|
||||||
8
output/wayback_machine.json
Normal file
8
output/wayback_machine.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[
|
||||||
|
"https://web.archive.org/web/20260211075808/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.zip?auth_key=1770796678-5a2fff9d792c4621b62bf9b541e36f4c-0-e9484399f81f6163d5ffea3ea3d0772f",
|
||||||
|
"https://web.archive.org/web/20260211080403/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.exe?auth_key=1770796924-4c08f546f40f471885825225162e3acd-0-051b324e1cee0bb6f261f16999d72abb",
|
||||||
|
"https://web.archive.org/web/20260211102702/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/NO0nx1dZDOVcjo27/HypergryphLauncher_v1.1.1.1124_1_1_endfield.zip?auth_key=1770805594-f034be52dc1c4149b8e5863d81942bc5-0-ebc04db7ac1c356da84cbd05abb7dc8a",
|
||||||
|
"https://web.archive.org/web/20260211103331/https://launcher-sign.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.zip?auth_key=1770805996-d0cbf63e930148b0911850e320f016f1-0-5cfcf50e25770622c3c1bd2ab32b3165",
|
||||||
|
"https://web.archive.org/web/20260211104513/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.1/1/1/9lgNrktxI8ARzguv/HypergryphLauncher_v1.1.1.1121_1_1_arknights.exe?auth_key=1770806682-d158e31170ce4841ad36c2f52ad9e818-0-aa7b23946d4c2499383620ea525a8792",
|
||||||
|
"https://web.archive.org/web/20260211112144/https://launcher-rule.hycdn.cn/abYeZZ16BPluCFyT/launcher/1.1.0/1/1/2vyVIpSrNaIQNLLk/HypergryphLauncher_v1.1.0.1111_1_1_official.exe?auth_key=1770808883-5e39f01f0f6244e8a94f354e98f4e12d-0-7b8f1742c7d1646b9c3d618f2dd58f0c"
|
||||||
|
]
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"cli-table3": "^0.6.5",
|
"cli-table3": "^0.6.5",
|
||||||
|
"cookie": "^1.1.1",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"ky": "^1.14.2",
|
"ky": "^1.14.2",
|
||||||
"log4js": "^6.9.1",
|
"log4js": "^6.9.1",
|
||||||
|
|||||||
239
src/cmds/test.ts
239
src/cmds/test.ts
@@ -7,6 +7,9 @@ import argvUtils from '../utils/argv.js';
|
|||||||
import appConfig from '../utils/config.js';
|
import appConfig from '../utils/config.js';
|
||||||
import logger from '../utils/logger.js';
|
import logger from '../utils/logger.js';
|
||||||
import mathUtils from '../utils/math.js';
|
import mathUtils from '../utils/math.js';
|
||||||
|
import webArchiveOrg from '../utils/webArchiveOrg.js';
|
||||||
|
|
||||||
|
let waybackCred: { user: string; sig: string } | null = null;
|
||||||
|
|
||||||
const formatBytes = (size: number) =>
|
const formatBytes = (size: number) =>
|
||||||
mathUtils.formatFileSize(size, {
|
mathUtils.formatFileSize(size, {
|
||||||
@@ -21,6 +24,7 @@ const formatBytes = (size: number) =>
|
|||||||
type LatestGameResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestGame>>;
|
type LatestGameResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestGame>>;
|
||||||
type LatestGameResourcesResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestGameResources>>;
|
type LatestGameResourcesResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestGameResources>>;
|
||||||
// type LatestLauncherResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestLauncher>>;
|
// type LatestLauncherResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestLauncher>>;
|
||||||
|
// type LatestLauncherExeResponse = Awaited<ReturnType<typeof apiUtils.akEndfield.launcher.latestLauncherExe>>;
|
||||||
|
|
||||||
interface StoredData<T> {
|
interface StoredData<T> {
|
||||||
req: any;
|
req: any;
|
||||||
@@ -36,23 +40,42 @@ interface GameTarget {
|
|||||||
dirName: string;
|
dirName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjectDiff(obj1: any, obj2: any) {
|
function getObjectDiff(
|
||||||
|
obj1: any,
|
||||||
|
obj2: any,
|
||||||
|
ignoreRules: {
|
||||||
|
path: string[];
|
||||||
|
pattern: RegExp;
|
||||||
|
}[] = [],
|
||||||
|
currentPath: string[] = [],
|
||||||
|
) {
|
||||||
const diff: any = {};
|
const diff: any = {};
|
||||||
const keys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
|
const keys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
|
||||||
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
const val1 = obj1?.[key];
|
const val1 = obj1?.[key];
|
||||||
const val2 = obj2?.[key];
|
const val2 = obj2?.[key];
|
||||||
if (JSON.stringify(val1) !== JSON.stringify(val2)) {
|
const fullPath = [...currentPath, key];
|
||||||
if (typeof val1 === 'object' && val1 !== null && typeof val2 === 'object' && val2 !== null) {
|
if (JSON.stringify(val1) === JSON.stringify(val2)) continue;
|
||||||
const nestedDiff = getObjectDiff(val1, val2);
|
|
||||||
if (Object.keys(nestedDiff).length > 0) {
|
const rule = ignoreRules.find(
|
||||||
diff[key] = nestedDiff;
|
(r) => r.path.length === fullPath.length && r.path.every((p, i) => p === fullPath[i]),
|
||||||
}
|
);
|
||||||
} else {
|
|
||||||
diff[key] = { old: val1, new: val2 };
|
if (rule && typeof val1 === 'string' && typeof val2 === 'string') {
|
||||||
}
|
const normalized1 = val1.replace(rule.pattern, '');
|
||||||
|
const normalized2 = val2.replace(rule.pattern, '');
|
||||||
|
if (normalized1 === normalized2) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val1 === 'object' && val1 !== null && typeof val2 === 'object' && val2 !== null) {
|
||||||
|
const nestedDiff = getObjectDiff(val1, val2, ignoreRules, fullPath);
|
||||||
|
if (Object.keys(nestedDiff).length > 0) diff[key] = nestedDiff;
|
||||||
|
} else {
|
||||||
|
diff[key] = { old: val1, new: val2 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +84,7 @@ async function saveResult<T>(
|
|||||||
version: string,
|
version: string,
|
||||||
data: { req: any; rsp: T },
|
data: { req: any; rsp: T },
|
||||||
saveLatest: boolean = true,
|
saveLatest: boolean = true,
|
||||||
|
ignoreRules: Parameters<typeof getObjectDiff>[2] = [],
|
||||||
) {
|
) {
|
||||||
const outputDir = argvUtils.getArgv()['outputDir'];
|
const outputDir = argvUtils.getArgv()['outputDir'];
|
||||||
const filePathBase = path.join(outputDir, ...subPaths);
|
const filePathBase = path.join(outputDir, ...subPaths);
|
||||||
@@ -71,20 +95,20 @@ async function saveResult<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dataStr = JSON.stringify(data, null, 2);
|
const dataStr = JSON.stringify(data, null, 2);
|
||||||
const dataMinified = JSON.stringify(data);
|
|
||||||
|
|
||||||
for (const filePath of filesToCheck) {
|
for (const filePath of filesToCheck) {
|
||||||
const file = Bun.file(filePath);
|
const file = Bun.file(filePath);
|
||||||
const exists = await file.exists();
|
const exists = await file.exists();
|
||||||
let currentData: any = null;
|
|
||||||
if (exists) {
|
if (!exists) {
|
||||||
currentData = await file.json();
|
|
||||||
}
|
|
||||||
if (!exists || JSON.stringify(currentData) !== dataMinified) {
|
|
||||||
if (exists) {
|
|
||||||
logger.trace(`Diff detected in ${filePath}:`, JSON.stringify(getObjectDiff(currentData, data), null, 2));
|
|
||||||
}
|
|
||||||
await Bun.write(filePath, dataStr);
|
await Bun.write(filePath, dataStr);
|
||||||
|
} else {
|
||||||
|
const currentData = await file.json();
|
||||||
|
const diff = getObjectDiff(currentData, data, ignoreRules);
|
||||||
|
if (Object.keys(diff).length > 0) {
|
||||||
|
logger.trace(`Diff detected in ${filePath}:`, JSON.stringify(diff, null, 2));
|
||||||
|
await Bun.write(filePath, dataStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +119,10 @@ async function saveResult<T>(
|
|||||||
allData = await allFile.json();
|
allData = await allFile.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
const exists = allData.some((e) => JSON.stringify({ req: e.req, rsp: e.rsp }) === dataMinified);
|
const exists = allData.some((e) => {
|
||||||
|
const diff = getObjectDiff({ req: e.req, rsp: e.rsp }, data, ignoreRules);
|
||||||
|
return Object.keys(diff).length === 0;
|
||||||
|
});
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
allData.push({ updatedAt: DateTime.now().toISO(), ...data });
|
allData.push({ updatedAt: DateTime.now().toISO(), ...data });
|
||||||
@@ -303,6 +330,93 @@ async function generateResourceListMd(channelStr: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function generateLauncherMd(type: 'zip' | 'exe') {
|
||||||
|
const cfg = appConfig.network.api.akEndfield;
|
||||||
|
const outputDir = argvUtils.getArgv()['outputDir'];
|
||||||
|
const settings = {
|
||||||
|
zip: {
|
||||||
|
subdir: 'launcher',
|
||||||
|
title: 'Launcher Packages (zip)',
|
||||||
|
headers: ['Date', 'Version', 'File', 'MD5 Checksum', 'Unpacked', 'Packed'],
|
||||||
|
align: ['---', '---', '---', '---', '--:', '--:'],
|
||||||
|
},
|
||||||
|
exe: {
|
||||||
|
subdir: 'launcherExe',
|
||||||
|
title: 'Launcher Packages (Installer)',
|
||||||
|
headers: ['Date', 'Version', 'File', 'Size'],
|
||||||
|
align: ['---', '---', '---', '--:'],
|
||||||
|
},
|
||||||
|
}[type];
|
||||||
|
|
||||||
|
const regions = [
|
||||||
|
{ id: 'os' as const, apps: ['EndField', 'Official'] as const, channel: cfg.channel.osWinRel },
|
||||||
|
{ id: 'cn' as const, apps: ['EndField', 'Arknights', 'Official'] as const, channel: cfg.channel.cnWinRel },
|
||||||
|
];
|
||||||
|
|
||||||
|
const mdTexts: string[] = [
|
||||||
|
`# ${settings.title}\n`,
|
||||||
|
...regions.flatMap((r) =>
|
||||||
|
r.apps.map((app) => `- [${r.id.toUpperCase()} ${app}](#launcher-${r.id}-${app.toLowerCase()})`),
|
||||||
|
),
|
||||||
|
'\n',
|
||||||
|
];
|
||||||
|
|
||||||
|
const waybackDb = await (async () => {
|
||||||
|
const localJsonPath = path.join(outputDir, 'wayback_machine.json');
|
||||||
|
return (await Bun.file(localJsonPath).json()) as string[];
|
||||||
|
})();
|
||||||
|
|
||||||
|
for (const region of regions) {
|
||||||
|
for (const appName of region.apps) {
|
||||||
|
const jsonPath = path.join(
|
||||||
|
outputDir,
|
||||||
|
'akEndfield',
|
||||||
|
'launcher',
|
||||||
|
settings.subdir,
|
||||||
|
appName,
|
||||||
|
String(region.channel),
|
||||||
|
'all.json',
|
||||||
|
);
|
||||||
|
const jsonData = (await Bun.file(jsonPath).json()) as StoredData<any>[];
|
||||||
|
|
||||||
|
mdTexts.push(
|
||||||
|
`<h2 id="launcher-${region.id}-${appName.toLowerCase()}">${region.id.toUpperCase()} ${appName}</h2>\n`,
|
||||||
|
`|${settings.headers.join('|')}|`,
|
||||||
|
`|${settings.align.join('|')}|`,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const e of jsonData) {
|
||||||
|
const url = type === 'zip' ? e.rsp.zip_package_url : e.rsp.exe_url;
|
||||||
|
const fileName = new URL(url).pathname.split('/').pop() ?? '';
|
||||||
|
const cleanUrl = new URL(url);
|
||||||
|
cleanUrl.search = '';
|
||||||
|
const waybackUrl = waybackDb.find((f) => f.includes(cleanUrl.toString()));
|
||||||
|
const fileLink = waybackUrl ? `${fileName} [Orig](${url}) / [Mirror](${waybackUrl})` : `[${fileName}](${url})`;
|
||||||
|
const date = DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss');
|
||||||
|
const row =
|
||||||
|
type === 'zip'
|
||||||
|
? [
|
||||||
|
date,
|
||||||
|
e.rsp.version,
|
||||||
|
fileLink,
|
||||||
|
`\`${e.rsp.md5}\``,
|
||||||
|
formatBytes(parseInt(e.rsp.total_size) - parseInt(e.rsp.package_size)),
|
||||||
|
formatBytes(parseInt(e.rsp.package_size)),
|
||||||
|
]
|
||||||
|
: [date, e.rsp.version, fileLink, formatBytes(parseInt(e.rsp.exe_size))];
|
||||||
|
|
||||||
|
mdTexts.push(`|${row.join('|')}|`);
|
||||||
|
}
|
||||||
|
mdTexts.push('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Bun.write(path.join(outputDir, 'akEndfield', 'launcher', settings.subdir, 'list.md'), mdTexts.join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 実行例
|
||||||
|
// await generateLauncherMd('zip');
|
||||||
|
// await generateLauncherMd('exe');
|
||||||
|
|
||||||
async function fetchAndSaveLatestGames(cfg: typeof appConfig.network.api.akEndfield, gameTargets: GameTarget[]) {
|
async function fetchAndSaveLatestGames(cfg: typeof appConfig.network.api.akEndfield, gameTargets: GameTarget[]) {
|
||||||
for (const target of gameTargets) {
|
for (const target of gameTargets) {
|
||||||
logger.debug(`Fetching latestGame (${target.name}) ...`);
|
logger.debug(`Fetching latestGame (${target.name}) ...`);
|
||||||
@@ -489,37 +603,68 @@ async function fetchAndSaveLatestGameResources(cfg: typeof appConfig.network.api
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAndSaveLatestLauncher(cfg: typeof appConfig.network.api.akEndfield, channelStr: string) {
|
async function fetchAndSaveLatestLauncher(cfg: typeof appConfig.network.api.akEndfield) {
|
||||||
logger.debug('Fetching latestLauncher ...');
|
logger.debug('Fetching latestLauncher ...');
|
||||||
const launcherTargetAppList = ['EndField', 'official'] as const;
|
const regions = [
|
||||||
for (const launcherTargetAppEntry of launcherTargetAppList) {
|
{
|
||||||
const rsp = await apiUtils.akEndfield.launcher.latestLauncher(
|
id: 'os' as const,
|
||||||
cfg.appCode.launcher.osWinRel,
|
apps: ['EndField', 'Official'] as const,
|
||||||
cfg.channel.osWinRel,
|
code: cfg.appCode.launcher.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
channel: cfg.channel.osWinRel,
|
||||||
null,
|
},
|
||||||
launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry,
|
{
|
||||||
);
|
id: 'cn' as const,
|
||||||
logger.info(`Fetched latestLauncher: v${rsp.version}, ${launcherTargetAppEntry}`);
|
apps: ['EndField', 'Arknights', 'Official'] as const,
|
||||||
const prettyRsp = {
|
code: cfg.appCode.launcher.cnWinRel,
|
||||||
req: {
|
channel: cfg.channel.cnWinRel,
|
||||||
appCode: cfg.appCode.launcher.osWinRel,
|
},
|
||||||
channel: cfg.channel.osWinRel,
|
];
|
||||||
subChannel: cfg.channel.osWinRel,
|
const removeQueryStr = (url: string): string => {
|
||||||
targetApp: launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry,
|
const urlObj = new URL(url);
|
||||||
},
|
urlObj.search = '';
|
||||||
rsp,
|
return urlObj.toString();
|
||||||
};
|
};
|
||||||
|
const saveToWM = async (url: string): Promise<void> => {
|
||||||
|
if (waybackCred === null) throw new Error('Wayback Machine auth is null');
|
||||||
|
const localJsonPath = path.join(argvUtils.getArgv()['outputDir'], 'wayback_machine.json');
|
||||||
|
const localJson: string[] = await Bun.file(localJsonPath).json();
|
||||||
|
if (!localJson.find((e) => e.includes(removeQueryStr(url)))) {
|
||||||
|
await webArchiveOrg.savePage(url, waybackCred);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await saveResult(
|
for (const { id, apps, code, channel } of regions) {
|
||||||
['akEndfield', 'launcher', 'launcher', launcherTargetAppEntry, channelStr],
|
for (const app of apps) {
|
||||||
rsp.version,
|
const apiArgs = [code, channel, channel, null] as const;
|
||||||
prettyRsp,
|
const rsp = await apiUtils.akEndfield.launcher.latestLauncher(...apiArgs, app, id);
|
||||||
);
|
const prettyRsp = { req: { appCode: code, channel, subChannel: channel, targetApp: app }, rsp };
|
||||||
|
const appLower = app.toLowerCase();
|
||||||
|
const rspExe = await apiUtils.akEndfield.launcher.latestLauncherExe(...apiArgs, appLower, id);
|
||||||
|
const prettyRspExe = { req: { appCode: code, channel, subChannel: channel, ta: appLower }, rsp: rspExe };
|
||||||
|
logger.info(`Fetched latestLauncher: v${rsp.version}, ${id}, ${app}`);
|
||||||
|
const basePath = ['akEndfield', 'launcher'];
|
||||||
|
const channelStr = String(channel);
|
||||||
|
const ignoreRules = [
|
||||||
|
{ path: ['rsp', 'zip_package_url'], pattern: /\?auth_key=.*$/ },
|
||||||
|
{ path: ['rsp', 'exe_url'], pattern: /\?auth_key=.*$/ },
|
||||||
|
];
|
||||||
|
if (rsp.zip_package_url.includes('?auth_key')) await saveToWM(rsp.zip_package_url);
|
||||||
|
if (rspExe.exe_url.includes('?auth_key')) await saveToWM(rspExe.exe_url);
|
||||||
|
await saveResult([...basePath, 'launcher', app, channelStr], rsp.version, prettyRsp, true, ignoreRules);
|
||||||
|
await saveResult([...basePath, 'launcherExe', app, channelStr], rspExe.version, prettyRspExe, true, ignoreRules);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mainCmdHandler() {
|
async function mainCmdHandler() {
|
||||||
|
waybackCred = await (async () => {
|
||||||
|
logger.debug('Fetching credentials for Wayback Machine ...');
|
||||||
|
const authTextData = await Bun.file('config/config_auth.txt').json();
|
||||||
|
const result = await webArchiveOrg.login(authTextData[0], authTextData[1]);
|
||||||
|
logger.info('Logged in to Wayback Machine');
|
||||||
|
return result;
|
||||||
|
})();
|
||||||
|
|
||||||
const cfg = appConfig.network.api.akEndfield;
|
const cfg = appConfig.network.api.akEndfield;
|
||||||
const channelStr = String(cfg.channel.osWinRel);
|
const channelStr = String(cfg.channel.osWinRel);
|
||||||
|
|
||||||
@@ -550,13 +695,15 @@ async function mainCmdHandler() {
|
|||||||
await fetchAndSaveLatestGames(cfg, gameTargets);
|
await fetchAndSaveLatestGames(cfg, gameTargets);
|
||||||
await fetchAndSaveLatestGamePatches(cfg, gameTargets);
|
await fetchAndSaveLatestGamePatches(cfg, gameTargets);
|
||||||
await fetchAndSaveLatestGameResources(cfg, channelStr);
|
await fetchAndSaveLatestGameResources(cfg, channelStr);
|
||||||
await fetchAndSaveLatestLauncher(cfg, channelStr);
|
await fetchAndSaveLatestLauncher(cfg);
|
||||||
|
|
||||||
for (const target of gameTargets) {
|
for (const target of gameTargets) {
|
||||||
await generateGameListMd(target);
|
await generateGameListMd(target);
|
||||||
await generatePatchListMd(target);
|
await generatePatchListMd(target);
|
||||||
}
|
}
|
||||||
await generateResourceListMd(channelStr);
|
await generateResourceListMd(channelStr);
|
||||||
|
await generateLauncherMd('zip');
|
||||||
|
await generateLauncherMd('exe');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default mainCmdHandler;
|
export default mainCmdHandler;
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ type LauncherLatestLauncher = {
|
|||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LauncherLatestLauncherExe = {
|
||||||
|
action: number;
|
||||||
|
version: string; // x.y.z
|
||||||
|
request_version: string; // x.y.z or blank
|
||||||
|
exe_url: string;
|
||||||
|
exe_size: string;
|
||||||
|
};
|
||||||
|
|
||||||
type LauncherWebSidebar = {
|
type LauncherWebSidebar = {
|
||||||
data_version: string;
|
data_version: string;
|
||||||
sidebars: {
|
sidebars: {
|
||||||
@@ -355,6 +363,7 @@ export type {
|
|||||||
LauncherLatestGame,
|
LauncherLatestGame,
|
||||||
LauncherLatestGameResources,
|
LauncherLatestGameResources,
|
||||||
LauncherLatestLauncher,
|
LauncherLatestLauncher,
|
||||||
|
LauncherLatestLauncherExe,
|
||||||
LauncherWebSidebar,
|
LauncherWebSidebar,
|
||||||
LauncherWebSingleEnt,
|
LauncherWebSingleEnt,
|
||||||
LauncherWebMainBgImage,
|
LauncherWebMainBgImage,
|
||||||
|
|||||||
@@ -58,22 +58,54 @@ export default {
|
|||||||
channel: number,
|
channel: number,
|
||||||
subChannel: number,
|
subChannel: number,
|
||||||
version: string | null,
|
version: string | null,
|
||||||
targetApp: 'EndField' | null,
|
targetApp: 'EndField' | 'Arknights' | 'Official',
|
||||||
|
region: 'os' | 'cn',
|
||||||
): Promise<TypesApiAkEndfield.LauncherLatestLauncher> => {
|
): Promise<TypesApiAkEndfield.LauncherLatestLauncher> => {
|
||||||
if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
|
if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
|
||||||
|
const domain =
|
||||||
|
region === 'cn'
|
||||||
|
? appConfig.network.api.akEndfield.base.launcherCN
|
||||||
|
: appConfig.network.api.akEndfield.base.launcher;
|
||||||
const rsp = await ky
|
const rsp = await ky
|
||||||
.get(`https://${appConfig.network.api.akEndfield.base.launcher}/launcher/get_latest`, {
|
.get(`https://${domain}/launcher/get_latest`, {
|
||||||
...defaultSettings.ky,
|
...defaultSettings.ky,
|
||||||
searchParams: {
|
searchParams: {
|
||||||
appcode: appCode,
|
appcode: appCode,
|
||||||
channel,
|
channel,
|
||||||
sub_channel: subChannel,
|
sub_channel: subChannel,
|
||||||
version: version ?? undefined,
|
version: version ?? undefined,
|
||||||
target_app: targetApp ?? undefined,
|
target_app: targetApp,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.json();
|
.json();
|
||||||
return rsp as TypesApiAkEndfield.LauncherLatestLauncher;
|
return rsp as TypesApiAkEndfield.LauncherLatestLauncher;
|
||||||
},
|
},
|
||||||
|
latestLauncherExe: async (
|
||||||
|
appCode: string,
|
||||||
|
channel: number,
|
||||||
|
subChannel: number,
|
||||||
|
version: string | null,
|
||||||
|
targetApp: 'endfield' | 'official' | string,
|
||||||
|
region: 'os' | 'cn',
|
||||||
|
): Promise<TypesApiAkEndfield.LauncherLatestLauncherExe> => {
|
||||||
|
if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
|
||||||
|
const domain =
|
||||||
|
region === 'cn'
|
||||||
|
? appConfig.network.api.akEndfield.base.launcherCN
|
||||||
|
: appConfig.network.api.akEndfield.base.launcher;
|
||||||
|
const rsp = await ky
|
||||||
|
.get(`https://${domain}/launcher/get_latest_launcher`, {
|
||||||
|
...defaultSettings.ky,
|
||||||
|
searchParams: {
|
||||||
|
appcode: appCode,
|
||||||
|
channel,
|
||||||
|
sub_channel: subChannel,
|
||||||
|
version: version ?? undefined,
|
||||||
|
ta: targetApp,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.LauncherLatestLauncherExe;
|
||||||
|
},
|
||||||
web: launcherWeb,
|
web: launcherWeb,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import akEndfield from './akEndfield/index.js';
|
import akEndfield from './akEndfield/index.js';
|
||||||
|
import webArchiveOrg from './webArchiveOrg/index.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
akEndfield,
|
akEndfield,
|
||||||
|
webArchiveOrg,
|
||||||
};
|
};
|
||||||
|
|||||||
11
src/utils/api/webArchiveOrg/defaultSettings.ts
Normal file
11
src/utils/api/webArchiveOrg/defaultSettings.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import appConfig from '../../config.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ky: {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': appConfig.network.userAgent.chromeWindows,
|
||||||
|
},
|
||||||
|
timeout: appConfig.network.timeout,
|
||||||
|
retry: { limit: appConfig.network.retryCount },
|
||||||
|
},
|
||||||
|
};
|
||||||
85
src/utils/api/webArchiveOrg/index.ts
Normal file
85
src/utils/api/webArchiveOrg/index.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import cookie from 'cookie';
|
||||||
|
import ky from 'ky';
|
||||||
|
import defaultSettings from './defaultSettings.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
login: {
|
||||||
|
getLoginToken: async (): Promise<string> => {
|
||||||
|
const rsp: any = await ky.get('https://archive.org/services/account/login/', defaultSettings.ky).json();
|
||||||
|
if (!rsp.value.token) throw new Error('Failed to get wayback machine login token');
|
||||||
|
return rsp.value.token;
|
||||||
|
},
|
||||||
|
login: async (username: string, password: string, token: string, remember: boolean = true) => {
|
||||||
|
const rsp = await ky.post('https://archive.org/services/account/login/', {
|
||||||
|
...defaultSettings.ky,
|
||||||
|
json: {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
remember: String(remember),
|
||||||
|
t: token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!((await rsp.json()) as any).success) throw new Error('Wayback Machine login error: ' + rsp);
|
||||||
|
return rsp.headers.getSetCookie().map((e) => cookie.parseSetCookie(e));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
save: async (url: string, auth: { user: string; sig: string }): Promise<string> => {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('url', url);
|
||||||
|
params.append('capture_all', 'on');
|
||||||
|
const rsp = await ky
|
||||||
|
.post('https://web.archive.org/save/' + url, {
|
||||||
|
...defaultSettings.ky,
|
||||||
|
headers: {
|
||||||
|
...defaultSettings.ky.headers,
|
||||||
|
Cookie: cookie.stringifyCookie({ 'logged-in-sig': auth.sig, 'logged-in-user': auth.user }),
|
||||||
|
},
|
||||||
|
body: params,
|
||||||
|
})
|
||||||
|
.text();
|
||||||
|
const match = rsp.match(/spn\.watchJob\("([^"]+)"/);
|
||||||
|
if (match && match[1]) {
|
||||||
|
return match[1]; // spn2-xxxxxxxxxxxxxxxxxxx
|
||||||
|
}
|
||||||
|
throw new Error('Wayback Machine save job id not found');
|
||||||
|
},
|
||||||
|
saveStatus: async (
|
||||||
|
jobId: string,
|
||||||
|
auth: { user: string; sig: string },
|
||||||
|
): Promise<
|
||||||
|
| {
|
||||||
|
status: 'success';
|
||||||
|
job_id: string;
|
||||||
|
resources: [];
|
||||||
|
download_size: number;
|
||||||
|
total_size: number;
|
||||||
|
timestamp: string;
|
||||||
|
original_url: string;
|
||||||
|
duration_sec: number;
|
||||||
|
counters: {
|
||||||
|
outlinks: number;
|
||||||
|
embeds: number;
|
||||||
|
};
|
||||||
|
http_status: number;
|
||||||
|
first_archive: boolean;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
status: 'pending';
|
||||||
|
job_id: string;
|
||||||
|
resources: [];
|
||||||
|
download_size?: number;
|
||||||
|
total_size?: number;
|
||||||
|
}
|
||||||
|
> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.get('https://web.archive.org/save/status/' + jobId, {
|
||||||
|
...defaultSettings.ky,
|
||||||
|
headers: {
|
||||||
|
...defaultSettings.ky.headers,
|
||||||
|
Cookie: cookie.stringifyCookie({ 'logged-in-sig': auth.sig, 'logged-in-user': auth.user }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as any;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -16,16 +16,17 @@ type ConfigType = AllRequired<
|
|||||||
api: {
|
api: {
|
||||||
akEndfield: {
|
akEndfield: {
|
||||||
appCode: {
|
appCode: {
|
||||||
game: { osWinRel: string };
|
game: { osWinRel: string; cnWinRel: string };
|
||||||
launcher: { osWinRel: string; osWinRelEpic: string };
|
launcher: { osWinRel: string; osWinRelEpic: string; cnWinRel: string };
|
||||||
accountService: { osWinRel: string; skport: string; binding: string };
|
accountService: { osWinRel: string; skport: string; binding: string };
|
||||||
u8: { osWinRel: string };
|
u8: { osWinRel: string };
|
||||||
};
|
};
|
||||||
channel: { osWinRel: number };
|
channel: { osWinRel: number; cnWinRel: number };
|
||||||
subChannel: { osWinRel: number; osWinRelEpic: number, osWinRelGooglePlay: number };
|
subChannel: { osWinRel: number; osWinRelEpic: number; osWinRelGooglePlay: number; cnWinRel: number };
|
||||||
base: {
|
base: {
|
||||||
accountService: string;
|
accountService: string;
|
||||||
launcher: string;
|
launcher: string;
|
||||||
|
launcherCN: string;
|
||||||
u8: string;
|
u8: string;
|
||||||
binding: string;
|
binding: string;
|
||||||
webview: string;
|
webview: string;
|
||||||
@@ -63,16 +64,17 @@ const initialConfig: ConfigType = {
|
|||||||
api: {
|
api: {
|
||||||
akEndfield: {
|
akEndfield: {
|
||||||
appCode: {
|
appCode: {
|
||||||
game: { osWinRel: 'YDUTE5gscDZ229CW' },
|
game: { osWinRel: 'YDUTE5gscDZ229CW', cnWinRel: '6LL0KJuqHBVz33WK' },
|
||||||
launcher: { osWinRel: 'TiaytKBUIEdoEwRT', osWinRelEpic: 'BBWoqCzuZ2bZ1Dro' },
|
launcher: { osWinRel: 'TiaytKBUIEdoEwRT', osWinRelEpic: 'BBWoqCzuZ2bZ1Dro', cnWinRel: 'abYeZZ16BPluCFyT' },
|
||||||
accountService: { osWinRel: 'd9f6dbb6bbd6bb33', skport: '6eb76d4e13aa36e6', binding: '3dacefa138426cfe' },
|
accountService: { osWinRel: 'd9f6dbb6bbd6bb33', skport: '6eb76d4e13aa36e6', binding: '3dacefa138426cfe' },
|
||||||
u8: { osWinRel: '973bd727dd11cbb6ead8' },
|
u8: { osWinRel: '973bd727dd11cbb6ead8' },
|
||||||
},
|
},
|
||||||
channel: { osWinRel: 6 },
|
channel: { osWinRel: 6, cnWinRel: 1 },
|
||||||
subChannel: { osWinRel: 6, osWinRelEpic: 801, osWinRelGooglePlay: 802 },
|
subChannel: { osWinRel: 6, osWinRelEpic: 801, osWinRelGooglePlay: 802, cnWinRel: 1 },
|
||||||
base: {
|
base: {
|
||||||
accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==',
|
accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==',
|
||||||
launcher: 'bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=',
|
launcher: 'bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=',
|
||||||
|
launcherCN: 'bGF1bmNoZXIuaHlwZXJncnlwaC5jb20vYXBp',
|
||||||
u8: 'dTguZ3J5cGhsaW5lLmNvbQ==',
|
u8: 'dTguZ3J5cGhsaW5lLmNvbQ==',
|
||||||
binding: 'YmluZGluZy1hcGktYWNjb3VudC1wcm9kLmdyeXBobGluZS5jb20=',
|
binding: 'YmluZGluZy1hcGktYWNjb3VudC1wcm9kLmdyeXBobGluZS5jb20=',
|
||||||
webview: 'ZWYtd2Vidmlldy5ncnlwaGxpbmUuY29t',
|
webview: 'ZWYtd2Vidmlldy5ncnlwaGxpbmUuY29t',
|
||||||
|
|||||||
65
src/utils/webArchiveOrg.ts
Normal file
65
src/utils/webArchiveOrg.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import path from 'node:path';
|
||||||
|
import { HTTPError } from 'ky';
|
||||||
|
import api from './api/index.js';
|
||||||
|
import argvUtils from './argv.js';
|
||||||
|
import logger from './logger.js';
|
||||||
|
import mathUtils from './math.js';
|
||||||
|
|
||||||
|
function formatBytes(bytes: number) {
|
||||||
|
return mathUtils.formatFileSize(bytes, {
|
||||||
|
decimals: 2,
|
||||||
|
decimalPadding: true,
|
||||||
|
useBinaryUnit: true,
|
||||||
|
useBitUnit: false,
|
||||||
|
unitVisible: true,
|
||||||
|
unit: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login(username: string, password: string): Promise<{ user: string; sig: string }> {
|
||||||
|
const token = await api.webArchiveOrg.login.getLoginToken();
|
||||||
|
const loginRet = await api.webArchiveOrg.login.login(username, password, token, true);
|
||||||
|
const credential = {
|
||||||
|
user: loginRet.find((e) => e.name === 'logged-in-user')?.value,
|
||||||
|
sig: loginRet.find((e) => e.name === 'logged-in-sig')?.value,
|
||||||
|
};
|
||||||
|
if (credential.sig && credential.user) return credential as { user: string; sig: string };
|
||||||
|
throw new Error('Wayback Machine auth error');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function savePage(url: string, auth: { user: string; sig: string }): Promise<string> {
|
||||||
|
const jobId = await api.webArchiveOrg.save(url, auth);
|
||||||
|
const result = await (async () => {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
const status = await api.webArchiveOrg.saveStatus(jobId, auth);
|
||||||
|
if (status.download_size && status.total_size)
|
||||||
|
logger.debug(
|
||||||
|
`Wayback Machine save: ${formatBytes(status.download_size)} / ${formatBytes(status.total_size)}`,
|
||||||
|
);
|
||||||
|
if (status.status === 'success') return status;
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof HTTPError) {
|
||||||
|
throw new Error(
|
||||||
|
`Wayback Machine save: HTTP ${err.response.status} ${err.response.statusText}: ${await err.response.text()}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
if (result.http_status >= 400) {
|
||||||
|
throw new Error('Wayback Machine save: http ' + result.http_status + ' error');
|
||||||
|
}
|
||||||
|
const resultUrl = `https://web.archive.org/web/${result.timestamp}/${result.original_url}`;
|
||||||
|
const localJsonPath = path.join(argvUtils.getArgv()['outputDir'], 'wayback_machine.json');
|
||||||
|
const localJson: string[] = await Bun.file(localJsonPath).json();
|
||||||
|
if (localJson.includes(resultUrl) === false) localJson.push(resultUrl);
|
||||||
|
await Bun.write(localJsonPath, JSON.stringify(localJson, null, 2));
|
||||||
|
return resultUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
login,
|
||||||
|
savePage,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user