mirror of
https://github.com/earthjasonlin/zzz-signal-search-export.git
synced 2025-08-04 19:20:08 +08:00
v1.0.0
This commit is contained in:
@@ -28,7 +28,7 @@ const start = async () => {
|
||||
lang: data.lang,
|
||||
export_time: formatDate(new Date()),
|
||||
export_timestamp: Math.ceil(Date.now() / 1000),
|
||||
export_app: 'star-rail-warp-export',
|
||||
export_app: 'zzz-signal-search-export',
|
||||
export_app_version: `v${version}`,
|
||||
region_time_zone: data.region_time_zone,
|
||||
srgf_version: 'v1.0'
|
||||
|
@@ -12,8 +12,8 @@ const { mergeData } = require('./utils/mergeData')
|
||||
const gachaTypeRaw = require('../gachaType.json')
|
||||
|
||||
const dataMap = new Map()
|
||||
const order = ['11', '12', '1', '2']
|
||||
let apiDomain = 'https://api-takumi.mihoyo.com'
|
||||
const order = ['2', '3', '1', '5']
|
||||
let apiDomain = 'https://public-operation-nap.mihoyo.com'
|
||||
|
||||
const saveData = async (data, url) => {
|
||||
const obj = Object.assign({}, data)
|
||||
@@ -23,10 +23,10 @@ const saveData = async (data, url) => {
|
||||
}
|
||||
|
||||
const defaultTypeMap = new Map([
|
||||
['11', '角色活动跃迁'],
|
||||
['12', '光锥活动跃迁'],
|
||||
['1', '常驻跃迁'],
|
||||
['2', '新手跃迁']
|
||||
['2', '独家频段'],
|
||||
['3', '音擎频段'],
|
||||
['1', '常驻频段'],
|
||||
['5', '邦布频段']
|
||||
])
|
||||
|
||||
const findDataFiles = async (dataPath, fileMap) => {
|
||||
@@ -86,7 +86,7 @@ const changeCurrent = async (uid) => {
|
||||
const detectGameLocale = async (userPath) => {
|
||||
let list = []
|
||||
const lang = app.getLocale()
|
||||
const arr = ['/miHoYo/崩坏:星穹铁道/', '/Cognosphere/Star Rail/']
|
||||
const arr = ['/miHoYo/绝区零/', '/Cognosphere/Zenless Zone Zero/']
|
||||
arr.forEach(str => {
|
||||
try {
|
||||
const pathname = path.join(userPath, '/AppData/LocalLow/', str, 'Player.log')
|
||||
@@ -165,7 +165,7 @@ const readLog = async () => {
|
||||
const getGachaLog = async ({ key, page, name, retryCount, url, endId }) => {
|
||||
const text = i18n.log
|
||||
try {
|
||||
const res = await request(`${url}&gacha_type=${key}&page=${page}&size=${20}${endId ? '&end_id=' + endId : ''}`)
|
||||
const res = await request(`${url}&real_gacha_type=${key}&page=${page}&size=${20}${endId ? '&end_id=' + endId : ''}`)
|
||||
if (res?.data?.list) {
|
||||
return res?.data
|
||||
}
|
||||
@@ -262,7 +262,7 @@ const tryGetUid = async (queryString) => {
|
||||
const url = `${apiDomain}/common/gacha_record/api/getGachaLog?${queryString}`
|
||||
try {
|
||||
for (let [key] of defaultTypeMap) {
|
||||
const res = await request(`${url}&gacha_type=${key}&page=1&size=6`)
|
||||
const res = await request(`${url}&real_gacha_type=${key}&page=1&size=6`)
|
||||
if (res.data.list && res.data.list.length) {
|
||||
return res.data.list[0].uid
|
||||
}
|
||||
@@ -291,7 +291,7 @@ const getQuerystring = (url) => {
|
||||
if (host.includes('webstatic-sea') || host.includes('hkrpg-api-os') || host.includes('api-os-takumi') || host.includes('hoyoverse.com')) {
|
||||
apiDomain = 'https://api-os-takumi.mihoyo.com'
|
||||
} else {
|
||||
apiDomain = 'https://api-takumi.mihoyo.com'
|
||||
apiDomain = 'https://public-operation-nap.mihoyo.com'
|
||||
}
|
||||
const authkey = searchParams.get('authkey')
|
||||
if (!authkey) {
|
||||
@@ -300,7 +300,7 @@ const getQuerystring = (url) => {
|
||||
}
|
||||
searchParams.delete('page')
|
||||
searchParams.delete('size')
|
||||
searchParams.delete('gacha_type')
|
||||
searchParams.delete('real_gacha_type')
|
||||
searchParams.delete('end_id')
|
||||
return searchParams
|
||||
}
|
||||
@@ -357,7 +357,7 @@ const getUrlFromConfig = () => {
|
||||
const tryRequest = async (url, retry = false) => {
|
||||
const queryString = getQuerystring(url)
|
||||
if (!queryString) return 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&real_gacha_type=1&end_id=0`
|
||||
try {
|
||||
const res = await request(gachaTypeUrl)
|
||||
checkResStatus(res)
|
||||
|
@@ -1,17 +1,7 @@
|
||||
const raw = {
|
||||
'zh-cn': require('../i18n/简体中文.json'),
|
||||
'zh-tw': require('../i18n/繁體中文.json'),
|
||||
'de-de': require('../i18n/Deutsch.json'),
|
||||
'en-us': require('../i18n/English.json'),
|
||||
'es-es': require('../i18n/Español.json'),
|
||||
'fr-fr': require('../i18n/Français.json'),
|
||||
'id-id': require('../i18n/Indonesia.json'),
|
||||
'ja-jp': require('../i18n/日本語.json'),
|
||||
'ko-kr': require('../i18n/한국어.json'),
|
||||
'pt-pt': require('../i18n/Português.json'),
|
||||
'ru-ru': require('../i18n/Pусский.json'),
|
||||
'th-th': require('../i18n/ภาษาไทย.json'),
|
||||
'vi-vn': require('../i18n/Tiếng Việt.json')
|
||||
'en-us': require('../i18n/English.json')
|
||||
}
|
||||
const config = require('./config')
|
||||
const isPlainObject = require('lodash/isPlainObject')
|
||||
|
@@ -5,7 +5,6 @@ require('./getData')
|
||||
require('./bridge')
|
||||
require('./excel')
|
||||
require('./SRGFJson')
|
||||
const { getUpdateInfo } = require('./update/index')
|
||||
|
||||
const isDev = !app.isPackaged
|
||||
let win = null
|
||||
@@ -54,12 +53,6 @@ if (!isFirstInstance) {
|
||||
if (proxyStatus.started) {
|
||||
disableProxy()
|
||||
}
|
||||
if (getUpdateInfo().status === 'moving') {
|
||||
e.preventDefault()
|
||||
setTimeout(() => {
|
||||
app.quit()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
app.on('quit', () => {
|
||||
|
@@ -1,185 +0,0 @@
|
||||
// Copyright (c) 2014 Max Ogden and other contributors
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// * Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// https://github.com/maxogden/extract-zip
|
||||
// eslint-disable-next-line node/no-unsupported-features/node-builtins
|
||||
const { createWriteStream, promises: fs } = require('original-fs')
|
||||
const getStream = require('get-stream')
|
||||
const path = require('path')
|
||||
const { promisify } = require('util')
|
||||
const stream = require('stream')
|
||||
const yauzl = require('yauzl')
|
||||
|
||||
const openZip = promisify(yauzl.open)
|
||||
const pipeline = promisify(stream.pipeline)
|
||||
|
||||
class Extractor {
|
||||
constructor (zipPath, opts) {
|
||||
this.zipPath = zipPath
|
||||
this.opts = opts
|
||||
}
|
||||
|
||||
async extract () {
|
||||
|
||||
this.zipfile = await openZip(this.zipPath, { lazyEntries: true })
|
||||
this.canceled = false
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.zipfile.on('error', err => {
|
||||
this.canceled = true
|
||||
reject(err)
|
||||
})
|
||||
this.zipfile.readEntry()
|
||||
|
||||
this.zipfile.on('close', () => {
|
||||
if (!this.canceled) {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
|
||||
this.zipfile.on('entry', async entry => {
|
||||
/* istanbul ignore if */
|
||||
if (this.canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (entry.fileName.startsWith('__MACOSX/')) {
|
||||
this.zipfile.readEntry()
|
||||
return
|
||||
}
|
||||
|
||||
const destDir = path.dirname(path.join(this.opts.dir, entry.fileName))
|
||||
|
||||
try {
|
||||
await fs.mkdir(destDir, { recursive: true })
|
||||
|
||||
const canonicalDestDir = await fs.realpath(destDir)
|
||||
const relativeDestDir = path.relative(this.opts.dir, canonicalDestDir)
|
||||
|
||||
if (relativeDestDir.split(path.sep).includes('..')) {
|
||||
throw new Error(`Out of bound path "${canonicalDestDir}" found while processing file ${entry.fileName}`)
|
||||
}
|
||||
|
||||
await this.extractEntry(entry)
|
||||
this.zipfile.readEntry()
|
||||
} catch (err) {
|
||||
this.canceled = true
|
||||
this.zipfile.close()
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async extractEntry (entry) {
|
||||
/* istanbul ignore if */
|
||||
if (this.canceled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.opts.onEntry) {
|
||||
this.opts.onEntry(entry, this.zipfile)
|
||||
}
|
||||
|
||||
const dest = path.join(this.opts.dir, entry.fileName)
|
||||
|
||||
// convert external file attr int into a fs stat mode int
|
||||
const mode = (entry.externalFileAttributes >> 16) & 0xFFFF
|
||||
// check if it's a symlink or dir (using stat mode constants)
|
||||
const IFMT = 61440
|
||||
const IFDIR = 16384
|
||||
const IFLNK = 40960
|
||||
const symlink = (mode & IFMT) === IFLNK
|
||||
let isDir = (mode & IFMT) === IFDIR
|
||||
|
||||
// Failsafe, borrowed from jsZip
|
||||
if (!isDir && entry.fileName.endsWith('/')) {
|
||||
isDir = true
|
||||
}
|
||||
|
||||
// check for windows weird way of specifying a directory
|
||||
// https://github.com/maxogden/extract-zip/issues/13#issuecomment-154494566
|
||||
const madeBy = entry.versionMadeBy >> 8
|
||||
if (!isDir) isDir = (madeBy === 0 && entry.externalFileAttributes === 16)
|
||||
|
||||
|
||||
const procMode = this.getExtractedMode(mode, isDir) & 0o777
|
||||
|
||||
// always ensure folders are created
|
||||
const destDir = isDir ? dest : path.dirname(dest)
|
||||
|
||||
const mkdirOptions = { recursive: true }
|
||||
if (isDir) {
|
||||
mkdirOptions.mode = procMode
|
||||
}
|
||||
await fs.mkdir(destDir, mkdirOptions)
|
||||
if (isDir) return
|
||||
|
||||
const readStream = await promisify(this.zipfile.openReadStream.bind(this.zipfile))(entry)
|
||||
|
||||
if (symlink) {
|
||||
const link = await getStream(readStream)
|
||||
await fs.symlink(link, dest)
|
||||
} else {
|
||||
await pipeline(readStream, createWriteStream(dest, { mode: procMode }))
|
||||
}
|
||||
}
|
||||
|
||||
getExtractedMode (entryMode, isDir) {
|
||||
let mode = entryMode
|
||||
// Set defaults, if necessary
|
||||
if (mode === 0) {
|
||||
if (isDir) {
|
||||
if (this.opts.defaultDirMode) {
|
||||
mode = parseInt(this.opts.defaultDirMode, 10)
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
mode = 0o755
|
||||
}
|
||||
} else {
|
||||
if (this.opts.defaultFileMode) {
|
||||
mode = parseInt(this.opts.defaultFileMode, 10)
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
mode = 0o644
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function (zipPath, opts) {
|
||||
|
||||
if (!path.isAbsolute(opts.dir)) {
|
||||
throw new Error('Target directory is expected to be absolute')
|
||||
}
|
||||
|
||||
await fs.mkdir(opts.dir, { recursive: true })
|
||||
opts.dir = await fs.realpath(opts.dir)
|
||||
return new Extractor(zipPath, opts).extract()
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
const { app } = require('electron')
|
||||
const fetch = require('electron-fetch').default
|
||||
const semver = require('semver')
|
||||
const util = require('util')
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const extract = require('../module/extract-zip')
|
||||
const { version } = require('../../../package.json')
|
||||
const { hash, sendMsg } = require('../utils')
|
||||
const config = require('../config')
|
||||
const i18n = require('../i18n')
|
||||
const streamPipeline = util.promisify(require('stream').pipeline)
|
||||
|
||||
async function download(url, filePath) {
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) throw new Error(`unexpected response ${response.statusText}`)
|
||||
await streamPipeline(response.body, fs.createWriteStream(filePath))
|
||||
}
|
||||
|
||||
const updateInfo = {
|
||||
status: 'init'
|
||||
}
|
||||
|
||||
const isDev = !app.isPackaged
|
||||
const appPath = isDev ? path.resolve(__dirname, '../../', 'update-dev/app'): app.getAppPath()
|
||||
const updatePath = isDev ? path.resolve(__dirname, '../../', 'update-dev/download') : path.resolve(appPath, '..', '..', 'update')
|
||||
|
||||
const update = async () => {
|
||||
if (isDev) return
|
||||
try {
|
||||
const url = 'https://star-rail-warp-export.css.moe/update'
|
||||
const res = await fetch(`${url}/manifest.json?t=${Math.floor(Date.now() / (1000 * 60 * 10))}`)
|
||||
const data = await res.json()
|
||||
if (!data.active) return
|
||||
if (semver.gt(data.version, version) && semver.gte(version, data.from)) {
|
||||
await fs.emptyDir(updatePath)
|
||||
const filePath = path.join(updatePath, data.name)
|
||||
if (!config.autoUpdate) {
|
||||
sendMsg(data.version, 'NEW_VERSION')
|
||||
return
|
||||
}
|
||||
updateInfo.status = 'downloading'
|
||||
await download(`${url}/${data.name}`, filePath)
|
||||
const buffer = await fs.readFile(filePath)
|
||||
const sha256 = hash(buffer)
|
||||
if (sha256 !== data.hash) return
|
||||
const appPathTemp = path.join(updatePath, 'app')
|
||||
await extract(filePath, { dir: appPathTemp })
|
||||
updateInfo.status = 'moving'
|
||||
await fs.emptyDir(appPath)
|
||||
await fs.copy(appPathTemp, appPath)
|
||||
updateInfo.status = 'finished'
|
||||
sendMsg(i18n.log.autoUpdate.success, 'UPDATE_HINT')
|
||||
}
|
||||
} catch (e) {
|
||||
updateInfo.status = 'failed'
|
||||
sendMsg(e, 'ERROR')
|
||||
}
|
||||
}
|
||||
|
||||
const getUpdateInfo = () => updateInfo
|
||||
|
||||
setTimeout(update, 1000)
|
||||
|
||||
exports.getUpdateInfo = getUpdateInfo
|
@@ -103,33 +103,13 @@ const sortData = (data) => {
|
||||
const langMap = new Map([
|
||||
['zh-cn', '简体中文'],
|
||||
['zh-tw', '繁體中文'],
|
||||
['de-de', 'Deutsch'],
|
||||
['en-us', 'English'],
|
||||
['es-es', 'Español'],
|
||||
['fr-fr', 'Français'],
|
||||
['id-id', 'Indonesia'],
|
||||
['ja-jp', '日本語'],
|
||||
['ko-kr', '한국어'],
|
||||
['pt-pt', 'Português'],
|
||||
['ru-ru', 'Pусский'],
|
||||
['th-th', 'ภาษาไทย'],
|
||||
['vi-vn', 'Tiếng Việt']
|
||||
['en-us', 'English']
|
||||
])
|
||||
|
||||
const localeMap = new Map([
|
||||
['zh-cn', ['zh', 'zh-CN']],
|
||||
['zh-tw', ['zh-TW']],
|
||||
['de-de', ['de-AT', 'de-CH', 'de-DE', 'de']],
|
||||
['en-us', ['en-AU', 'en-CA', 'en-GB', 'en-NZ', 'en-US', 'en-ZA', 'en']],
|
||||
['es-es', ['es', 'es-419']],
|
||||
['fr-fr', ['fr-CA', 'fr-CH', 'fr-FR', 'fr']],
|
||||
['id-id', ['id']],
|
||||
['ja-jp', ['ja']],
|
||||
['ko-kr', ['ko']],
|
||||
['pt-pt', ['pt-BR', 'pt-PT', 'pt']],
|
||||
['ru-ru', ['ru']],
|
||||
['th-th', ['th']],
|
||||
['vi-vn', ['vi']]
|
||||
['en-us', ['en-AU', 'en-CA', 'en-GB', 'en-NZ', 'en-US', 'en-ZA', 'en']]
|
||||
])
|
||||
|
||||
const detectLocale = (value) => {
|
||||
|
Reference in New Issue
Block a user