diff --git a/entry.js b/entry.js index 255db22..778700c 100644 --- a/entry.js +++ b/entry.js @@ -9,7 +9,8 @@ const { const path = require('path'); -const { Genshinlib } = require('./public/js/Genshinlib'); +const Store = require('electron-store'); +Store.initRenderer(); let mainWindow; @@ -70,8 +71,6 @@ function createWindow () // mainWindow.webContents.openDevTools(); } -// Set language on start -app.commandLine.appendSwitch('lang', Genshinlib.lang.launcher ?? 'en-us'); // This method will be called when Electron has finished // initialization and is ready to create browser windows. @@ -89,8 +88,6 @@ app.whenReady().then(() => { // This has to be here otherwise webContents is invalid ipcMain.on('change-lang', (event, args) => { - app.commandLine.appendSwitch('lang', Genshinlib.lang.launcher); - mainWindow.webContents.send('change-lang', { 'lang': args.lang }); }); diff --git a/package.json b/package.json index ed820c9..f7304d9 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "dependencies": { "cash-dom": "^8.1.0", "discord-rpc": "^4.0.1", + "electron-store": "^8.0.1", "follow-redirects": "^1.14.4" } } diff --git a/src/sass/settings.sass b/src/sass/settings.sass index fd655ab..d496d3c 100644 --- a/src/sass/settings.sass +++ b/src/sass/settings.sass @@ -126,11 +126,6 @@ body border-radius: 12px - cursor: pointer - - &:hover - background-color: #eff2ff - .checkbox-mark display: flex @@ -151,8 +146,6 @@ body width: 12px .checkbox-active - background-color: #eff2ff - .checkbox-mark background-color: #657ef8 diff --git a/src/ts/index.ts b/src/ts/index.ts index 3238725..aedad4c 100644 --- a/src/ts/index.ts +++ b/src/ts/index.ts @@ -2,9 +2,7 @@ const path = require('path'); const fs = require('fs'); const { exec } = require('child_process'); const { ipcRenderer } = require('electron'); - import $ from 'cash-dom'; -import { i18n } from './lib/i18n'; import { Genshinlib } from './lib/Genshinlib'; import { LauncherUI } from './lib/LauncherUI'; @@ -24,8 +22,9 @@ $(() => { if (Genshinlib.version !== null) document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version; + // On Start configuration of LauncherUI + LauncherUI.updateLang(Genshinlib.getConfig('lang.launcher') ?? 'en-us'); LauncherUI.setState('game-launch-available'); - LauncherUI.updateBackground(); LauncherUI.updateSocial(); @@ -53,7 +52,7 @@ $(() => { let old; for (let i = 0; i < data.game.latest.voice_packs.length; ++i) - if (data.game.latest.voice_packs[i].language == Genshinlib.lang.voice) + if (data.game.latest.voice_packs[i].language == Genshinlib.getConfig('lang.voice')) { voicePack = data.game.latest.voice_packs[i]; @@ -80,14 +79,14 @@ $(() => { // For some reason this keeps breaking and locking up most of the time. Tools.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); }).then(() => { console.log(`%c> Unpacking voice data...`, 'font-size: 16px'); LauncherUI.initProgressBar(); Tools.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); }).then(() => { fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name)); LauncherUI.setState('game-launch-available'); @@ -166,7 +165,7 @@ $(() => { } // Launching game - if ($('#launch').text() == i18n.translate('Launch')) + if ($('#launch').text() == LauncherUI.i18n.translate('Launch')) { console.log(`%c> Starting the game...`, 'font-size: 16px'); @@ -197,9 +196,7 @@ $(() => { { wineExeutable = 'wine'; - Genshinlib.updateConfig({ - runner: null - }); + Genshinlib.updateConfig('runner', null); } } @@ -244,7 +241,7 @@ $(() => { } // Apply test patch - else if ($('#launch').text() == i18n.translate('TestPatch')) + else if ($('#launch').text() == LauncherUI.i18n.translate('TestPatch')) { console.log(`%c> Applying patch...`, 'font-size: 16px'); @@ -284,7 +281,7 @@ $(() => { LauncherUI.initProgressBar(); Tools.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); }).then(() => { /** * Unpacking downloaded game @@ -298,7 +295,7 @@ $(() => { LauncherUI.initProgressBar(); Tools.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); }).then(() => { /** * Downloading voice data @@ -311,7 +308,7 @@ $(() => { let voicePack = diff.voice_packs[1]; // en-us for (let i = 0; i < diff.voice_packs.length; ++i) - if (diff.voice_packs[i].language == Genshinlib.lang.voice) + if (diff.voice_packs[i].language == Genshinlib.getConfig('lang.voice')) { voicePack = diff.voice_packs[i]; @@ -321,7 +318,7 @@ $(() => { LauncherUI.initProgressBar(); Tools.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); }).then(() => { /** * Unpacking downloaded game @@ -332,13 +329,11 @@ $(() => { LauncherUI.initProgressBar(); Tools.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { - LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference); + LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); }).then(() => { fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name)); - Genshinlib.updateConfig({ - version: data.game.latest.version - }); + Genshinlib.updateConfig('version', data.game.latest.version); // Patch available if (Genshinlib.getPatchInfo().version === data.game.latest.version) @@ -348,14 +343,14 @@ $(() => { console.log(`%c> Applying patch...`, 'font-size: 16px'); // patch-applying state changes only button text - $('#downloaded').text(i18n.translate('ApplyPatch')); + $('#downloaded').text(LauncherUI.i18n.translate('ApplyPatch')); Genshinlib.patchGame(data.game.latest.version, () => { LauncherUI.setState('game-launch-available'); ipcRenderer.send('notification', { title: document.title, - body: i18n.translate('GameDownloaded') + body: LauncherUI.i18n.translate('GameDownloaded') }); }, (data) => console.log(data.toString())); } diff --git a/src/ts/lib/Genshinlib.ts b/src/ts/lib/Genshinlib.ts index 9a8f6bb..41f2999 100644 --- a/src/ts/lib/Genshinlib.ts +++ b/src/ts/lib/Genshinlib.ts @@ -1,5 +1,6 @@ -import GIJSON from './GIJSON'; +import GIJSON from '../types/GIJSON'; import { Tools } from './Tools'; +const Store = require('electron-store'); const https = require('follow-redirects').https; @@ -9,6 +10,23 @@ const os = require('os'); const { spawn, exec } = require('child_process'); const dns = require('dns'); +const config = new Store({ + defaults: { + lang: { + launcher: 'en-us', + voice: 'en-us' + }, + background: { + time: null, + file: null + }, + version: null, + patch: null, + runner: null, + rpc: false, + }, +}); + type Runner = { name: string, // Runner title which will be showed in the list version: string, // Runner version @@ -24,38 +42,12 @@ type DXVK = { uri: string }; -type Config = { - lang: { - launcher: 'en-us' | 'ru-ru' | 'fr-fr' | 'id-id' | 'de-de' | 'es-es' | 'pt-pt' | 'th-th' | 'vi-vn' | 'ko-kr' | 'ja-jp' | 'zh-tw' | 'zh-cn', - voice: 'en-us' | 'ko-kr' | 'ja-jp' | 'zh-cn' - }, - background: { - time: string|null, - file: string|null - }, - version: string|null, - patch: { - version: string|null, - state: 'testing' | 'stable' - }, - runner: null | { - name: string, - folder: string, - executable: string - }, - dxvk: string|null, - rpc: boolean -}; - export class Genshinlib { public static readonly patchDir: string = path.join(path.dirname(__dirname), '..', 'patch'); public static readonly patchJson: string = path.join(this.patchDir, 'patch.json'); - public static readonly patchSh = path.join(this.patchDir, 'patch.sh'); - public static readonly patchAntiCrashSh = path.join(this.patchDir, 'patch_anti_logincrash.sh'); public static readonly launcherDir: string = path.join(os.homedir(), 'genshin-impact-launcher'); - public static readonly launcherJson: string = path.join(this.launcherDir, 'launcher.json'); public static readonly tmpPatchDir: string = path.join(this.launcherDir, 'gi-on-linux'); @@ -70,16 +62,11 @@ export class Genshinlib protected static readonly runnersUri: string = 'https://notabug.org/nobody/an-anime-game-launcher/raw/main/runners.json'; protected static readonly dxvksUri: string = 'https://notabug.org/nobody/an-anime-game-launcher/raw/main/dxvks.json'; - public static get version(): Config['version'] + public static get version(): string|null { return this.getConfig('version'); } - public static get lang(): Config['lang'] - { - return this.getConfig('lang'); - } - public static getRunners (): Promise<[{ title: string, runners: Runner[] }]> { return new Promise((resolve, reject) => { @@ -104,51 +91,15 @@ export class Genshinlib public static getConfig (property: string|null = null, splitProperty: boolean = true): any { - if (!fs.existsSync(this.launcherJson)) - fs.writeFileSync(this.launcherJson, JSON.stringify({ - lang: { - launcher: 'en-us', - voice: 'en-us' - }, - background: { - time: null, - file: null - }, - version: null, - patch: null, - runner: null, - rpc: false - }, null, 4)); - - let config = JSON.parse(fs.readFileSync(this.launcherJson)); - if (property === null) return config; - else - { - if (!splitProperty) - return config[property]; - - property.split('.').forEach(prop => config = config[prop]); - - return config; - } + return config.get(property) } - public static setConfig (info: Config): Genshinlib + public static updateConfig (cname: string, value: string|boolean|null|number): Genshinlib { - fs.writeFileSync(this.launcherJson, JSON.stringify(info, null, 4)); - - return this; - } - - public static updateConfig (config: any): Genshinlib - { - return this.setConfig({ - ...this.getConfig(), - ...config - }); + return config.set(cname, value); } public static async getData (): Promise @@ -174,17 +125,13 @@ export class Genshinlib if (!this.getConfig('background.time') || new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate()).toString() >= this.getConfig('background.time')!) { - await fetch(this.backgroundUri + this.lang.launcher) + await fetch(this.backgroundUri + this.getConfig('lang.launcher')) .then(res => res.json()) .then(async resdone => { let prevBackground = this.getConfig('background.file'); - this.updateConfig({ - background: { - time: new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate() + 7).toString(), - file: resdone.data.adv.background.replace(/.*\//, '') - } - }); + this.updateConfig('background.time', new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate() + 7).toString()); + this.updateConfig('background.file', resdone.data.adv.background.replace(/.*\//, '')); if (fs.existsSync(path.join(this.launcherDir, this.getConfig('background.file')))) background = path.join(this.launcherDir, this.getConfig('background.file')); diff --git a/src/ts/lib/LauncherUI.ts b/src/ts/lib/LauncherUI.ts index 9f2c591..438d6b3 100644 --- a/src/ts/lib/LauncherUI.ts +++ b/src/ts/lib/LauncherUI.ts @@ -13,12 +13,20 @@ type LauncherState = export class LauncherUI { protected static _launcherState: LauncherState = 'game-launch-available'; + protected static _i18n: any; public static get launcherState(): LauncherState { return this._launcherState; } + public static get i18n(): any + { + if (!this._i18n) + this._i18n = i18n; + return this._i18n; + } + public static setState (state: LauncherState) { $('#downloader-panel').css('display', 'none'); @@ -27,40 +35,40 @@ export class LauncherUI switch (state) { case 'patch-unavailable': - $('#launch').text(i18n.translate('PatchRequired')); + $('#launch').text(this.i18n.translate('PatchRequired')); $('#launch').attr('disabled', 'disabled'); $('#launch').addClass('hint--top') .addClass('hint--medium'); - $('#launch').attr('data-hint', i18n.translate('PatchRequiredHint')); + $('#launch').attr('data-hint', this.i18n.translate('PatchRequiredHint')); break; case 'test-patch-available': - $('#launch').text(i18n.translate('TestPatch')); + $('#launch').text(this.i18n.translate('TestPatch')); $('#launch').addClass('button-blue') .addClass('hint--top') .addClass('hint--large'); - $('#launch').attr('data-hint', i18n.translate('TestPatchHint')); + $('#launch').attr('data-hint', this.i18n.translate('TestPatchHint')); break; case 'patch-applying': - $('#launch').text(i18n.translate('ApplyPatch')); + $('#launch').text(this.i18n.translate('ApplyPatch')); $('#launch').attr('disabled', 'disabled'); break; case 'game-update-available': - $('#launch').text(i18n.translate('Update')); + $('#launch').text(this.i18n.translate('Update')); break; case 'game-installation-available': - $('#launch').text(i18n.translate('Install')); + $('#launch').text(this.i18n.translate('Install')); break; @@ -73,7 +81,7 @@ export class LauncherUI .removeClass('hint--medium') .removeClass('hint--large'); - $('#launch').text(i18n.translate('Launch')); + $('#launch').text(this.i18n.translate('Launch')); break; } @@ -158,7 +166,7 @@ export class LauncherUI public static updateSocial (): void { - fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.lang.launcher}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`) + fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.getConfig('lang.launcher')}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`) .then(res => res.text()) .then(body => { $('#__layout').remove(); @@ -172,10 +180,10 @@ export class LauncherUI public static updateLang (lang: string|null = null): void { if (lang !== null) - i18n.setLang(lang); + this.i18n.setLang(lang); $('*[i18id]').each((i, element) => { - element.innerText = i18n.translate(element.getAttribute('i18id')!); + element.innerText = this.i18n.translate(element.getAttribute('i18id')!); }); } } \ No newline at end of file diff --git a/src/ts/settings.ts b/src/ts/settings.ts index dc000b2..4780ccb 100644 --- a/src/ts/settings.ts +++ b/src/ts/settings.ts @@ -4,15 +4,17 @@ const { ipcRenderer } = require('electron'); const { exec } = require('child_process'); import $ from 'cash-dom'; -import { i18n } from './lib/i18n'; import { Genshinlib } from './lib/Genshinlib'; import { LauncherUI } from './lib/LauncherUI'; import { Tools } from './lib/Tools'; $(() => { + // Make sure settings is shown in correct language. + LauncherUI.updateLang(Genshinlib.getConfig('lang.launcher') ?? 'en-us'); + $('*[i18id]').each((i, element) => { - element.innerText = i18n.translate(element.getAttribute('i18id')?.toString()!); + element.innerText = LauncherUI.i18n.translate(element.getAttribute('i18id')?.toString()!); }); $('.menu-item').on('click', (e) => { @@ -29,7 +31,7 @@ $(() => { $(`.menu-item[anchor=${anchor}]`).addClass('menu-item-active'); }); - $('.checkbox').on('click', (e) => { + $('.checkbox-mark').on('click', (e) => { let item = $(e.target); while (!item.hasClass('checkbox')) @@ -39,31 +41,24 @@ $(() => { }); // Select the saved options in launcher.json on load - $(`#voice-list option[value="${Genshinlib.lang.voice}"]`).prop('selected', true); - $(`#language-list option[value="${Genshinlib.lang.launcher}"]`).prop('selected', true); + $(`#voice-list option[value="${Genshinlib.getConfig('lang.voice')}"]`).prop('selected', true); + $(`#language-list option[value="${Genshinlib.getConfig('lang.launcher')}"]`).prop('selected', true); if (Genshinlib.getConfig('rpc')) $('#discord-rpc').addClass('checkbox-active'); $('#discord-rpc').on('classChange', () => { - Genshinlib.updateConfig({ - rpc: $('#discord-rpc').hasClass('checkbox-active') - }); + Genshinlib.updateConfig('rpc', $('#discord-rpc').hasClass('checkbox-active')); ipcRenderer.send('rpc-toggle'); }); $('#voice-list').on('change', (e) => { - let activeVP = Genshinlib.lang.voice; + let activeVP = Genshinlib.getConfig('voice'); if (activeVP != e.target.value) { - Genshinlib.updateConfig({ - lang: { - launcher: Genshinlib.lang.launcher, - voice: e.target.value - } - }); + Genshinlib.updateConfig('lang.voice', e.target.value); ipcRenderer.send('updateVP', { 'oldvp': activeVP }); @@ -75,23 +70,12 @@ $(() => { }); $('#language-list').on('change', (e) => { - let activeLang = Genshinlib.lang.launcher; + let activeLang = Genshinlib.getConfig('lang.launcher'); if (activeLang != e.target.value) { - Genshinlib.updateConfig({ - lang: { - launcher: e.target.value, - voice: Genshinlib.lang.voice - }, - - // This is required as the file name changes on the API but since we don't call the API before checking - // if the time is null or expired we set time to null here. - background: { - time: null, - file: Genshinlib.getConfig('background.file') - } - }); + Genshinlib.updateConfig('lang.launcher', e.target.value); + Genshinlib.updateConfig('background.time', null); LauncherUI.updateLang(e.target.value); @@ -160,13 +144,9 @@ $(() => { if (item.find('div').css('display') === 'none') { - Genshinlib.updateConfig({ - runner: { - name: runner.name, - folder: runner.folder, - executable: runner.executable - } - }); + Genshinlib.updateConfig('runner.name', runner.name); + Genshinlib.updateConfig('runner.folder', runner.folder); + Genshinlib.updateConfig('runner.executable', runner.executable); $('#runners-list > .list-item').removeClass('list-item-active'); item.addClass('list-item-active'); @@ -239,9 +219,7 @@ $(() => { }); installer.on('close', () => { - Genshinlib.updateConfig({ - dxvk: dxvk.version - }); + Genshinlib.updateConfig('dxvk', dxvk.version); $('#dxvk-list > .list-item').removeClass('list-item-active'); item.addClass('list-item-active'); diff --git a/src/ts/lib/GIJSON.d.ts b/src/ts/types/GIJSON.d.ts similarity index 100% rename from src/ts/lib/GIJSON.d.ts rename to src/ts/types/GIJSON.d.ts diff --git a/tsconfig.json b/tsconfig.json index 8becd53..5210a74 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,6 @@ "removeComments": true, "outDir": "public/js" }, - "include": ["src/ts/*", "src/ts/lib/*"], + "include": ["src/ts/*", "src/ts/lib/*", "src/ts/types/*"], "exclude": ["node_modules", "**/*.spec.ts"] } \ No newline at end of file