mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-03-08 09:07:57 +03:00
Merge branch 'neutralino' of https://gitlab.com/KRypt0n_/an-anime-game-launcher into neutralino
This commit is contained in:
commit
65ab2a8be7
12 changed files with 232 additions and 95 deletions
16
index.html
16
index.html
|
@ -9,24 +9,22 @@
|
|||
|
||||
<body>
|
||||
<div id="app" theme="light">
|
||||
<h1 id="progress"></h1>
|
||||
|
||||
<img class="background">
|
||||
<img class="background" :src="backgroundUri">
|
||||
|
||||
<div id="downloader-panel" class="dark" style="display: none">
|
||||
<div id="downloader-label">
|
||||
<div class="downloader-panel" theme="dark">
|
||||
<div class="downloader-label">
|
||||
<span id="downloaded">Downloading</span>
|
||||
<span id="speed"></span>
|
||||
<span id="eta"></span>
|
||||
</div>
|
||||
|
||||
<div class="progress-bar" id="downloader">
|
||||
|
||||
<div class="progress-bar">
|
||||
<div class="progress"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="launcher-content">
|
||||
<iframe id="social" scrolling="no" style="position: absolute; border: 0; top: 0; left: 0;" width="100%" height="100%"></iframe>
|
||||
<iframe id="social" :src="socialUri" scrolling="no" style="position: absolute; border: 0; top: 0; left: 0;" width="100%" height="100%"></iframe>
|
||||
</div>
|
||||
|
||||
<div id="settings">
|
||||
|
@ -42,4 +40,4 @@
|
|||
<script type="module" src="/src/entry.js"></script>
|
||||
<script type="module" lang="ts" src="/src/pages/index.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"applicationId": "com.krypt0nn.an-anime-game-linux-launcher",
|
||||
"version": "1.0.0",
|
||||
"version": "3.0.0",
|
||||
"defaultMode": "window",
|
||||
"port": 0,
|
||||
"documentRoot": "/bundle/",
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"@neutralinojs/neu": "^8.0.0",
|
||||
"@vitejs/plugin-vue": "^2.0.1",
|
||||
"sass": "^1.45.1",
|
||||
"vite": "^2.7.4"
|
||||
"vite": "^2.7.6"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,62 +1,31 @@
|
|||
import * as Vue from 'vue/dist/vue.esm-bundler';
|
||||
import { createApp } from 'vue/dist/vue.esm-bundler';
|
||||
|
||||
import Window from '../ts/neutralino/Window';
|
||||
import Patch from '../ts/Patch';
|
||||
import Voice from '../ts/Voice';
|
||||
import fetch from '../ts/core/Fetch';
|
||||
import Downloader from '../ts/core/Downloader';
|
||||
|
||||
const app = Vue.createApp({
|
||||
import Launcher from '../ts/Launcher';
|
||||
|
||||
let app = createApp({
|
||||
data: () => ({
|
||||
progress: '0%'
|
||||
socialUri: '',
|
||||
backgroundUri: ''
|
||||
}),
|
||||
|
||||
methods: {
|
||||
showAbout: () => Window.open('about')
|
||||
},
|
||||
|
||||
mounted: () => {
|
||||
Window.current.show();
|
||||
mounted()
|
||||
{
|
||||
const launcher = new Launcher(this);
|
||||
|
||||
Patch.latest.then(console.log);
|
||||
new Promise(async (resolve) => {
|
||||
await launcher.updateSocial();
|
||||
await launcher.updateBackground();
|
||||
|
||||
/*fetch('https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?key=gcStgarh&launcher_id=10', 1000)
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
|
||||
response.body().then((body) => console.log(body.length));
|
||||
});*/
|
||||
|
||||
/*Downloader.download('https://github.com/GloriousEggroll/wine-ge-custom/releases/download/6.20-GE-1/wine-lutris-ge-6.20-1-x86_64.tar.xz', '123.tar.xz').then((stream) => {
|
||||
stream.start(() => console.log('Downloading started'));
|
||||
stream.finish(() => console.log('Downloading finished'));
|
||||
|
||||
stream.progress((current, total) => console.log(`${Math.round(current / total * 100)}%`));
|
||||
});*/
|
||||
|
||||
/*Runners.download('wine-lutris-ge-6.20-1-x86_64').then((stream) => {
|
||||
stream.downloadStart(() => console.log('Downloading started'));
|
||||
stream.downloadFinish(() => console.log('Downloading finished'));
|
||||
|
||||
stream.unpackStart(() => console.log('Unpacking started'));
|
||||
stream.unpackFinish(() => console.log('Unpacking finished'));
|
||||
});*/
|
||||
|
||||
/*DXVK.download('1.8').then((stream) => {
|
||||
stream.downloadStart(() => console.log('Downloading started'));
|
||||
stream.downloadFinish(() => console.log('Downloading finished'));
|
||||
|
||||
stream.unpackStart(() => console.log('Unpacking started'));
|
||||
stream.unpackFinish(() => console.log('Unpacking finished'));
|
||||
});*/
|
||||
|
||||
/*Archive.unpack('Audio_English(US)_2.3.0.zip', 'tmp').then((stream) => {
|
||||
stream.progress((current, total) => {
|
||||
console.log(`${Math.round(current / total * 100)}%`);
|
||||
});
|
||||
|
||||
stream.finish(() => console.log('finished'));
|
||||
});*/
|
||||
resolve(null);
|
||||
}).then(() => {
|
||||
Window.current.show();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -75,33 +75,10 @@
|
|||
.unactive
|
||||
display: none
|
||||
|
||||
.progress-bar
|
||||
padding: 0
|
||||
|
||||
background-color: rgba(0, 0, 0, .1)
|
||||
border: 1px solid rgba(0, 0, 0, .2)
|
||||
border-radius: 8px
|
||||
|
||||
.progress
|
||||
width: 0
|
||||
height: 100%
|
||||
|
||||
background-color: rgba(255, 255, 255, .7)
|
||||
border-radius: 6px
|
||||
|
||||
#downloader-panel
|
||||
.downloader-panel
|
||||
user-select: none
|
||||
|
||||
#downloader
|
||||
position: absolute
|
||||
|
||||
left: 48px
|
||||
bottom: 68px
|
||||
|
||||
width: 720px
|
||||
height: 36px
|
||||
|
||||
#downloader-label
|
||||
.downloader-label
|
||||
position: absolute
|
||||
|
||||
left: 48px
|
||||
|
@ -120,11 +97,34 @@
|
|||
color: #cccccc
|
||||
font-weight: 100
|
||||
|
||||
#downloader-panel.dark
|
||||
.progress-bar
|
||||
position: absolute
|
||||
|
||||
padding: 0
|
||||
|
||||
left: 48px
|
||||
bottom: 68px
|
||||
|
||||
width: 720px
|
||||
height: 36px
|
||||
|
||||
background-color: rgba(0, 0, 0, .1)
|
||||
border: 1px solid rgba(0, 0, 0, .2)
|
||||
border-radius: 8px
|
||||
|
||||
.progress
|
||||
width: 0
|
||||
height: 100%
|
||||
|
||||
background-color: rgba(255, 255, 255, .7)
|
||||
border-radius: 6px
|
||||
|
||||
|
||||
/*#downloader-panel.dark
|
||||
#downloader-label
|
||||
#downloaded, #speed, #eta
|
||||
color: rgba(0, 0, 0, .7)
|
||||
|
||||
#downloader
|
||||
background-color: rgba(0,0,0,.3)
|
||||
border: 1px solid rgba(0,0,0,.4)
|
||||
border: 1px solid rgba(0,0,0,.4)
|
|
@ -1,11 +1,10 @@
|
|||
import constants from './Constants';
|
||||
|
||||
declare const Neutralino;
|
||||
declare const NL_CWD;
|
||||
|
||||
// Ok yea, null and object aren't scalars
|
||||
// Ok yea, null, object and boolean aren't scalars
|
||||
// but I don't care
|
||||
type scalar = null | string | number | object;
|
||||
type scalar = null | string | number | boolean | object;
|
||||
|
||||
export default class Configs
|
||||
{
|
||||
|
|
|
@ -90,6 +90,16 @@ class Paths
|
|||
return new Promise(async (resolve) => resolve(`${await this.launcherDir}/config.json`));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache file
|
||||
*
|
||||
* @default "~/.local/share/anime-game-launcher/cache.json"
|
||||
*/
|
||||
public static get cache(): Promise<string>
|
||||
{
|
||||
return new Promise(async (resolve) => resolve(`${await this.launcherDir}/cache.json`));
|
||||
}
|
||||
|
||||
public static readonly prefix = Prefix;
|
||||
|
||||
/**
|
||||
|
|
95
src/ts/Launcher.ts
Normal file
95
src/ts/Launcher.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
import constants from './Constants';
|
||||
import Configs from './Configs';
|
||||
import fetch from './core/Fetch';
|
||||
|
||||
export default class Launcher
|
||||
{
|
||||
public app;
|
||||
|
||||
public constructor(app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get background image URI
|
||||
*
|
||||
* Neutralino is unnable to load local files
|
||||
* so we sadly can't provide proper caching
|
||||
*/
|
||||
/*public getBackgroundUri(): Promise<string>
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
Cache.get('background').then(async (background) => {
|
||||
const launcherDir = await constants.paths.launcherDir;
|
||||
|
||||
// If the background is not cached or
|
||||
// the cache is expired
|
||||
if (background === null || background.expired)
|
||||
{
|
||||
const header = await fetch(constants.backgroundUri + await Configs.get('lang.launcher'));
|
||||
|
||||
// Reject an error if background server is not available
|
||||
if (!header.ok)
|
||||
reject(new Error(`${constants.placeholders.uppercase.company}'s background server is not responding`));
|
||||
|
||||
else
|
||||
{
|
||||
header.body().then(async (body) => {
|
||||
const json = JSON.parse(body);
|
||||
|
||||
// If the background wasn't loaded - then again reject an error
|
||||
if (json.data.adv.background === undefined)
|
||||
reject(new Error('Background property wasn\'t found'));
|
||||
|
||||
else
|
||||
{
|
||||
// Store some background info to the cache
|
||||
await Cache.set('background', {
|
||||
gameVersion: (await Game.latest).version,
|
||||
cachedAt: Math.round(Date.now() / 1000)
|
||||
}, 7 * 24 * 60 * 60);
|
||||
|
||||
console.log(json.data.adv.background);
|
||||
|
||||
// Download background picture and return path to it
|
||||
Downloader.download(json.data.adv.background, `${launcherDir}/background.png`)
|
||||
.then((stream) => {
|
||||
stream.finish(() => resolve(`file://${launcherDir}/background.png`));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Background is cached
|
||||
// todo: add cache auto dropping when the banner is updated
|
||||
else resolve(`file://${launcherDir}/background.png`);
|
||||
});
|
||||
});
|
||||
}*/
|
||||
|
||||
public updateBackground(): Promise<void>
|
||||
{
|
||||
return new Promise(async (resolve) => {
|
||||
fetch(constants.backgroundUri + await Configs.get('lang.launcher'))
|
||||
.then((header) => header.body().then((body) => {
|
||||
this.app.backgroundUri = JSON.parse(body).data.adv.background;
|
||||
|
||||
resolve();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update launcher social buttons
|
||||
*/
|
||||
public updateSocial(): Promise<void>
|
||||
{
|
||||
return new Promise(async (resolve) => {
|
||||
this.app.socialUri = `https://${constants.placeholders.lowercase.first}.${constants.placeholders.lowercase.company}.com/launcher/10/${await Configs.get('lang.launcher')}?api_url=https%3A%2F%2Fapi-os-takumi.${constants.placeholders.lowercase.company}.com%2Fhk4e_global&key=gcStgarh&prev=false`;
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
};
|
|
@ -9,8 +9,6 @@ import constants from './Constants';
|
|||
import Game from './Game';
|
||||
import fetch from './core/Fetch';
|
||||
|
||||
declare const Neutralino;
|
||||
|
||||
export default class Patch
|
||||
{
|
||||
public static fetchTimeout: number = 3000;
|
||||
|
|
70
src/ts/core/Cache.ts
Normal file
70
src/ts/core/Cache.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
import constants from '../Constants';
|
||||
|
||||
type Record = {
|
||||
expired: boolean;
|
||||
value: object|object[];
|
||||
};
|
||||
|
||||
declare const Neutralino;
|
||||
|
||||
export default class Cache
|
||||
{
|
||||
/**
|
||||
* Get cached value
|
||||
*
|
||||
* @returns null if this value is not cached
|
||||
*/
|
||||
public static get(name: string): Promise<Record|null>
|
||||
{
|
||||
return new Promise(async (resolve) => {
|
||||
Neutralino.filesystem.readFile(await constants.paths.cache)
|
||||
.then((cache) => {
|
||||
cache = JSON.parse(cache);
|
||||
|
||||
if (cache[name] === undefined)
|
||||
resolve(null);
|
||||
|
||||
else
|
||||
{
|
||||
resolve({
|
||||
expired: cache[name].ttl !== null ? Date.now() > cache[name].ttl * 1000 : false,
|
||||
value: JSON.parse(atob(cache[name].value))
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => resolve(null));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache value
|
||||
*
|
||||
* @param name name of the value to cache
|
||||
* @param value value to cache
|
||||
* @param ttl number of seconds to cache
|
||||
*
|
||||
* @returns promise that indicates when the value will be cached
|
||||
*/
|
||||
public static set(name: string, value: object|object[], ttl: number|null = null): Promise<void>
|
||||
{
|
||||
return new Promise((resolve) => {
|
||||
constants.paths.cache.then((cacheFile) => {
|
||||
let cache = {};
|
||||
|
||||
Neutralino.filesystem.readFile(cacheFile)
|
||||
.then((cacheRaw) => cache = JSON.parse(cacheRaw))
|
||||
.catch(() => {});
|
||||
|
||||
cache[name] = {
|
||||
ttl: ttl !== null ? Math.round(Date.now() / 1000) + ttl : null,
|
||||
value: btoa(JSON.stringify(value))
|
||||
};
|
||||
|
||||
Neutralino.filesystem.writeFile(cacheFile, JSON.stringify(cache))
|
||||
.then(() => resolve());
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export type { Record };
|
|
@ -101,8 +101,8 @@ export default class Downloader
|
|||
/**
|
||||
* Download file
|
||||
*
|
||||
* @param uri
|
||||
* @param output
|
||||
* @param uri file's uri to download
|
||||
* @param output relative or absolute path to the file to save it as
|
||||
*
|
||||
* @returns downloading stream
|
||||
*/
|
||||
|
|
|
@ -7,9 +7,7 @@ export default defineConfig({
|
|||
server: {
|
||||
port: 8080
|
||||
},
|
||||
plugins: [
|
||||
vue()
|
||||
],
|
||||
plugins: [vue()],
|
||||
base: '',
|
||||
build: {
|
||||
outDir: 'bundle',
|
||||
|
|
Loading…
Add table
Reference in a new issue