mirror of
https://github.com/earthjasonlin/star-rail-warp-export.git
synced 2025-08-03 19:02:44 +08:00
[FEAT] UIGF v4 支持 (#72)
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
const { app, ipcMain, dialog } = require('electron')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const getData = require('./getData').getData
|
||||
const { version } = require('../../package.json')
|
||||
const i18n = require('./i18n')
|
||||
|
||||
const getTimeString = () => {
|
||||
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
|
||||
}
|
||||
|
||||
const formatDate = (date) => {
|
||||
let y = date.getFullYear()
|
||||
let m = `${date.getMonth()+1}`.padStart(2, '0')
|
||||
let d = `${date.getDate()}`.padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${date.toLocaleString('zh-cn', { hour12: false }).slice(-8)}`
|
||||
}
|
||||
|
||||
const start = async () => {
|
||||
const { dataMap, current } = await getData()
|
||||
const data = dataMap.get(current)
|
||||
if (!data.result.size) {
|
||||
throw new Error('数据为空')
|
||||
}
|
||||
const result = {
|
||||
info: {
|
||||
uid: data.uid,
|
||||
lang: data.lang,
|
||||
export_time: formatDate(new Date()),
|
||||
export_timestamp: Math.ceil(Date.now() / 1000),
|
||||
export_app: 'star-rail-warp-export',
|
||||
export_app_version: `v${version}`,
|
||||
region_time_zone: data.region_time_zone,
|
||||
srgf_version: 'v1.0'
|
||||
},
|
||||
list: []
|
||||
}
|
||||
const listTemp = []
|
||||
for (let [type, arr] of data.result) {
|
||||
arr.forEach(log => {
|
||||
listTemp.push({
|
||||
gacha_id: log.gacha_id,
|
||||
gacha_type: log.gacha_type,
|
||||
item_id: log.item_id,
|
||||
count: '1',
|
||||
time: log.time,
|
||||
name: log.name,
|
||||
item_type: log.item_type,
|
||||
rank_type: log.rank_type,
|
||||
id: log.id
|
||||
})
|
||||
})
|
||||
}
|
||||
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
|
||||
listTemp.forEach(item => {
|
||||
result.list.push({
|
||||
...item
|
||||
})
|
||||
})
|
||||
const filePath = dialog.showSaveDialogSync({
|
||||
defaultPath: path.join(app.getPath('downloads'), `SRGF_${data.uid}_${getTimeString()}`),
|
||||
filters: [
|
||||
{ name: i18n.srgf.fileType, extensions: ['json'] }
|
||||
]
|
||||
})
|
||||
if (filePath) {
|
||||
await fs.ensureFile(filePath)
|
||||
await fs.writeFile(filePath, JSON.stringify(result))
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.handle('EXPORT_SRGF_JSON', async () => {
|
||||
await start()
|
||||
})
|
174
src/main/UIGFJson.js
Normal file
174
src/main/UIGFJson.js
Normal file
@@ -0,0 +1,174 @@
|
||||
const { app, ipcMain, dialog } = require('electron')
|
||||
const fs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const { getData, saveData, changeCurrent, convertTimeZone } = require('./getData')
|
||||
const config = require('./config')
|
||||
const { name, version } = require('../../package.json')
|
||||
const i18n = require('./i18n')
|
||||
const { mergeData } = require('./utils/mergeData')
|
||||
const { sendMsg } = require('./utils')
|
||||
const idJson = require('../idJson.json')
|
||||
|
||||
const getTimeString = () => {
|
||||
return new Date().toLocaleString('sv').replace(/[- :]/g, '').slice(0, -2)
|
||||
}
|
||||
|
||||
const formatDate = (date) => {
|
||||
let y = date.getFullYear()
|
||||
let m = `${date.getMonth()+1}`.padStart(2, '0')
|
||||
let d = `${date.getDate()}`.padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${date.toLocaleString('zh-cn', { hour12: false }).slice(-8)}`
|
||||
}
|
||||
|
||||
const exportUIGF = async (uids) => {
|
||||
const { dataMap, current } = await getData()
|
||||
const result = {
|
||||
info: {
|
||||
export_timestamp: Math.ceil(Date.now() / 1000),
|
||||
export_app: `${name}`,
|
||||
export_app_version: `v${version}`,
|
||||
version: "v4.0"
|
||||
},
|
||||
hkrpg: []
|
||||
}
|
||||
let fulldata = []
|
||||
uids.forEach(uid => {
|
||||
fulldata.push(dataMap.get(uid))
|
||||
})
|
||||
if (!fulldata.length) {
|
||||
throw new Error('数据为空')
|
||||
}
|
||||
fulldata.forEach(data => {
|
||||
const listTemp = []
|
||||
for (let [type, arr] of data.result) {
|
||||
arr.forEach(log => {
|
||||
listTemp.push({
|
||||
gacha_id: log.gacha_id,
|
||||
gacha_type: log.gacha_type,
|
||||
item_id: log.item_id,
|
||||
count: log.count,
|
||||
time: log.time,
|
||||
name: log.name,
|
||||
item_type: log.item_type,
|
||||
rank_type: log.rank_type,
|
||||
id: log.id
|
||||
})
|
||||
})
|
||||
}
|
||||
listTemp.sort((a, b) => Number(BigInt(a.id) - BigInt(b.id)))
|
||||
let dataTemp = {
|
||||
uid: data.uid,
|
||||
timezone: data.region_time_zone,
|
||||
lang: data.lang,
|
||||
list: []
|
||||
}
|
||||
listTemp.forEach(item => {
|
||||
dataTemp.list.push({
|
||||
...item
|
||||
})
|
||||
})
|
||||
result.hkrpg.push(dataTemp)
|
||||
})
|
||||
const filePath = dialog.showSaveDialogSync({
|
||||
defaultPath: path.join(app.getPath('downloads'), fulldata.length > 1 ? `UIGF_${getTimeString()}` : `UIGF_${fulldata[0].uid}_${getTimeString()}`),
|
||||
filters: [
|
||||
{ name: i18n.uigf.fileType, extensions: ['json'] }
|
||||
]
|
||||
})
|
||||
if (filePath) {
|
||||
await fs.ensureFile(filePath)
|
||||
await fs.writeFile(filePath, JSON.stringify(result))
|
||||
}
|
||||
}
|
||||
|
||||
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.hkrpg.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: recordEntry.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) => {
|
||||
await exportUIGF(uids)
|
||||
})
|
||||
|
||||
ipcMain.handle('IMPORT_UIGF_JSON', async () => {
|
||||
return await importUIGF()
|
||||
})
|
@@ -29,6 +29,19 @@ const defaultTypeMap = new Map([
|
||||
['2', '新手跃迁']
|
||||
])
|
||||
|
||||
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 files = await readdir(dataPath)
|
||||
if (files?.length) {
|
||||
@@ -58,6 +71,13 @@ const readData = async () => {
|
||||
const data = await readJSON(dataPath, name)
|
||||
data.typeMap = new Map(data.typeMap) || defaultTypeMap
|
||||
data.result = new Map(data.result)
|
||||
data.result.forEach((value, key) => {
|
||||
value.forEach(item => {
|
||||
if (!('count' in item)) {
|
||||
item.count = "1";
|
||||
}
|
||||
});
|
||||
});
|
||||
if (data.uid) {
|
||||
dataMap.set(data.uid, data)
|
||||
}
|
||||
@@ -414,13 +434,21 @@ const fetchData = async (urlOverride) => {
|
||||
const lang = searchParams.get('lang')
|
||||
let originUid = ''
|
||||
let originRegion = ''
|
||||
let originTimeZone = ''
|
||||
let localTimeZone
|
||||
for (const type of gachaType) {
|
||||
const { list, uid, region, region_time_zone } = await getGachaLogs(type, queryString)
|
||||
await sleep(0.3)
|
||||
if (localTimeZone === undefined) {
|
||||
localTimeZone = dataMap.get(uid)?.region_time_zone
|
||||
if (localTimeZone === undefined) {
|
||||
localTimeZone = region_time_zone
|
||||
}
|
||||
}
|
||||
list.forEach(item => {
|
||||
item.time = convertTimeZone(item.time, region_time_zone, localTimeZone)
|
||||
})
|
||||
const logs = list.map((item) => {
|
||||
const { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type } = item
|
||||
return { id, item_id, item_type, name, rank_type, time, gacha_id, gacha_type }
|
||||
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 }
|
||||
})
|
||||
logs.reverse()
|
||||
typeMap.set(type.key, type.name)
|
||||
@@ -431,11 +459,8 @@ const fetchData = async (urlOverride) => {
|
||||
if (!originRegion) {
|
||||
originRegion = region
|
||||
}
|
||||
if (!originTimeZone) {
|
||||
originTimeZone = region_time_zone
|
||||
}
|
||||
}
|
||||
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region: originRegion, region_time_zone: originTimeZone }
|
||||
const data = { result, typeMap, time: Date.now(), uid: originUid, lang, region: originRegion, region_time_zone: localTimeZone }
|
||||
const localData = dataMap.get(originUid)
|
||||
const mergedResult = mergeData(localData, data)
|
||||
data.result = mergedResult
|
||||
@@ -518,3 +543,6 @@ exports.getData = () => {
|
||||
|
||||
exports.getUrl = getUrl
|
||||
exports.deleteData = deleteData
|
||||
exports.saveData = saveData
|
||||
exports.changeCurrent = changeCurrent
|
||||
exports.convertTimeZone = convertTimeZone
|
@@ -76,7 +76,7 @@ const parseText = (text, data) => {
|
||||
}
|
||||
|
||||
const mainProps = [
|
||||
'symbol', 'ui', 'log', 'excel',"srgf"
|
||||
'symbol', 'ui', 'log', 'excel',"uigf"
|
||||
]
|
||||
|
||||
const i18n = new Proxy(raw, {
|
||||
|
@@ -4,7 +4,7 @@ const { disableProxy, proxyStatus } = require('./module/system-proxy')
|
||||
require('./getData')
|
||||
require('./bridge')
|
||||
require('./excel')
|
||||
require('./SRGFJson')
|
||||
require('./UIGFJson')
|
||||
const { getUpdateInfo } = require('./update/index')
|
||||
|
||||
const isDev = !app.isPackaged
|
||||
|
Reference in New Issue
Block a user