mirror of
https://github.com/earthjasonlin/zzz-signal-search-export.git
synced 2025-04-20 23:50:17 +08:00
209 lines
5.3 KiB
JavaScript
209 lines
5.3 KiB
JavaScript
const fs = require('fs-extra')
|
||
const path = require('path')
|
||
const fetch = require('electron-fetch').default
|
||
const { BrowserWindow, app } = require('electron')
|
||
const crypto = require('crypto')
|
||
const unhandled = require('electron-unhandled')
|
||
const windowStateKeeper = require('electron-window-state')
|
||
const debounce = require('lodash/debounce')
|
||
|
||
const isDev = !app.isPackaged
|
||
|
||
const userPath = app.getPath('userData')
|
||
const appRoot = isDev ? path.resolve(__dirname, '..', '..') : path.resolve(app.getAppPath(), '..', '..')
|
||
const userDataPath = path.resolve(appRoot, 'userData')
|
||
const globalUserDataPath = path.resolve(userPath, 'userData')
|
||
|
||
let win = null
|
||
const initWindow = () => {
|
||
let mainWindowState = windowStateKeeper({
|
||
defaultWidth: 888,
|
||
defaultHeight: 550
|
||
})
|
||
win = new BrowserWindow({
|
||
x: mainWindowState.x,
|
||
y: mainWindowState.y,
|
||
width: mainWindowState.width,
|
||
height: mainWindowState.height,
|
||
backgroundColor: '#fff',
|
||
webPreferences: {
|
||
contextIsolation:false,
|
||
nodeIntegration: true
|
||
}
|
||
})
|
||
const saveState = debounce(mainWindowState.saveState, 500)
|
||
win.on('resize', () => saveState(win))
|
||
win.on('move', () => saveState(win))
|
||
return win
|
||
}
|
||
|
||
const getWin = () => win
|
||
|
||
const log = []
|
||
const sendMsg = (text, type = 'LOAD_DATA_STATUS') => {
|
||
if (win) {
|
||
win.webContents.send(type, text)
|
||
}
|
||
if (type !== 'LOAD_DATA_STATUS') {
|
||
log.push([Date.now(), type, text])
|
||
saveLog()
|
||
}
|
||
}
|
||
|
||
const saveLog = () => {
|
||
const text = log.map(item => {
|
||
const time = new Date(item[0]).toLocaleString()
|
||
const type = item[1] === 'LOAD_DATA_STATUS' ? 'INFO' : item[1]
|
||
const text = item[2]
|
||
return `[${type}][${time}]${text}`
|
||
}).join('\r\n')
|
||
fs.outputFile(path.join(userDataPath, 'log.txt'), text)
|
||
}
|
||
|
||
const authkeyMask = (text = '') => {
|
||
return text.replace(/authkey=[^&]+&/g, 'authkey=***&')
|
||
}
|
||
|
||
unhandled({
|
||
showDialog: false,
|
||
logger: function (err) {
|
||
log.push([Date.now(), 'ERROR', authkeyMask(err.stack)])
|
||
saveLog()
|
||
}
|
||
})
|
||
|
||
const request = async (url) => {
|
||
const res = await fetch(url, {
|
||
timeout: 15 * 1000
|
||
})
|
||
return await res.json()
|
||
}
|
||
|
||
const sleep = (sec = 1) => {
|
||
return new Promise(rev => {
|
||
setTimeout(rev, sec * 1000)
|
||
})
|
||
}
|
||
|
||
const sortData = (data) => {
|
||
return data.map(item => {
|
||
const [time, name, type, rank] = item
|
||
return {
|
||
time, name, type, rank,
|
||
timestamp: new Date(time)
|
||
}
|
||
}).sort((a, b) => a.timestamp - b.timestamp)
|
||
.map(item => {
|
||
const { time, name, type, rank } = item
|
||
return [time, name, type, rank]
|
||
})
|
||
}
|
||
|
||
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']
|
||
])
|
||
|
||
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']]
|
||
])
|
||
|
||
const detectLocale = (value) => {
|
||
const locale = value || app.getLocale()
|
||
let result = 'zh-cn'
|
||
for (let [key, list] of localeMap) {
|
||
if (locale === key || list.includes(locale)) {
|
||
result = key
|
||
break
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
const saveJSON = async (name, data) => {
|
||
try {
|
||
await fs.outputJSON(path.join(userDataPath, name), data)
|
||
if (!isDev) {
|
||
await fs.outputJSON(path.join(globalUserDataPath, name), data)
|
||
}
|
||
} catch (e) {
|
||
sendMsg(e, 'ERROR')
|
||
await sleep(3)
|
||
}
|
||
}
|
||
|
||
const readJSON = async (dataPath, name) => {
|
||
let data = null
|
||
try {
|
||
data = await fs.readJSON(path.join(dataPath, name))
|
||
} catch (e) {}
|
||
return data
|
||
}
|
||
|
||
const hash = (data, type = 'sha256') => {
|
||
const hmac = crypto.createHmac(type, 'hk4e')
|
||
hmac.update(data)
|
||
return hmac.digest('hex')
|
||
}
|
||
|
||
const scryptKey = crypto.scryptSync(userPath, 'hk4e', 24)
|
||
const cipherAes = (data) => {
|
||
const algorithm = 'aes-192-cbc'
|
||
const iv = Buffer.alloc(16, 0)
|
||
const cipher = crypto.createCipheriv(algorithm, scryptKey, iv)
|
||
let encrypted = cipher.update(data, 'utf8', 'hex')
|
||
encrypted += cipher.final('hex')
|
||
return encrypted
|
||
}
|
||
|
||
const decipherAes = (encrypted) => {
|
||
const algorithm = 'aes-192-cbc'
|
||
const iv = Buffer.alloc(16, 0)
|
||
const decipher = crypto.createDecipheriv(algorithm, scryptKey, iv)
|
||
let decrypted = decipher.update(encrypted, 'hex', 'utf8')
|
||
decrypted += decipher.final('utf8')
|
||
return decrypted
|
||
}
|
||
|
||
const interfaces = require('os').networkInterfaces()
|
||
const localIp = () => {
|
||
for (var devName in interfaces) {
|
||
var iface = interfaces[devName]
|
||
|
||
for (var i = 0; i < iface.length; i++) {
|
||
var alias = iface[i]
|
||
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal)
|
||
return alias.address
|
||
}
|
||
}
|
||
return '127.0.0.1'
|
||
}
|
||
|
||
module.exports = {
|
||
sleep, request, hash, cipherAes, decipherAes, saveLog,
|
||
sendMsg, readJSON, saveJSON, initWindow, getWin, localIp, userPath, detectLocale, langMap,
|
||
appRoot, userDataPath, globalUserDataPath
|
||
} |