mirror of
https://github.com/earthjasonlin/zzz-signal-search-export.git
synced 2025-04-21 16:00:17 +08:00
Compare commits
17 Commits
14cfda3986
...
v1.1.6
Author | SHA1 | Date | |
---|---|---|---|
5a3159d4cb
|
|||
38b99bf4dc
|
|||
0cd9c071d7
|
|||
bf582d0194
|
|||
5dec6a8273
|
|||
0e429a4762
|
|||
5164a17dca
|
|||
a660c03bb5
|
|||
d7457f2bfb
|
|||
223ab899e0
|
|||
f62ca1d7e7
|
|||
c034b2e70a
|
|||
a2faa86f0c
|
|||
510bfdab7a
|
|||
f616944755
|
|||
7300c6e719
|
|||
6fe12da9be
|
@ -2,7 +2,7 @@ const fs = require('fs-extra')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const AdmZip = require('adm-zip')
|
const AdmZip = require('adm-zip')
|
||||||
const { version } = require('../package.json')
|
const { version, autoUpdateActive, autoUpdateFrom } = require('../package.json')
|
||||||
|
|
||||||
const hash = (data, type = 'sha256') => {
|
const hash = (data, type = 'sha256') => {
|
||||||
const hmac = crypto.createHmac(type, 'nap')
|
const hmac = crypto.createHmac(type, 'nap')
|
||||||
@ -32,9 +32,9 @@ const start = async () => {
|
|||||||
await fs.copy(zipPath, path.resolve(outputPath, `${hashName}.zip`))
|
await fs.copy(zipPath, path.resolve(outputPath, `${hashName}.zip`))
|
||||||
await fs.remove(zipPath)
|
await fs.remove(zipPath)
|
||||||
await fs.outputJSON(path.join(outputPath, 'manifest.json'), {
|
await fs.outputJSON(path.join(outputPath, 'manifest.json'), {
|
||||||
active: true,
|
active: autoUpdateActive,
|
||||||
version,
|
version: version,
|
||||||
from: '0.0.1',
|
from: autoUpdateFrom,
|
||||||
name: `${hashName}.zip`,
|
name: `${hashName}.zip`,
|
||||||
hash: sha256
|
hash: sha256
|
||||||
})
|
})
|
||||||
|
@ -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. 打开游戏的调频详情页面
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
如果需要导出多个账号的数据,可以点击旁边的加号按钮。
|
如果需要导出多个账号的数据,可以点击旁边的加号按钮。
|
||||||
|
|
||||||
然后游戏切换的新账号,再打开跃迁历史记录,工具再点击“加载数据”按钮。
|
然后游戏切换的新账号,再打开调频历史记录,工具再点击“加载数据”按钮。
|
||||||
|
|
||||||
## Devlopment
|
## Devlopment
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "zzz-signal-search-export",
|
"name": "zzz-signal-search-export",
|
||||||
"version": "1.0.10",
|
"version": "1.1.6",
|
||||||
|
"autoUpdateActive": true,
|
||||||
|
"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>",
|
||||||
"homepage": "https://github.com/earthjasonlin/zzz-signal-search-export",
|
"homepage": "https://github.com/earthjasonlin/zzz-signal-search-export",
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
"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 (Beta)",
|
"ui.button.uigf": "Export UIGF",
|
||||||
|
"ui.button.import": "Import UIGF",
|
||||||
"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",
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
"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 (Beta)",
|
"ui.button.uigf":"导出UIGF",
|
||||||
|
"ui.button.import":"导入UIGF",
|
||||||
"ui.button.url": "输入URL",
|
"ui.button.url": "输入URL",
|
||||||
"ui.button.setting": "设置",
|
"ui.button.setting": "设置",
|
||||||
"ui.button.option": "选项",
|
"ui.button.option": "选项",
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
"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 (Beta)",
|
"ui.button.uigf":"導出UIGF",
|
||||||
|
"ui.button.import":"導入UIGF",
|
||||||
"ui.button.url": "輸入URL",
|
"ui.button.url": "輸入URL",
|
||||||
"ui.button.setting": "設置",
|
"ui.button.setting": "設置",
|
||||||
"ui.button.option": "選項",
|
"ui.button.option": "選項",
|
||||||
|
2487
src/idJson.json
Normal file
2487
src/idJson.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,13 @@
|
|||||||
const { app, ipcMain, dialog } = require('electron')
|
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 getData = require('./getData').getData
|
const { getData, saveData, changeCurrent, convertTimeZone } = require('./getData')
|
||||||
|
const config = require('./config')
|
||||||
const { name, version } = require('../../package.json')
|
const { name, version } = require('../../package.json')
|
||||||
const i18n = require('./i18n')
|
const i18n = require('./i18n')
|
||||||
const { exit } = require('process')
|
const { mergeData } = require('./utils/mergeData')
|
||||||
|
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)
|
||||||
@ -16,8 +19,7 @@ const formatDate = (date) => {
|
|||||||
let d = `${date.getDate()}`.padStart(2, '0')
|
let d = `${date.getDate()}`.padStart(2, '0')
|
||||||
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 exportUIGF = async (uids) => {
|
||||||
const start = async (uids) => {
|
|
||||||
const result = {
|
const result = {
|
||||||
info: {
|
info: {
|
||||||
export_timestamp: Math.ceil(Date.now() / 1000),
|
export_timestamp: Math.ceil(Date.now() / 1000),
|
||||||
@ -35,16 +37,7 @@ const start = async (uids) => {
|
|||||||
if (!fulldata.length) {
|
if (!fulldata.length) {
|
||||||
throw new Error('数据为空')
|
throw new Error('数据为空')
|
||||||
}
|
}
|
||||||
const serverTimeZone = new Map([
|
|
||||||
["prod_gf_cn", 8],
|
|
||||||
["prod_gf_jp", 8]
|
|
||||||
])
|
|
||||||
fulldata.forEach(data => {
|
fulldata.forEach(data => {
|
||||||
let timezone
|
|
||||||
timezone = serverTimeZone.get(data.region)
|
|
||||||
if(!timezone) {
|
|
||||||
throw new Error('不支持此服务器')
|
|
||||||
}
|
|
||||||
const listTemp = []
|
const listTemp = []
|
||||||
for (let [type, arr] of data.result) {
|
for (let [type, arr] of data.result) {
|
||||||
arr.forEach(log => {
|
arr.forEach(log => {
|
||||||
@ -64,7 +57,7 @@ const start = async (uids) => {
|
|||||||
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
|
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
|
||||||
let dataTemp = {
|
let dataTemp = {
|
||||||
uid: data.uid,
|
uid: data.uid,
|
||||||
timezone: timezone,
|
timezone: data.region_time_zone,
|
||||||
lang: data.lang,
|
lang: data.lang,
|
||||||
list: []
|
list: []
|
||||||
}
|
}
|
||||||
@ -87,6 +80,95 @@ const start = async (uids) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const importUIGF = async () => {
|
||||||
|
const filepath = await dialog.showOpenDialogSync({
|
||||||
|
properties: ['openFile'],
|
||||||
|
filters: [
|
||||||
|
{ name: i18n.uigf.fileType, extensions: ['json'] }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
if (!filepath) return
|
||||||
|
const { dataMap, current } = await getData()
|
||||||
|
try {
|
||||||
|
const jsonData = fs.readJsonSync(filepath[0])
|
||||||
|
if('info' in jsonData && 'version' in jsonData.info) {
|
||||||
|
if (jsonData.info.version !== 'v4.0') {
|
||||||
|
sendMsg('不支持此版本UIGF')
|
||||||
|
console.error('不支持此版本UIGF')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendMsg('UIGF格式错误')
|
||||||
|
console.error('UIGF格式错误')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonData.nap.forEach(uidData => {
|
||||||
|
const resultTemp = []
|
||||||
|
const isNew = !Boolean(dataMap.has(uidData.uid))
|
||||||
|
|
||||||
|
let region_time_zone
|
||||||
|
if (!isNew) region_time_zone = dataMap.get(uidData.uid).region_time_zone
|
||||||
|
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 => {
|
||||||
|
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({
|
||||||
|
gacha_id: recordEntry.gacha_id,
|
||||||
|
gacha_type: recordEntry.gacha_type,
|
||||||
|
item_id: recordEntry.item_id,
|
||||||
|
count: recordEntry.count ?? "1",
|
||||||
|
time: convertTimeZone(recordEntry.time, uidData.timezone, region_time_zone),
|
||||||
|
name: idTargetLangJson?.[recordEntry.item_id].name ?? recordEntry.name,
|
||||||
|
item_type: idTargetLangJson?.[recordEntry.item_id].item_type ?? recordEntry.item_type,
|
||||||
|
rank_type: rank_type,
|
||||||
|
id: recordEntry.id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const resultTempGrouped = resultTemp.reduce((acc, curr) => {
|
||||||
|
if (!acc[curr.gacha_type]) {
|
||||||
|
acc[curr.gacha_type] = []
|
||||||
|
}
|
||||||
|
acc[curr.gacha_type].push(curr)
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
const resultTempMap = new Map(Object.entries(resultTempGrouped))
|
||||||
|
const resultMap = { result: resultTempMap, uid: uidData.uid}
|
||||||
|
let data
|
||||||
|
const mergedData = mergeData(dataMap.get(uidData.uid), resultMap)
|
||||||
|
if (isNew) {
|
||||||
|
data = { result: mergedData, time: Date.now(), uid: uidData.uid, lang: targetLang, region_time_zone: uidData.timezone, deleted: false }
|
||||||
|
} else {
|
||||||
|
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, '')
|
||||||
|
changeCurrent(uidData.uid)
|
||||||
|
dataMap.set(uidData.uid, data)
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
dataMap,
|
||||||
|
current: config.current
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
sendMsg(error, 'ERROR')
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.handle('EXPORT_UIGF_JSON', async (event, uids) => {
|
ipcMain.handle('EXPORT_UIGF_JSON', async (event, uids) => {
|
||||||
await start(uids)
|
await exportUIGF(uids)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('IMPORT_UIGF_JSON', async () => {
|
||||||
|
return await importUIGF()
|
||||||
})
|
})
|
@ -29,6 +29,27 @@ const defaultTypeMap = new Map([
|
|||||||
['5', '邦布频段']
|
['5', '邦布频段']
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const serverTimeZone = new Map([
|
||||||
|
["prod_gf_cn", 8],
|
||||||
|
["prod_gf_jp", 8],
|
||||||
|
["prod_gf_us", -5],
|
||||||
|
["prod_gf_eu", 1],
|
||||||
|
["prod_gf_sg", 8]
|
||||||
|
])
|
||||||
|
|
||||||
|
const convertTimeZone = (dateTimeStr, fromTimeZoneOffset, toTimeZoneOffset) => {
|
||||||
|
let date = new Date(dateTimeStr.replace(' ', 'T') + 'Z');
|
||||||
|
let utcDate = new Date(date.getTime() - fromTimeZoneOffset * 60 * 60 * 1000);
|
||||||
|
let targetDate = new Date(utcDate.getTime() + toTimeZoneOffset * 60 * 60 * 1000);
|
||||||
|
let year = targetDate.getUTCFullYear();
|
||||||
|
let month = String(targetDate.getUTCMonth() + 1).padStart(2, '0');
|
||||||
|
let day = String(targetDate.getUTCDate()).padStart(2, '0');
|
||||||
|
let hours = String(targetDate.getUTCHours()).padStart(2, '0');
|
||||||
|
let minutes = String(targetDate.getUTCMinutes()).padStart(2, '0');
|
||||||
|
let seconds = String(targetDate.getUTCSeconds()).padStart(2, '0');
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
const findDataFiles = async (dataPath, fileMap) => {
|
const findDataFiles = async (dataPath, fileMap) => {
|
||||||
const files = await readdir(dataPath)
|
const files = await readdir(dataPath)
|
||||||
if (files?.length) {
|
if (files?.length) {
|
||||||
@ -93,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')
|
||||||
@ -203,7 +224,6 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
let logs = []
|
let logs = []
|
||||||
let uid = ''
|
let uid = ''
|
||||||
let region = ''
|
let region = ''
|
||||||
let region_time_zone = ''
|
|
||||||
let endId = '0'
|
let endId = '0'
|
||||||
const url = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}`
|
const url = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}`
|
||||||
do {
|
do {
|
||||||
@ -221,9 +241,6 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
if (!region) {
|
if (!region) {
|
||||||
region = res.region
|
region = res.region
|
||||||
}
|
}
|
||||||
if (!region_time_zone) {
|
|
||||||
region_time_zone = res.region_time_zone
|
|
||||||
}
|
|
||||||
list.push(...logs)
|
list.push(...logs)
|
||||||
page += 1
|
page += 1
|
||||||
|
|
||||||
@ -252,7 +269,7 @@ const getGachaLogs = async ({ name, key }, queryString) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (logs.length > 0)
|
} while (logs.length > 0)
|
||||||
return { list, uid, region, region_time_zone }
|
return { list, uid, region }
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkResStatus = (res) => {
|
const checkResStatus = (res) => {
|
||||||
@ -425,10 +442,25 @@ const fetchData = async (urlOverride) => {
|
|||||||
const typeMap = new Map()
|
const typeMap = new Map()
|
||||||
const lang = searchParams.get('lang')
|
const lang = searchParams.get('lang')
|
||||||
let originUid = ''
|
let originUid = ''
|
||||||
let originRegion = ''
|
let localTimeZone
|
||||||
let originTimeZone = ''
|
|
||||||
for (const type of gachaType) {
|
for (const type of gachaType) {
|
||||||
const { list, uid, region, region_time_zone } = await getGachaLogs(type, queryString)
|
const { list, uid, region} = await getGachaLogs(type, queryString)
|
||||||
|
const region_time_zone = serverTimeZone.get(region)
|
||||||
|
if(!region_time_zone) {
|
||||||
|
sendMsg('不支持此服务器')
|
||||||
|
console.error('不支持此服务器')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (localTimeZone === undefined) {
|
||||||
|
localTimeZone = dataMap.get(uid)?.region_time_zone
|
||||||
|
if (localTimeZone === undefined) {
|
||||||
|
localTimeZone = region_time_zone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localTimeZone === Number(localTimeZone)
|
||||||
|
list.forEach(item => {
|
||||||
|
item.time = convertTimeZone(item.time, region_time_zone, localTimeZone)
|
||||||
|
})
|
||||||
const logs = list.map((item) => {
|
const logs = list.map((item) => {
|
||||||
const { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count} = item
|
const { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count} = item
|
||||||
return { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count }
|
return { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type, count }
|
||||||
@ -439,14 +471,8 @@ const fetchData = async (urlOverride) => {
|
|||||||
if (!originUid) {
|
if (!originUid) {
|
||||||
originUid = uid
|
originUid = uid
|
||||||
}
|
}
|
||||||
if (!originRegion) {
|
|
||||||
originRegion = region
|
|
||||||
}
|
}
|
||||||
if (!originTimeZone) {
|
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region_time_zone: localTimeZone }
|
||||||
originTimeZone = region_time_zone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
||||||
@ -527,5 +553,9 @@ exports.getData = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.serverTimeZone = serverTimeZone
|
||||||
exports.getUrl = getUrl
|
exports.getUrl = getUrl
|
||||||
exports.deleteData = deleteData
|
exports.deleteData = deleteData
|
||||||
|
exports.saveData = saveData
|
||||||
|
exports.changeCurrent = changeCurrent
|
||||||
|
exports.convertTimeZone = convertTimeZone
|
@ -12,6 +12,7 @@
|
|||||||
<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>
|
||||||
@ -272,11 +273,25 @@ const exportUIGFJSON = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const importData = async () => {
|
||||||
|
state.status = 'loading'
|
||||||
|
const data = await ipcRenderer.invoke('IMPORT_UIGF_JSON')
|
||||||
|
if (data) {
|
||||||
|
state.dataMap = data.dataMap
|
||||||
|
state.current = data.current
|
||||||
|
state.status = 'loaded'
|
||||||
|
} else {
|
||||||
|
state.status = 'failed'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const exportCommand = (type) => {
|
const exportCommand = (type) => {
|
||||||
if (type === 'excel') {
|
if (type === 'excel') {
|
||||||
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 () => {
|
||||||
|
@ -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
77
tools/getIdMap.py
Normal 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()
|
Reference in New Issue
Block a user