Compare commits

...

14 Commits

12 changed files with 2603 additions and 21 deletions

View File

@ -6,7 +6,7 @@
一个使用 Electron 制作的小工具,需要在 Windows 操作系统上运行。 一个使用 Electron 制作的小工具,需要在 Windows 操作系统上运行。
通过读取游戏日志或者代理模式获取访问游戏跃迁记录 API 所需的 authKey然后再使用获取到的 authKey 来读取游戏跃迁记录。 通过读取游戏日志或者代理模式获取访问游戏调频记录 API 所需的 authKey然后再使用获取到的 authKey 来读取游戏调频记录。
## 其它语言 ## 其它语言
@ -15,7 +15,7 @@
## 使用说明 ## 使用说明
1. 下载工具后解压 - 下载地址: [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip) / [123云盘](https://www.123pan.com/s/Vs9uVv-ShhE.html) / [蓝奏云(密码:zzzz](https://www.lanzouh.com/b00eewtvxa) 1. 下载工具后解压 - 下载地址: [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip) / [123云盘](https://www.123pan.com/s/Vs9uVv-ShhE.html) / [蓝奏云(密码:zzzz](https://www.lanzouh.com/b00eewtvxa)
2. 打开游戏的跃迁详情页面 2. 打开游戏的调频详情页面
![详情页面](/docs/wish-history.jpg) ![详情页面](/docs/wish-history.jpg)
@ -34,7 +34,7 @@
如果需要导出多个账号的数据,可以点击旁边的加号按钮。 如果需要导出多个账号的数据,可以点击旁边的加号按钮。
然后游戏切换的新账号,再打开跃迁历史记录,工具再点击“加载数据”按钮。 然后游戏切换的新账号,再打开调频历史记录,工具再点击“加载数据”按钮。
## Devlopment ## Devlopment

View File

@ -6,7 +6,7 @@ This project is modified from the [star-rail-warp-export](https://github.com/biu
A tool made from Electron that runs on the Windows operating system. A tool made from Electron that runs on the Windows operating system.
Read the game log or proxy to get the authKey needed to access the game warp history API, and then use the authKey to read the game wish history. Read the game log or proxy to get the authKey needed to access the game signal search history API, and then use the authKey to read the game wish history.
## Other languages ## Other languages
@ -18,7 +18,7 @@ If you feel that the existing translation is inappropriate, you can send a pull
1. Unzip after downloading the tool - [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip) 1. Unzip after downloading the tool - [GitHub](https://github.com/earthjasonlin/zzz-signal-search-export/releases/latest/download/ZzzSignalSearchExport.zip)
2. Open the warp details page of the game 2. Open the signal search details page of the game
![warp details](/docs/wish-history-en.jpg) ![warp details](/docs/wish-history-en.jpg)

View File

@ -1,7 +1,7 @@
{ {
"name": "zzz-signal-search-export", "name": "zzz-signal-search-export",
"version": "1.1.0", "version": "1.1.6",
"autoUpdateActive": false, "autoUpdateActive": true,
"autoUpdateFrom": "1.1.0", "autoUpdateFrom": "1.1.0",
"main": "./dist/electron/main/main.js", "main": "./dist/electron/main/main.js",
"author": "earthjasonlin <https://git.loliquq.cn/earthjasonlin>", "author": "earthjasonlin <https://git.loliquq.cn/earthjasonlin>",

View File

@ -3,7 +3,7 @@
"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.files": "Import/Export",
"ui.button.excel": "Export Excel", "ui.button.excel": "Export Excel",
"ui.button.uigf": "Export UIGF", "ui.button.uigf": "Export UIGF",
"ui.button.import": "Import UIGF", "ui.button.import": "Import UIGF",

View File

@ -3,7 +3,7 @@
"ui.button.load": "加载数据", "ui.button.load": "加载数据",
"ui.button.update": "更新数据", "ui.button.update": "更新数据",
"ui.button.directUpdate": "直接更新", "ui.button.directUpdate": "直接更新",
"ui.button.files": "导出文件", "ui.button.files": "导入/导出",
"ui.button.excel": "导出Excel", "ui.button.excel": "导出Excel",
"ui.button.uigf":"导出UIGF", "ui.button.uigf":"导出UIGF",
"ui.button.import":"导入UIGF", "ui.button.import":"导入UIGF",

View File

@ -3,7 +3,7 @@
"ui.button.load": "加載數據", "ui.button.load": "加載數據",
"ui.button.update": "更新數據", "ui.button.update": "更新數據",
"ui.button.directUpdate": "直接更新", "ui.button.directUpdate": "直接更新",
"ui.button.files": "導出文件", "ui.button.files": "導入/匯出",
"ui.button.excel": "導出Excel", "ui.button.excel": "導出Excel",
"ui.button.uigf":"導出UIGF", "ui.button.uigf":"導出UIGF",
"ui.button.import":"導入UIGF", "ui.button.import":"導入UIGF",

2487
src/idJson.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ const { name, version } = require('../../package.json')
const i18n = require('./i18n') const i18n = require('./i18n')
const { mergeData } = require('./utils/mergeData') const { mergeData } = require('./utils/mergeData')
const { sendMsg } = require('./utils') const { sendMsg } = require('./utils')
const idJson = require('../idJson.json')
const getTimeString = () => { const getTimeString = () => {
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2) return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
@ -104,23 +105,35 @@ const importUIGF = async () => {
jsonData.nap.forEach(uidData => { jsonData.nap.forEach(uidData => {
const resultTemp = [] const resultTemp = []
const isNew = !Boolean(dataMap.has(uidData.uid)) const isNew = !Boolean(dataMap.has(uidData.uid))
let region_time_zone let region_time_zone
if (!isNew) region_time_zone = dataMap.get(uidData.uid).region_time_zone if (!isNew) region_time_zone = dataMap.get(uidData.uid).region_time_zone
else region_time_zone = uidData.timezone else region_time_zone = uidData.timezone
let targetLang
if (!isNew) targetLang = dataMap.get(uidData.uid).lang
else targetLang = uidData.lang
if(!idJson[targetLang] && (!uidData.list[0].name || !uidData.list[0].item_type || !uidData.list[0].rank_type)) targetLang = config.lang
let idTargetLangJson = idJson[targetLang]
uidData.list.forEach(recordEntry => { uidData.list.forEach(recordEntry => {
let rank_type
if (idTargetLangJson?.[recordEntry.item_id].rank_type) rank_type = String(idTargetLangJson[recordEntry.item_id].rank_type)
else rank_type = recordEntry.rank_type
resultTemp.push({ resultTemp.push({
gacha_id: recordEntry.gacha_id, gacha_id: recordEntry.gacha_id,
gacha_type: recordEntry.gacha_type, gacha_type: recordEntry.gacha_type,
item_id: recordEntry.item_id, item_id: recordEntry.item_id,
count: recordEntry.count, count: recordEntry.count ?? "1",
time: convertTimeZone(recordEntry.time, uidData.timezone, region_time_zone), time: convertTimeZone(recordEntry.time, uidData.timezone, region_time_zone),
name: recordEntry.name, name: idTargetLangJson?.[recordEntry.item_id].name ?? recordEntry.name,
item_type: recordEntry.item_type, item_type: idTargetLangJson?.[recordEntry.item_id].item_type ?? recordEntry.item_type,
rank_type: recordEntry.rank_type, rank_type: rank_type,
id: recordEntry.id id: recordEntry.id
}) })
}) })
const resultTempGrouped = resultTemp.reduce((acc, curr) => { const resultTempGrouped = resultTemp.reduce((acc, curr) => {
if (!acc[curr.gacha_type]) { if (!acc[curr.gacha_type]) {
acc[curr.gacha_type] = [] acc[curr.gacha_type] = []
@ -133,9 +146,9 @@ const importUIGF = async () => {
let data let data
const mergedData = mergeData(dataMap.get(uidData.uid), resultMap) const mergedData = mergeData(dataMap.get(uidData.uid), resultMap)
if (isNew) { if (isNew) {
data = { result: mergedData, time: Date.now(), uid: uidData.uid, lang: uidData.lang, region_time_zone: uidData.timezone, deleted: false } data = { result: mergedData, time: Date.now(), uid: uidData.uid, lang: targetLang, region_time_zone: uidData.timezone, deleted: false }
} else { } else {
data = { result: mergedData, time: Date.now(), uid: dataMap.get(uidData.uid).uid, lang: dataMap.get(uidData.uid).lang, region_time_zone: dataMap.get(uidData.uid).region_time_zone, deleted: dataMap.get(uidData.uid).deleted } data = { result: mergedData, time: Date.now(), uid: dataMap.get(uidData.uid).uid, lang: targetLang, region_time_zone: dataMap.get(uidData.uid).region_time_zone, deleted: dataMap.get(uidData.uid).deleted }
} }
saveData(data, '') saveData(data, '')

View File

@ -31,7 +31,10 @@ const defaultTypeMap = new Map([
const serverTimeZone = new Map([ const serverTimeZone = new Map([
["prod_gf_cn", 8], ["prod_gf_cn", 8],
["prod_gf_jp", 8] ["prod_gf_jp", 8],
["prod_gf_us", -5],
["prod_gf_eu", 1],
["prod_gf_sg", 8]
]) ])
const convertTimeZone = (dateTimeStr, fromTimeZoneOffset, toTimeZoneOffset) => { const convertTimeZone = (dateTimeStr, fromTimeZoneOffset, toTimeZoneOffset) => {
@ -111,7 +114,7 @@ const changeCurrent = async (uid) => {
const detectGameLocale = async (userPath) => { const detectGameLocale = async (userPath) => {
let list = [] let list = []
const lang = app.getLocale() const lang = app.getLocale()
const arr = ['/miHoYo/绝区零/', '/Cognosphere/Zenless Zone Zero/'] const arr = ['/miHoYo/绝区零/', '/miHoYo/ZenlessZoneZero/']
arr.forEach(str => { arr.forEach(str => {
try { try {
const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player.log') const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player.log')

View File

@ -4,7 +4,7 @@
<div class="space-x-3"> <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-dropdown :disabled="!gachaData" @command="exportCommand"> <el-dropdown :disabled="!gachaData" @command="exportCommand">
<el-button :disabled="!gachaData" icon="download" class="focus:outline-none" type="success" plain> <el-button :disabled="!gachaData" icon="folder-opened" class="focus:outline-none" type="success" plain>
{{ui.button.files}} {{ui.button.files}}
<el-icon class="el-icon--right"><arrow-down /></el-icon> <el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button> </el-button>
@ -12,10 +12,10 @@
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="excel">{{ui.button.excel}}</el-dropdown-item> <el-dropdown-item command="excel">{{ui.button.excel}}</el-dropdown-item>
<el-dropdown-item command="uigf-json">{{ui.button.uigf}}</el-dropdown-item> <el-dropdown-item command="uigf-json">{{ui.button.uigf}}</el-dropdown-item>
<el-dropdown-item command="import-json" divided>{{ui.button.import}}</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<el-button @click="importData()" icon="upload" class="focus:outline-none" type="success" plain>{{ui.button.import}}</el-button>
<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>
@ -290,6 +290,8 @@ const exportCommand = (type) => {
saveExcel() saveExcel()
} else if (type === 'uigf-json') { } else if (type === 'uigf-json') {
exportUIGFJSON() exportUIGFJSON()
} else if (type === 'import-json') {
importData()
} }
} }
const openCacheFolder = async () => { const openCacheFolder = async () => {

View File

@ -32,7 +32,7 @@ const props = defineProps({
const chart = ref(null); const chart = ref(null);
const colors = ["#eeaa66", "#fac858", "#ee6666", "#5470c6", "#ba66ee", "#91cc75", "#73c0de"]; const colors = ["#fac858", "#fac858", "#ee6666", "#5470c6", "#5470c6", "#91cc75", "#73c0de"];
const parseData = (detail, type) => { const parseData = (detail, type) => {
const text = props.i18n.ui.data; const text = props.i18n.ui.data;

77
tools/getIdMap.py Normal file
View File

@ -0,0 +1,77 @@
# pylint: disable=C0116, C0103, C0201
"""Download and process data from the Hakushin API"""
import json
import requests
from opencc import OpenCC
# 初始化 OpenCC 转换器
cc = OpenCC('s2t')
# 获取 JSON 数据
weapon_url = 'https://api.hakush.in/zzz/data/weapon.json'
character_url = 'https://api.hakush.in/zzz/data/character.json'
bangboo_url = 'https://api.hakush.in/zzz/data/bangboo.json'
# 语言映射配置
language_map = {
"zh-cn": "CHS",
"zh-tw": "CHS", # 简体转繁体
"en-us": "EN",
"ja-jp": "JA",
"ko-kr": "KO"
}
# 类型映射配置
type_map = {
"weapon": {"zh-cn": "音擎", "zh-tw": "音擎", "en-us": "W-Engines", "ja-jp": "音動機", "ko-kr": "W-엔진"},
"character": {"zh-cn": "代理人", "zh-tw": "代理人", "en-us": "Agents",
"ja-jp": "エージェント", "ko-kr": "에이전트"},
"bangboo": {"zh-cn": "邦布", "zh-tw": "邦布", "en-us": "Bangboo",
"ja-jp": "ボンプ", "ko-kr": "「Bangboo」"}
}
def fetch_json(url):
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
def transform_data(data, item_type):
transformed = {lang: {} for lang in language_map.keys()}
for id_, item in data.items():
for lang, key in language_map.items():
name = item[key] if lang != 'zh-tw' else cc.convert(item['CHS'])
transformed[lang][id_] = {
"name": name,
"item_type": type_map[item_type][lang],
"rank_type": item['rank']
}
return transformed
def main():
try:
weapon_data = fetch_json(weapon_url)
character_data = fetch_json(character_url)
bangboo_data = fetch_json(bangboo_url)
transformed_data = {lang: {} for lang in language_map.keys()}
weapon_transformed = transform_data(weapon_data, "weapon")
character_transformed = transform_data(character_data, "character")
bangboo_transformed = transform_data(bangboo_data, "bangboo")
for lang in language_map.keys():
transformed_data[lang].update(weapon_transformed[lang])
transformed_data[lang].update(character_transformed[lang])
transformed_data[lang].update(bangboo_transformed[lang])
with open('./src/idJson.json', 'w', encoding='utf-8') as f:
json.dump(transformed_data, f, ensure_ascii=False, indent=2)
print("Data successfully transformed and saved")
except requests.RequestException as e:
print(f"Error fetching data: {e}")
if __name__ == "__main__":
main()