diff --git a/README.md b/README.md
index bf91430..bfd3d88 100644
--- a/README.md
+++ b/README.md
@@ -15,8 +15,12 @@ The APIs currently being monitored are as follows:
To easily view information about past versions of game packages and other items, please refer to the following page.
-- [**Game packages**](/output/akEndfield/launcher/game/6/list.md) (Windows)
-- [**Game patch packages**](/output/akEndfield/launcher/game/6/list_patch.md) (Windows)
+- **Game packages**
+ - [Windows Official](/output/akEndfield/launcher/game/6/list.md)
+ - [Windows Epic](/output/akEndfield/launcher/game/801/list.md)
+- **Game patch packages**
+ - [Windows Official](/output/akEndfield/launcher/game/6/list_patch.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)
## Contributing
diff --git a/config/config.yaml b/config/config.yaml
index f16ba87..f9a2ae4 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -6,6 +6,7 @@ network:
osWinRel: YDUTE5gscDZ229CW
launcher:
osWinRel: TiaytKBUIEdoEwRT
+ osWinRelEpic: BBWoqCzuZ2bZ1Dro
accountService:
osWinRel: d9f6dbb6bbd6bb33
skport: 6eb76d4e13aa36e6
@@ -15,6 +16,9 @@ network:
osWinRel: YDUTE5gscDZ229CW
channel:
osWinRel: 6
+ subChannel:
+ osWinRel: 6
+ osWinRelEpic: 801
base:
accountService: YXMuZ3J5cGhsaW5lLmNvbQ==
launcher: bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=
diff --git a/output/akEndfield/launcher/game/6/list.md b/output/akEndfield/launcher/game/6/list.md
index 7b3dfd6..20be9c1 100644
--- a/output/akEndfield/launcher/game/6/list.md
+++ b/output/akEndfield/launcher/game/6/list.md
@@ -1,4 +1,4 @@
-# Game Packages
+# Game Packages (Official)
- [1.0.13 (2026/01/22 16:31:25)](#ver-1.0.13-1769070686)
- [1.0.14 (2026/01/25 18:30:20)](#ver-1.0.14-1769337021)
diff --git a/output/akEndfield/launcher/game/6/list_patch.md b/output/akEndfield/launcher/game/6/list_patch.md
index 7eb7138..fb9d18c 100644
--- a/output/akEndfield/launcher/game/6/list_patch.md
+++ b/output/akEndfield/launcher/game/6/list_patch.md
@@ -1,4 +1,4 @@
-# Game Patch Packages
+# Game Patch Packages (Official)
- [1.0.13 → 1.0.14 (2026/01/26 01:33:36)](#ver-1.0.13-1.0.14-1769362417)
diff --git a/output/akEndfield/launcher/game/801/all.json b/output/akEndfield/launcher/game/801/all.json
new file mode 100644
index 0000000..5bbe631
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/all.json
@@ -0,0 +1,212 @@
+[
+ {
+ "updatedAt": "2026-01-28T12:50:37.254+09:00",
+ "req": {
+ "appCode": "YDUTE5gscDZ229CW",
+ "launcherAppCode": "BBWoqCzuZ2bZ1Dro",
+ "channel": 6,
+ "subChannel": 801,
+ "launcherSubChannel": 801
+ },
+ "rsp": {
+ "action": 1,
+ "version": "1.0.14",
+ "request_version": "",
+ "pkg": {
+ "packs": [
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.001",
+ "md5": "6f24f6b31eec12cfb6ce243d2bd8d743",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.002",
+ "md5": "8ceee32676963a697f0e8daa6acc2f6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.003",
+ "md5": "17d0f31bdf6a1be25e30da9995176877",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.004",
+ "md5": "fc6fb86ccab29f745c0aec22c611d751",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.005",
+ "md5": "abf77711160c031c74c9728dc0386338",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.006",
+ "md5": "075b3e86c03965aab435b7c72bb58511",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.007",
+ "md5": "a6b90ccd5eb148b07ffd608494182da9",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.008",
+ "md5": "5cd8023b0e4cb18b7aa35d10c65dc202",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.009",
+ "md5": "b11d86cfdb5dc9015a4b532b2ebf5d22",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.010",
+ "md5": "687e457fd9636feb9ea08f5e7c7a3283",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.011",
+ "md5": "a6889c0be1318ade55404bcdb213b33c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.012",
+ "md5": "568e1fa0bdde5d3f3b6430df7322d546",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.013",
+ "md5": "a81ca3c9d29a56ad9456e1ec4abe1c5f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.014",
+ "md5": "ac7b33dfb9d0de719d179d394e2bee35",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.015",
+ "md5": "3bb928beea143f3907c8f7ce73e52826",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.016",
+ "md5": "49e0c09001b1fb49ae63a9b44d372925",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.017",
+ "md5": "65bfc97ceaa9b6d080f968042a905ec6",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.018",
+ "md5": "974d7944f0e2ef76ce8f9ca7fbcb28e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.019",
+ "md5": "2c156a6a8336276ed8b5b02a6dbb5959",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.020",
+ "md5": "69fe77f015206da76ba38aa7abdbb28c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.021",
+ "md5": "20d5dd8dbae5d51e773ed69ee045c92a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.022",
+ "md5": "58ca42ab9632728a8461e0ecdb4b8165",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.023",
+ "md5": "2c8291bd497fe908f5b8aa5549bf4304",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.024",
+ "md5": "6f9cbf57b8f8a2dc7637f1872b87416a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.025",
+ "md5": "2f5cb6fd50a2716a05099961f52a48e5",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.026",
+ "md5": "f29cd5eca40e386b1cd3a085543ff1e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.027",
+ "md5": "fdb52f1ae980c590e7166338767f8dec",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.028",
+ "md5": "6df9b808c3730f33a9a51bcdec2d8649",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.029",
+ "md5": "4828a3bf5b39df973fcca0f0bb75f66b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.030",
+ "md5": "df44af4813e0e9ed782431978a6d380f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.031",
+ "md5": "6ec0bed387f20fdd8dce7973e97ef539",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.032",
+ "md5": "a74e239dbd4d3ebfcc0cf11cf6c64a6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.033",
+ "md5": "07efc779c9eee6ed3178089237be45d3",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.034",
+ "md5": "0f1074ef1be0f9fa4197c96a3e126827",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.035",
+ "md5": "28feac64d9b4341dd01e82a10ef8fb1b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.036",
+ "md5": "f231f823973d7bcf3f3bd34dcca742f9",
+ "package_size": "507588945"
+ }
+ ],
+ "total_size": "83960339238",
+ "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/files",
+ "url": "",
+ "md5": "",
+ "package_size": "0",
+ "file_id": "0",
+ "sub_channel": "801",
+ "game_files_md5": "9ad92d0a57c7c34ee3f0fe7eeebe514d"
+ },
+ "patch": null,
+ "state": 0,
+ "launcher_action": 0
+ }
+ }
+]
diff --git a/output/akEndfield/launcher/game/801/all_patch.json b/output/akEndfield/launcher/game/801/all_patch.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/all_patch.json
@@ -0,0 +1 @@
+[]
diff --git a/output/akEndfield/launcher/game/801/latest.json b/output/akEndfield/launcher/game/801/latest.json
new file mode 100644
index 0000000..e14fc89
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/latest.json
@@ -0,0 +1,209 @@
+{
+ "req": {
+ "appCode": "YDUTE5gscDZ229CW",
+ "launcherAppCode": "BBWoqCzuZ2bZ1Dro",
+ "channel": 6,
+ "subChannel": 801,
+ "launcherSubChannel": 801
+ },
+ "rsp": {
+ "action": 1,
+ "version": "1.0.14",
+ "request_version": "",
+ "pkg": {
+ "packs": [
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.001",
+ "md5": "6f24f6b31eec12cfb6ce243d2bd8d743",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.002",
+ "md5": "8ceee32676963a697f0e8daa6acc2f6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.003",
+ "md5": "17d0f31bdf6a1be25e30da9995176877",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.004",
+ "md5": "fc6fb86ccab29f745c0aec22c611d751",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.005",
+ "md5": "abf77711160c031c74c9728dc0386338",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.006",
+ "md5": "075b3e86c03965aab435b7c72bb58511",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.007",
+ "md5": "a6b90ccd5eb148b07ffd608494182da9",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.008",
+ "md5": "5cd8023b0e4cb18b7aa35d10c65dc202",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.009",
+ "md5": "b11d86cfdb5dc9015a4b532b2ebf5d22",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.010",
+ "md5": "687e457fd9636feb9ea08f5e7c7a3283",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.011",
+ "md5": "a6889c0be1318ade55404bcdb213b33c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.012",
+ "md5": "568e1fa0bdde5d3f3b6430df7322d546",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.013",
+ "md5": "a81ca3c9d29a56ad9456e1ec4abe1c5f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.014",
+ "md5": "ac7b33dfb9d0de719d179d394e2bee35",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.015",
+ "md5": "3bb928beea143f3907c8f7ce73e52826",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.016",
+ "md5": "49e0c09001b1fb49ae63a9b44d372925",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.017",
+ "md5": "65bfc97ceaa9b6d080f968042a905ec6",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.018",
+ "md5": "974d7944f0e2ef76ce8f9ca7fbcb28e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.019",
+ "md5": "2c156a6a8336276ed8b5b02a6dbb5959",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.020",
+ "md5": "69fe77f015206da76ba38aa7abdbb28c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.021",
+ "md5": "20d5dd8dbae5d51e773ed69ee045c92a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.022",
+ "md5": "58ca42ab9632728a8461e0ecdb4b8165",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.023",
+ "md5": "2c8291bd497fe908f5b8aa5549bf4304",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.024",
+ "md5": "6f9cbf57b8f8a2dc7637f1872b87416a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.025",
+ "md5": "2f5cb6fd50a2716a05099961f52a48e5",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.026",
+ "md5": "f29cd5eca40e386b1cd3a085543ff1e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.027",
+ "md5": "fdb52f1ae980c590e7166338767f8dec",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.028",
+ "md5": "6df9b808c3730f33a9a51bcdec2d8649",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.029",
+ "md5": "4828a3bf5b39df973fcca0f0bb75f66b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.030",
+ "md5": "df44af4813e0e9ed782431978a6d380f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.031",
+ "md5": "6ec0bed387f20fdd8dce7973e97ef539",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.032",
+ "md5": "a74e239dbd4d3ebfcc0cf11cf6c64a6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.033",
+ "md5": "07efc779c9eee6ed3178089237be45d3",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.034",
+ "md5": "0f1074ef1be0f9fa4197c96a3e126827",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.035",
+ "md5": "28feac64d9b4341dd01e82a10ef8fb1b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.036",
+ "md5": "f231f823973d7bcf3f3bd34dcca742f9",
+ "package_size": "507588945"
+ }
+ ],
+ "total_size": "83960339238",
+ "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/files",
+ "url": "",
+ "md5": "",
+ "package_size": "0",
+ "file_id": "0",
+ "sub_channel": "801",
+ "game_files_md5": "9ad92d0a57c7c34ee3f0fe7eeebe514d"
+ },
+ "patch": null,
+ "state": 0,
+ "launcher_action": 0
+ }
+}
diff --git a/output/akEndfield/launcher/game/801/list.md b/output/akEndfield/launcher/game/801/list.md
new file mode 100644
index 0000000..a13c3c2
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/list.md
@@ -0,0 +1,49 @@
+# Game Packages (Epic)
+
+- [1.0.14 (2026/01/28 11:50:37)](#ver-1.0.14-1769572238)
+
+
1.0.14 (2026/01/28 11:50:37)
+
+
+ | Unpacked Size | 42.72 GiB |
+ | Packed Size | 35.47 GiB |
+
+
+| File | MD5 Checksum | Size |
+| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- | ---------: |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.001](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.001) | `6f24f6b31eec12cfb6ce243d2bd8d743` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.002](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.002) | `8ceee32676963a697f0e8daa6acc2f6e` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.003](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.003) | `17d0f31bdf6a1be25e30da9995176877` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.004](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.004) | `fc6fb86ccab29f745c0aec22c611d751` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.005](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.005) | `abf77711160c031c74c9728dc0386338` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.006](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.006) | `075b3e86c03965aab435b7c72bb58511` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.007](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.007) | `a6b90ccd5eb148b07ffd608494182da9` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.008](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.008) | `5cd8023b0e4cb18b7aa35d10c65dc202` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.009](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.009) | `b11d86cfdb5dc9015a4b532b2ebf5d22` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.010](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.010) | `687e457fd9636feb9ea08f5e7c7a3283` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.011](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.011) | `a6889c0be1318ade55404bcdb213b33c` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.012](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.012) | `568e1fa0bdde5d3f3b6430df7322d546` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.013](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.013) | `a81ca3c9d29a56ad9456e1ec4abe1c5f` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.014](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.014) | `ac7b33dfb9d0de719d179d394e2bee35` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.015](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.015) | `3bb928beea143f3907c8f7ce73e52826` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.016](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.016) | `49e0c09001b1fb49ae63a9b44d372925` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.017](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.017) | `65bfc97ceaa9b6d080f968042a905ec6` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.018](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.018) | `974d7944f0e2ef76ce8f9ca7fbcb28e7` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.019](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.019) | `2c156a6a8336276ed8b5b02a6dbb5959` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.020](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.020) | `69fe77f015206da76ba38aa7abdbb28c` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.021](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.021) | `20d5dd8dbae5d51e773ed69ee045c92a` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.022](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.022) | `58ca42ab9632728a8461e0ecdb4b8165` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.023](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.023) | `2c8291bd497fe908f5b8aa5549bf4304` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.024](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.024) | `6f9cbf57b8f8a2dc7637f1872b87416a` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.025](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.025) | `2f5cb6fd50a2716a05099961f52a48e5` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.026](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.026) | `f29cd5eca40e386b1cd3a085543ff1e7` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.027](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.027) | `fdb52f1ae980c590e7166338767f8dec` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.028](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.028) | `6df9b808c3730f33a9a51bcdec2d8649` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.029](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.029) | `4828a3bf5b39df973fcca0f0bb75f66b` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.030](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.030) | `df44af4813e0e9ed782431978a6d380f` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.031](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.031) | `6ec0bed387f20fdd8dce7973e97ef539` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.032](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.032) | `a74e239dbd4d3ebfcc0cf11cf6c64a6e` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.033](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.033) | `07efc779c9eee6ed3178089237be45d3` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.034](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.034) | `0f1074ef1be0f9fa4197c96a3e126827` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.035](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.035) | `28feac64d9b4341dd01e82a10ef8fb1b` | 1.00 GiB |
+| [Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.036](https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.036) | `f231f823973d7bcf3f3bd34dcca742f9` | 484.07 MiB |
diff --git a/output/akEndfield/launcher/game/801/list_patch.md b/output/akEndfield/launcher/game/801/list_patch.md
new file mode 100644
index 0000000..718f597
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/list_patch.md
@@ -0,0 +1 @@
+# Game Patch Packages (Epic)
diff --git a/output/akEndfield/launcher/game/801/v1.0.14.json b/output/akEndfield/launcher/game/801/v1.0.14.json
new file mode 100644
index 0000000..e14fc89
--- /dev/null
+++ b/output/akEndfield/launcher/game/801/v1.0.14.json
@@ -0,0 +1,209 @@
+{
+ "req": {
+ "appCode": "YDUTE5gscDZ229CW",
+ "launcherAppCode": "BBWoqCzuZ2bZ1Dro",
+ "channel": 6,
+ "subChannel": 801,
+ "launcherSubChannel": 801
+ },
+ "rsp": {
+ "action": 1,
+ "version": "1.0.14",
+ "request_version": "",
+ "pkg": {
+ "packs": [
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.001",
+ "md5": "6f24f6b31eec12cfb6ce243d2bd8d743",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.002",
+ "md5": "8ceee32676963a697f0e8daa6acc2f6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.003",
+ "md5": "17d0f31bdf6a1be25e30da9995176877",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.004",
+ "md5": "fc6fb86ccab29f745c0aec22c611d751",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.005",
+ "md5": "abf77711160c031c74c9728dc0386338",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.006",
+ "md5": "075b3e86c03965aab435b7c72bb58511",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.007",
+ "md5": "a6b90ccd5eb148b07ffd608494182da9",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.008",
+ "md5": "5cd8023b0e4cb18b7aa35d10c65dc202",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.009",
+ "md5": "b11d86cfdb5dc9015a4b532b2ebf5d22",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.010",
+ "md5": "687e457fd9636feb9ea08f5e7c7a3283",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.011",
+ "md5": "a6889c0be1318ade55404bcdb213b33c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.012",
+ "md5": "568e1fa0bdde5d3f3b6430df7322d546",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.013",
+ "md5": "a81ca3c9d29a56ad9456e1ec4abe1c5f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.014",
+ "md5": "ac7b33dfb9d0de719d179d394e2bee35",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.015",
+ "md5": "3bb928beea143f3907c8f7ce73e52826",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.016",
+ "md5": "49e0c09001b1fb49ae63a9b44d372925",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.017",
+ "md5": "65bfc97ceaa9b6d080f968042a905ec6",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.018",
+ "md5": "974d7944f0e2ef76ce8f9ca7fbcb28e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.019",
+ "md5": "2c156a6a8336276ed8b5b02a6dbb5959",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.020",
+ "md5": "69fe77f015206da76ba38aa7abdbb28c",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.021",
+ "md5": "20d5dd8dbae5d51e773ed69ee045c92a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.022",
+ "md5": "58ca42ab9632728a8461e0ecdb4b8165",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.023",
+ "md5": "2c8291bd497fe908f5b8aa5549bf4304",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.024",
+ "md5": "6f9cbf57b8f8a2dc7637f1872b87416a",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.025",
+ "md5": "2f5cb6fd50a2716a05099961f52a48e5",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.026",
+ "md5": "f29cd5eca40e386b1cd3a085543ff1e7",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.027",
+ "md5": "fdb52f1ae980c590e7166338767f8dec",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.028",
+ "md5": "6df9b808c3730f33a9a51bcdec2d8649",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.029",
+ "md5": "4828a3bf5b39df973fcca0f0bb75f66b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.030",
+ "md5": "df44af4813e0e9ed782431978a6d380f",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.031",
+ "md5": "6ec0bed387f20fdd8dce7973e97ef539",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.032",
+ "md5": "a74e239dbd4d3ebfcc0cf11cf6c64a6e",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.033",
+ "md5": "07efc779c9eee6ed3178089237be45d3",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.034",
+ "md5": "0f1074ef1be0f9fa4197c96a3e126827",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.035",
+ "md5": "28feac64d9b4341dd01e82a10ef8fb1b",
+ "package_size": "1073741824"
+ },
+ {
+ "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/packs/Beyond_Release_v1d0-Rel-os-5157154-11_prod_obt_epic.zip.036",
+ "md5": "f231f823973d7bcf3f3bd34dcca742f9",
+ "package_size": "507588945"
+ }
+ ],
+ "total_size": "83960339238",
+ "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/801/Windows/1.0.14_Qk2mXHuAH1JWKF37/files",
+ "url": "",
+ "md5": "",
+ "package_size": "0",
+ "file_id": "0",
+ "sub_channel": "801",
+ "game_files_md5": "9ad92d0a57c7c34ee3f0fe7eeebe514d"
+ },
+ "patch": null,
+ "state": 0,
+ "launcher_action": 0
+ }
+}
diff --git a/src/cmds/test.ts b/src/cmds/test.ts
index 97ef20c..1c5e7d9 100644
--- a/src/cmds/test.ts
+++ b/src/cmds/test.ts
@@ -79,112 +79,149 @@ async function mainCmdHandler() {
const cfg = appConfig.network.api.akEndfield;
const channelStr = String(cfg.channel.osWinRel);
- await (async () => {
- logger.debug('Fetching latestGame ...');
- const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
- cfg.appCode.game.osWinRel,
- cfg.appCode.launcher.osWinRel,
- cfg.channel.osWinRel,
- cfg.channel.osWinRel,
- cfg.channel.osWinRel,
- null,
- );
- logger.info(
- `Fetched latestGame: v${rsp.version}, ${mathUtils.formatFileSize(
- parseInt(rsp.pkg.total_size) - mathUtils.arrayTotal(rsp.pkg.packs.map((e) => parseInt(e.package_size))),
- {
- decimals: 2,
- decimalPadding: true,
- useBinaryUnit: true,
- useBitUnit: false,
- unitVisible: true,
- unit: null,
- },
- )}`,
- );
- const prettyRsp = {
- req: {
- appCode: cfg.appCode.game.osWinRel,
- launcherAppCode: cfg.appCode.launcher.osWinRel,
- channel: cfg.channel.osWinRel,
- subChannel: cfg.channel.osWinRel,
- launcherSubChannel: cfg.channel.osWinRel,
- },
- rsp,
- };
+ const gameTargets = [
+ {
+ name: 'Official',
+ launcherAppCode: cfg.appCode.launcher.osWinRel,
+ subChannel: cfg.channel.osWinRel,
+ launcherSubChannel: cfg.channel.osWinRel,
+ dirName: String(cfg.channel.osWinRel),
+ },
+ {
+ name: 'Epic',
+ launcherAppCode: cfg.appCode.launcher.osWinRelEpic,
+ subChannel: cfg.subChannel.osWinRelEpic,
+ launcherSubChannel: cfg.subChannel.osWinRelEpic,
+ dirName: String(cfg.subChannel.osWinRelEpic),
+ },
+ ];
- await saveResult(['akEndfield', 'launcher', 'game', channelStr], rsp.version, prettyRsp);
- })();
-
- await (async () => {
- logger.debug('Fetching latestGame (patch) ...');
- const gameAllJson = await Bun.file(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'all.json'),
- ).json();
- const patchAllJson = await Bun.file(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'all_patch.json'),
- ).json();
- const versionList = ([...new Set(gameAllJson.map((e: any) => e.rsp.version))] as string[])
- .sort((a, b) => semver.compare(b, a))
- .slice(1);
- let needWrite: boolean = false;
- const queue = new PQueue({ concurrency: appConfig.threadCount.network });
- for (const ver of versionList) {
- queue.add(async () => {
- const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
- cfg.appCode.game.osWinRel,
- cfg.appCode.launcher.osWinRel,
- cfg.channel.osWinRel,
- cfg.channel.osWinRel,
- cfg.channel.osWinRel,
- ver,
- );
- const prettyRsp = {
- req: {
- appCode: cfg.appCode.game.osWinRel,
- launcherAppCode: cfg.appCode.launcher.osWinRel,
- channel: cfg.channel.osWinRel,
- subChannel: cfg.channel.osWinRel,
- launcherSubChannel: cfg.channel.osWinRel,
- version: ver,
- },
- rsp,
- };
- if (rsp.patch === null) return;
- if (
- patchAllJson
- .map((e: any) => JSON.stringify({ req: e.req, rsp: e.rsp }))
- .includes(JSON.stringify(prettyRsp)) === false
- ) {
- logger.debug(
- `Fetched latestGame (patch): v${rsp.request_version} -> v${rsp.version}, ${mathUtils.formatFileSize(
- parseInt(rsp.patch.total_size) - parseInt(rsp.patch.package_size),
- {
- decimals: 2,
- decimalPadding: true,
- unitVisible: true,
- useBinaryUnit: true,
- useBitUnit: false,
- unit: null,
- },
- )}`,
- );
- patchAllJson.push({
- updatedAt: DateTime.now().toISO(),
- ...prettyRsp,
- });
- needWrite = true;
- }
- });
- }
- await queue.onIdle();
- if (needWrite) {
- await Bun.write(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'all_patch.json'),
- JSON.stringify(patchAllJson, null, 2),
+ for (const target of gameTargets) {
+ await (async () => {
+ logger.debug(`Fetching latestGame (${target.name}) ...`);
+ const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
+ cfg.appCode.game.osWinRel,
+ target.launcherAppCode,
+ cfg.channel.osWinRel,
+ target.subChannel,
+ target.launcherSubChannel,
+ null,
);
- }
- })();
+ logger.info(
+ `Fetched latestGame (${target.name}): v${rsp.version}, ${mathUtils.formatFileSize(
+ parseInt(rsp.pkg.total_size) - mathUtils.arrayTotal(rsp.pkg.packs.map((e) => parseInt(e.package_size))),
+ {
+ decimals: 2,
+ decimalPadding: true,
+ useBinaryUnit: true,
+ useBitUnit: false,
+ unitVisible: true,
+ unit: null,
+ },
+ )}`,
+ );
+ const prettyRsp = {
+ req: {
+ appCode: cfg.appCode.game.osWinRel,
+ launcherAppCode: target.launcherAppCode,
+ channel: cfg.channel.osWinRel,
+ subChannel: target.subChannel,
+ launcherSubChannel: target.launcherSubChannel,
+ },
+ rsp,
+ };
+
+ await saveResult(['akEndfield', 'launcher', 'game', target.dirName], rsp.version, prettyRsp);
+ })();
+ }
+
+ for (const target of gameTargets) {
+ await (async () => {
+ logger.debug(`Fetching latestGame (patch) (${target.name}) ...`);
+ const gameAllJsonPath = path.join(
+ argvUtils.getArgv()['outputDir'],
+ 'akEndfield',
+ 'launcher',
+ 'game',
+ target.dirName,
+ 'all.json',
+ );
+ const patchAllJsonPath = path.join(
+ argvUtils.getArgv()['outputDir'],
+ 'akEndfield',
+ 'launcher',
+ 'game',
+ target.dirName,
+ 'all_patch.json',
+ );
+
+ if (!(await Bun.file(gameAllJsonPath).exists())) return;
+
+ const gameAllJson = await Bun.file(gameAllJsonPath).json();
+ let patchAllJson: any[] = [];
+ if (await Bun.file(patchAllJsonPath).exists()) {
+ patchAllJson = await Bun.file(patchAllJsonPath).json();
+ }
+
+ const versionList = ([...new Set(gameAllJson.map((e: any) => e.rsp.version))] as string[])
+ .sort((a, b) => semver.compare(b, a))
+ .slice(1);
+ let needWrite: boolean = false;
+ const queue = new PQueue({ concurrency: appConfig.threadCount.network });
+ for (const ver of versionList) {
+ queue.add(async () => {
+ const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
+ cfg.appCode.game.osWinRel,
+ target.launcherAppCode,
+ cfg.channel.osWinRel,
+ target.subChannel,
+ target.launcherSubChannel,
+ ver,
+ );
+ const prettyRsp = {
+ req: {
+ appCode: cfg.appCode.game.osWinRel,
+ launcherAppCode: target.launcherAppCode,
+ channel: cfg.channel.osWinRel,
+ subChannel: target.subChannel,
+ launcherSubChannel: target.launcherSubChannel,
+ version: ver,
+ },
+ rsp,
+ };
+ if (rsp.patch === null) return;
+ if (
+ patchAllJson
+ .map((e: any) => JSON.stringify({ req: e.req, rsp: e.rsp }))
+ .includes(JSON.stringify(prettyRsp)) === false
+ ) {
+ logger.debug(
+ `Fetched latestGame (patch) (${target.name}): v${rsp.request_version} -> v${rsp.version}, ${mathUtils.formatFileSize(
+ parseInt(rsp.patch.total_size) - parseInt(rsp.patch.package_size),
+ {
+ decimals: 2,
+ decimalPadding: true,
+ unitVisible: true,
+ useBinaryUnit: true,
+ useBitUnit: false,
+ unit: null,
+ },
+ )}`,
+ );
+ patchAllJson.push({
+ updatedAt: DateTime.now().toISO(),
+ ...prettyRsp,
+ });
+ needWrite = true;
+ }
+ });
+ }
+ await queue.onIdle();
+ if (needWrite) {
+ await Bun.write(patchAllJsonPath, JSON.stringify(patchAllJson, null, 2));
+ }
+ })();
+ }
await (async () => {
logger.debug('Fetching latestGameRes ...');
@@ -283,103 +320,126 @@ async function mainCmdHandler() {
await (async () => {
//* Markdown generate
- await (async () => {
- const gameAllJson = await Bun.file(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'all.json'),
- ).json();
- const mdTexts: string[] = [];
- mdTexts.push(
- ...[
- '# Game Packages\n',
- ...gameAllJson.map(
- (e: any) =>
- `- [${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})](#ver-${e.rsp.version}-${Math.ceil(DateTime.fromISO(e.updatedAt).toSeconds())})`,
- ),
- '',
- ],
- ...gameAllJson.map((e: any) =>
- [
- `${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})
\n`,
- ``,
- ` | Unpacked Size | ${mathUtils.formatFileSize(
- e.rsp.pkg.total_size - mathUtils.arrayTotal(e.rsp.pkg.packs.map((f: any) => parseInt(f.package_size))),
- {
- decimals: 2,
- decimalPadding: true,
- unitVisible: true,
- useBinaryUnit: true,
- useBitUnit: false,
- unit: null,
- },
- )} |
`,
- ` | Packed Size | ${mathUtils.formatFileSize(mathUtils.arrayTotal(e.rsp.pkg.packs.map((f: any) => parseInt(f.package_size))), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })} |
`,
- `
\n`,
- `|File|MD5 Checksum|Size|`,
- `|:--|:--|--:|`,
- ...e.rsp.pkg.packs.map((f: any) => [
- `|[${new URL(f.url).pathname.split('/').pop() ?? ''}](${f.url})|\`${f.md5}\`|${mathUtils.formatFileSize(parseInt(f.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
- ]),
+ for (const target of gameTargets) {
+ await (async () => {
+ const gameAllJsonPath = path.join(
+ argvUtils.getArgv()['outputDir'],
+ 'akEndfield',
+ 'launcher',
+ 'game',
+ target.dirName,
+ 'all.json',
+ );
+ if (!(await Bun.file(gameAllJsonPath).exists())) return;
+ const gameAllJson = await Bun.file(gameAllJsonPath).json();
+ const mdTexts: string[] = [];
+ mdTexts.push(
+ ...[
+ `# Game Packages (${target.name})\n`,
+ ...gameAllJson.map(
+ (e: any) =>
+ `- [${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})](#ver-${e.rsp.version}-${Math.ceil(DateTime.fromISO(e.updatedAt).toSeconds())})`,
+ ),
'',
- ].join('\n'),
- ),
- );
- await Bun.write(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'list.md'),
- mdTexts.join('\n'),
- );
- })();
+ ],
+ ...gameAllJson.map((e: any) =>
+ [
+ `${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})
\n`,
+ ``,
+ ` | Unpacked Size | ${mathUtils.formatFileSize(
+ e.rsp.pkg.total_size - mathUtils.arrayTotal(e.rsp.pkg.packs.map((f: any) => parseInt(f.package_size))),
+ {
+ decimals: 2,
+ decimalPadding: true,
+ unitVisible: true,
+ useBinaryUnit: true,
+ useBitUnit: false,
+ unit: null,
+ },
+ )} |
`,
+ ` | Packed Size | ${mathUtils.formatFileSize(mathUtils.arrayTotal(e.rsp.pkg.packs.map((f: any) => parseInt(f.package_size))), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })} |
`,
+ `
\n`,
+ `|File|MD5 Checksum|Size|`,
+ `|:--|:--|--:|`,
+ ...e.rsp.pkg.packs.map((f: any) => [
+ `|[${new URL(f.url).pathname.split('/').pop() ?? ''}](${f.url})|\`${f.md5}\`|${mathUtils.formatFileSize(parseInt(f.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
+ ]),
+ '',
+ ].join('\n'),
+ ),
+ );
+ await Bun.write(
+ path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', target.dirName, 'list.md'),
+ mdTexts.join('\n'),
+ );
+ })();
- await (async () => {
- const gameAllJson = await Bun.file(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'all_patch.json'),
- ).json();
- const mdTexts: string[] = [];
- mdTexts.push(
- ...[
- '# Game Patch Packages\n',
- ...gameAllJson.map(
- (e: any) =>
- `- [${e.rsp.request_version} → ${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})](#ver-${e.rsp.request_version}-${e.rsp.version}-${Math.ceil(DateTime.fromISO(e.updatedAt).toSeconds())})`,
- ),
- '',
- ],
- ...gameAllJson.map((e: any) =>
- [
- `${e.rsp.request_version} → ${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})
\n`,
- ``,
- ` | Unpacked Size | ${mathUtils.formatFileSize(
- e.rsp.patch.total_size -
- mathUtils.arrayTotal(e.rsp.patch.patches.map((f: any) => parseInt(f.package_size))),
- {
- decimals: 2,
- decimalPadding: true,
- unitVisible: true,
- useBinaryUnit: true,
- useBitUnit: false,
- unit: null,
- },
- )} |
`,
- ` | Packed Size | ${mathUtils.formatFileSize(mathUtils.arrayTotal(e.rsp.patch.patches.map((f: any) => parseInt(f.package_size))), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })} |
`,
- `
\n`,
- `|File|MD5 Checksum|Size|`,
- `|:--|:--|--:|`,
- ...(e.rsp.patch.url
- ? [
- `|[${new URL(e.rsp.patch.url).pathname.split('/').pop() ?? ''}](${e.rsp.patch.url})|\`${e.rsp.patch.md5}\`|${mathUtils.formatFileSize(parseInt(e.rsp.patch.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
- ]
- : []),
- ...e.rsp.patch.patches.map((f: any) => [
- `|[${new URL(f.url).pathname.split('/').pop() ?? ''}](${f.url})|\`${f.md5}\`|${mathUtils.formatFileSize(parseInt(f.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
- ]),
+ await (async () => {
+ const patchAllJsonPath = path.join(
+ argvUtils.getArgv()['outputDir'],
+ 'akEndfield',
+ 'launcher',
+ 'game',
+ target.dirName,
+ 'all_patch.json',
+ );
+ if (!(await Bun.file(patchAllJsonPath).exists())) return;
+ const gameAllJson = await Bun.file(patchAllJsonPath).json();
+ const mdTexts: string[] = [];
+ mdTexts.push(
+ ...[
+ `# Game Patch Packages (${target.name})\n`,
+ ...gameAllJson.map(
+ (e: any) =>
+ `- [${e.rsp.request_version} → ${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})](#ver-${e.rsp.request_version}-${e.rsp.version}-${Math.ceil(DateTime.fromISO(e.updatedAt).toSeconds())})`,
+ ),
'',
- ].join('\n'),
- ),
- );
- await Bun.write(
- path.join(argvUtils.getArgv()['outputDir'], 'akEndfield', 'launcher', 'game', channelStr, 'list_patch.md'),
- mdTexts.join('\n'),
- );
- })();
+ ],
+ ...gameAllJson.map((e: any) =>
+ [
+ `${e.rsp.request_version} → ${e.rsp.version} (${DateTime.fromISO(e.updatedAt, { setZone: true }).setZone('UTC+8').toFormat('yyyy/MM/dd HH:mm:ss')})
\n`,
+ ``,
+ ` | Unpacked Size | ${mathUtils.formatFileSize(
+ e.rsp.patch.total_size -
+ mathUtils.arrayTotal(e.rsp.patch.patches.map((f: any) => parseInt(f.package_size))),
+ {
+ decimals: 2,
+ decimalPadding: true,
+ unitVisible: true,
+ useBinaryUnit: true,
+ useBitUnit: false,
+ unit: null,
+ },
+ )} |
`,
+ ` | Packed Size | ${mathUtils.formatFileSize(mathUtils.arrayTotal(e.rsp.patch.patches.map((f: any) => parseInt(f.package_size))), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })} |
`,
+ `
\n`,
+ `|File|MD5 Checksum|Size|`,
+ `|:--|:--|--:|`,
+ ...(e.rsp.patch.url
+ ? [
+ `|[${new URL(e.rsp.patch.url).pathname.split('/').pop() ?? ''}](${e.rsp.patch.url})|\`${e.rsp.patch.md5}\`|${mathUtils.formatFileSize(parseInt(e.rsp.patch.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
+ ]
+ : []),
+ ...e.rsp.patch.patches.map((f: any) => [
+ `|[${new URL(f.url).pathname.split('/').pop() ?? ''}](${f.url})|\`${f.md5}\`|${mathUtils.formatFileSize(parseInt(f.package_size), { decimals: 2, decimalPadding: true, unitVisible: true, useBinaryUnit: true, useBitUnit: false, unit: null })}|`,
+ ]),
+ '',
+ ].join('\n'),
+ ),
+ );
+ await Bun.write(
+ path.join(
+ argvUtils.getArgv()['outputDir'],
+ 'akEndfield',
+ 'launcher',
+ 'game',
+ target.dirName,
+ 'list_patch.md',
+ ),
+ mdTexts.join('\n'),
+ );
+ })();
+ }
await (async () => {
const mdTexts: string[] = [];
diff --git a/src/utils/api.ts b/src/utils/api.ts
index ed05d6b..2b6b18d 100644
--- a/src/utils/api.ts
+++ b/src/utils/api.ts
@@ -1,461 +1,9 @@
-import ky from 'ky';
-import semver from 'semver';
-import * as TypesApiAkEndfield from '../types/api/akEndfield/Api.js';
-import appConfig from './config.js';
-
-const defaultKySettings = {
- headers: {
- 'User-Agent': appConfig.network.userAgent.minimum,
- },
- timeout: appConfig.network.timeout,
- retry: { limit: appConfig.network.retryCount },
-};
-
-const launcherWebLang = [
- 'de-de',
- 'en-us',
- 'es-mx',
- 'fr-fr',
- 'id-id',
- 'it-it',
- 'ja-jp',
- 'ko-kr',
- 'pt-br',
- 'ru-ru',
- 'th-th',
- 'vi-vn',
- 'zh-cn',
- 'zh-tw',
-] as const;
+import accountService from './api/accountService.js';
+import binding from './api/binding.js';
+import launcher from './api/launcher.js';
+import u8 from './api/u8.js';
+import webview from './api/webview.js';
export default {
- defaultKySettings,
- apiAkEndfield: {
- launcher: {
- latestGame: async (
- appCode: string,
- launcherAppCode: string,
- channel: number,
- subChannel: number,
- launcherSubChannel: number,
- version: string | null,
- ): Promise => {
- if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest`, {
- ...defaultKySettings,
- searchParams: {
- appcode: appCode,
- launcher_appcode: launcherAppCode,
- channel,
- sub_channel: subChannel,
- launcher_sub_channel: launcherSubChannel,
- version: version ?? undefined,
- },
- })
- .json();
- return rsp as TypesApiAkEndfield.LauncherLatestGame;
- },
- latestGameResources: async (
- appCode: string,
- gameVersion: string, // example: 1.0
- version: string,
- randStr: string,
- platform: 'Windows' | 'Android' | 'iOS' | 'PlayStation',
- ): Promise => {
- if (!semver.valid(version)) throw new Error(`Invalid version string (${version})`);
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest_resources`, {
- ...defaultKySettings,
- searchParams: {
- appcode: appCode,
- game_version: gameVersion,
- version: version,
- platform,
- rand_str: randStr,
- },
- })
- .json();
- return rsp as TypesApiAkEndfield.LauncherLatestGameResources;
- },
- latestLauncher: async (
- appCode: string,
- channel: number,
- subChannel: number,
- version: string | null,
- targetApp: 'EndField' | null,
- ): Promise => {
- if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.launcher}/launcher/get_latest`, {
- ...defaultKySettings,
- searchParams: {
- appcode: appCode,
- channel,
- sub_channel: subChannel,
- version: version ?? undefined,
- targetApp: targetApp ?? undefined,
- },
- })
- .json();
- return rsp as TypesApiAkEndfield.LauncherLatestLauncher;
- },
- web: {
- sidebar: async (
- appCode: string,
- channel: number,
- subChannel: number,
- language: (typeof launcherWebLang)[number],
- platform: 'Windows' = 'Windows',
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
- ...defaultKySettings,
- json: {
- proxy_reqs: [
- {
- kind: 'get_sidebar',
- get_sidebar_req: {
- appcode: appCode,
- channel: String(channel),
- sub_channel: String(subChannel),
- language,
- platform,
- source: 'launcher',
- },
- },
- ],
- },
- })
- .json();
- return (rsp as any).proxy_rsps[0].get_sidebar_rsp as TypesApiAkEndfield.LauncherWebSidebar;
- },
- singleEnt: async (
- appCode: string,
- channel: number,
- subChannel: number,
- language: (typeof launcherWebLang)[number],
- platform: 'Windows' = 'Windows',
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
- ...defaultKySettings,
- json: {
- proxy_reqs: [
- {
- kind: 'get_single_ent',
- get_single_ent_req: {
- appcode: appCode,
- channel: String(channel),
- sub_channel: String(subChannel),
- language,
- platform,
- source: 'launcher',
- },
- },
- ],
- },
- })
- .json();
- return (rsp as any).proxy_rsps[0].get_single_ent_rsp as TypesApiAkEndfield.LauncherWebSingleEnt;
- },
- mainBgImage: async (
- appCode: string,
- channel: number,
- subChannel: number,
- language: (typeof launcherWebLang)[number],
- platform: 'Windows' = 'Windows',
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
- ...defaultKySettings,
- json: {
- proxy_reqs: [
- {
- kind: 'get_main_bg_image',
- get_main_bg_image_req: {
- appcode: appCode,
- channel: String(channel),
- sub_channel: String(subChannel),
- language,
- platform,
- source: 'launcher',
- },
- },
- ],
- },
- })
- .json();
- return (rsp as any).proxy_rsps[0].get_main_bg_image_rsp as TypesApiAkEndfield.LauncherWebMainBgImage;
- },
- banner: async (
- appCode: string,
- channel: number,
- subChannel: number,
- language: (typeof launcherWebLang)[number],
- platform: 'Windows' = 'Windows',
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
- ...defaultKySettings,
- json: {
- proxy_reqs: [
- {
- kind: 'get_banner',
- get_banner_req: {
- appcode: appCode,
- channel: String(channel),
- sub_channel: String(subChannel),
- language,
- platform,
- source: 'launcher',
- },
- },
- ],
- },
- })
- .json();
- return (rsp as any).proxy_rsps[0].get_banner_rsp as TypesApiAkEndfield.LauncherWebBanner;
- },
- announcement: async (
- appCode: string,
- channel: number,
- subChannel: number,
- language: (typeof launcherWebLang)[number],
- platform: 'Windows' = 'Windows',
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
- ...defaultKySettings,
- json: {
- proxy_reqs: [
- {
- kind: 'get_announcement',
- get_announcement_req: {
- appcode: appCode,
- channel: String(channel),
- sub_channel: String(subChannel),
- language,
- platform,
- source: 'launcher',
- },
- },
- ],
- },
- })
- .json();
- return (rsp as any).proxy_rsps[0].get_announcement_rsp as TypesApiAkEndfield.LauncherWebAnnouncement;
- },
- },
- },
- accountService: {
- user: {
- auth: {
- v1: {
- tokenByEmailPassword: async (
- email: string,
- password: string,
- from: number = 0,
- ): Promise => {
- const rsp = await ky
- .post(
- `https://${appConfig.network.api.akEndfield.base.accountService}/user/auth/v1/token_by_email_password`,
- { ...defaultKySettings, json: { email, from, password } },
- )
- .json();
- return rsp as TypesApiAkEndfield.AccSrvUserAuthV1TokenByEmail;
- },
- },
- },
- oauth2: {
- v2: {
- grant: async (
- appCode: string,
- token: string,
- type: T = 0 as any, // 0 = return grant uid (Gxxxxxxxxx) and code, 1 = return hgId and token
- ): Promise<
- T extends 0 ? TypesApiAkEndfield.AccSrvUserOAuth2V2Grant : TypesApiAkEndfield.AccSrvUserOAuth2V2GrantType1
- > => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.accountService}/user/oauth2/v2/grant`, {
- ...defaultKySettings,
- json: { appCode, token, type },
- })
- .json();
- return rsp as any;
- },
- },
- },
- info: {
- v1: {
- basic: async (appCode: string, token: string): Promise => {
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.accountService}/user/info/v1/basic`, {
- ...defaultKySettings,
- searchParams: { appCode, token },
- })
- .json();
- return rsp as TypesApiAkEndfield.AccSrvUserInfoV1Basic;
- },
- thirdParty: async (
- appCode: string,
- token: string,
- ): Promise => {
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.accountService}/user/info/v1/third_party`, {
- ...defaultKySettings,
- searchParams: { appCode, token },
- })
- .json();
- return rsp as TypesApiAkEndfield.AccSrvUserInfoV1ThirdParty;
- },
- },
- },
- },
- },
- u8: {
- user: {
- auth: {
- v2: {
- tokenByChToken: async (
- appCode: string,
- channelMasterId: number,
- channelToken: string,
- platform: number = 2,
- type: number = 0,
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.u8}/u8/user/auth/v2/token_by_channel_token`, {
- ...defaultKySettings,
- json: {
- appCode,
- channelMasterId,
- channelToken: JSON.stringify({
- code: channelToken,
- type: 1,
- isSuc: true,
- }),
- type,
- platform,
- },
- })
- .json();
- return rsp as TypesApiAkEndfield.U8UserAuthV2ChToken;
- },
- grant: async (
- token: string,
- platform: number = 2,
- type: number = 0,
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.u8}/u8/user/auth/v2/grant`, {
- ...defaultKySettings,
- json: { token, type, platform },
- })
- .json();
- return rsp as TypesApiAkEndfield.U8UserAuthV2Grant;
- },
- },
- },
- },
- game: {
- server: {
- v1: {
- serverList: async (token: string): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.u8}/game/server/v1/server_list`, {
- ...defaultKySettings,
- json: { token },
- })
- .json();
- return rsp as TypesApiAkEndfield.U8GameServerV1ServerList;
- },
- },
- },
- role: {
- v1: {
- confirmServer: async (
- token: string,
- serverId: number,
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.u8}/game/role/v1/confirm_server`, {
- ...defaultKySettings,
- json: { token, serverId: String(serverId) },
- })
- .json();
- return rsp as TypesApiAkEndfield.U8GameRoleV1ConfirmServer;
- },
- },
- },
- },
- },
- binding: {
- account: {
- binding: {
- v1: {
- bindingList: async (
- // appCode: 'arknights' | 'endfield',
- token: string,
- ): Promise => {
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.binding}/account/binding/v1/binding_list`, {
- ...defaultKySettings,
- searchParams: { token },
- })
- .json();
- return rsp as TypesApiAkEndfield.BindApiAccBindV1BindList;
- },
- u8TokenByUid: async (
- token: string,
- uid: string,
- ): Promise => {
- const rsp = await ky
- .post(`https://${appConfig.network.api.akEndfield.base.binding}/account/binding/v1/u8_token_by_uid`, {
- ...defaultKySettings,
- json: { token, uid },
- })
- .json();
- return rsp as TypesApiAkEndfield.BindApiAccBindV1U8TokenByUid;
- },
- },
- },
- },
- },
- webview: {
- record: {
- char: async (
- token: string,
- serverId: number, // 2 or 3
- poolType:
- | 'E_CharacterGachaPoolType_Beginner'
- | 'E_CharacterGachaPoolType_Standard'
- | 'E_CharacterGachaPoolType_Special',
- seqId: string | null,
- lang: (typeof launcherWebLang)[number] = 'ja-jp',
- ): Promise => {
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.webview}/api/record/char`, {
- ...defaultKySettings,
- searchParams: { lang, seq_id: seqId ?? undefined, pool_type: poolType, token, server_id: serverId },
- })
- .json();
- return rsp as TypesApiAkEndfield.WebViewRecordChar;
- },
- },
- content: async (
- serverId: number, // 2 or 3
- poolId: string,
- lang: (typeof launcherWebLang)[number] = 'ja-jp',
- ): Promise => {
- const rsp = await ky
- .get(`https://${appConfig.network.api.akEndfield.base.webview}/api/content`, {
- ...defaultKySettings,
- searchParams: { lang, pool_id: poolId, server_id: serverId },
- })
- .json();
- return rsp as TypesApiAkEndfield.WebViewRecordContent;
- },
- },
- },
+ apiAkEndfield: { launcher, accountService, u8, binding, webview },
};
diff --git a/src/utils/api/accountService.ts b/src/utils/api/accountService.ts
new file mode 100644
index 0000000..5dade9a
--- /dev/null
+++ b/src/utils/api/accountService.ts
@@ -0,0 +1,67 @@
+import ky from 'ky';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+export default {
+ user: {
+ auth: {
+ v1: {
+ tokenByEmailPassword: async (
+ email: string,
+ password: string,
+ from: number = 0,
+ ): Promise => {
+ const rsp = await ky
+ .post(
+ `https://${appConfig.network.api.akEndfield.base.accountService}/user/auth/v1/token_by_email_password`,
+ { ...defaultSettings.ky, json: { email, from, password } },
+ )
+ .json();
+ return rsp as TypesApiAkEndfield.AccSrvUserAuthV1TokenByEmail;
+ },
+ },
+ },
+ oauth2: {
+ v2: {
+ grant: async (
+ appCode: string,
+ token: string,
+ type: T = 0 as any, // 0 = return grant uid (Gxxxxxxxxx) and code, 1 = return hgId and token
+ ): Promise<
+ T extends 0 ? TypesApiAkEndfield.AccSrvUserOAuth2V2Grant : TypesApiAkEndfield.AccSrvUserOAuth2V2GrantType1
+ > => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.accountService}/user/oauth2/v2/grant`, {
+ ...defaultSettings.ky,
+ json: { appCode, token, type },
+ })
+ .json();
+ return rsp as any;
+ },
+ },
+ },
+ info: {
+ v1: {
+ basic: async (appCode: string, token: string): Promise => {
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.accountService}/user/info/v1/basic`, {
+ ...defaultSettings.ky,
+ searchParams: { appCode, token },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.AccSrvUserInfoV1Basic;
+ },
+ thirdParty: async (appCode: string, token: string): Promise => {
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.accountService}/user/info/v1/third_party`, {
+ ...defaultSettings.ky,
+ searchParams: { appCode, token },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.AccSrvUserInfoV1ThirdParty;
+ },
+ },
+ },
+ },
+};
diff --git a/src/utils/api/binding.ts b/src/utils/api/binding.ts
new file mode 100644
index 0000000..44b7016
--- /dev/null
+++ b/src/utils/api/binding.ts
@@ -0,0 +1,34 @@
+import ky from 'ky';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+export default {
+ account: {
+ binding: {
+ v1: {
+ bindingList: async (
+ // appCode: 'arknights' | 'endfield',
+ token: string,
+ ): Promise => {
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.binding}/account/binding/v1/binding_list`, {
+ ...defaultSettings.ky,
+ searchParams: { token },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.BindApiAccBindV1BindList;
+ },
+ u8TokenByUid: async (token: string, uid: string): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.binding}/account/binding/v1/u8_token_by_uid`, {
+ ...defaultSettings.ky,
+ json: { token, uid },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.BindApiAccBindV1U8TokenByUid;
+ },
+ },
+ },
+ },
+};
diff --git a/src/utils/api/defaultSettings.ts b/src/utils/api/defaultSettings.ts
new file mode 100644
index 0000000..01aabcd
--- /dev/null
+++ b/src/utils/api/defaultSettings.ts
@@ -0,0 +1,27 @@
+import appConfig from '../config.js';
+
+export default {
+ ky: {
+ headers: {
+ 'User-Agent': appConfig.network.userAgent.minimum,
+ },
+ timeout: appConfig.network.timeout,
+ retry: { limit: appConfig.network.retryCount },
+ },
+ launcherWebLang: [
+ 'de-de',
+ 'en-us',
+ 'es-mx',
+ 'fr-fr',
+ 'id-id',
+ 'it-it',
+ 'ja-jp',
+ 'ko-kr',
+ 'pt-br',
+ 'ru-ru',
+ 'th-th',
+ 'vi-vn',
+ 'zh-cn',
+ 'zh-tw',
+ ] as const,
+};
diff --git a/src/utils/api/launcher.ts b/src/utils/api/launcher.ts
new file mode 100644
index 0000000..3574bad
--- /dev/null
+++ b/src/utils/api/launcher.ts
@@ -0,0 +1,79 @@
+import ky from 'ky';
+import semver from 'semver';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+import launcherWeb from './launcherWeb.js';
+
+export default {
+ latestGame: async (
+ appCode: string,
+ launcherAppCode: string,
+ channel: number,
+ subChannel: number,
+ launcherSubChannel: number,
+ version: string | null,
+ ): Promise => {
+ if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest`, {
+ ...defaultSettings.ky,
+ searchParams: {
+ appcode: appCode,
+ launcher_appcode: launcherAppCode,
+ channel,
+ sub_channel: subChannel,
+ launcher_sub_channel: launcherSubChannel,
+ version: version ?? undefined,
+ },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.LauncherLatestGame;
+ },
+ latestGameResources: async (
+ appCode: string,
+ gameVersion: string, // example: 1.0
+ version: string,
+ randStr: string,
+ platform: 'Windows' | 'Android' | 'iOS' | 'PlayStation',
+ ): Promise => {
+ if (!semver.valid(version)) throw new Error(`Invalid version string (${version})`);
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest_resources`, {
+ ...defaultSettings.ky,
+ searchParams: {
+ appcode: appCode,
+ game_version: gameVersion,
+ version: version,
+ platform,
+ rand_str: randStr,
+ },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.LauncherLatestGameResources;
+ },
+ latestLauncher: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ version: string | null,
+ targetApp: 'EndField' | null,
+ ): Promise => {
+ if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`);
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.launcher}/launcher/get_latest`, {
+ ...defaultSettings.ky,
+ searchParams: {
+ appcode: appCode,
+ channel,
+ sub_channel: subChannel,
+ version: version ?? undefined,
+ targetApp: targetApp ?? undefined,
+ },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.LauncherLatestLauncher;
+ },
+ web: launcherWeb,
+};
diff --git a/src/utils/api/launcherWeb.ts b/src/utils/api/launcherWeb.ts
new file mode 100644
index 0000000..fbb8ca0
--- /dev/null
+++ b/src/utils/api/launcherWeb.ts
@@ -0,0 +1,152 @@
+import ky from 'ky';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+export default {
+ sidebar: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ language: (typeof defaultSettings.launcherWebLang)[number],
+ platform: 'Windows' = 'Windows',
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
+ ...defaultSettings.ky,
+ json: {
+ proxy_reqs: [
+ {
+ kind: 'get_sidebar',
+ get_sidebar_req: {
+ appcode: appCode,
+ channel: String(channel),
+ sub_channel: String(subChannel),
+ language,
+ platform,
+ source: 'launcher',
+ },
+ },
+ ],
+ },
+ })
+ .json();
+ return (rsp as any).proxy_rsps[0].get_sidebar_rsp as TypesApiAkEndfield.LauncherWebSidebar;
+ },
+ singleEnt: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ language: (typeof defaultSettings.launcherWebLang)[number],
+ platform: 'Windows' = 'Windows',
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
+ ...defaultSettings.ky,
+ json: {
+ proxy_reqs: [
+ {
+ kind: 'get_single_ent',
+ get_single_ent_req: {
+ appcode: appCode,
+ channel: String(channel),
+ sub_channel: String(subChannel),
+ language,
+ platform,
+ source: 'launcher',
+ },
+ },
+ ],
+ },
+ })
+ .json();
+ return (rsp as any).proxy_rsps[0].get_single_ent_rsp as TypesApiAkEndfield.LauncherWebSingleEnt;
+ },
+ mainBgImage: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ language: (typeof defaultSettings.launcherWebLang)[number],
+ platform: 'Windows' = 'Windows',
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
+ ...defaultSettings.ky,
+ json: {
+ proxy_reqs: [
+ {
+ kind: 'get_main_bg_image',
+ get_main_bg_image_req: {
+ appcode: appCode,
+ channel: String(channel),
+ sub_channel: String(subChannel),
+ language,
+ platform,
+ source: 'launcher',
+ },
+ },
+ ],
+ },
+ })
+ .json();
+ return (rsp as any).proxy_rsps[0].get_main_bg_image_rsp as TypesApiAkEndfield.LauncherWebMainBgImage;
+ },
+ banner: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ language: (typeof defaultSettings.launcherWebLang)[number],
+ platform: 'Windows' = 'Windows',
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
+ ...defaultSettings.ky,
+ json: {
+ proxy_reqs: [
+ {
+ kind: 'get_banner',
+ get_banner_req: {
+ appcode: appCode,
+ channel: String(channel),
+ sub_channel: String(subChannel),
+ language,
+ platform,
+ source: 'launcher',
+ },
+ },
+ ],
+ },
+ })
+ .json();
+ return (rsp as any).proxy_rsps[0].get_banner_rsp as TypesApiAkEndfield.LauncherWebBanner;
+ },
+ announcement: async (
+ appCode: string,
+ channel: number,
+ subChannel: number,
+ language: (typeof defaultSettings.launcherWebLang)[number],
+ platform: 'Windows' = 'Windows',
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, {
+ ...defaultSettings.ky,
+ json: {
+ proxy_reqs: [
+ {
+ kind: 'get_announcement',
+ get_announcement_req: {
+ appcode: appCode,
+ channel: String(channel),
+ sub_channel: String(subChannel),
+ language,
+ platform,
+ source: 'launcher',
+ },
+ },
+ ],
+ },
+ })
+ .json();
+ return (rsp as any).proxy_rsps[0].get_announcement_rsp as TypesApiAkEndfield.LauncherWebAnnouncement;
+ },
+};
diff --git a/src/utils/api/u8.ts b/src/utils/api/u8.ts
new file mode 100644
index 0000000..af54a9d
--- /dev/null
+++ b/src/utils/api/u8.ts
@@ -0,0 +1,82 @@
+import ky from 'ky';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+export default {
+ user: {
+ auth: {
+ v2: {
+ tokenByChToken: async (
+ appCode: string,
+ channelMasterId: number,
+ channelToken: string,
+ platform: number = 2,
+ type: number = 0,
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.u8}/u8/user/auth/v2/token_by_channel_token`, {
+ ...defaultSettings.ky,
+ json: {
+ appCode,
+ channelMasterId,
+ channelToken: JSON.stringify({
+ code: channelToken,
+ type: 1,
+ isSuc: true,
+ }),
+ type,
+ platform,
+ },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.U8UserAuthV2ChToken;
+ },
+ grant: async (
+ token: string,
+ platform: number = 2,
+ type: number = 0,
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.u8}/u8/user/auth/v2/grant`, {
+ ...defaultSettings.ky,
+ json: { token, type, platform },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.U8UserAuthV2Grant;
+ },
+ },
+ },
+ },
+ game: {
+ server: {
+ v1: {
+ serverList: async (token: string): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.u8}/game/server/v1/server_list`, {
+ ...defaultSettings.ky,
+ json: { token },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.U8GameServerV1ServerList;
+ },
+ },
+ },
+ role: {
+ v1: {
+ confirmServer: async (
+ token: string,
+ serverId: number,
+ ): Promise => {
+ const rsp = await ky
+ .post(`https://${appConfig.network.api.akEndfield.base.u8}/game/role/v1/confirm_server`, {
+ ...defaultSettings.ky,
+ json: { token, serverId: String(serverId) },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.U8GameRoleV1ConfirmServer;
+ },
+ },
+ },
+ },
+};
diff --git a/src/utils/api/webview.ts b/src/utils/api/webview.ts
new file mode 100644
index 0000000..8f5e928
--- /dev/null
+++ b/src/utils/api/webview.ts
@@ -0,0 +1,40 @@
+import ky from 'ky';
+import * as TypesApiAkEndfield from '../../types/api/akEndfield/Api.js';
+import appConfig from '../config.js';
+import defaultSettings from './defaultSettings.js';
+
+export default {
+ record: {
+ char: async (
+ token: string,
+ serverId: number, // 2 or 3
+ poolType:
+ | 'E_CharacterGachaPoolType_Beginner'
+ | 'E_CharacterGachaPoolType_Standard'
+ | 'E_CharacterGachaPoolType_Special',
+ seqId: string | null,
+ lang: (typeof defaultSettings.launcherWebLang)[number] = 'ja-jp',
+ ): Promise => {
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.webview}/api/record/char`, {
+ ...defaultSettings.ky,
+ searchParams: { lang, seq_id: seqId ?? undefined, pool_type: poolType, token, server_id: serverId },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.WebViewRecordChar;
+ },
+ },
+ content: async (
+ serverId: number, // 2 or 3
+ poolId: string,
+ lang: (typeof defaultSettings.launcherWebLang)[number] = 'ja-jp',
+ ): Promise => {
+ const rsp = await ky
+ .get(`https://${appConfig.network.api.akEndfield.base.webview}/api/content`, {
+ ...defaultSettings.ky,
+ searchParams: { lang, pool_id: poolId, server_id: serverId },
+ })
+ .json();
+ return rsp as TypesApiAkEndfield.WebViewRecordContent;
+ },
+};
diff --git a/src/utils/config.ts b/src/utils/config.ts
index 77934fe..05aff82 100644
--- a/src/utils/config.ts
+++ b/src/utils/config.ts
@@ -17,11 +17,12 @@ type ConfigType = AllRequired<
akEndfield: {
appCode: {
game: { osWinRel: string };
- launcher: { osWinRel: string };
+ launcher: { osWinRel: string; osWinRelEpic: string };
accountService: { osWinRel: string; skport: string; binding: string };
u8: { osWinRel: string };
};
channel: { osWinRel: number };
+ subChannel: { osWinRel: number; osWinRelEpic: number };
base: {
accountService: string;
launcher: string;
@@ -63,11 +64,12 @@ const initialConfig: ConfigType = {
akEndfield: {
appCode: {
game: { osWinRel: 'YDUTE5gscDZ229CW' },
- launcher: { osWinRel: 'TiaytKBUIEdoEwRT' },
+ launcher: { osWinRel: 'TiaytKBUIEdoEwRT', osWinRelEpic: 'BBWoqCzuZ2bZ1Dro' },
accountService: { osWinRel: 'd9f6dbb6bbd6bb33', skport: '6eb76d4e13aa36e6', binding: '3dacefa138426cfe' },
u8: { osWinRel: '973bd727dd11cbb6ead8' },
},
channel: { osWinRel: 6 },
+ subChannel: { osWinRel: 6, osWinRelEpic: 801 },
base: {
accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==',
launcher: 'bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=',