mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-12-24 18:48:14 +03:00
Merge remote-tracking branch 'original/main' into term
This commit is contained in:
commit
a7a208645a
24 changed files with 329 additions and 333 deletions
4
entry.js
4
entry.js
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
"GameDownloaded": "ゲームのインストールに成功しました",
|
"GameDownloaded": "ゲームのインストールに成功しました",
|
||||||
"ApplyPatch": "パッチの適用...",
|
"ApplyPatch": "パッチの適用...",
|
||||||
"PatchRequired": "要パッチ",
|
"PatchRequired": "要パッチ",
|
||||||
"PatchRequiredHint": "このゲームバージョンにはアンチチートパッチがありません。数日待ってから再度お試しください。",
|
"PatchRequiredHint": "このゲームバージョンにはアンチチートパッチがありません。数日待ってから再度お試しください",
|
||||||
"TestPatch": "テストパッチの適用",
|
"TestPatch": "テストパッチの適用",
|
||||||
"TestPatchHint": "このゲームバージョンにはアンチチートパッチがありますが、テスト段階にあります。安定するまで数日お待ちいただくか、ご自身の責任で適用してください。"
|
"TestPatchHint": "このゲームバージョンにはアンチチートパッチがありますが、テスト段階にあります。安定するまで数日お待ちいただくか、ご自身の責任で適用してください"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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": "Эта версия игры имеет лишь тестовый патч античита. Вы можете подождать пару дней до того, как он станет стабильным, либо применить его на свой страх и риск"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -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"
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
"GameDownloaded": "游戏安装成功",
|
"GameDownloaded": "游戏安装成功",
|
||||||
"ApplyPatch": "应用补丁...",
|
"ApplyPatch": "应用补丁...",
|
||||||
"PatchRequired": "需要补丁",
|
"PatchRequired": "需要补丁",
|
||||||
"PatchRequiredHint": "此游戏版本没有防作弊补丁。请等待几天,然后重试。",
|
"PatchRequiredHint": "此游戏版本没有防作弊补丁。请等待几天,然后重试",
|
||||||
"TestPatch": "应用测试补丁",
|
"TestPatch": "应用测试补丁",
|
||||||
"TestPatchHint": "此游戏版本有防作弊补丁,但处于测试阶段。您可以等待几天直到它稳定或自担风险应用它。"
|
"TestPatchHint": "此游戏版本有防作弊补丁,但处于测试阶段。您可以等待几天直到它稳定或自担风险应用它"
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
"GameDownloaded": "遊戲安裝成功",
|
"GameDownloaded": "遊戲安裝成功",
|
||||||
"ApplyPatch": "Applying patch...",
|
"ApplyPatch": "Applying patch...",
|
||||||
"PatchRequired": "需要補丁",
|
"PatchRequired": "需要補丁",
|
||||||
"PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試。",
|
"PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試",
|
||||||
"TestPatch": "應用測試補丁",
|
"TestPatch": "應用測試補丁",
|
||||||
"TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它。"
|
"TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它"
|
||||||
}
|
}
|
115
src/ts/index.ts
115
src/ts/index.ts
|
@ -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
46
src/ts/lib/DiscordRPC.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
0
src/ts/GIJSON.d.ts → src/ts/lib/GIJSON.d.ts
vendored
0
src/ts/GIJSON.d.ts → src/ts/lib/GIJSON.d.ts
vendored
|
@ -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
133
src/ts/lib/Tools.ts
Normal 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());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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'
|
||||||
)));
|
)));
|
||||||
}
|
}
|
|
@ -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) => {
|
||||||
|
|
|
@ -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"]
|
||||||
}
|
}
|
Loading…
Reference in a new issue