Merge branch 'term' of Maroxy/an-ordinary-launcher into main

This commit is contained in:
nobody 2021-10-22 12:08:49 +00:00 committed by Gogs
commit 2015b831b0
8 changed files with 207 additions and 40 deletions

View file

@ -1,4 +1,4 @@
const { app, BrowserWindow, ipcMain, Notification } = require('electron');
const { app, BrowserWindow, ipcMain, Notification, shell } = require('electron');
const path = require('path');
let mainWindow;
@ -30,6 +30,13 @@ function createWindow ()
mainWindow.loadFile(path.join(__dirname, 'public', 'html', 'index.html'));
// open URLs in Browser instead of an pop-up in electron app.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return { action: 'deny' };
});
// mainWindow.webContents.openDevTools();
}

View file

@ -2,7 +2,8 @@
"name": "an-anime-game-linux-launcher",
"version": "2.2.0-beta3",
"description": "An Anime Game Linux Launcher",
"author": "Nikita Podvirnyy",
"author": "Nikita Podvirnyy (https://notabug.org/nobody)",
"contributors": ["Marie Piontek <marie@mxy.gg> (https://marie.omg.lol)"],
"license": "GPL-3.0",
"main": "entry.js",
"scripts": {
@ -28,8 +29,7 @@
{
"target": "AppImage",
"arch": [
"x64",
"ia32"
"x64"
]
}
]

1
public/css/layout.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -8,6 +8,7 @@
<!-- CSS styles -->
<link rel="stylesheet" href="../css/index.css">
<link rel="stylesheet" href="../css/hint.min.css">
<link rel="stylesheet" href="../css/layout.min.css">
<!-- JS scripts -->
<script>require('../js/index.js');</script>

69
src/ts/GIJSON.d.ts vendored Normal file
View file

@ -0,0 +1,69 @@
interface VoicePack {
language: string;
name: string;
path: string;
size: string;
md5: string;
}
interface Latest {
name: string;
version: string;
path: string;
size: string;
md5: string;
entry: string;
voice_packs: VoicePack[];
decompressed_path: string;
segments: any[];
}
interface Diff {
name: string;
version: string;
path: string;
size: string;
md5: string;
is_recommended_update: boolean;
voice_packs: VoicePack[];
}
interface Game {
latest: Latest;
diffs: Diff[];
}
interface Plugins {
name: string;
version: string;
path: string;
size: string;
md5: string;
entry: string;
}
interface Plugin {
plugins: Plugins[];
version: string;
}
interface DeprecatedPackage {
name: string;
md5: string;
}
interface Data {
game: Game;
plugin: Plugin;
web_url: string;
force_update?: any;
pre_download_game?: any;
deprecated_packages: DeprecatedPackage[];
sdk?: any;
}
export default interface GIJSON {
retcode: number;
message: string;
data: Data;
}

View file

@ -1,14 +1,20 @@
import GIJSON from "./GIJSON";
const https = require('https');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { spawn } = require('child_process');
const { spawn, exec } = require('child_process');
type Config = {
lang: {
launcher: 'en-us' | 'ru-ru' | 'fr-fr' | 'id-id' | 'de-de' | 'es-es' | 'pt-pt' | 'th-th' | 'vi-vn' | 'ko-kr' | 'ja-jp' | 'zh-tw' | 'zh-cn',
voice: 'en-us' | 'ko-kr' | 'ja-jp' | 'zh-cn'
},
background: {
time: string|null,
name: string|null
},
version: string|null,
patch: {
version: string|null,
@ -26,6 +32,8 @@ export class Genshinlib
public static readonly launcherDir: string = path.join(os.homedir(), 'genshin-impact-launcher');
public static readonly launcherJson: string = path.join(this.launcherDir, 'launcher.json');
public static readonly TMPpatchDir: string = path.join(this.launcherDir, 'gi-on-linux');
public static readonly prefixDir: string = path.join(this.launcherDir, 'game');
public static readonly gameDir: string = path.join(this.prefixDir, 'drive_c', 'Program Files', 'Genshin Impact');
@ -49,6 +57,10 @@ export class Genshinlib
launcher: 'en-us',
voice: 'en-us'
},
background: {
time: null,
name: null
},
version: null,
patch: null
}, null, 4));
@ -72,10 +84,9 @@ export class Genshinlib
response.on('data', (chunk: any) => data += chunk);
response.on('end', () => {
data = JSON.parse(data);
let jsondata: GIJSON = JSON.parse(data);
// @ts-expect-error
return data.message === 'OK' ? resolve(data.data) : reject(null);
return jsondata.message === 'OK' ? resolve(jsondata.data) : reject(null);
});
}).on('error', (err: Error) => {
reject(err);
@ -86,10 +97,39 @@ export class Genshinlib
public static async getBackgroundUri (): Promise<string>
{
let bg = '';
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(`https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/content?filter_adv=true&launcher_id=10&language=${this.lang.launcher}`)
.then(res => res.json())
.then(async resdone => {
let oldbg = this.getConfig().background.name;
await fetch(`https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/content?filter_adv=true&launcher_id=10&language=${this.lang.launcher}`)
.then(res => res.json())
.then(resdone => bg = resdone.data.adv.background);
this.setConfig({
...this.getConfig(),
background: {
time: new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate() + 7).toString(),
name: resdone.data.adv.background.replace(/.*\//, '')
}
});
if (fs.existsSync(path.join(this.launcherDir, this.getConfig().background.name)))
{
bg = path.join(this.launcherDir, this.getConfig().background.name);
}
else
{
await this.downloadFile(resdone.data.adv.background, path.join(this.launcherDir, this.getConfig().background.name), (current: number, total: number, difference: number) => null).then(() => {
!oldbg ? console.log('No Old Background Found.') : fs.unlinkSync(path.join(this.launcherDir, oldbg));
bg = path.join(this.launcherDir, this.getConfig().background.name);
});
};
});
}
else
{
bg = path.join(this.launcherDir, this.getConfig().background.name);
};
return bg;
}
@ -137,16 +177,14 @@ export class Genshinlib
line = line.slice(0, -1);
let matches = /^(\d+) [a-zA-Z\:]+[ ]+(\d+)[ ]+[0-9\-]+% [0-9\-]+ [0-9\:]+ [a-f0-9]{8} (.+)/.exec(line);
return {
// @ts-expect-error
path: matches[3],
if (matches) {
return {
path: matches[3],
// @ts-expect-error
compressedSize: parseInt(matches[2]),
compressedSize: parseInt(matches[2]),
// @ts-expect-error
uncompressedSize: parseInt(matches[1])
uncompressedSize: parseInt(matches[1])
};
};
});
@ -162,7 +200,7 @@ export class Genshinlib
items[1] = path.relative(unpackedPath, items[1].trim());
files.forEach(file => {
if (file.path == items[1])
if (file?.path == items[1])
{
current += file.compressedSize;
@ -230,6 +268,52 @@ export class Genshinlib
return fs.existsSync(path.join(prefixPath, 'drive_c'));
}
public static patchGame (version: string, onFinish: () => void, onData: (data: string) => void) {
this.downloadFile('https://notabug.org/Krock/GI-on-Linux/archive/master.zip', 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(() => {
// Delete zip file and assign patch directory.
fs.unlinkSync(path.join(this.launcherDir, 'krock.zip'));
let patchdir: string = path.join(this.TMPpatchDir, version.replace(/\./g, ''));
// Patch out the testing phase content from the shell files if active and make sure the shell files are executable.
exec(`cd ${patchdir} && sed -i '/^echo "If you would like to test this patch, modify this script and remove the line below this one."/,+5d' patch.sh`);
exec(`cd ${patchdir} && sed -i '/^echo " necessary afterwards (Friday?). If that's the case, comment the line below."/,+2d' patch_anti_logincrash.sh`);
exec(`chmod +x ${path.join(patchdir, 'patch.sh')}`);
exec(`chmod +x ${path.join(patchdir, 'patch_anti_logincrash.sh')}`);
// Execute the patch file with "yes yes" in the beginning to agree to the choices.
let patcherProcess = exec(`yes yes | ${path.join(patchdir, 'patch.sh')}`, {
cwd: this.gameDir,
env: {
...process.env,
WINEPREFIX: this.prefixDir
}
});
patcherProcess.stdout.on('data', (data: string) => onData(data));
patcherProcess.on('close', () => {
// Execute the patch file with "yes" in the beginning to agree to the choice.
let patcherAntiCrashProcess = exec(`yes | ${path.join(patchdir, 'patch_anti_logincrash.sh')}`, {
cwd: this.gameDir,
env: {
...process.env,
WINEPREFIX: this.prefixDir
}
});
patcherAntiCrashProcess.stdout.on('data', (data: string) => onData(data));
patcherAntiCrashProcess.on('close', () => {
fs.rmSync(this.TMPpatchDir, { recursive: true });
onFinish();
});
});
});
});
}
/*
public static applyPatch (onFinish: () => void, onData: (data: string) => void)
{
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
@ -262,5 +346,5 @@ export class Genshinlib
onFinish();
});
});
}
}*/
}

View file

@ -111,20 +111,21 @@ export class LauncherUI
if (Date.now() - this.progressBar.prevTime > 1000)
{
type etaType = string | number;
let elapsed = (Date.now() - this.progressBar.beganAt) / 1000;
let eta = Math.round(total * elapsed / current - elapsed);
let etaHours: etaType = Math.floor(eta / 3600),
etaMinutes: etaType = Math.floor((eta - etaHours * 3600) / 60),
etaSeconds: etaType = eta - etaHours * 3600 - etaMinutes * 60;
let etaHours = Math.floor(eta / 3600),
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
if (etaHours < 10) // @ts-expect-error
if (etaHours < 10)
etaHours = '0' + etaHours.toString();
if (etaMinutes < 10) // @ts-expect-error
if (etaMinutes < 10)
etaMinutes = '0' + etaMinutes.toString();
if (etaSeconds < 10) // @ts-expect-error
if (etaSeconds < 10)
etaSeconds = '0' + etaSeconds.toString();
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);

View file

@ -19,18 +19,22 @@ $(() => {
// Don't really think we need this, but maybe in future~~
/*fetch(`https://genshin.mihoyo.com/launcher/10/${ Genshinlib.getConfig().lang.launcher }?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`)
fetch(`https://genshin.mihoyo.com/launcher/10/${ Genshinlib.getConfig().lang.launcher }?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`)
.then(res => res.text())
.then(body => {
$(body).appendTo('#launchcontent');
// Get the element which should have the launchers content.
let container = document.getElementById('launchcontent');
// $('.home__main').detach('.home-swiper-wrap')
// Parse the HTML and append the HTML from the site to the div.
let parser = new DOMParser();
let converted = parser.parseFromString(body, 'text/html');
container!.appendChild(converted.getElementById('__layout')!);
// Get the home container to remove the functions that don't work currently.
// let home = container!.getElementsByClassName('home__main')[0];
// home.removeChild(home.getElementsByClassName('home-swiper-wrap')[0]);
// home.removeChild(home.getElementsByClassName('home-news')[0]);
});*/
let home = container!.getElementsByClassName('home__main')[0];
home.removeChild(home.getElementsByClassName('home-swiper-wrap')[0]);
home.removeChild(home.getElementsByClassName('home-news')[0]);
});
Genshinlib.getData().then(data => {
// Update available
@ -54,7 +58,7 @@ $(() => {
LauncherUI.setState('patch-applying');
Genshinlib.applyPatch(() => {
Genshinlib.patchGame(data.game.latest.version, () => {
LauncherUI.setState('game-launch-available');
}, (data) => console.log(data.toString()));
}
@ -72,7 +76,7 @@ $(() => {
LauncherUI.setState('patch-applying');
Genshinlib.applyPatch(() => {
Genshinlib.patchGame(data.game.latest.version, () => {
LauncherUI.setState('game-launch-available');
}, (data) => console.log(data.toString()));
}
@ -132,7 +136,7 @@ $(() => {
LauncherUI.setState('patch-applying');
Genshinlib.applyPatch(() => {
Genshinlib.patchGame(data.game.latest.version, () => {
LauncherUI.setState('game-launch-available');
}, (data) => console.log(data.toString()));
}
@ -233,12 +237,12 @@ $(() => {
// patch-applying state changes only button text
$('#downloaded').text('Applying patch...');
Genshinlib.applyPatch(() => {
Genshinlib.patchGame(data.game.latest.version, () => {
LauncherUI.setState('game-launch-available');
ipcRenderer.send('notification', {
title: document.title,
content: 'Game was succesfully installed'
content: 'Game was successfully installed'
});
}, (data) => console.log(data.toString()));
}