pull #9 implementation

This commit is contained in:
Observer KRypt0n_ 2021-10-23 22:44:24 +02:00
parent 9d8e07b037
commit 2a6c3d5780
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
8 changed files with 152 additions and 135 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
node_modules
dist
package-lock.json
yarn.lock
wineprefix-installation.log
public/css/index.css
public/css/settings.css

View file

@ -9,6 +9,8 @@ const {
const path = require('path');
const { Genshinlib } = require('./public/js/Genshinlib');
let mainWindow;
ipcMain.handle('hide-window', () => mainWindow.hide());
@ -69,10 +71,7 @@ function createWindow ()
}
// Set language on start
if(Genshinlib.getConfig().lang.launcher)
app.commandLine.appendSwitch('lang', Genshinlib.getConfig().lang.launcher);
else
app.commandLine.appendSwitch('lang', 'en-us');
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.
@ -88,10 +87,11 @@ app.whenReady().then(() => {
createWindow();
});
// This has to be here otherwise webContents is invalid.
ipcMain.on('changelang', (event, args) => {
app.commandLine.appendSwitch('lang', Genshinlib.getConfig().lang.launcher);
mainWindow.webContents.send('changelang', { 'lang': args.lang });
// 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 });
});
ipcMain.on('updateVP', (event, args) => {

View file

@ -18,14 +18,15 @@
<div class="menu">
<div class="menu-item menu-item-active" anchor="general" i18id="GeneralSettings">General</div>
<div class="menu-item" anchor="runners" i18id="Runners">Runners</div>
<div class="menu-item" anchor="dxvks">DXVK</div>
<div class="menu-item" anchor="dxvks" i18id="DXVK">DXVK</div>
</div>
<div class="settings">
<div class="settings-item" id="general">
<h2 i18id="GeneralSettings">General</h2>
<hr>
<h3 i18id="Langs">Language</h3>
<select class="dropdown-menu" id="language-list">
<option value="en-us">English (US)</option>
<option value="zh-cn">中文(简化)(Chinese Simplified)</option>
@ -41,20 +42,27 @@
<option value="zh-tw">中文(繁體)(Chinese Traditional)</option>
<option value="vi-vn">Tiếng Việt (Vietnamese)</option>
</select>
<br>
<h3 i18id="Voice">Voice Pack</h3>
<select class="dropdown-menu" id="voice-list" disabled>
<option value="en-us">English (US)</option>
<option value="zh-cn">汉语 (Chinese)</option>
<option value="ja-jp">日本語 (Japanese)</option>
<option value="ko-kr">한국어 (Korean)</option>
</select>
<br>
<h3>Discord RPC</h3>
<input type="checkbox" id="drpc" name="drpc">
<br>
</div>
<hr>
<div class="settings-item" id="runners">
<h2>Runners</h2>

View file

@ -93,9 +93,9 @@ export class Genshinlib
public static getDXVKs (): Promise<DXVK[]>
{
return new Promise((resolve, reject) => {
fetch(this.runnersUri)
fetch(this.dxvksUri)
.then(response => response.json())
.then(runners => resolve(runners));
.then(dxvks => resolve(dxvks));
});
// return new Promise(resolve => resolve(JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'dxvks.json')))));
@ -510,4 +510,4 @@ export class Genshinlib
});
});
}*/
}
}

View file

@ -1,5 +1,6 @@
import $ from 'cash-dom';
import i18n from './i18n';
import { Genshinlib } from './Genshinlib';
import { i18n } from './i18n';
type LauncherState =
'patch-unavailable' |
@ -18,11 +19,6 @@ export class LauncherUI
return this._launcherState;
}
public static refreshLang (langcode: string)
{
i18n.updatelang(langcode);
}
public static setState (state: LauncherState)
{
$('#downloader-panel').css('display', 'none');
@ -154,4 +150,9 @@ export class LauncherUI
$('#downloader .progress').css('width', '0');
}
public static updateBackground (): void
{
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${uri})`));
}
}

View file

@ -1,39 +1,44 @@
const path = require("path");
const path = require('path');
const fs = require('fs');
let loadedLanguage: any;
function i18n(): any {
if(fs.existsSync(path.join(path.dirname(__dirname), 'locales', navigator.language.toLowerCase() + '.json'))) {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', navigator.language.toLowerCase() + '.json'), 'utf8'));
export class i18n
{
public static loadedLanguage: any;
public static translate (phrase: string)
{
if (i18n.loadedLanguage === undefined)
this.setLang(navigator.language);
return i18n.loadedLanguage[phrase] ?? phrase;
}
else {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', 'en.json'), 'utf8'));
}
};
i18n.prototype.translate = function(phrase: any) {
let translation = loadedLanguage[phrase];
public static setLang (lang: string)
{
lang = lang.toLowerCase();
if(translation === undefined) {
translation = phrase;
}
// Test if the locale is the same string so if it's de-de or id-id remove -de or -id like navigator.language does.
let samecode = new RegExp(`(${lang.replace(/-.*$/, '')}.*){2}`, 'g');
return translation
}
if (samecode.test(lang.toLowerCase()))
lang = lang.replace(/-.*$/, '');
i18n.prototype.updatelang = function(newlang: string) {
// Test if the locale is the same string so if it's de-de or id-id remove -de or -id like navigator.language does.
let samecode = new RegExp(`(${newlang.toLowerCase().replace(/-.*$/, '')}.*){2}`, 'g');
samecode.test(newlang.toLowerCase()) ? newlang = newlang.toLowerCase().replace(/-.*$/, '') : newlang = newlang.toLowerCase();
if (newlang == 'ja-jp') newlang = 'ja';
if (newlang == 'vi-vn') newlang = 'vi';
switch (lang)
{
case 'ja-jp':
lang = 'ja';
if(fs.existsSync(path.join(path.dirname(__dirname), 'locales', newlang + '.json'))) {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', newlang + '.json'), 'utf8'));
}
else {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', 'en.json'), 'utf8'));
break;
case 'vi-vn':
lang = 'vi';
break;
}
i18n.loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales',
fs.existsSync(path.join(path.dirname(__dirname), 'locales', lang + '.json')) ?
lang + '.json' : 'en.json'
)));
}
}
export default new (i18n as any);

View file

@ -3,10 +3,9 @@ const fs = require('fs');
const discordrpc = require("discord-rpc");
const { exec } = require('child_process');
const { ipcRenderer } = require('electron');
let rpc: any;
import $ from 'cash-dom';
import i18n from './i18n';
import { i18n } from './i18n';
import { Genshinlib } from './Genshinlib';
import { LauncherUI } from './LauncherUI';
@ -17,32 +16,51 @@ if (!fs.existsSync(Genshinlib.prefixDir))
if (!fs.existsSync(Genshinlib.runnersDir))
fs.mkdirSync(Genshinlib.runnersDir, { recursive: true });
if (!fs.existsSync(Genshinlib.dxvksDir))
fs.mkdirSync(Genshinlib.dxvksDir, { recursive: true });
$(() => {
if (Genshinlib.version !== null)
document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version;
if (Genshinlib.getConfig().rpc) {
rpc = new discordrpc.Client({ transport: "ipc" });
LauncherUI.setState('game-launch-available');
LauncherUI.updateBackground();
fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.lang.launcher}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`)
.then(res => res.text())
.then(body => {
$(body).find('#__layout').appendTo('#launchcontent');
$('#launchcontent .home__main .home-swiper-wrap').remove();
$('#launchcontent .home__main .home-news').remove();
});
ipcRenderer.on('change-lang', (event: void, data: any) => {
LauncherUI.updateBackground();
LauncherUI.setState(LauncherUI.launcherState);
i18n.setLang(data.lang);
});
let rpc: any;
// FIXME
if (Genshinlib.getConfig().rpc)
{
rpc = new discordrpc.Client({ transport: 'ipc' });
rpc.login({ clientId: '901534333360304168' }).catch(console.error);
rpc.on('ready', () => {
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
details: 'Preparing to launch',
largeImageKey: 'launcher',
largeImageText: 'An Anime Game Launcher',
instance: false,
});
});
}
LauncherUI.setState('game-launch-available');
ipcRenderer.on('changelang', (event: void, data: any) => {
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`));
LauncherUI.refreshLang(data.lang);
LauncherUI.setState(LauncherUI.launcherState);
});
// FIXME
ipcRenderer.on('rpcstate', (event: void, data: any) => {
if(!rpc) {
rpc = new discordrpc.Client({ transport: "ipc" });
@ -71,6 +89,7 @@ $(() => {
}
});
// FIXME
ipcRenderer.on('updateVP', (event: void, remotedata: any) => {
Genshinlib.getData().then(data => {
LauncherUI.initProgressBar();
@ -122,17 +141,6 @@ $(() => {
});
});
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`));
fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.lang.launcher}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`)
.then(res => res.text())
.then(body => {
$(body).find('#__layout').appendTo('#launchcontent');
$('#launchcontent .home__main .home-swiper-wrap').remove();
$('#launchcontent .home__main .home-news').remove();
});
Genshinlib.getData().then(data => {
// Update available
if (Genshinlib.version != data.game.latest.version)
@ -242,38 +250,44 @@ $(() => {
console.log(`Wine executable: ${wineExeutable}`);
if (rpc)
rpc.setActivity({
details: `In-Game`,
largeImageKey: `game`,
largeImageText: `An Anime Game Launcher`,
startTimestamp: parseInt(new Date().setDate(new Date().getDate()).toString()),
instance: false,
});
exec(`${wineExeutable} launcher.bat`, {
cwd: Genshinlib.gameDir,
env: {
...process.env,
WINEPREFIX: Genshinlib.prefixDir
// FIXME
if (rpc)
{
rpc.setActivity({
details: `In-Game`,
largeImageKey: `game`,
largeImageText: `An Anime Game Launcher`,
startTimestamp: parseInt(new Date().setDate(new Date().getDate()).toString()),
instance: false,
});
}
}, (err: any, stdout: any, stderr: any) => {
console.log(`%c> Game closed`, 'font-size: 16px');
exec(`${wineExeutable} launcher.bat`, {
cwd: Genshinlib.gameDir,
env: {
...process.env,
WINEPREFIX: Genshinlib.prefixDir
}
}, (err: any, stdout: any, stderr: any) => {
console.log(`%c> Game closed`, 'font-size: 16px');
ipcRenderer.invoke('show-window');
if (rpc)
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
instance: false,
});
// FIXME
if (rpc)
{
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
instance: false,
});
}
console.log(err);
console.log(stdout);
console.log(stderr);
});
console.log(err);
console.log(stdout);
console.log(stderr);
});
ipcRenderer.invoke('hide-window');
}

View file

@ -4,13 +4,13 @@ const { ipcRenderer } = require('electron');
const { exec } = require('child_process');
import $ from 'cash-dom';
import i18n from './i18n';
import { i18n } from './i18n';
import { Genshinlib } from './Genshinlib';
$(() => {
$("*[i18id]").each((i, el) => {
el.innerText = i18n.translate(el.getAttribute('i18id')?.toString());
$('*[i18id]').each((i, element) => {
element.innerText = i18n.translate(element.getAttribute('i18id')?.toString()!);
});
$('.menu-item').on('click', (e) => {
@ -27,22 +27,14 @@ $(() => {
$(`.menu-item[anchor=${anchor}]`).addClass('menu-item-active');
});
// Select the saved options in launcher.json on load.
$(`#voice-list option[value="${Genshinlib.getConfig().lang.voice}"]`).prop('selected', true);
// 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);
if (Genshinlib.getConfig().rpc)
$(`#drpc`).prop('checked', true);
$(`#language-list option[value="${Genshinlib.getConfig().lang.launcher}"]`).prop('selected', true);
$('#drpc').on('change', (e) => {
if ($("#drpc").is(':checked'))
{
ipcRenderer.send('rpcstate', {});
}
else
{
ipcRenderer.send('rpcstate', {});
}
})
$('#drpc').on('change', () => ipcRenderer.send('rpcstate', {}));
$('#voice-list').on('change', (e) => {
let activeVP = Genshinlib.getConfig().lang.voice;
@ -61,25 +53,24 @@ $(() => {
$(`#voice-list option[value="${activeVP}"]`).removeProp('selected');
$(`#voice-list option[value="${e.target.value}"]`).prop('selected', true);
}
else
{
console.log('VP can\' be changed to the already set language');
}
else console.log('VP can\' be changed to the already set language');
});
$('#language-list').on('change', (e) => {
let activeLNG = Genshinlib.getConfig().lang.launcher;
let activeLang = Genshinlib.lang.launcher;
if (activeLNG != e.target.value)
if (activeLang != e.target.value)
{
Genshinlib.updateConfig({
lang: {
launcher: e.target.value,
voice: Genshinlib.getConfig().lang.voice
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.
// 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.
Genshinlib.updateConfig({
background: {
time: null,
@ -88,19 +79,16 @@ $(() => {
});
// Send language updates
i18n.updatelang(e.target.value);
ipcRenderer.send('changelang', { 'lang': e.target.value });
$("*[i18id]").each((i, el) => {
el.innerText = i18n.translate(el.getAttribute('i18id')?.toString());
i18n.setLang(e.target.value);
ipcRenderer.send('change-lang', { 'lang': e.target.value });
$('*[i18id]').each((i, element) => {
element.innerText = i18n.translate(element.getAttribute('i18id')?.toString()!);
});
$(`#language-list option[value="${activeLNG}"]`).removeProp('selected');
$(`#language-list option[value="${activeLang}"]`).removeProp('selected');
$(`#language-list option[value="${e.target.value}"]`).prop('selected', true);
}
else
{
console.log('New language can\' be changed to the already set language');
}
});
let activeRunner = Genshinlib.getConfig().runner;