Merge remote-tracking branch 'original/main' into term

This commit is contained in:
Maroxy 2021-10-24 10:35:58 +02:00
commit a7a208645a
24 changed files with 329 additions and 333 deletions

View file

@ -98,9 +98,7 @@ app.whenReady().then(() => {
mainWindow.webContents.send('updateVP', { 'oldvp': args.oldvp }); mainWindow.webContents.send('updateVP', { 'oldvp': args.oldvp });
}); });
ipcMain.on('rpcstate', (event, args) => { ipcMain.on('rpc-toggle', () => mainWindow.webContents.send('rpc-toggle'));
mainWindow.webContents.send('rpcstate', {});
});
}); });
// Quit when all windows are closed, except on macOS. There, it's common // Quit when all windows are closed, except on macOS. There, it's common

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Spiel würde erfolgreich heruntergeladen", "GameDownloaded": "Spiel würde erfolgreich heruntergeladen",
"ApplyPatch": "Patch wird angewendet", "ApplyPatch": "Patch wird angewendet",
"PatchRequired": "Patch nicht verfügbar", "PatchRequired": "Patch nicht verfügbar",
"PatchRequiredHint": "Diese Spielversion hat noch kein anti-cheat patch, Bitte warten sie ein paar Tage bevor sie es erneut versuchen.", "PatchRequiredHint": "Diese Spielversion hat noch kein anti-cheat patch, Bitte warten sie ein paar Tage bevor sie es erneut versuchen",
"TestPatch": "Test Patch anwenden", "TestPatch": "Test Patch anwenden",
"TestPatchHint": "Diese Spielversion hat ein anti-cheat patch aber es befindet sich noch in der Testphase. Sie können noch ein paar Tage warten bis es Stabil ist oder auf eigenen Risiko den Testpatch anwenden." "TestPatchHint": "Diese Spielversion hat ein anti-cheat patch aber es befindet sich noch in der Testphase. Sie können noch ein paar Tage warten bis es Stabil ist oder auf eigenen Risiko den Testpatch anwenden"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "ゲームのインストールに成功しました", "GameDownloaded": "ゲームのインストールに成功しました",
"ApplyPatch": "パッチの適用...", "ApplyPatch": "パッチの適用...",
"PatchRequired": "要パッチ", "PatchRequired": "要パッチ",
"PatchRequiredHint": "このゲームバージョンにはアンチチートパッチがありません。数日待ってから再度お試しください", "PatchRequiredHint": "このゲームバージョンにはアンチチートパッチがありません。数日待ってから再度お試しください",
"TestPatch": "テストパッチの適用", "TestPatch": "テストパッチの適用",
"TestPatchHint": "このゲームバージョンにはアンチチートパッチがありますが、テスト段階にあります。安定するまで数日お待ちいただくか、ご自身の責任で適用してください" "TestPatchHint": "このゲームバージョンにはアンチチートパッチがありますが、テスト段階にあります。安定するまで数日お待ちいただくか、ご自身の責任で適用してください"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -1,19 +1,19 @@
{ {
"Install": "Install", "Install": "Установить",
"Update": "Update", "Update": "Обновить",
"Launch": "Launch", "Launch": "Запустить",
"Runners": "Runners", "Runners": "Версии Wine",
"Langs": "Languages", "Langs": "Языки",
"Voice": "Voice Pack", "Voice": "Озвучка",
"SettingsTitle": "Settings", "SettingsTitle": "Настройки",
"GeneralSettings": "General", "GeneralSettings": "Общее",
"WineVersion": "Wine version", "WineVersion": "Версии Wine",
"Downloading": "Downloading", "Downloading": "Загрузка",
"Unpack": "Unpacking", "Unpack": "Распаковка",
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Игра была успешно установлена",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Применение патча...",
"PatchRequired": "Patch required", "PatchRequired": "Необходим патч",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "Эта версия игры не имеет патча античита. Пожалуйста, подождите несколько дней и попробуйте снова",
"TestPatch": "Apply test patch", "TestPatch": "Применить тестовый патч",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "Эта версия игры имеет лишь тестовый патч античита. Вы можете подождать пару дней до того, как он станет стабильным, либо применить его на свой страх и риск"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "Game was successfully installed", "GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required", "PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.", "PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again",
"TestPatch": "Apply test patch", "TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk." "TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "游戏安装成功", "GameDownloaded": "游戏安装成功",
"ApplyPatch": "应用补丁...", "ApplyPatch": "应用补丁...",
"PatchRequired": "需要补丁", "PatchRequired": "需要补丁",
"PatchRequiredHint": "此游戏版本没有防作弊补丁。请等待几天,然后重试", "PatchRequiredHint": "此游戏版本没有防作弊补丁。请等待几天,然后重试",
"TestPatch": "应用测试补丁", "TestPatch": "应用测试补丁",
"TestPatchHint": "此游戏版本有防作弊补丁,但处于测试阶段。您可以等待几天直到它稳定或自担风险应用它" "TestPatchHint": "此游戏版本有防作弊补丁,但处于测试阶段。您可以等待几天直到它稳定或自担风险应用它"
} }

View file

@ -13,7 +13,7 @@
"GameDownloaded": "遊戲安裝成功", "GameDownloaded": "遊戲安裝成功",
"ApplyPatch": "Applying patch...", "ApplyPatch": "Applying patch...",
"PatchRequired": "需要補丁", "PatchRequired": "需要補丁",
"PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試", "PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試",
"TestPatch": "應用測試補丁", "TestPatch": "應用測試補丁",
"TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它" "TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它"
} }

View file

@ -1,12 +1,13 @@
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const discordrpc = require("discord-rpc");
const { exec } = require('child_process'); const { exec } = require('child_process');
const { ipcRenderer } = require('electron'); const { ipcRenderer } = require('electron');
import $ from 'cash-dom'; import $ from 'cash-dom';
import { Genshinlib } from './Genshinlib'; import { Genshinlib } from './lib/Genshinlib';
import { LauncherUI } from './LauncherUI'; import { LauncherUI } from './lib/LauncherUI';
import { Tools } from './lib/Tools';
import { DiscordRPC } from './lib/DiscordRPC';
if (!fs.existsSync(Genshinlib.prefixDir)) if (!fs.existsSync(Genshinlib.prefixDir))
fs.mkdirSync(Genshinlib.prefixDir, { recursive: true }); fs.mkdirSync(Genshinlib.prefixDir, { recursive: true });
@ -21,61 +22,24 @@ $(() => {
if (Genshinlib.version !== null) if (Genshinlib.version !== null)
document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version; document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version;
ipcRenderer.on('change-lang', (event: void, data: any) => {
LauncherUI.updateBackground();
LauncherUI.updateSocial();
LauncherUI.updateLang(data.lang);
});
LauncherUI.setState('game-launch-available'); LauncherUI.setState('game-launch-available');
LauncherUI.updateBackground(); LauncherUI.updateBackground();
LauncherUI.updateSocial(); LauncherUI.updateSocial();
let rpc: any; ipcRenderer.on('change-lang', (event: void, data: any) => {
LauncherUI.updateLang(data.lang);
// FIXME LauncherUI.updateBackground();
if (Genshinlib.getConfig().rpc) LauncherUI.updateSocial();
{
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',
instance: false,
});
});
}
// FIXME
ipcRenderer.on('rpcstate', (event: void, data: any) => {
if(!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`,
instance: false,
});
}); });
if (!Genshinlib.getConfig().rpc) if (Genshinlib.getConfig('rpc'))
Genshinlib.updateConfig({ DiscordRPC.init();
rpc: true
}); ipcRenderer.on('rpc-toggle', () => {
} else { DiscordRPC.isActive() ?
rpc.clearActivity(); DiscordRPC.init() :
rpc.destroy(); DiscordRPC.close();
rpc = false;
Genshinlib.updateConfig({
rpc: false
});
}
}); });
// FIXME // FIXME
@ -113,14 +77,14 @@ $(() => {
console.log(`%c> Downloading voice data...`, 'font-size: 16px'); console.log(`%c> Downloading voice data...`, 'font-size: 16px');
// For some reason this keeps breaking and locking up most of the time. // For some reason this keeps breaking and locking up most of the time.
Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => { Tools.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference);
}).then(() => { }).then(() => {
console.log(`%c> Unpacking voice data...`, 'font-size: 16px'); console.log(`%c> Unpacking voice data...`, 'font-size: 16px');
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { Tools.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference);
}).then(() => { }).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name)); fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
@ -136,7 +100,7 @@ $(() => {
LauncherUI.setState(Genshinlib.version === null ? 'game-installation-available' : 'game-update-available'); LauncherUI.setState(Genshinlib.version === null ? 'game-installation-available' : 'game-update-available');
// Patch version is incorrect // Patch version is incorrect
else if (Genshinlib.getConfig().patch && Genshinlib.getConfig().patch.version != Genshinlib.getPatchInfo().version) else if (Genshinlib.getConfig('patch') && Genshinlib.getConfig('patch.version') != Genshinlib.getPatchInfo().version)
{ {
// Patch is not available // Patch is not available
if (Genshinlib.getPatchInfo().version !== data.game.latest.version) if (Genshinlib.getPatchInfo().version !== data.game.latest.version)
@ -164,7 +128,7 @@ $(() => {
// Current patch is in testing phase, // Current patch is in testing phase,
// but stable is available // but stable is available
else if (Genshinlib.getConfig().patch && Genshinlib.getConfig().patch.version == Genshinlib.getPatchInfo().version && Genshinlib.getConfig().patch.state == 'testing' && Genshinlib.getPatchInfo().state == 'stable') else if (Genshinlib.getConfig('patch') && Genshinlib.getConfig('patch.version') == Genshinlib.getPatchInfo().version && Genshinlib.getConfig('patch.state') == 'testing' && Genshinlib.getPatchInfo().state == 'stable')
{ {
console.log(`%c> Applying patch...`, 'font-size: 16px'); console.log(`%c> Applying patch...`, 'font-size: 16px');
@ -219,12 +183,12 @@ $(() => {
{ {
let wineExeutable = 'wine'; let wineExeutable = 'wine';
if (Genshinlib.getConfig().runner !== null) if (Genshinlib.getConfig('runner') !== null)
{ {
wineExeutable = path.join( wineExeutable = path.join(
Genshinlib.runnersDir, Genshinlib.runnersDir,
Genshinlib.getConfig().runner?.folder, Genshinlib.getConfig('runner.folder'),
Genshinlib.getConfig().runner?.executable Genshinlib.getConfig('runner.executable')
); );
if (!fs.existsSync(wineExeutable)) if (!fs.existsSync(wineExeutable))
@ -239,15 +203,12 @@ $(() => {
console.log(`Wine executable: ${wineExeutable}`); console.log(`Wine executable: ${wineExeutable}`);
// FIXME if (DiscordRPC.isActive())
if (rpc)
{ {
rpc.setActivity({ DiscordRPC.setActivity({
details: `In-Game`, details: 'In-Game',
largeImageKey: `game`, largeImageKey: 'game',
largeImageText: `An Anime Game Launcher`, largeImageText: 'An Anime Game Launcher'
startTimestamp: parseInt(new Date().setDate(new Date().getDate()).toString()),
instance: false,
}); });
} }
@ -262,14 +223,12 @@ $(() => {
ipcRenderer.invoke('show-window'); ipcRenderer.invoke('show-window');
// FIXME if (DiscordRPC.isActive())
if (rpc)
{ {
rpc.setActivity({ DiscordRPC.setActivity({
details: `Preparing to launch`, details: 'Preparing to launch',
largeImageKey: `launcher`, largeImageKey: 'launcher',
largeImageText: `An Anime Game Launcher`, largeImageText: 'An Anime Game Launcher'
instance: false,
}); });
} }
@ -322,7 +281,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => { Tools.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
@ -336,7 +295,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { Tools.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
@ -359,7 +318,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => { Tools.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Downloading'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
@ -370,7 +329,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { Tools.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference); LauncherUI.updateProgressBar(LauncherUI.i18n.translate('Unpack'), current, total, difference);
}).then(() => { }).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name)); fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));

46
src/ts/lib/DiscordRPC.ts Normal file
View file

@ -0,0 +1,46 @@
const discordRpc = require('discord-rpc');
export class DiscordRPC
{
protected static readonly clientId = '901534333360304168';
protected static rpc: any = null;
public static init ()
{
this.rpc = new discordRpc.Client({ transport: 'ipc' });
this.rpc.login({ clientId: this.clientId }).catch(console.error);
this.rpc.on('ready', () => {
this.rpc.setActivity({
details: 'Preparing to launch',
largeImageKey: 'launcher',
largeImageText: 'An Anime Game Launcher',
instance: false
});
});
}
public static setActivity (activity: any): void
{
this.rpc?.setActivity({
startTimestamp: parseInt(new Date().setDate(new Date().getDate()).toString()),
instance: false,
...activity
});
}
public static isActive (): boolean
{
return this.rpc !== null;
}
public static close (): void
{
this.rpc?.clearActivity();
this.rpc?.destroy();
this.rpc = null;
}
}

View file

@ -1,4 +1,5 @@
import GIJSON from './GIJSON'; import GIJSON from './GIJSON';
import { Tools } from './Tools';
const https = require('follow-redirects').https; const https = require('follow-redirects').https;
@ -42,13 +43,13 @@ type Config = {
folder: string, folder: string,
executable: string executable: string
}, },
rpc: boolean, dxvk: string|null,
dxvk: string|null rpc: boolean
}; };
export class Genshinlib export class Genshinlib
{ {
public static readonly patchDir: string = path.join(path.dirname(__dirname), 'patch'); 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 patchJson: string = path.join(this.patchDir, 'patch.json');
public static readonly patchSh = path.join(this.patchDir, 'patch.sh'); 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 patchAntiCrashSh = path.join(this.patchDir, 'patch_anti_logincrash.sh');
@ -71,12 +72,12 @@ export class Genshinlib
public static get version(): Config['version'] public static get version(): Config['version']
{ {
return this.getConfig().version; return this.getConfig('version');
} }
public static get lang(): Config['lang'] public static get lang(): Config['lang']
{ {
return this.getConfig().lang; return this.getConfig('lang');
} }
public static getRunners (): Promise<[{ title: string, runners: Runner[] }]> public static getRunners (): Promise<[{ title: string, runners: Runner[] }]>
@ -101,7 +102,7 @@ export class Genshinlib
// return new Promise(resolve => resolve(JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'dxvks.json'))))); // return new Promise(resolve => resolve(JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'dxvks.json')))));
} }
public static getConfig (): Config public static getConfig (property: string|null = null, splitProperty: boolean = true): any
{ {
if (!fs.existsSync(this.launcherJson)) if (!fs.existsSync(this.launcherJson))
fs.writeFileSync(this.launcherJson, JSON.stringify({ fs.writeFileSync(this.launcherJson, JSON.stringify({
@ -119,7 +120,20 @@ export class Genshinlib
rpc: false rpc: false
}, null, 4)); }, null, 4));
return JSON.parse(fs.readFileSync(this.launcherJson)); 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;
}
} }
public static setConfig (info: Config): Genshinlib public static setConfig (info: Config): Genshinlib
@ -158,12 +172,12 @@ export class Genshinlib
{ {
let background = ''; let background = '';
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!) 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.lang.launcher)
.then(res => res.json()) .then(res => res.json())
.then(async resdone => { .then(async resdone => {
let prevBackground = this.getConfig().background.file; let prevBackground = this.getConfig('background.file');
this.updateConfig({ this.updateConfig({
background: { background: {
@ -172,23 +186,23 @@ export class Genshinlib
} }
}); });
if (fs.existsSync(path.join(this.launcherDir, this.getConfig().background.file))) if (fs.existsSync(path.join(this.launcherDir, this.getConfig('background.file'))))
background = path.join(this.launcherDir, this.getConfig().background.file); background = path.join(this.launcherDir, this.getConfig('background.file'));
else else
{ {
await this.downloadFile(resdone.data.adv.background, path.join(this.launcherDir, this.getConfig().background.file), (current: number, total: number, difference: number) => null).then(() => { await Tools.downloadFile(resdone.data.adv.background, path.join(this.launcherDir, this.getConfig('background.file')), (current: number, total: number, difference: number) => null).then(() => {
!prevBackground ? !prevBackground ?
console.log('No old background found') : console.log('No old background found') :
fs.unlinkSync(path.join(this.launcherDir, prevBackground)); fs.unlinkSync(path.join(this.launcherDir, prevBackground));
background = path.join(this.launcherDir, this.getConfig().background.file); background = path.join(this.launcherDir, this.getConfig('background.file'));
}); });
}; };
}); });
} }
else background = path.join(this.launcherDir, this.getConfig().background.file); else background = path.join(this.launcherDir, this.getConfig('background.file'));
return background; return background;
} }
@ -228,131 +242,6 @@ export class Genshinlib
}); });
} }
public static async downloadFile (uri: string, savePath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
https.get(uri, (response: any) => {
let length = parseInt(response.headers['content-length'], 10),
total = 0;
response.on('data', (chunk: any) => {
total += chunk.length;
progress(total, length, chunk.length);
fs.appendFileSync(savePath, chunk);
});
response.on('end', () => resolve());
}).on('error', (err: Error) => reject(err));
});
}
public static async unzip (zipPath: string, unpackedPath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
let listenerProcess = spawn('unzip', ['-v', zipPath]),
filesList = '';
listenerProcess.stdout.on('data', (data: string) => filesList += data);
listenerProcess.on('close', () => {
let files = filesList.split(/\r\n|\r|\n/).slice(3, -3).map(line => {
line = line.trim();
if (line.slice(-1) == '/')
line = line.slice(0, -1);
let matches = /^(\d+) [a-zA-Z\:]+[ ]+(\d+)[ ]+[0-9\-]+% [0-9\-]+ [0-9\:]+ [a-f0-9]{8} (.+)/.exec(line);
if (matches)
return {
path: matches[3],
compressedSize: parseInt(matches[2]),
uncompressedSize: parseInt(matches[1])
};
});
let total = fs.statSync(zipPath)['size'], current = 0;
let unpackerProcess = spawn('unzip', ['-o', zipPath, '-d', unpackedPath]);
unpackerProcess.stdout.on('data', (data: string) => {
data.toString().split(/\r\n|\r|\n/).forEach(line => {
let items = line.split(': ');
if (items[1] !== undefined)
{
items[1] = path.relative(unpackedPath, items[1].trim());
files.forEach(file => {
if (file?.path == items[1])
{
current += file.compressedSize;
progress(current, total, file.compressedSize);
}
});
}
});
});
unpackerProcess.on('close', () => resolve());
});
});
}
public static async untar (tarPath: string, unpackedPath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
let listenerProcess = spawn('tar', ['-tvf', tarPath]),
filesList = '', total = 0;
listenerProcess.stdout.on('data', (data: string) => filesList += data);
listenerProcess.on('close', () => {
let files = filesList.split(/\r\n|\r|\n/).slice(3, -3).map(line => {
line = line.trim();
if (line.slice(-1) == '/')
line = line.slice(0, -1);
let matches = /^[dwxr\-]+ [\w/]+[ ]+(\d+) [0-9\-]+ [0-9\:]+ (.+)/.exec(line);
// TODO: compressedSize?
if (matches)
{
total += parseInt(matches[1]);
return {
path: matches[2],
uncompressedSize: parseInt(matches[1])
};
}
});
let current = 0;
let unpackerProcess = spawn('tar', ['-xvf', tarPath, '-C', unpackedPath]);
unpackerProcess.stdout.on('data', (data: string) => {
data.toString().split(/\r\n|\r|\n/).forEach(line => {
line = line.trim();
files.forEach(file => {
if (file?.path == line)
{
current += file.uncompressedSize; // compressedSize
progress(current, total, file.uncompressedSize); // compressedSize
}
});
});
});
unpackerProcess.on('close', () => resolve());
});
});
}
// WINEPREFIX='/home/observer/genshin-impact-launcher/wineprefix' winetricks corefonts usetakefocus=n // WINEPREFIX='/home/observer/genshin-impact-launcher/wineprefix' winetricks corefonts usetakefocus=n
public static async installPrefix (prefixpath: string, progress: (output: string, current: number, total: number) => void): Promise<void> public static async installPrefix (prefixpath: string, progress: (output: string, current: number, total: number) => void): Promise<void>
{ {
@ -377,13 +266,13 @@ export class Genshinlib
let installationProgress = 0; let installationProgress = 0;
let installerProcess; let installerProcess;
if (this.getConfig().runner) if (this.getConfig('runner'))
{ {
installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n', 'dxvk191'], { installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n', 'dxvk191'], {
env: { env: {
...process.env, ...process.env,
WINEPREFIX: prefixpath, WINEPREFIX: prefixpath,
WINE: path.join(this.runnersDir, this.getConfig().runner?.folder, this.getConfig().runner?.executable) WINE: path.join(this.runnersDir, this.getConfig('runner.folder'), this.getConfig('runner.executable'))
} }
}); });
} }
@ -421,8 +310,8 @@ export class Genshinlib
public static patchGame (version: string, onFinish: () => void, onData: (data: string) => void) public static patchGame (version: string, onFinish: () => void, onData: (data: string) => void)
{ {
this.downloadFile(this.patchUri, path.join(this.launcherDir, 'krock.zip'), (current: number, total: number, difference: number) => null).then(() => { Tools.downloadFile(this.patchUri, path.join(this.launcherDir, 'krock.zip'), (current: number, total: number, difference: number) => null).then(() => {
this.unzip(path.join(this.launcherDir, 'krock.zip'), this.launcherDir, (current: number, total: number, difference: number) => null).then(() => { Tools.unzip(path.join(this.launcherDir, 'krock.zip'), this.launcherDir, (current: number, total: number, difference: number) => null).then(() => {
// Delete zip file and assign patch directory. // Delete zip file and assign patch directory.
fs.unlinkSync(path.join(this.launcherDir, 'krock.zip')); fs.unlinkSync(path.join(this.launcherDir, 'krock.zip'));
@ -476,38 +365,4 @@ export class Genshinlib
}); });
}); });
} }
/*public static applyPatch (onFinish: () => void, onData: (data: string) => void)
{
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
cwd: Genshinlib.gameDir,
env: {
...process.env,
WINEPREFIX: Genshinlib.prefixDir
}
});
patcherProcess.stdout.on('data', (data: string) => onData(data));
patcherProcess.on('close', () => {
let patcherAntiCrashProcess = spawn('bash', [Genshinlib.patchAntiCrashSh], {
cwd: Genshinlib.gameDir,
env: {
...process.env,
WINEPREFIX: Genshinlib.prefixDir
}
});
patcherAntiCrashProcess.stdout.on('data', (data: string) => onData(data));
patcherAntiCrashProcess.on('close', () => {
Genshinlib.setConfig({
...Genshinlib.getConfig(),
patch: Genshinlib.getPatchInfo()
});
onFinish();
});
});
}*/
} }

133
src/ts/lib/Tools.ts Normal file
View file

@ -0,0 +1,133 @@
const https = require('follow-redirects').https;
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
export class Tools
{
public static async downloadFile (uri: string, savePath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
https.get(uri, (response: any) => {
let length = parseInt(response.headers['content-length'], 10),
total = 0;
response.on('data', (chunk: any) => {
total += chunk.length;
progress(total, length, chunk.length);
fs.appendFileSync(savePath, chunk);
});
response.on('end', () => resolve());
}).on('error', (err: Error) => reject(err));
});
}
public static async unzip (zipPath: string, unpackedPath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
let listenerProcess = spawn('unzip', ['-v', zipPath]),
filesList = '';
listenerProcess.stdout.on('data', (data: string) => filesList += data);
listenerProcess.on('close', () => {
let files = filesList.split(/\r\n|\r|\n/).slice(3, -3).map(line => {
line = line.trim();
if (line.slice(-1) == '/')
line = line.slice(0, -1);
let matches = /^(\d+) [a-zA-Z\:]+[ ]+(\d+)[ ]+[0-9\-]+% [0-9\-]+ [0-9\:]+ [a-f0-9]{8} (.+)/.exec(line);
if (matches)
return {
path: matches[3],
compressedSize: parseInt(matches[2]),
uncompressedSize: parseInt(matches[1])
};
});
let total = fs.statSync(zipPath)['size'], current = 0;
let unpackerProcess = spawn('unzip', ['-o', zipPath, '-d', unpackedPath]);
unpackerProcess.stdout.on('data', (data: string) => {
data.toString().split(/\r\n|\r|\n/).forEach(line => {
let items = line.split(': ');
if (items[1] !== undefined)
{
items[1] = path.relative(unpackedPath, items[1].trim());
files.forEach(file => {
if (file?.path == items[1])
{
current += file.compressedSize;
progress(current, total, file.compressedSize);
}
});
}
});
});
unpackerProcess.on('close', () => resolve());
});
});
}
public static async untar (tarPath: string, unpackedPath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
let listenerProcess = spawn('tar', ['-tvf', tarPath]),
filesList = '', total = 0;
listenerProcess.stdout.on('data', (data: string) => filesList += data);
listenerProcess.on('close', () => {
let files = filesList.split(/\r\n|\r|\n/).slice(3, -3).map(line => {
line = line.trim();
if (line.slice(-1) == '/')
line = line.slice(0, -1);
let matches = /^[dwxr\-]+ [\w/]+[ ]+(\d+) [0-9\-]+ [0-9\:]+ (.+)/.exec(line);
// TODO: compressedSize?
if (matches)
{
total += parseInt(matches[1]);
return {
path: matches[2],
uncompressedSize: parseInt(matches[1])
};
}
});
let current = 0;
let unpackerProcess = spawn('tar', ['-xvf', tarPath, '-C', unpackedPath]);
unpackerProcess.stdout.on('data', (data: string) => {
data.toString().split(/\r\n|\r|\n/).forEach(line => {
line = line.trim();
files.forEach(file => {
if (file?.path == line)
{
current += file.uncompressedSize; // compressedSize
progress(current, total, file.uncompressedSize); // compressedSize
}
});
});
});
unpackerProcess.on('close', () => resolve());
});
});
}
}

View file

@ -3,6 +3,8 @@ const fs = require('fs');
export class i18n export class i18n
{ {
public static readonly localesDir = path.join(path.dirname(__dirname), '..', 'locales');
public static loadedLanguage: any; public static loadedLanguage: any;
public static translate (phrase: string) public static translate (phrase: string)
@ -36,8 +38,8 @@ export class i18n
break; break;
} }
i18n.loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', i18n.loadedLanguage = JSON.parse(fs.readFileSync(path.join(this.localesDir,
fs.existsSync(path.join(path.dirname(__dirname), 'locales', lang + '.json')) ? fs.existsSync(path.join(this.localesDir, lang + '.json')) ?
lang + '.json' : 'en.json' lang + '.json' : 'en.json'
))); )));
} }

View file

@ -4,8 +4,10 @@ const { ipcRenderer } = require('electron');
const { exec } = require('child_process'); const { exec } = require('child_process');
import $ from 'cash-dom'; import $ from 'cash-dom';
import { Genshinlib } from './Genshinlib'; import { i18n } from './lib/i18n';
import { LauncherUI } from './LauncherUI'; import { Genshinlib } from './lib/Genshinlib';
import { LauncherUI } from './lib/LauncherUI';
import { Tools } from './lib/Tools';
$(() => { $(() => {
@ -31,10 +33,16 @@ $(() => {
$(`#voice-list option[value="${Genshinlib.lang.voice}"]`).prop('selected', true); $(`#voice-list option[value="${Genshinlib.lang.voice}"]`).prop('selected', true);
$(`#language-list option[value="${Genshinlib.lang.launcher}"]`).prop('selected', true); $(`#language-list option[value="${Genshinlib.lang.launcher}"]`).prop('selected', true);
if (Genshinlib.getConfig().rpc) if (Genshinlib.getConfig('rpc'))
$(`#drpc`).prop('checked', true); $('#drpc').prop('checked', true);
$('#drpc').on('change', () => ipcRenderer.send('rpcstate', {})); $('#drpc').on('change', () => {
Genshinlib.updateConfig({
rpc: $('#drpc').prop('checked')
});
ipcRenderer.send('rpc-toggle');
});
$('#voice-list').on('change', (e) => { $('#voice-list').on('change', (e) => {
let activeVP = Genshinlib.lang.voice; let activeVP = Genshinlib.lang.voice;
@ -66,32 +74,27 @@ $(() => {
lang: { lang: {
launcher: e.target.value, launcher: e.target.value,
voice: Genshinlib.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 // 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. // if the time is null or expired we set time to null here.
Genshinlib.updateConfig({
background: { background: {
time: null, time: null,
file: Genshinlib.getConfig().background.file file: Genshinlib.getConfig('background.file')
} }
}); });
// Send language updates
LauncherUI.updateLang(e.target.value); LauncherUI.updateLang(e.target.value);
ipcRenderer.send('change-lang', { 'lang': e.target.value });
/*$('*[i18id]').each((i, element) => { // Send language updates
element.innerText = i18n.translate(element.getAttribute('i18id')?.toString()!); ipcRenderer.send('change-lang', { 'lang': e.target.value });
});*/
$(`#language-list option[value="${activeLang}"]`).removeProp('selected'); $(`#language-list option[value="${activeLang}"]`).removeProp('selected');
$(`#language-list option[value="${e.target.value}"]`).prop('selected', true); $(`#language-list option[value="${e.target.value}"]`).prop('selected', true);
} }
}); });
let activeRunner = Genshinlib.getConfig().runner; let activeRunner = Genshinlib.getConfig('runner');
Genshinlib.getRunners().then(runners => { Genshinlib.getRunners().then(runners => {
runners.forEach(category => { runners.forEach(category => {
@ -116,11 +119,11 @@ $(() => {
let div = item.find('div'); let div = item.find('div');
Genshinlib.downloadFile(runner.uri, path.join(Genshinlib.launcherDir, runner.name), (current: number, total: number, difference: number) => { Tools.downloadFile(runner.uri, path.join(Genshinlib.launcherDir, runner.name), (current: number, total: number, difference: number) => {
div.text(`${ Math.round(current / total * 100) }%`); div.text(`${ Math.round(current / total * 100) }%`);
}).then(() => { }).then(() => {
let unpacker = runner.archive === 'tar' ? let unpacker = runner.archive === 'tar' ?
Genshinlib.untar : Genshinlib.unzip; Tools.untar : Tools.unzip;
unpacker( unpacker(
path.join(Genshinlib.launcherDir, runner.name), path.join(Genshinlib.launcherDir, runner.name),
@ -165,7 +168,7 @@ $(() => {
}); });
}); });
let activeDXVK = Genshinlib.getConfig().dxvk; let activeDXVK = Genshinlib.getConfig('dxvk');
Genshinlib.getDXVKs().then(dxvks => { Genshinlib.getDXVKs().then(dxvks => {
dxvks.forEach(dxvk => { dxvks.forEach(dxvk => {
@ -187,10 +190,10 @@ $(() => {
let div = item.find('div'); let div = item.find('div');
Genshinlib.downloadFile(dxvk.uri, path.join(Genshinlib.launcherDir, 'dxvk-' + dxvk.version), (current: number, total: number, difference: number) => { Tools.downloadFile(dxvk.uri, path.join(Genshinlib.launcherDir, 'dxvk-' + dxvk.version), (current: number, total: number, difference: number) => {
div.text(`${ Math.round(current / total * 100) }%`); div.text(`${ Math.round(current / total * 100) }%`);
}).then(() => { }).then(() => {
Genshinlib.untar( Tools.untar(
path.join(Genshinlib.launcherDir, 'dxvk-' + dxvk.version), path.join(Genshinlib.launcherDir, 'dxvk-' + dxvk.version),
Genshinlib.dxvksDir, Genshinlib.dxvksDir,
(current: number, total: number, difference: number) => { (current: number, total: number, difference: number) => {

View file

@ -9,6 +9,6 @@
"removeComments": true, "removeComments": true,
"outDir": "public/js" "outDir": "public/js"
}, },
"include": ["src/ts/*"], "include": ["src/ts/*", "src/ts/lib/*"],
"exclude": ["node_modules", "**/*.spec.ts"] "exclude": ["node_modules", "**/*.spec.ts"]
} }