Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
49c1685e5e | |||
89a0553c59 | |||
3605826953 | |||
75f2f2dd4f | |||
947101cc43 | |||
8628625a27 | |||
4ab2f60b53 | |||
f2592040cb | |||
9de5ba1025 | |||
839b8fd54a | |||
38cb320628 | |||
8a0d96cf3e | |||
298ea3e053 | |||
82f42e56db | |||
a2dcda6be0 | |||
dcaad1d544 | |||
69042728da | |||
0103a0fb4b | |||
1052a4bffb | |||
2fd8730cdd | |||
bbc52af184 | |||
38ed348865 | |||
29548310c5 | |||
3617599d32 | |||
c724727886 | |||
d324aee160 | |||
5a5a7c1327 | |||
77a1d611be | |||
3dbb746a38 | |||
b88b57ae62 | |||
677ab3750d | |||
f95470504d | |||
8d45af5089 | |||
8a9c7a3b56 | |||
2a670c7023 | |||
d732d523a8 |
13
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
custom: https://afdian.net/a/haisha
|
31
.github/workflows/build-update.yml
vendored
@ -1,31 +0,0 @@
|
|||||||
name: Build Update
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: '16.x'
|
|
||||||
- name: Build Update
|
|
||||||
run: |
|
|
||||||
yarn --frozen-lockfile
|
|
||||||
yarn build:dir
|
|
||||||
yarn build-update
|
|
||||||
- name: Deploy
|
|
||||||
if: success()
|
|
||||||
uses: crazy-max/ghaction-github-pages@v2
|
|
||||||
with:
|
|
||||||
commit_message: Update app
|
|
||||||
build_dir: ./build/update
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@ -15,7 +15,9 @@
|
|||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
||||||
1. 下载工具后解压 - 下载地址: [Github](https://github.com/biuuu/star-rail-warp-export/releases/latest/download/StarRailWarpExport.zip) / [蓝奏云](https://wwvt.lanzoum.com/b022mikwh) 密码:f1iy
|
1. 下载工具后解压 - 下载地址: [Github](https://github.com/biuuu/star-rail-warp-export/releases/latest/download/StarRailWarpExport.zip) / [蓝奏云](https://wwvt.lanzoum.com/b022mikwh) 密码:f1iy
|
||||||
2. 打开游戏的跃迁历史记录
|
2. 打开游戏的跃迁详情页面
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
3. 点击工具的“加载数据”按钮
|
3. 点击工具的“加载数据”按钮
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ If you feel that the existing translation is inappropriate, you can send a pull
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. Unzip after downloading the tool - [Download](https://github.com/biuuu/star-rail-warp-export/releases/latest/download/StarRailWarpExport.zip)
|
1. Unzip after downloading the tool - [Download](https://github.com/biuuu/star-rail-warp-export/releases/latest/download/StarRailWarpExport.zip)
|
||||||
2. Open the warp history of the game
|
2. Open the warp details page of the game
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
3. Click the tool's "Load data" button
|
3. Click the tool's "Load data" button
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 55 KiB |
BIN
docs/preview.png
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 46 KiB |
10
package.json
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "star-rail-warp-export",
|
"name": "star-rail-warp-export",
|
||||||
"version": "0.0.4",
|
"version": "0.1.4",
|
||||||
"main": "./dist/electron/main/main.js",
|
"main": "./dist/electron/main/main.js",
|
||||||
"author": "biuuu <https://github.com/biuuu>",
|
"author": "biuuu <https://github.com/biuuu>",
|
||||||
|
"homepage": "https://github.com/biuuu/star-rail-warp-export",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node .electron-vite/dev-runner.js",
|
"dev": "node .electron-vite/dev-runner.js",
|
||||||
@ -71,7 +72,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@element-plus/icons-vue": "^0.2.6",
|
"@element-plus/icons-vue": "^2.1.0",
|
||||||
"@rollup/plugin-alias": "^3.1.9",
|
"@rollup/plugin-alias": "^3.1.9",
|
||||||
"@rollup/plugin-commonjs": "^21.0.1",
|
"@rollup/plugin-commonjs": "^21.0.1",
|
||||||
"@rollup/plugin-json": "^4.1.0",
|
"@rollup/plugin-json": "^4.1.0",
|
||||||
@ -87,13 +88,14 @@
|
|||||||
"del": "^6.0.0",
|
"del": "^6.0.0",
|
||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"electron": "^16.0.7",
|
"electron": "^16.0.7",
|
||||||
"electron-builder": "^22.14.5",
|
"electron-builder": "^23.0.2",
|
||||||
"electron-fetch": "^1.7.4",
|
"electron-fetch": "^1.7.4",
|
||||||
"electron-unhandled": "^3.0.2",
|
"electron-unhandled": "^3.0.2",
|
||||||
"electron-window-state": "^5.0.3",
|
"electron-window-state": "^5.0.3",
|
||||||
"element-plus": "^1.3.0-beta.7",
|
"element-plus": "^2.3.7",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"get-stream": "^6.0.1",
|
"get-stream": "^6.0.1",
|
||||||
|
"glob": "^10.3.3",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
275
src/gachaType.json
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
[
|
||||||
|
[
|
||||||
|
"de-de",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Figuren-Aktionswarp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Lichtkegel-Aktionswarp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Standardwarp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Einsteigerwarp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ru-ru",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Прыжок события: Персонаж"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Прыжок события: Световой конус"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Стандартный прыжок"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Прыжок новичка"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"th-th",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "กิจกรรมวาร์ปตัวละคร"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "กิจกรรมวาร์ป Light Cone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "วาร์ปถาวร"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "วาร์ปสำหรับมือใหม่"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zh-cn",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "角色活动跃迁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "光锥活动跃迁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "常驻跃迁"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "新手跃迁"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"zh-tw",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "角色活動躍遷"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "光錐活動躍遷"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "常駐躍遷"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "新手躍遷"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"en-us",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Character Event Warp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Light Cone Event Warp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Regular Warp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Starter Warp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"es-es",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Salto de evento de personaje"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Salto de evento de cono de luz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Salto normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Salto de principiante"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"fr-fr",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Saut hyperespace événement de personnage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Saut hyperespace événement de cônes de lumière"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Saut hyperespace classique"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Saut hyperespace de départ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"id-id",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Event Warp Karakter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Event Warp Light Cone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Warp Reguler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Warp Pemula"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ja-jp",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "イベント跳躍・キャラクター"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "イベント跳躍・光円錐"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "恒常跳躍"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "初心者跳躍"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"ko-kr",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "캐릭터 이벤트 워프"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "광추 이벤트 워프"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "상시 워프"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "초보자 워프"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"pt-pt",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Salto Hiperespacial de Evento de Personagem"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Salto Hiperespacial de Evento de Cone de Luz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Salto Hiperespacial Permanente"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Salto Hiperespacial Inicial"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"vi-vn",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "11",
|
||||||
|
"name": "Bước Nhảy Sự Kiện Nhân Vật"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "12",
|
||||||
|
"name": "Bước Nhảy Sự Kiện Nón Ánh Sáng"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "1",
|
||||||
|
"name": "Bước Nhảy Vĩnh Viễn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "2",
|
||||||
|
"name": "Bước Nhảy Tân Thủ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
@ -3,6 +3,7 @@
|
|||||||
"ui.button.load": "Lade Daten",
|
"ui.button.load": "Lade Daten",
|
||||||
"ui.button.update": "Aktualisieren",
|
"ui.button.update": "Aktualisieren",
|
||||||
"ui.button.excel": "In Excel exportieren",
|
"ui.button.excel": "In Excel exportieren",
|
||||||
|
"ui.button.srgf": "In JSON exportieren",
|
||||||
"ui.button.url": "Eingabe URL",
|
"ui.button.url": "Eingabe URL",
|
||||||
"ui.button.setting": "Einstellungen",
|
"ui.button.setting": "Einstellungen",
|
||||||
"ui.button.option": "Optionen",
|
"ui.button.option": "Optionen",
|
||||||
@ -75,5 +76,6 @@
|
|||||||
"excel.wish2": "Wunsch 2",
|
"excel.wish2": "Wunsch 2",
|
||||||
"excel.customFont": "Arial",
|
"excel.customFont": "Arial",
|
||||||
"excel.filePrefix": "",
|
"excel.filePrefix": "",
|
||||||
"excel.fileType": "Excel Datei"
|
"excel.fileType": "Excel Datei",
|
||||||
|
"srgf.fileType": "Star Rail Gacha Log Format Datei"
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,16 @@
|
|||||||
"ui.button.load": "Load data",
|
"ui.button.load": "Load data",
|
||||||
"ui.button.update": "Update",
|
"ui.button.update": "Update",
|
||||||
"ui.button.directUpdate": "Direct update",
|
"ui.button.directUpdate": "Direct update",
|
||||||
|
"ui.button.files": "Export Files",
|
||||||
"ui.button.excel": "Export Excel",
|
"ui.button.excel": "Export Excel",
|
||||||
|
"ui.button.srgf": "Export JSON",
|
||||||
"ui.button.url": "Input URL",
|
"ui.button.url": "Input URL",
|
||||||
"ui.button.setting": "Settings",
|
"ui.button.setting": "Settings",
|
||||||
"ui.button.option": "Option",
|
"ui.button.option": "Option",
|
||||||
"ui.button.startProxy": "Proxy mode",
|
"ui.button.startProxy": "Proxy mode",
|
||||||
"ui.button.solution": "Solution",
|
"ui.button.solution": "Solution",
|
||||||
"ui.button.cacheFolder": "Open cache folder",
|
"ui.button.cacheFolder": "Open cache folder",
|
||||||
|
"ui.button.copyUrl": "Copy URL",
|
||||||
"ui.select.newAccount": "New account",
|
"ui.select.newAccount": "New account",
|
||||||
"ui.hint.newAccount": "Export data from other accounts",
|
"ui.hint.newAccount": "Export data from other accounts",
|
||||||
"ui.hint.init": "Please open your warp history inside the game client before clicking on the 'Load data' button",
|
"ui.hint.init": "Please open your warp history inside the game client before clicking on the 'Load data' button",
|
||||||
@ -30,9 +33,9 @@
|
|||||||
"ui.data.average": "5 star on average",
|
"ui.data.average": "5 star on average",
|
||||||
"ui.data.chara5": "5 star character",
|
"ui.data.chara5": "5 star character",
|
||||||
"ui.data.chara4": "4 star character",
|
"ui.data.chara4": "4 star character",
|
||||||
"ui.data.weapon5": "5 star light cone",
|
"ui.data.weapon5": "5 star Light Cone",
|
||||||
"ui.data.weapon4": "4 star light cone",
|
"ui.data.weapon4": "4 star Light Cone",
|
||||||
"ui.data.weapon3": "3 star light cone",
|
"ui.data.weapon3": "3 star Light Cone",
|
||||||
"ui.setting.title": "Settings",
|
"ui.setting.title": "Settings",
|
||||||
"ui.setting.language": "Language",
|
"ui.setting.language": "Language",
|
||||||
"ui.setting.languageHint": "When the translation is missing, English will be displayed by default.",
|
"ui.setting.languageHint": "When the translation is missing, English will be displayed by default.",
|
||||||
@ -41,8 +44,9 @@
|
|||||||
"ui.setting.cnServer": "CN server",
|
"ui.setting.cnServer": "CN server",
|
||||||
"ui.setting.seaServer": "Global server",
|
"ui.setting.seaServer": "Global server",
|
||||||
"ui.setting.logTypeHint": "Choose which server generated logs to be used first when acquiring URL from game logs",
|
"ui.setting.logTypeHint": "Choose which server generated logs to be used first when acquiring URL from game logs",
|
||||||
|
"ui.setting.dataManagerHint": "Unnecessary data can be deleted",
|
||||||
"ui.setting.autoUpdate": "Auto update",
|
"ui.setting.autoUpdate": "Auto update",
|
||||||
"ui.setting.hideNovice": "Hide Departure Warp",
|
"ui.setting.hideNovice": "Hide Starter Warp",
|
||||||
"ui.setting.proxyMode": "Proxy mode",
|
"ui.setting.proxyMode": "Proxy mode",
|
||||||
"ui.setting.proxyModeHint": "When we fail to get the URL from system logs, use the system proxy",
|
"ui.setting.proxyModeHint": "When we fail to get the URL from system logs, use the system proxy",
|
||||||
"ui.setting.fetchFullHistory": "Get complete data",
|
"ui.setting.fetchFullHistory": "Get complete data",
|
||||||
@ -56,6 +60,15 @@
|
|||||||
"ui.urlDialog.placeholder": "Please enter the URL with authentication information",
|
"ui.urlDialog.placeholder": "Please enter the URL with authentication information",
|
||||||
"ui.common.cancel": "Cancel",
|
"ui.common.cancel": "Cancel",
|
||||||
"ui.common.ok": "OK",
|
"ui.common.ok": "OK",
|
||||||
|
"ui.common.data": "Data",
|
||||||
|
"ui.common.dataManage": "Data Management",
|
||||||
|
"ui.common.updateTime": "Update Date",
|
||||||
|
"ui.common.status": "Status",
|
||||||
|
"ui.common.action": "Operation",
|
||||||
|
"ui.common.deleted": "Deleted",
|
||||||
|
"ui.common.normal": "Normal",
|
||||||
|
"ui.common.delete": "Delete",
|
||||||
|
"ui.common.restore": "Restore",
|
||||||
"log.save.failed": "Failed to save local data",
|
"log.save.failed": "Failed to save local data",
|
||||||
"log.file.notFound": "Unable to find game logs, please make sure you already opened warp history inside the game client",
|
"log.file.notFound": "Unable to find game logs, please make sure you already opened warp history inside the game client",
|
||||||
"log.url.notFound": "Unable to find URL",
|
"log.url.notFound": "Unable to find URL",
|
||||||
@ -83,6 +96,8 @@
|
|||||||
"excel.customFont": "Arial",
|
"excel.customFont": "Arial",
|
||||||
"excel.filePrefix": "Star Rail Warp logger",
|
"excel.filePrefix": "Star Rail Warp logger",
|
||||||
"excel.fileType": "Excel file",
|
"excel.fileType": "Excel file",
|
||||||
|
"srgf.fileType": "Star Rail Gacha Log Format file",
|
||||||
"ui.extra.cacheClean": "1. Confirm whether the warp history in the game has been opened, and if the error \"User authentication expired\" still appears, try the following steps \n2. Close the game window of Star Rail \n3. Click the \"Open Web Cache Folder\" button above to open the \"Cache\" folder \n4. Delete the \"Cache_ Data\" folder \n5. Start the Star Rail game and open the warp history page in the game \n6. Close this dialog and click the \"Update Data\" button",
|
"ui.extra.cacheClean": "1. Confirm whether the warp history in the game has been opened, and if the error \"User authentication expired\" still appears, try the following steps \n2. Close the game window of Star Rail \n3. Click the \"Open Web Cache Folder\" button above to open the \"Cache\" folder \n4. Delete the \"Cache_ Data\" folder \n5. Start the Star Rail game and open the warp history page in the game \n6. Close this dialog and click the \"Update Data\" button",
|
||||||
"ui.extra.findCacheFolder": "If the \"Open cache folder\" button does not respond, you can manually find the game's web cache folder. The directory is \"Your game installation path/Star Rail/Game/StarRail_Data/webCaches/Cache/\""
|
"ui.extra.findCacheFolder": "If the \"Open cache folder\" button does not respond, you can manually find the game's web cache folder. The directory is \"Your game installation path/Star Rail/Games/StarRail_Data/webCaches/Cache/\"",
|
||||||
|
"ui.extra.urlCopied": "URL Copied"
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"ui.button.update": "Mettre à jour",
|
"ui.button.update": "Mettre à jour",
|
||||||
"ui.button.directUpdate": "Mise à jour directe",
|
"ui.button.directUpdate": "Mise à jour directe",
|
||||||
"ui.button.excel": "Exporter vers Excel",
|
"ui.button.excel": "Exporter vers Excel",
|
||||||
|
"ui.button.srgf": "Exporter vers JSON",
|
||||||
"ui.button.url": "URL d'import",
|
"ui.button.url": "URL d'import",
|
||||||
"ui.button.setting": "Paramètres",
|
"ui.button.setting": "Paramètres",
|
||||||
"ui.button.option": "Options",
|
"ui.button.option": "Options",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"ui.button.load": "データの読み込み",
|
"ui.button.load": "データの読み込み",
|
||||||
"ui.button.update": "更新データ",
|
"ui.button.update": "更新データ",
|
||||||
"ui.button.excel": "Excelにエクスポート",
|
"ui.button.excel": "Excelにエクスポート",
|
||||||
|
"ui.button.srgf": "JSONにエクスポート",
|
||||||
"ui.button.url": "URL入力",
|
"ui.button.url": "URL入力",
|
||||||
"ui.button.setting": "設定",
|
"ui.button.setting": "設定",
|
||||||
"ui.button.option": "オプション",
|
"ui.button.option": "オプション",
|
||||||
@ -18,7 +19,7 @@
|
|||||||
"ui.data.sum": "合計",
|
"ui.data.sum": "合計",
|
||||||
"ui.data.no5star": "連星5取得しません",
|
"ui.data.no5star": "連星5取得しません",
|
||||||
"ui.data.character": "キャラ",
|
"ui.data.character": "キャラ",
|
||||||
"ui.data.weapon": "武器",
|
"ui.data.weapon": "光円錐",
|
||||||
"ui.data.star5": "星5",
|
"ui.data.star5": "星5",
|
||||||
"ui.data.star4": "星4",
|
"ui.data.star4": "星4",
|
||||||
"ui.data.star3": "星3",
|
"ui.data.star3": "星3",
|
||||||
@ -26,9 +27,9 @@
|
|||||||
"ui.data.average": "星5取得平均回数",
|
"ui.data.average": "星5取得平均回数",
|
||||||
"ui.data.chara5": "星5キャラ",
|
"ui.data.chara5": "星5キャラ",
|
||||||
"ui.data.chara4": "星4キャラ",
|
"ui.data.chara4": "星4キャラ",
|
||||||
"ui.data.weapon5": "星5武器",
|
"ui.data.weapon5": "星5光円錐",
|
||||||
"ui.data.weapon4": "星4武器",
|
"ui.data.weapon4": "星4光円錐",
|
||||||
"ui.data.weapon3": "星3武器",
|
"ui.data.weapon3": "星3光円錐",
|
||||||
"ui.setting.title": "設定",
|
"ui.setting.title": "設定",
|
||||||
"ui.setting.language": "言語",
|
"ui.setting.language": "言語",
|
||||||
"ui.setting.languageHint": "翻訳されていない場合は、デフォルトで英語が表示されます。",
|
"ui.setting.languageHint": "翻訳されていない場合は、デフォルトで英語が表示されます。",
|
||||||
|
@ -3,13 +3,16 @@
|
|||||||
"ui.button.load": "加载数据",
|
"ui.button.load": "加载数据",
|
||||||
"ui.button.update": "更新数据",
|
"ui.button.update": "更新数据",
|
||||||
"ui.button.directUpdate": "直接更新",
|
"ui.button.directUpdate": "直接更新",
|
||||||
|
"ui.button.files": "导出文件",
|
||||||
"ui.button.excel": "导出Excel",
|
"ui.button.excel": "导出Excel",
|
||||||
|
"ui.button.srgf":"导出JSON",
|
||||||
"ui.button.url": "输入URL",
|
"ui.button.url": "输入URL",
|
||||||
"ui.button.setting": "设置",
|
"ui.button.setting": "设置",
|
||||||
"ui.button.option": "选项",
|
"ui.button.option": "选项",
|
||||||
"ui.button.startProxy": "代理模式",
|
"ui.button.startProxy": "代理模式",
|
||||||
"ui.button.solution": "解决办法",
|
"ui.button.solution": "解决办法",
|
||||||
"ui.button.cacheFolder": "打开网页缓存文件夹",
|
"ui.button.cacheFolder": "打开网页缓存文件夹",
|
||||||
|
"ui.button.copyUrl": "复制URL",
|
||||||
"ui.select.newAccount": "新账号",
|
"ui.select.newAccount": "新账号",
|
||||||
"ui.hint.newAccount": "从其它账号导出数据",
|
"ui.hint.newAccount": "从其它账号导出数据",
|
||||||
"ui.hint.init": "请先在游戏里打开任意一个抽卡记录后再点击“加载数据”按钮",
|
"ui.hint.init": "请先在游戏里打开任意一个抽卡记录后再点击“加载数据”按钮",
|
||||||
@ -22,7 +25,7 @@
|
|||||||
"ui.data.sum": "已累计",
|
"ui.data.sum": "已累计",
|
||||||
"ui.data.no5star": "抽未出5星",
|
"ui.data.no5star": "抽未出5星",
|
||||||
"ui.data.character": "角色",
|
"ui.data.character": "角色",
|
||||||
"ui.data.weapon": "武器",
|
"ui.data.weapon": "光锥",
|
||||||
"ui.data.star5": "5星",
|
"ui.data.star5": "5星",
|
||||||
"ui.data.star4": "4星",
|
"ui.data.star4": "4星",
|
||||||
"ui.data.star3": "3星",
|
"ui.data.star3": "3星",
|
||||||
@ -30,9 +33,9 @@
|
|||||||
"ui.data.average": "5星平均出货次数为",
|
"ui.data.average": "5星平均出货次数为",
|
||||||
"ui.data.chara5": "5星角色",
|
"ui.data.chara5": "5星角色",
|
||||||
"ui.data.chara4": "4星角色",
|
"ui.data.chara4": "4星角色",
|
||||||
"ui.data.weapon5": "5星武器",
|
"ui.data.weapon5": "5星光锥",
|
||||||
"ui.data.weapon4": "4星武器",
|
"ui.data.weapon4": "4星光锥",
|
||||||
"ui.data.weapon3": "3星武器",
|
"ui.data.weapon3": "3星光锥",
|
||||||
"ui.setting.title": "设置",
|
"ui.setting.title": "设置",
|
||||||
"ui.setting.language": "语言",
|
"ui.setting.language": "语言",
|
||||||
"ui.setting.languageHint": "缺少翻译时,会默认显示简体中文",
|
"ui.setting.languageHint": "缺少翻译时,会默认显示简体中文",
|
||||||
@ -41,8 +44,9 @@
|
|||||||
"ui.setting.cnServer": "国服",
|
"ui.setting.cnServer": "国服",
|
||||||
"ui.setting.seaServer": "外服",
|
"ui.setting.seaServer": "外服",
|
||||||
"ui.setting.logTypeHint": "使用游戏日志获取URL时,优先选择哪种服务器生成的日志文件。",
|
"ui.setting.logTypeHint": "使用游戏日志获取URL时,优先选择哪种服务器生成的日志文件。",
|
||||||
|
"ui.setting.dataManagerHint": "可以删除不需要的数据。",
|
||||||
"ui.setting.autoUpdate": "自动更新",
|
"ui.setting.autoUpdate": "自动更新",
|
||||||
"ui.setting.hideNovice": "隐藏始发跃迁",
|
"ui.setting.hideNovice": "隐藏新手跃迁",
|
||||||
"ui.setting.proxyMode": "代理模式",
|
"ui.setting.proxyMode": "代理模式",
|
||||||
"ui.setting.proxyModeHint": "通过设置系统代理来获取URL,无法从日志中获取到有效的URL时才会启动代理服务器。",
|
"ui.setting.proxyModeHint": "通过设置系统代理来获取URL,无法从日志中获取到有效的URL时才会启动代理服务器。",
|
||||||
"ui.setting.fetchFullHistory": "获取完整数据",
|
"ui.setting.fetchFullHistory": "获取完整数据",
|
||||||
@ -56,6 +60,15 @@
|
|||||||
"ui.urlDialog.placeholder": "请输入带有身份认证信息的URL",
|
"ui.urlDialog.placeholder": "请输入带有身份认证信息的URL",
|
||||||
"ui.common.cancel": "取消",
|
"ui.common.cancel": "取消",
|
||||||
"ui.common.ok": "确定",
|
"ui.common.ok": "确定",
|
||||||
|
"ui.common.data": "数据",
|
||||||
|
"ui.common.dataManage": "数据管理",
|
||||||
|
"ui.common.updateTime": "更新日期",
|
||||||
|
"ui.common.status": "状态",
|
||||||
|
"ui.common.action": "操作",
|
||||||
|
"ui.common.deleted": "已删除",
|
||||||
|
"ui.common.normal": "正常",
|
||||||
|
"ui.common.delete": "删除",
|
||||||
|
"ui.common.restore": "恢复",
|
||||||
"log.save.failed": "保存本地数据失败",
|
"log.save.failed": "保存本地数据失败",
|
||||||
"log.file.notFound": "未找到游戏日志,确认是否已打开游戏抽卡记录",
|
"log.file.notFound": "未找到游戏日志,确认是否已打开游戏抽卡记录",
|
||||||
"log.url.notFound": "未找到URL",
|
"log.url.notFound": "未找到URL",
|
||||||
@ -83,6 +96,8 @@
|
|||||||
"excel.customFont": "微软雅黑",
|
"excel.customFont": "微软雅黑",
|
||||||
"excel.filePrefix": "星穹铁道跃迁记录",
|
"excel.filePrefix": "星穹铁道跃迁记录",
|
||||||
"excel.fileType": "Excel文件",
|
"excel.fileType": "Excel文件",
|
||||||
|
"srgf.fileType":"星穹铁道跃迁记录格式文件",
|
||||||
"ui.extra.cacheClean": "1. 确认是否已经打开游戏内的抽卡历史记录,如果仍然出现“身份认证已过期”的错误,再尝试下面的步骤\n2. 关闭星穹铁道的游戏窗口\n3. 点击上方的“打开缓存文件夹”按钮,打开Cache文件夹\n4. 删除Cache_Data文件夹\n5. 启动星穹铁道游戏,打开游戏内抽卡历史记录页面\n6. 关闭这个对话框,再点击“更新数据”按钮",
|
"ui.extra.cacheClean": "1. 确认是否已经打开游戏内的抽卡历史记录,如果仍然出现“身份认证已过期”的错误,再尝试下面的步骤\n2. 关闭星穹铁道的游戏窗口\n3. 点击上方的“打开缓存文件夹”按钮,打开Cache文件夹\n4. 删除Cache_Data文件夹\n5. 启动星穹铁道游戏,打开游戏内抽卡历史记录页面\n6. 关闭这个对话框,再点击“更新数据”按钮",
|
||||||
"ui.extra.findCacheFolder": "如果点“打开缓存文件夹”按钮没有反应,可以手动找到游戏的网页缓存文件夹,目录为“你的游戏安装路径/Star Rail/Game/StarRail_Data/webCaches/Cache/”"
|
"ui.extra.findCacheFolder": "如果点“打开缓存文件夹”按钮没有反应,可以手动找到游戏的网页缓存文件夹,目录为“你的游戏安装路径/Star Rail/Game/StarRail_Data/webCaches/Cache/”",
|
||||||
|
"ui.extra.urlCopied": "URL已复制"
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
"ui.button.load": "載入資料",
|
"ui.button.load": "載入資料",
|
||||||
"ui.button.update": "更新資料",
|
"ui.button.update": "更新資料",
|
||||||
"ui.button.directUpdate": "直接更新",
|
"ui.button.directUpdate": "直接更新",
|
||||||
|
"ui.button.files": "匯出檔案",
|
||||||
"ui.button.excel": "匯出 Excel",
|
"ui.button.excel": "匯出 Excel",
|
||||||
|
"ui.button.srgf": "匯出 JSON",
|
||||||
"ui.button.url": "輸入 URL",
|
"ui.button.url": "輸入 URL",
|
||||||
"ui.button.setting": "設定",
|
"ui.button.setting": "設定",
|
||||||
"ui.button.option": "選項",
|
"ui.button.option": "選項",
|
||||||
"ui.button.startProxy": "Proxy 模式",
|
"ui.button.startProxy": "Proxy 模式",
|
||||||
"ui.button.solution": "解決方案",
|
"ui.button.solution": "解決方法",
|
||||||
"ui.button.cacheFolder": "開啟快取資料夾",
|
"ui.button.cacheFolder": "開啟快取資料夾",
|
||||||
"ui.select.newAccount": "新帳號",
|
"ui.select.newAccount": "新帳號",
|
||||||
"ui.hint.newAccount": "從其他帳號匯出資料",
|
"ui.hint.newAccount": "從其他帳號匯出資料",
|
||||||
@ -16,13 +18,13 @@
|
|||||||
"ui.hint.lastUpdate": "上次資料更新時間為",
|
"ui.hint.lastUpdate": "上次資料更新時間為",
|
||||||
"ui.hint.relaunchHint": "更新已完成,按下按鈕重新啟動工具後生效",
|
"ui.hint.relaunchHint": "更新已完成,按下按鈕重新啟動工具後生效",
|
||||||
"ui.hint.failed": "作業失敗",
|
"ui.hint.failed": "作業失敗",
|
||||||
"ui.win.title": "",
|
"ui.win.title": "崩壞:星穹鐵道 躍遷記錄匯出工具",
|
||||||
"ui.data.total": "總計",
|
"ui.data.total": "總計",
|
||||||
"ui.data.times": "抽",
|
"ui.data.times": "抽",
|
||||||
"ui.data.sum": "已累計",
|
"ui.data.sum": "已累計",
|
||||||
"ui.data.no5star": "抽未出5星",
|
"ui.data.no5star": "抽未出5星",
|
||||||
"ui.data.character": "角色",
|
"ui.data.character": "角色",
|
||||||
"ui.data.weapon": "武器",
|
"ui.data.weapon": "光錐",
|
||||||
"ui.data.star5": "5星",
|
"ui.data.star5": "5星",
|
||||||
"ui.data.star4": "4星",
|
"ui.data.star4": "4星",
|
||||||
"ui.data.star3": "3星",
|
"ui.data.star3": "3星",
|
||||||
@ -30,9 +32,9 @@
|
|||||||
"ui.data.average": "5星平均出貨次數為",
|
"ui.data.average": "5星平均出貨次數為",
|
||||||
"ui.data.chara5": "5星角色",
|
"ui.data.chara5": "5星角色",
|
||||||
"ui.data.chara4": "4星角色",
|
"ui.data.chara4": "4星角色",
|
||||||
"ui.data.weapon5": "5星武器",
|
"ui.data.weapon5": "5星光錐",
|
||||||
"ui.data.weapon4": "4星武器",
|
"ui.data.weapon4": "4星光錐",
|
||||||
"ui.data.weapon3": "3星武器",
|
"ui.data.weapon3": "3星光錐",
|
||||||
"ui.setting.title": "設定",
|
"ui.setting.title": "設定",
|
||||||
"ui.setting.language": "語言",
|
"ui.setting.language": "語言",
|
||||||
"ui.setting.languageHint": "缺少翻譯時,預設會顯示簡體中文。",
|
"ui.setting.languageHint": "缺少翻譯時,預設會顯示簡體中文。",
|
||||||
@ -42,7 +44,7 @@
|
|||||||
"ui.setting.seaServer": "國際服",
|
"ui.setting.seaServer": "國際服",
|
||||||
"ui.setting.logTypeHint": "使用遊戲記錄取得 URL 時,優先選擇哪種伺服器產生的記錄檔案。",
|
"ui.setting.logTypeHint": "使用遊戲記錄取得 URL 時,優先選擇哪種伺服器產生的記錄檔案。",
|
||||||
"ui.setting.autoUpdate": "自動更新",
|
"ui.setting.autoUpdate": "自動更新",
|
||||||
"ui.setting.hideNovice": "",
|
"ui.setting.hideNovice": "隱藏新手躍遷",
|
||||||
"ui.setting.proxyMode": "Proxy 模式",
|
"ui.setting.proxyMode": "Proxy 模式",
|
||||||
"ui.setting.proxyModeHint": "透過設定系統 Proxy 以取得 URL,將會在從系統記錄中取得 URL 失敗時啟動。",
|
"ui.setting.proxyModeHint": "透過設定系統 Proxy 以取得 URL,將會在從系統記錄中取得 URL 失敗時啟動。",
|
||||||
"ui.setting.fetchFullHistory": "取得完整資料",
|
"ui.setting.fetchFullHistory": "取得完整資料",
|
||||||
@ -81,8 +83,9 @@
|
|||||||
"excel.header.remark": "備註",
|
"excel.header.remark": "備註",
|
||||||
"excel.wish2": "躍遷-2",
|
"excel.wish2": "躍遷-2",
|
||||||
"excel.customFont": "微軟正黑體",
|
"excel.customFont": "微軟正黑體",
|
||||||
"excel.filePrefix": "",
|
"excel.filePrefix": "星穹鐵道躍遷紀錄",
|
||||||
"excel.fileType": "Excel 檔案",
|
"excel.fileType": "Excel 檔案",
|
||||||
"ui.extra.cacheClean": "1. 確認是否已經開啟遊戲內的躍遷歷史紀錄,如果仍然出現「身分驗證已過期」的錯誤,再嘗試下面的步驟\n2. 關閉原神的遊戲視窗\n3. 按一下上方的「開啟快取資料夾」按鈕,開啟「Cache」資料夾\n4. 刪除「Cache_Data」資料夾\n5. 啟動原神遊戲,開啟遊戲內躍遷歷史紀錄頁面\n6. 關閉這個對話方塊,再按下「更新資料」按鈕",
|
"srgf.fileType":"星穹鐵道躍遷紀錄格式檔案",
|
||||||
"ui.extra.findCacheFolder": "如果按下「開啟快取資料夾」按鈕沒有回應,可以手動找到遊戲的網頁快取資料夾,目錄為「您的遊戲安裝路徑/Star Rail/Game/StarRail_Data/webCaches/Cache/」"
|
"ui.extra.cacheClean": "1. 確認是否已經開啟遊戲內的躍遷歷史紀錄,如果仍然出現「身分驗證已過期」的錯誤,再嘗試下面的步驟\n2. 關閉「崩壞:星穹鐵道」的遊戲視窗\n3. 按一下上方的「開啟快取資料夾」按鈕,開啟「Cache」資料夾\n4. 刪除「Cache_Data」資料夾\n5. 啟動「崩壞:星穹鐵道」遊戲,開啟遊戲內躍遷歷史紀錄頁面\n6. 關閉這個對話方塊,再按下「更新資料」按鈕",
|
||||||
|
"ui.extra.findCacheFolder": "如果按下「開啟快取資料夾」按鈕沒有回應,可以手動找到遊戲的網頁快取資料夾,目錄為「您的遊戲安裝路徑/Star Rail/Games/StarRail_Data/webCaches/Cache/」"
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ const fs = require('fs-extra')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const getData = require('./getData').getData
|
const getData = require('./getData').getData
|
||||||
const { version } = require('../../package.json')
|
const { version } = require('../../package.json')
|
||||||
|
const i18n = require('./i18n')
|
||||||
|
|
||||||
const getTimeString = () => {
|
const getTimeString = () => {
|
||||||
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
|
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
|
||||||
@ -15,67 +16,51 @@ const formatDate = (date) => {
|
|||||||
return `${y}-${m}-${d} ${date.toLocaleString('zh-cn', { hour12: false }).slice(-8)}`
|
return `${y}-${m}-${d} ${date.toLocaleString('zh-cn', { hour12: false }).slice(-8)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const fakeIdFn = () => {
|
|
||||||
let id = 1000000000000000000n
|
|
||||||
return () => {
|
|
||||||
id = id + 1n
|
|
||||||
return id.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const shouldBeString = (value) => {
|
|
||||||
if (typeof value !== 'string') {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
const { dataMap, current } = await getData()
|
const { dataMap, current } = await getData()
|
||||||
const data = dataMap.get(current)
|
const data = dataMap.get(current)
|
||||||
if (!data.result.size) {
|
if (!data.result.size) {
|
||||||
throw new Error('数据为空')
|
throw new Error('数据为空')
|
||||||
}
|
}
|
||||||
const fakeId = fakeIdFn()
|
|
||||||
const result = {
|
const result = {
|
||||||
info: {
|
info: {
|
||||||
uid: data.uid,
|
uid: data.uid,
|
||||||
lang: data.lang,
|
lang: data.lang,
|
||||||
export_time: formatDate(new Date()),
|
export_time: formatDate(new Date()),
|
||||||
export_timestamp: Date.now(),
|
export_timestamp: Math.ceil(Date.now() / 1000),
|
||||||
export_app: 'genshin-wish-export',
|
export_app: 'star-rail-warp-export',
|
||||||
export_app_version: `v${version}`,
|
export_app_version: `v${version}`,
|
||||||
uigf_version: 'v2.2'
|
region_time_zone: data.region_time_zone,
|
||||||
|
srgf_version: 'v1.0'
|
||||||
},
|
},
|
||||||
list: []
|
list: []
|
||||||
}
|
}
|
||||||
const listTemp = []
|
const listTemp = []
|
||||||
for (let [type, arr] of data.result) {
|
for (let [type, arr] of data.result) {
|
||||||
arr.forEach(item => {
|
arr.forEach(log => {
|
||||||
listTemp.push({
|
listTemp.push({
|
||||||
gacha_type: shouldBeString(item[4]) || type,
|
gacha_id: log.gacha_id,
|
||||||
time: item[0],
|
gacha_type: log.gacha_type,
|
||||||
timestamp: new Date(item[0]).getTime(),
|
item_id: log.item_id,
|
||||||
name: item[1],
|
count: '1',
|
||||||
item_type: item[2],
|
time: log.time,
|
||||||
rank_type: `${item[3]}`,
|
name: log.name,
|
||||||
id: shouldBeString(item[5]) || '',
|
item_type: log.item_type,
|
||||||
uigf_gacha_type: type
|
rank_type: log.rank_type,
|
||||||
|
id: log.id
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
listTemp.sort((a, b) => a.timestamp - b.timestamp)
|
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
|
||||||
listTemp.forEach(item => {
|
listTemp.forEach(item => {
|
||||||
delete item.timestamp
|
|
||||||
result.list.push({
|
result.list.push({
|
||||||
...item,
|
...item
|
||||||
id: item.id || fakeId()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const filePath = dialog.showSaveDialogSync({
|
const filePath = dialog.showSaveDialogSync({
|
||||||
defaultPath: path.join(app.getPath('downloads'), `UIGF_${data.uid}_${getTimeString()}`),
|
defaultPath: path.join(app.getPath('downloads'), `SRGF_${data.uid}_${getTimeString()}`),
|
||||||
filters: [
|
filters: [
|
||||||
{ name: 'JSON文件', extensions: ['json'] }
|
{ name: i18n.srgf.fileType, extensions: ['json'] }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
if (filePath) {
|
if (filePath) {
|
||||||
@ -84,6 +69,6 @@ const start = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.handle('EXPORT_UIGF_JSON', async () => {
|
ipcMain.handle('EXPORT_SRGF_JSON', async () => {
|
||||||
await start()
|
await start()
|
||||||
})
|
})
|
15
src/main/bridge.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const { clipboard, ipcMain } = require('electron')
|
||||||
|
const { getUrl, deleteData } = require('./getData')
|
||||||
|
|
||||||
|
ipcMain.handle('COPY_URL', async () => {
|
||||||
|
const url = await getUrl()
|
||||||
|
if (url) {
|
||||||
|
clipboard.writeText(url)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('DELETE_DATA', async (event, uid, action) => {
|
||||||
|
await deleteData(uid, action)
|
||||||
|
})
|
@ -1,4 +1,4 @@
|
|||||||
const { readJSON, saveJSON, decipherAes, cipherAes, detectLocale } = require('./utils')
|
const { readJSON, saveJSON, decipherAes, cipherAes, detectLocale, userDataPath, globalUserDataPath } = require('./utils')
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
urls: [],
|
urls: [],
|
||||||
@ -13,7 +13,10 @@ const config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getLocalConfig = async () => {
|
const getLocalConfig = async () => {
|
||||||
const localConfig = await readJSON('config.json')
|
let localConfig = await readJSON(userDataPath, 'config.json')
|
||||||
|
if (!localConfig) {
|
||||||
|
localConfig = await readJSON(globalUserDataPath, 'config.json')
|
||||||
|
}
|
||||||
if (!localConfig) return
|
if (!localConfig) return
|
||||||
const configTemp = {}
|
const configTemp = {}
|
||||||
for (let key in localConfig) {
|
for (let key in localConfig) {
|
||||||
|
@ -4,7 +4,6 @@ const { app, ipcMain, dialog } = require('electron')
|
|||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const i18n = require('./i18n')
|
const i18n = require('./i18n')
|
||||||
const cloneDeep = require('lodash-es/cloneDeep').default
|
|
||||||
|
|
||||||
function pad(num) {
|
function pad(num) {
|
||||||
return `${num}`.padStart(2, "0");
|
return `${num}`.padStart(2, "0");
|
||||||
@ -58,7 +57,7 @@ const start = async () => {
|
|||||||
const workbook = new ExcelJS.Workbook()
|
const workbook = new ExcelJS.Workbook()
|
||||||
for (let [key, value] of data.result) {
|
for (let [key, value] of data.result) {
|
||||||
const name = data.typeMap.get(key)
|
const name = data.typeMap.get(key)
|
||||||
const sheet = workbook.addWorksheet(name, {views: [{state: 'frozen', ySplit: 1}]})
|
const sheet = workbook.addWorksheet(name.replace(/[*?:\/\\]/g, ' '), {views: [{state: 'frozen', ySplit: 1}]})
|
||||||
let width = [24, 14, 8, 8, 8, 8, 8]
|
let width = [24, 14, 8, 8, 8, 8, 8]
|
||||||
if (!data.lang.includes('zh-')) {
|
if (!data.lang.includes('zh-')) {
|
||||||
width = [24, 32, 16, 12, 12, 12, 8]
|
width = [24, 32, 16, 12, 12, 12, 8]
|
||||||
@ -87,7 +86,7 @@ const start = async () => {
|
|||||||
arr.push(total)
|
arr.push(total)
|
||||||
arr.push(pity)
|
arr.push(pity)
|
||||||
temp.push(arr)
|
temp.push(arr)
|
||||||
if (log.rank_type === 5) {
|
if (log.rank_type === '5') {
|
||||||
pity = 0
|
pity = 0
|
||||||
}
|
}
|
||||||
// if (key === '301') {
|
// if (key === '301') {
|
||||||
|
@ -3,12 +3,13 @@ const util = require('util')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { URL } = require('url')
|
const { URL } = require('url')
|
||||||
const { app, ipcMain, shell } = require('electron')
|
const { app, ipcMain, shell } = require('electron')
|
||||||
const { sleep, request, sendMsg, readJSON, saveJSON, detectLocale, userDataPath, userPath, localIp, langMap } = require('./utils')
|
const { sleep, request, sendMsg, readJSON, saveJSON, detectLocale, getCacheText, userDataPath, userPath, localIp, langMap, globalUserDataPath } = require('./utils')
|
||||||
const config = require('./config')
|
const config = require('./config')
|
||||||
const i18n = require('./i18n')
|
const i18n = require('./i18n')
|
||||||
const { enableProxy, disableProxy } = require('./module/system-proxy')
|
const { enableProxy, disableProxy } = require('./module/system-proxy')
|
||||||
const mitmproxy = require('./module/node-mitmproxy')
|
const mitmproxy = require('./module/node-mitmproxy')
|
||||||
const { mergeData } = require('./utils/mergeData')
|
const { mergeData } = require('./utils/mergeData')
|
||||||
|
const gachaTypeRaw = require('../gachaType.json')
|
||||||
|
|
||||||
const dataMap = new Map()
|
const dataMap = new Map()
|
||||||
const order = ['11', '12', '1', '2']
|
const order = ['11', '12', '1', '2']
|
||||||
@ -17,7 +18,6 @@ let apiDomain = 'https://api-takumi.mihoyo.com'
|
|||||||
const saveData = async (data, url) => {
|
const saveData = async (data, url) => {
|
||||||
const obj = Object.assign({}, data)
|
const obj = Object.assign({}, data)
|
||||||
obj.result = [...obj.result]
|
obj.result = [...obj.result]
|
||||||
obj.typeMap = [...obj.typeMap]
|
|
||||||
await config.save()
|
await config.save()
|
||||||
await saveJSON(`gacha-list-${data.uid}.json`, obj)
|
await saveJSON(`gacha-list-${data.uid}.json`, obj)
|
||||||
}
|
}
|
||||||
@ -25,29 +25,46 @@ const saveData = async (data, url) => {
|
|||||||
const defaultTypeMap = new Map([
|
const defaultTypeMap = new Map([
|
||||||
['11', '角色活动跃迁'],
|
['11', '角色活动跃迁'],
|
||||||
['12', '光锥活动跃迁'],
|
['12', '光锥活动跃迁'],
|
||||||
['1', '群星跃迁'],
|
['1', '常驻跃迁'],
|
||||||
['2', '始发跃迁']
|
['2', '新手跃迁']
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const findDataFiles = async (dataPath, fileMap) => {
|
||||||
|
const files = await readdir(dataPath)
|
||||||
|
if (files?.length) {
|
||||||
|
for (let name of files) {
|
||||||
|
if (/^gacha-list-\d+\.json$/.test(name) && !fileMap.has(name)) {
|
||||||
|
fileMap.set(name, dataPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectDataFiles = async () => {
|
||||||
|
await fs.ensureDir(userDataPath)
|
||||||
|
await fs.ensureDir(globalUserDataPath)
|
||||||
|
const fileMap = new Map()
|
||||||
|
await findDataFiles(userDataPath, fileMap)
|
||||||
|
await findDataFiles(globalUserDataPath, fileMap)
|
||||||
|
return fileMap
|
||||||
|
}
|
||||||
|
|
||||||
let localDataReaded = false
|
let localDataReaded = false
|
||||||
const readdir = util.promisify(fs.readdir)
|
const readdir = util.promisify(fs.readdir)
|
||||||
const readData = async () => {
|
const readData = async () => {
|
||||||
if (localDataReaded) return
|
if (localDataReaded) return
|
||||||
localDataReaded = true
|
localDataReaded = true
|
||||||
await fs.ensureDir(userDataPath)
|
const fileMap = await collectDataFiles()
|
||||||
const files = await readdir(userDataPath)
|
for (let [name, dataPath] of fileMap) {
|
||||||
for (let name of files) {
|
try {
|
||||||
if (/^gacha-list-\d+\.json$/.test(name)) {
|
const data = await readJSON(dataPath, name)
|
||||||
try {
|
data.typeMap = new Map(data.typeMap) || defaultTypeMap
|
||||||
const data = await readJSON(name)
|
data.result = new Map(data.result)
|
||||||
data.typeMap = new Map(data.typeMap) || defaultTypeMap
|
if (data.uid) {
|
||||||
data.result = new Map(data.result)
|
dataMap.set(data.uid, data)
|
||||||
if (data.uid) {
|
|
||||||
dataMap.set(data.uid, data)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
sendMsg(e, 'ERROR')
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
sendMsg(e, 'ERROR')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((!config.current && dataMap.size) || (config.current && dataMap.size && !dataMap.has(config.current))) {
|
if ((!config.current && dataMap.size) || (config.current && dataMap.size && !dataMap.has(config.current))) {
|
||||||
@ -55,6 +72,14 @@ const readData = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteData = async (uid, action) => {
|
||||||
|
const data = dataMap.get(uid)
|
||||||
|
if (data) {
|
||||||
|
data.deleted = action
|
||||||
|
await saveData(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const changeCurrent = async (uid) => {
|
const changeCurrent = async (uid) => {
|
||||||
config.current = uid
|
config.current = uid
|
||||||
await config.save()
|
await config.save()
|
||||||
@ -66,7 +91,7 @@ const detectGameLocale = async (userPath) => {
|
|||||||
const arr = ['/miHoYo/崩坏:星穹铁道/', '/Cognosphere/Star Rail/']
|
const arr = ['/miHoYo/崩坏:星穹铁道/', '/Cognosphere/Star Rail/']
|
||||||
arr.forEach(str => {
|
arr.forEach(str => {
|
||||||
try {
|
try {
|
||||||
const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player-prev.log')
|
const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player.log')
|
||||||
fs.accessSync(pathname, fs.constants.F_OK)
|
fs.accessSync(pathname, fs.constants.F_OK)
|
||||||
list.push(pathname)
|
list.push(pathname)
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
@ -115,12 +140,12 @@ const readLog = async () => {
|
|||||||
}
|
}
|
||||||
const promises = logPaths.map(async logpath => {
|
const promises = logPaths.map(async logpath => {
|
||||||
const logText = await fs.readFile(logpath, 'utf8')
|
const logText = await fs.readFile(logpath, 'utf8')
|
||||||
const gamePathMch = logText.match(/\w:\/.*?(Star\sRail\/Game\/StarRail_Data)/)
|
const gamePathMch = logText.match(/\w:\/.*?\/StarRail_Data\//i)
|
||||||
if (gamePathMch) {
|
if (gamePathMch) {
|
||||||
const cacheText = await fs.readFile(path.join(gamePathMch[0], '/webCaches/Cache/Cache_Data/data_2'), 'utf8')
|
const [cacheText, cacheFile] = await getCacheText(gamePathMch[0])
|
||||||
const urlMch = cacheText.match(/https.+?&auth_appid=webview_gacha&.+?authkey=.+?&game_biz=hkrpg_.+?&plat_type=pc/g)
|
const urlMch = cacheText.match(/https.+?&auth_appid=webview_gacha&.+?authkey=.+?&game_biz=hkrpg_.+?&plat_type=pc/g)
|
||||||
if (urlMch) {
|
if (urlMch) {
|
||||||
cacheFolder = path.join(gamePathMch[0], '/webCaches/Cache/')
|
cacheFolder = cacheFile.replace(/Cache_Data[/\\]data_2$/, '')
|
||||||
return getLatestUrl(urlMch)
|
return getLatestUrl(urlMch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,7 +168,10 @@ const getGachaLog = async ({ key, page, name, retryCount, url, endId }) => {
|
|||||||
const text = i18n.log
|
const text = i18n.log
|
||||||
try {
|
try {
|
||||||
const res = await request(`${url}&gacha_type=${key}&page=${page}&size=${20}${endId ? '&end_id=' + endId : ''}`)
|
const res = await request(`${url}&gacha_type=${key}&page=${page}&size=${20}${endId ? '&end_id=' + endId : ''}`)
|
||||||
return res.data.list
|
if (res?.data?.list) {
|
||||||
|
return res?.data
|
||||||
|
}
|
||||||
|
throw new Error(res?.message || res)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (retryCount) {
|
if (retryCount) {
|
||||||
sendMsg(i18n.parse(text.fetch.retry, { name, page, count: 6 - retryCount }))
|
sendMsg(i18n.parse(text.fetch.retry, { name, page, count: 6 - retryCount }))
|
||||||
@ -161,7 +189,8 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
const text = i18n.log
|
const text = i18n.log
|
||||||
let page = 1
|
let page = 1
|
||||||
let list = []
|
let list = []
|
||||||
let res = []
|
let res = null
|
||||||
|
let logs = []
|
||||||
let uid = ''
|
let uid = ''
|
||||||
let region = ''
|
let region = ''
|
||||||
let region_time_zone = ''
|
let region_time_zone = ''
|
||||||
@ -175,8 +204,9 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
sendMsg(i18n.parse(text.fetch.current, { name, page }))
|
sendMsg(i18n.parse(text.fetch.current, { name, page }))
|
||||||
res = await getGachaLog({ key, page, name, url, endId, retryCount: 5 })
|
res = await getGachaLog({ key, page, name, url, endId, retryCount: 5 })
|
||||||
await sleep(0.3)
|
await sleep(0.3)
|
||||||
if (!uid && res.length) {
|
logs = res?.list || []
|
||||||
uid = res[0].uid
|
if (!uid && logs.length) {
|
||||||
|
uid = logs[0].uid
|
||||||
}
|
}
|
||||||
if (!region) {
|
if (!region) {
|
||||||
region = res.region
|
region = res.region
|
||||||
@ -184,14 +214,14 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
if (!region_time_zone) {
|
if (!region_time_zone) {
|
||||||
region_time_zone = res.region_time_zone
|
region_time_zone = res.region_time_zone
|
||||||
}
|
}
|
||||||
list.push(...res)
|
list.push(...logs)
|
||||||
page += 1
|
page += 1
|
||||||
|
|
||||||
if (res.length) {
|
if (logs.length) {
|
||||||
endId = res[res.length - 1].id
|
endId = logs[logs.length - 1].id
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.fetchFullHistory && res.length && uid && dataMap.has(uid)) {
|
if (!config.fetchFullHistory && logs.length && uid && dataMap.has(uid)) {
|
||||||
const result = dataMap.get(uid).result
|
const result = dataMap.get(uid).result
|
||||||
if (result.has(key)) {
|
if (result.has(key)) {
|
||||||
const arr = result.get(key)
|
const arr = result.get(key)
|
||||||
@ -199,7 +229,7 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
const localLatestId = arr[arr.length - 1].id
|
const localLatestId = arr[arr.length - 1].id
|
||||||
if (localLatestId) {
|
if (localLatestId) {
|
||||||
let shouldBreak = false
|
let shouldBreak = false
|
||||||
res.forEach(item => {
|
logs.forEach(item => {
|
||||||
if (item.id === localLatestId) {
|
if (item.id === localLatestId) {
|
||||||
shouldBreak = true
|
shouldBreak = true
|
||||||
}
|
}
|
||||||
@ -211,7 +241,7 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (res.length > 0)
|
} while (logs.length > 0)
|
||||||
return { list, uid, region, region_time_zone }
|
return { list, uid, region, region_time_zone }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +265,6 @@ const tryGetUid = async (queryString) => {
|
|||||||
try {
|
try {
|
||||||
for (let [key] of defaultTypeMap) {
|
for (let [key] of defaultTypeMap) {
|
||||||
const res = await request(`${url}&gacha_type=${key}&page=1&size=6`)
|
const res = await request(`${url}&gacha_type=${key}&page=1&size=6`)
|
||||||
checkResStatus(res)
|
|
||||||
if (res.data.list && res.data.list.length) {
|
if (res.data.list && res.data.list.length) {
|
||||||
return res.data.list[0].uid
|
return res.data.list[0].uid
|
||||||
}
|
}
|
||||||
@ -244,7 +273,7 @@ const tryGetUid = async (queryString) => {
|
|||||||
return config.current
|
return config.current
|
||||||
}
|
}
|
||||||
|
|
||||||
const gachaTypeMap = new Map(JSON.parse('[["de-de",[{"key":"11","name":"Figuren-Aktionswarp"},{"key":"12","name":"Lichtkegel-Aktionswarp"},{"key":"1","name":"Stellarwarp"},{"key":"2","name":"Startwarp"}]],["ru-ru",[{"key":"11","name":"Прыжок события: Персонаж"},{"key":"12","name":"Прыжок события: Световой конус"},{"key":"1","name":"Звёздный Прыжок"},{"key":"2","name":"Отправной Прыжок"}]],["th-th",[{"key":"11","name":"กิจกรรมวาร์ปตัวละคร"},{"key":"12","name":"กิจกรรมวาร์ป Light Cone"},{"key":"1","name":"วาร์ปสู่ดวงดาว"},{"key":"2","name":"ก้าวแรกแห่งการวาร์ป"}]],["zh-cn",[{"key":"11","name":"角色活动跃迁"},{"key":"12","name":"光锥活动跃迁"},{"key":"1","name":"群星跃迁"},{"key":"2","name":"始发跃迁"}]],["zh-tw",[{"key":"11","name":"角色活動躍遷"},{"key":"12","name":"光錐活動躍遷"},{"key":"1","name":"群星躍遷"},{"key":"2","name":"始發躍遷"}]],["en-us",[{"key":"11","name":"Character Event Warp"},{"key":"12","name":"Light Cone Event Warp"},{"key":"1","name":"Stellar Warp"},{"key":"2","name":"Departure Warp"}]],["es-es",[{"key":"11","name":"Salto de evento de personaje"},{"key":"12","name":"Salto de evento de cono de luz"},{"key":"1","name":"Salto estelar"},{"key":"2","name":"Salto de partida"}]],["fr-fr",[{"key":"11","name":"Saut hyperespace événement de personnage"},{"key":"12","name":"Saut hyperespace événement de cônes de lumière"},{"key":"1","name":"Saut stellaire"},{"key":"2","name":"Saut hyperespace de départ"}]],["id-id",[{"key":"11","name":"Event Warp Karakter"},{"key":"12","name":"Event Warp Light Cone"},{"key":"1","name":"Warp Bintang-Bintang"},{"key":"2","name":"Warp Keberangkatan"}]],["ja-jp",[{"key":"11","name":"イベント跳躍・キャラクター"},{"key":"12","name":"イベント跳躍・光円錐"},{"key":"1","name":"群星跳躍"},{"key":"2","name":"始発跳躍"}]],["ko-kr",[{"key":"11","name":"캐릭터 이벤트 워프"},{"key":"12","name":"광추 이벤트 워프"},{"key":"1","name":"뭇별의 워프"},{"key":"2","name":"초행길 워프"}]],["pt-pt",[{"key":"11","name":"Salto Hiperespacial de Evento de Personagem"},{"key":"12","name":"Salto Hiperespacial de Evento de Cone de Luz"},{"key":"1","name":"Salto Hiperespacial Estelar"},{"key":"2","name":"Salto Hiperespacial de Novatos"}]],["vi-vn",[{"key":"11","name":"Bước Nhảy Sự Kiện Nhân Vật"},{"key":"12","name":"Bước Nhảy Sự Kiện Nón Ánh Sáng"},{"key":"1","name":"Bước Nhảy Chòm Sao"},{"key":"2","name":"Bước Nhảy Đầu Tiên"}]]]'))
|
const gachaTypeMap = new Map(gachaTypeRaw)
|
||||||
const getGachaType = (lang) => {
|
const getGachaType = (lang) => {
|
||||||
const locale = detectLocale(lang)
|
const locale = detectLocale(lang)
|
||||||
return gachaTypeMap.get(locale || lang)
|
return gachaTypeMap.get(locale || lang)
|
||||||
@ -333,10 +362,7 @@ const tryRequest = async (url, retry = false) => {
|
|||||||
const gachaTypeUrl = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}&page=1&size=5&gacha_type=1&end_id=0`
|
const gachaTypeUrl = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}&page=1&size=5&gacha_type=1&end_id=0`
|
||||||
try {
|
try {
|
||||||
const res = await request(gachaTypeUrl)
|
const res = await request(gachaTypeUrl)
|
||||||
if (res.retcode !== 0) {
|
checkResStatus(res)
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 'ERR_PROXY_CONNECTION_FAILED' && !retry) {
|
if (e.code === 'ERR_PROXY_CONNECTION_FAILED' && !retry) {
|
||||||
await disableProxy()
|
await disableProxy()
|
||||||
@ -351,11 +377,6 @@ const getUrl = async () => {
|
|||||||
let url = await readLog()
|
let url = await readLog()
|
||||||
if (!url && config.proxyMode) {
|
if (!url && config.proxyMode) {
|
||||||
url = await useProxy()
|
url = await useProxy()
|
||||||
} else if (url) {
|
|
||||||
const result = await tryRequest(url)
|
|
||||||
if (!result && config.proxyMode) {
|
|
||||||
url = await useProxy()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
@ -372,6 +393,9 @@ const fetchData = async (urlOverride) => {
|
|||||||
sendMsg(message)
|
sendMsg(message)
|
||||||
throw new Error(message)
|
throw new Error(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await tryRequest(url)
|
||||||
|
|
||||||
const searchParams = getQuerystring(url)
|
const searchParams = getQuerystring(url)
|
||||||
if (!searchParams) {
|
if (!searchParams) {
|
||||||
const message = text.url.incorrect
|
const message = text.url.incorrect
|
||||||
@ -412,7 +436,7 @@ const fetchData = async (urlOverride) => {
|
|||||||
originTimeZone = region_time_zone
|
originTimeZone = region_time_zone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const data = { result, time: Date.now(), typeMap, uid: originUid, lang, region: originRegion, region_time_zone: originTimeZone }
|
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region: originRegion, region_time_zone: originTimeZone }
|
||||||
const localData = dataMap.get(originUid)
|
const localData = dataMap.get(originUid)
|
||||||
const mergedResult = mergeData(localData, data)
|
const mergedResult = mergeData(localData, data)
|
||||||
data.result = mergedResult
|
data.result = mergedResult
|
||||||
@ -456,7 +480,7 @@ ipcMain.handle('READ_DATA', async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('CHANGE_UID', (event, uid) => {
|
ipcMain.handle('CHANGE_UID', (event, uid) => {
|
||||||
config.current = uid
|
changeCurrent(uid)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('GET_CONFIG', () => {
|
ipcMain.handle('GET_CONFIG', () => {
|
||||||
@ -492,3 +516,6 @@ exports.getData = () => {
|
|||||||
current: config.current
|
current: config.current
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.getUrl = getUrl
|
||||||
|
exports.deleteData = deleteData
|
||||||
|
@ -42,14 +42,24 @@ const parseData = (data) => {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const assignData = (objA, objB) => {
|
||||||
|
const temp = { ...objA }
|
||||||
|
for (let key in objB) {
|
||||||
|
if (objB[key]) {
|
||||||
|
temp[key] = objB[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
const i18nMap = new Map()
|
const i18nMap = new Map()
|
||||||
const prepareData = () => {
|
const prepareData = () => {
|
||||||
for (let key in raw) {
|
for (let key in raw) {
|
||||||
let temp = {}
|
let temp = {}
|
||||||
if (key === 'zh-tw') {
|
if (key === 'zh-tw') {
|
||||||
Object.assign(temp, raw['zh-cn'], raw[key])
|
temp = assignData(raw['zh-cn'], raw[key])
|
||||||
} else {
|
} else {
|
||||||
Object.assign(temp, raw['zh-cn'], raw['en-us'], raw[key])
|
temp = assignData(raw['zh-cn'], assignData(raw['en-us'], raw[key]))
|
||||||
}
|
}
|
||||||
i18nMap.set(key, parseData(temp))
|
i18nMap.set(key, parseData(temp))
|
||||||
}
|
}
|
||||||
@ -66,7 +76,7 @@ const parseText = (text, data) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mainProps = [
|
const mainProps = [
|
||||||
'symbol', 'ui', 'log', 'excel'
|
'symbol', 'ui', 'log', 'excel',"srgf"
|
||||||
]
|
]
|
||||||
|
|
||||||
const i18n = new Proxy(raw, {
|
const i18n = new Proxy(raw, {
|
||||||
|
@ -2,8 +2,9 @@ const { app, BrowserWindow, ipcMain } = require('electron')
|
|||||||
const { initWindow } = require('./utils')
|
const { initWindow } = require('./utils')
|
||||||
const { disableProxy, proxyStatus } = require('./module/system-proxy')
|
const { disableProxy, proxyStatus } = require('./module/system-proxy')
|
||||||
require('./getData')
|
require('./getData')
|
||||||
|
require('./bridge')
|
||||||
require('./excel')
|
require('./excel')
|
||||||
require('./UIGFJson')
|
require('./SRGFJson')
|
||||||
const { getUpdateInfo } = require('./update/index')
|
const { getUpdateInfo } = require('./update/index')
|
||||||
|
|
||||||
const isDev = !app.isPackaged
|
const isDev = !app.isPackaged
|
||||||
|
@ -6,13 +6,14 @@ const crypto = require('crypto')
|
|||||||
const unhandled = require('electron-unhandled')
|
const unhandled = require('electron-unhandled')
|
||||||
const windowStateKeeper = require('electron-window-state')
|
const windowStateKeeper = require('electron-window-state')
|
||||||
const debounce = require('lodash/debounce')
|
const debounce = require('lodash/debounce')
|
||||||
const Registry = require('winreg')
|
const { glob } = require('glob')
|
||||||
|
|
||||||
const isDev = !app.isPackaged
|
const isDev = !app.isPackaged
|
||||||
|
|
||||||
const userPath = app.getPath('userData')
|
const userPath = app.getPath('userData')
|
||||||
const appRoot = isDev ? path.resolve(__dirname, '..', '..') : userPath
|
const appRoot = isDev ? path.resolve(__dirname, '..', '..') : path.resolve(app.getAppPath(), '..', '..')
|
||||||
const userDataPath = path.resolve(appRoot, 'userData')
|
const userDataPath = path.resolve(appRoot, 'userData')
|
||||||
|
const globalUserDataPath = path.resolve(userPath, 'userData')
|
||||||
|
|
||||||
let win = null
|
let win = null
|
||||||
const initWindow = () => {
|
const initWindow = () => {
|
||||||
@ -25,6 +26,7 @@ const initWindow = () => {
|
|||||||
y: mainWindowState.y,
|
y: mainWindowState.y,
|
||||||
width: mainWindowState.width,
|
width: mainWindowState.width,
|
||||||
height: mainWindowState.height,
|
height: mainWindowState.height,
|
||||||
|
backgroundColor: '#fff',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
contextIsolation:false,
|
contextIsolation:false,
|
||||||
nodeIntegration: true
|
nodeIntegration: true
|
||||||
@ -56,7 +58,7 @@ const saveLog = () => {
|
|||||||
const text = item[2]
|
const text = item[2]
|
||||||
return `[${type}][${time}]${text}`
|
return `[${type}][${time}]${text}`
|
||||||
}).join('\r\n')
|
}).join('\r\n')
|
||||||
fs.outputFileSync(path.join(userDataPath, 'log.txt'), text)
|
fs.outputFile(path.join(userDataPath, 'log.txt'), text)
|
||||||
}
|
}
|
||||||
|
|
||||||
const authkeyMask = (text = '') => {
|
const authkeyMask = (text = '') => {
|
||||||
@ -134,7 +136,7 @@ const detectLocale = (value) => {
|
|||||||
const locale = value || app.getLocale()
|
const locale = value || app.getLocale()
|
||||||
let result = 'zh-cn'
|
let result = 'zh-cn'
|
||||||
for (let [key, list] of localeMap) {
|
for (let [key, list] of localeMap) {
|
||||||
if (list.includes(locale)) {
|
if (locale === key || list.includes(locale)) {
|
||||||
result = key
|
result = key
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -144,19 +146,20 @@ const detectLocale = (value) => {
|
|||||||
|
|
||||||
const saveJSON = async (name, data) => {
|
const saveJSON = async (name, data) => {
|
||||||
try {
|
try {
|
||||||
await fs.outputJSON(path.join(userDataPath, name), data, {
|
await fs.outputJSON(path.join(userDataPath, name), data)
|
||||||
spaces: 2
|
if (!isDev) {
|
||||||
})
|
await fs.outputJSON(path.join(globalUserDataPath, name), data)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendMsg(e, 'ERROR')
|
sendMsg(e, 'ERROR')
|
||||||
await sleep(3)
|
await sleep(3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const readJSON = async (name) => {
|
const readJSON = async (dataPath, name) => {
|
||||||
let data = null
|
let data = null
|
||||||
try {
|
try {
|
||||||
data = await fs.readJSON(path.join(userDataPath, name))
|
data = await fs.readJSON(path.join(dataPath, name))
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
@ -200,8 +203,23 @@ const localIp = () => {
|
|||||||
return '127.0.0.1'
|
return '127.0.0.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
async function getCacheText(gamePath) {
|
||||||
sleep, request, hash, cipherAes, decipherAes, saveLog,
|
const results = await glob(path.join(gamePath, '/webCaches{/,/*/}Cache/Cache_Data/data_2'), {
|
||||||
sendMsg, readJSON, saveJSON, initWindow, getWin, localIp, userPath, detectLocale, langMap,
|
stat: true,
|
||||||
appRoot, userDataPath
|
withFileTypes: true,
|
||||||
|
nodir: true,
|
||||||
|
windowsPathsNoEscape: true
|
||||||
|
})
|
||||||
|
const timeSortedFiles = results
|
||||||
|
.sort((a, b) => b.mtimeMs - a.mtimeMs)
|
||||||
|
.map(path => path.fullpath())
|
||||||
|
const cacheText = await fs.readFile(path.join(timeSortedFiles[0]), 'utf8')
|
||||||
|
|
||||||
|
return [cacheText, timeSortedFiles[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sleep, request, hash, cipherAes, decipherAes, saveLog, getCacheText,
|
||||||
|
sendMsg, readJSON, saveJSON, initWindow, getWin, localIp, userPath, detectLocale, langMap,
|
||||||
|
appRoot, userDataPath, globalUserDataPath
|
||||||
}
|
}
|
@ -1,9 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="ui" class="relative">
|
<div v-if="ui" class="relative">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div>
|
<div class="space-x-3">
|
||||||
<el-button type="primary" :icon="state.status === 'init' ? 'milk-tea': 'refresh-right'" class="focus:outline-none" :disabled="!allowClick()" plain @click="fetchData()" :loading="state.status === 'loading'">{{state.status === 'init' ? ui.button.load: ui.button.update}}</el-button>
|
<el-button type="primary" :icon="state.status === 'init' ? 'milk-tea': 'refresh-right'" class="focus:outline-none" :disabled="!allowClick()" plain @click="fetchData()" :loading="state.status === 'loading'">{{state.status === 'init' ? ui.button.load: ui.button.update}}</el-button>
|
||||||
<el-button icon="folder-opened" @click="saveExcel" class="focus:outline-none" :disabled="!gachaData" type="success" plain>{{ui.button.excel}}</el-button>
|
<el-dropdown :disabled="!gachaData" @command="exportCommand">
|
||||||
|
<el-button :disabled="!gachaData" icon="folder-opened" class="focus:outline-none" type="success" plain>
|
||||||
|
{{ui.button.files}}
|
||||||
|
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item command="excel">{{ui.button.excel}}</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="srgf-json">{{ui.button.srgf}}</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
<el-tooltip v-if="detail && state.status !== 'loading'" :content="ui.hint.newAccount" placement="bottom">
|
<el-tooltip v-if="detail && state.status !== 'loading'" :content="ui.hint.newAccount" placement="bottom">
|
||||||
<el-button @click="newUser()" plain icon="plus" class="focus:outline-none"></el-button>
|
<el-button @click="newUser()" plain icon="plus" class="focus:outline-none"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -12,20 +23,21 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<el-select v-if="state.status !== 'loading' && state.dataMap && (state.dataMap.size > 1 || (state.dataMap.size === 1 && state.current === 0))" class="w-44" @change="changeCurrent" v-model="uidSelectText">
|
<el-select v-if="state.status !== 'loading' && dataMap && (dataMap.size > 1 || (dataMap.size === 1 && state.current === 0))" class="w-44" @change="changeCurrent" v-model="uidSelectText">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item of state.dataMap"
|
v-for="item of dataMap"
|
||||||
:key="item[0]"
|
:key="item[0]"
|
||||||
:label="maskUid(item[0])"
|
:label="maskUid(item[0])"
|
||||||
:value="item[0]">
|
:value="item[0]">
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-dropdown @command="optionCommand" >
|
<el-dropdown @command="optionCommand">
|
||||||
<el-button @click="showSetting(true)" class="focus:outline-none" plain type="info" icon="more" >{{ui.button.option}}</el-button>
|
<el-button @click="showSetting(true)" class="focus:outline-none" plain type="info" icon="more" >{{ui.button.option}}</el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item command="setting" icon="setting">{{ui.button.setting}}</el-dropdown-item>
|
<el-dropdown-item command="setting" icon="setting">{{ui.button.setting}}</el-dropdown-item>
|
||||||
<el-dropdown-item :disabled="!allowClick() || state.status === 'loading'" command="url" icon="link">{{ui.button.url}}</el-dropdown-item>
|
<el-dropdown-item :disabled="!allowClick() || state.status === 'loading'" command="url" icon="link">{{ui.button.url}}</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="copyUrl" icon="DocumentCopy">{{ui.button.copyUrl}}</el-dropdown-item>
|
||||||
<el-dropdown-item :disabled="!allowClick() || state.status === 'loading'" command="proxy" icon="position">{{ui.button.startProxy}}</el-dropdown-item>
|
<el-dropdown-item :disabled="!allowClick() || state.status === 'loading'" command="proxy" icon="position">{{ui.button.startProxy}}</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
@ -42,9 +54,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Setting v-show="state.showSetting" :i18n="state.i18n" @changeLang="getI18nData()" @close="showSetting(false)"></Setting>
|
<Setting v-show="state.showSetting" :i18n="state.i18n" :gacha-data-info="dataInfo" @refreshData="readData()" @changeLang="getI18nData()" @close="showSetting(false)"></Setting>
|
||||||
|
|
||||||
<el-dialog :title="ui.urlDialog.title" v-model="state.showUrlDlg" width="90%" custom-class="max-w-md">
|
<el-dialog :title="ui.urlDialog.title" v-model="state.showUrlDlg" width="90%" class="max-w-md">
|
||||||
<p class="mb-4 text-gray-500">{{ui.urlDialog.hint}}</p>
|
<p class="mb-4 text-gray-500">{{ui.urlDialog.hint}}</p>
|
||||||
<el-input type="textarea" :autosize="{minRows: 4, maxRows: 6}" :placeholder="ui.urlDialog.placeholder" v-model="state.urlInput" spellcheck="false"></el-input>
|
<el-input type="textarea" :autosize="{minRows: 4, maxRows: 6}" :placeholder="ui.urlDialog.placeholder" v-model="state.urlInput" spellcheck="false"></el-input>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -55,17 +67,18 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog :title="ui.button.solution" v-model="state.showCacheCleanDlg" width="90%" custom-class="max-w-md">
|
<el-dialog :title="ui.button.solution" v-model="state.showCacheCleanDlg" width="90%" class="max-w-md cache-clean-dialog">
|
||||||
<el-button plain icon="folder" type="primary" @click="openCacheFolder">{{ui.button.cacheFolder}}</el-button>
|
<el-button plain icon="folder" type="success" @click="openCacheFolder">{{ui.button.cacheFolder}}</el-button>
|
||||||
<p class="my-4 leading-2 text-gray-600 text-sm whitespace-pre-line">{{ui.extra.cacheClean}}</p>
|
<p class="my-2 flex flex-col text-teal-800 text-[13px]">
|
||||||
<p class="my-2 text-gray-400 text-xs">{{ui.extra.findCacheFolder}}</p>
|
<span class="my-1" v-for="txt of cacheCleanTextList">{{ txt }}</span>
|
||||||
|
</p>
|
||||||
|
<p class="my-2 text-gray-500 text-xs">{{ui.extra.findCacheFolder}}</p>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="dialog-footer text-center">
|
<div class="dialog-footer text-center">
|
||||||
<el-button type="primary" @click="state.showCacheCleanDlg = false" class="focus:outline-none">{{ui.common.ok}}</el-button>
|
<el-button type="primary" @click="state.showCacheCleanDlg = false" class="focus:outline-none">{{ui.common.ok}}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -77,6 +90,8 @@ import GachaDetail from './components/GachaDetail.vue'
|
|||||||
import Setting from './components/Setting.vue'
|
import Setting from './components/Setting.vue'
|
||||||
import gachaDetail from './gachaDetail'
|
import gachaDetail from './gachaDetail'
|
||||||
import { version } from '../../package.json'
|
import { version } from '../../package.json'
|
||||||
|
import gachaType from '../gachaType.json'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
status: 'init',
|
status: 'init',
|
||||||
@ -93,12 +108,39 @@ const state = reactive({
|
|||||||
config: {}
|
config: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const dataMap = computed(() => {
|
||||||
|
const result = new Map()
|
||||||
|
for (let [uid, data] of state.dataMap) {
|
||||||
|
if (!data.deleted) {
|
||||||
|
result.set(uid, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
const dataInfo = computed(() => {
|
||||||
|
const result = []
|
||||||
|
for (let [uid, data] of state.dataMap) {
|
||||||
|
result.push({
|
||||||
|
uid, time: data.time, deleted: data.deleted
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
const ui = computed(() => {
|
const ui = computed(() => {
|
||||||
if (state.i18n) {
|
if (state.i18n) {
|
||||||
return state.i18n.ui
|
return state.i18n.ui
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cacheCleanTextList = computed(() => {
|
||||||
|
if (ui.value) {
|
||||||
|
return ui.value.extra?.cacheClean?.split('\n')
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
const gachaData = computed(() => {
|
const gachaData = computed(() => {
|
||||||
return state.dataMap.get(state.current)
|
return state.dataMap.get(state.current)
|
||||||
})
|
})
|
||||||
@ -114,7 +156,7 @@ const uidSelectText = computed(() => {
|
|||||||
const allowClick = () => {
|
const allowClick = () => {
|
||||||
const data = state.dataMap.get(state.current)
|
const data = state.dataMap.get(state.current)
|
||||||
if (!data) return true
|
if (!data) return true
|
||||||
if (Date.now() - data.time < 1000 * 60) {
|
if (Date.now() - data.time < 1000 * 10) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -142,18 +184,26 @@ const hint = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const detail = computed(() => {
|
const detail = computed(() => {
|
||||||
const data = state.dataMap.get(state.current)
|
const data = dataMap.value.get(state.current)
|
||||||
if (data) {
|
if (data) {
|
||||||
return gachaDetail(data.result)
|
return gachaDetail(data.result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const typeMap = computed(() => {
|
const typeMap = computed(() => {
|
||||||
const data = state.dataMap.get(state.current)
|
const gachaTypeMap = new Map(gachaType)
|
||||||
return data.typeMap
|
const type = gachaTypeMap.get(state.config.lang)
|
||||||
|
const result = new Map()
|
||||||
|
if (type) {
|
||||||
|
for (let { key, name } of type) {
|
||||||
|
result.set(key, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
const fetchData = async (url) => {
|
const fetchData = async (url) => {
|
||||||
|
state.log = ''
|
||||||
state.status = 'loading'
|
state.status = 'loading'
|
||||||
const data = await ipcRenderer.invoke('FETCH_DATA', url)
|
const data = await ipcRenderer.invoke('FETCH_DATA', url)
|
||||||
if (data) {
|
if (data) {
|
||||||
@ -188,6 +238,18 @@ const saveExcel = async () => {
|
|||||||
await ipcRenderer.invoke('SAVE_EXCEL')
|
await ipcRenderer.invoke('SAVE_EXCEL')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exportSRGFJSON = () => {
|
||||||
|
ipcRenderer.invoke('EXPORT_SRGF_JSON')
|
||||||
|
}
|
||||||
|
|
||||||
|
const exportCommand = (type) => {
|
||||||
|
if (type === 'excel') {
|
||||||
|
saveExcel()
|
||||||
|
} else if (type === 'srgf-json') {
|
||||||
|
exportSRGFJSON()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const openCacheFolder = async () => {
|
const openCacheFolder = async () => {
|
||||||
await ipcRenderer.invoke('OPEN_CACHE_FOLDER')
|
await ipcRenderer.invoke('OPEN_CACHE_FOLDER')
|
||||||
}
|
}
|
||||||
@ -231,6 +293,8 @@ const optionCommand = (type) => {
|
|||||||
state.showUrlDlg = true
|
state.showUrlDlg = true
|
||||||
} else if (type === 'proxy') {
|
} else if (type === 'proxy') {
|
||||||
fetchData('proxy')
|
fetchData('proxy')
|
||||||
|
} else if (type === 'copyUrl') {
|
||||||
|
copyUrl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +306,15 @@ const updateConfig = async () => {
|
|||||||
state.config = await ipcRenderer.invoke('GET_CONFIG')
|
state.config = await ipcRenderer.invoke('GET_CONFIG')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyUrl = async () => {
|
||||||
|
const successed = await ipcRenderer.invoke('COPY_URL')
|
||||||
|
if (successed) {
|
||||||
|
ElMessage.success(ui.value.extra.urlCopied)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(state.i18n.log.url.notFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await readData()
|
await readData()
|
||||||
await getI18nData()
|
await getI18nData()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-white pt-2 pb-4 px-6 w-full h-full absolute inset-0">
|
<div class="bg-white py-4 px-6 w-screen h-screen fixed inset-0 overflow-y-auto">
|
||||||
<div class="flex content-center items-center mb-4 justify-between">
|
<div class="flex content-center items-center mb-4 justify-between">
|
||||||
<h3 class="text-lg">{{text.title}}</h3>
|
<h3 class="text-lg">{{text.title}}</h3>
|
||||||
<el-button icon="close" @click="closeSetting" plain circle type="default" class="w-8 h-8 relative -right-4 -top-2 shadow-md focus:shadow-none focus:outline-none"></el-button>
|
<el-button icon="close" @click="closeSetting" plain circle type="default" class="w-8 h-8 shadow-md focus:shadow-none focus:outline-none fixed top-4 right-6"></el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="settingForm" label-width="120px">
|
<el-form :model="settingForm" label-width="120px">
|
||||||
<el-form-item :label="text.language">
|
<el-form-item :label="text.language">
|
||||||
@ -19,6 +19,10 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<p class="text-gray-400 text-xs m-1.5">{{text.logTypeHint}}</p>
|
<p class="text-gray-400 text-xs m-1.5">{{text.logTypeHint}}</p>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="common.data">
|
||||||
|
<el-button type="primary" plain @click="state.showDataDialog = true">{{common.dataManage}}</el-button>
|
||||||
|
<p class="text-gray-400 text-xs m-1.5">{{text.dataManagerHint}}</p>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item :label="text.autoUpdate">
|
<el-form-item :label="text.autoUpdate">
|
||||||
<el-switch
|
<el-switch
|
||||||
@change="saveSetting"
|
@change="saveSetting"
|
||||||
@ -51,21 +55,49 @@
|
|||||||
<h3 class="text-lg my-4">{{about.title}}</h3>
|
<h3 class="text-lg my-4">{{about.title}}</h3>
|
||||||
<p class="text-gray-600 text-xs mt-1">{{about.license}}</p>
|
<p class="text-gray-600 text-xs mt-1">{{about.license}}</p>
|
||||||
<p class="text-gray-600 text-xs mt-1 pb-6">Github: <a @click="openGithub" class="cursor-pointer text-blue-400">https://github.com/biuuu/star-rail-warp-export</a></p>
|
<p class="text-gray-600 text-xs mt-1 pb-6">Github: <a @click="openGithub" class="cursor-pointer text-blue-400">https://github.com/biuuu/star-rail-warp-export</a></p>
|
||||||
|
<el-dialog v-model="state.showDataDialog" :title="common.dataManage" width="90%">
|
||||||
|
<div class="">
|
||||||
|
<el-table :data="gachaDataInfo" border stripe>
|
||||||
|
<el-table-column property="uid" label="UID" width="128" />
|
||||||
|
<el-table-column property="time" :label="common.updateTime">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ new Date(scope.row.time).toLocaleString() }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column property="deleted" :label="common.status" width="128">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag type="info" size="small" v-if="scope.row.deleted">{{common.deleted}}</el-tag>
|
||||||
|
<el-tag type="success" size="small" v-else>{{common.normal}}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column property="deleted" :label="common.action" width="128">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip :content="scope.row.deleted ? common.restore : common.delete" placement="top">
|
||||||
|
<el-button :loading="state.dataActionLoading" size="small" icon="refresh" plain type="success" @click="deleteData(scope.row.uid, false)" v-if="scope.row.deleted"></el-button>
|
||||||
|
<el-button :loading="state.dataActionLoading" size="small" icon="delete" plain type="danger" @click="deleteData(scope.row.uid, true)" v-else></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const { ipcRenderer, shell } = require('electron')
|
const { ipcRenderer, shell } = require('electron')
|
||||||
import { reactive, onMounted, computed } from 'vue'
|
import { reactive, onMounted, computed } from 'vue'
|
||||||
|
|
||||||
const emit = defineEmits(['close', 'changeLang'])
|
const emit = defineEmits(['close', 'changeLang', 'refreshData'])
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
i18n: Object
|
i18n: Object,
|
||||||
|
gachaDataInfo: Array
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
langMap: new Map()
|
langMap: new Map(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const settingForm = reactive({
|
const settingForm = reactive({
|
||||||
@ -77,6 +109,12 @@ const settingForm = reactive({
|
|||||||
hideNovice: true
|
hideNovice: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
showDataDialog: false,
|
||||||
|
dataActionLoading: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const common = computed(() => props.i18n.ui.common)
|
||||||
const text = computed(() => props.i18n.ui.setting)
|
const text = computed(() => props.i18n.ui.setting)
|
||||||
const about = computed(() => props.i18n.ui.about)
|
const about = computed(() => props.i18n.ui.about)
|
||||||
|
|
||||||
@ -101,8 +139,11 @@ const disableProxy = async () => {
|
|||||||
const openGithub = () => shell.openExternal('https://github.com/biuuu/star-rail-warp-export')
|
const openGithub = () => shell.openExternal('https://github.com/biuuu/star-rail-warp-export')
|
||||||
const openLink = (link) => shell.openExternal(link)
|
const openLink = (link) => shell.openExternal(link)
|
||||||
|
|
||||||
const exportUIGFJSON = () => {
|
const deleteData = async (uid, action) => {
|
||||||
ipcRenderer.invoke('EXPORT_UIGF_JSON')
|
state.dataActionLoading = true
|
||||||
|
await ipcRenderer.invoke('DELETE_DATA', uid, action)
|
||||||
|
state.dataActionLoading = false
|
||||||
|
emit('refreshData')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
@ -6,11 +6,17 @@
|
|||||||
:root {
|
:root {
|
||||||
--el-font-size-base: 12px !important;
|
--el-font-size-base: 12px !important;
|
||||||
}
|
}
|
||||||
body::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
height: 6px;
|
height: 6px;
|
||||||
}
|
}
|
||||||
body::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
@apply rounded-full bg-gray-300;
|
@apply rounded-full bg-gray-300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.cache-clean-dialog .el-dialog__body {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import * as IconComponents from '@element-plus/icons-vue'
|
import * as IconComponents from '@element-plus/icons-vue'
|
||||||
|
|
||||||
const weaponTypeNames = new Set([
|
const weaponTypeNames = new Set([
|
||||||
'光锥', 'Light Cone', '光錐', 'Lichtkegel', 'Conos de luz', 'cônes de lumière', '光円錐', '광추', 'Cones de Luz', 'Световые конусы', 'Nón Ánh Sáng'
|
'光锥', '光錐', 'Lichtkegel', 'Light Cone', 'Conos de luz', 'cônes de lumière', '光円錐', '광추', 'Cones de Luz', 'Световые конусы', 'Nón Ánh Sáng', 'Cône de lumière'
|
||||||
])
|
])
|
||||||
|
|
||||||
const characterTypeNames = new Set([
|
const characterTypeNames = new Set([
|
||||||
'角色', 'Character', '캐릭터', 'キャラクター', 'Personaje', 'Personnage', 'Персонажи', 'ตัวละคร', 'Nhân Vật', 'Figur', 'Karakter', 'Personagem'
|
'角色', 'Figur', 'Character', 'Personajes', 'Personnages', 'Karakter', 'キャラクター', '캐릭터', 'Personagens', 'Персонажи', 'ตัวละคร', 'Nhân Vật', 'Personnage'
|
||||||
])
|
])
|
||||||
|
|
||||||
const isCharacter = (name) => characterTypeNames.has(name)
|
const isCharacter = (name) => characterTypeNames.has(name)
|
||||||
|