mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-03-15 20:51:39 +03:00
API improvements
- made `Downloader.pause()` and `resume()` methods to pause/resume downloading - made `AbstractInstaller.pauseDownload()` and `resumeDownload()` methods - (probably) fixed some special cases of `Domain.getInfo()` method work - added translations for progress bar - added pause/resume functionality for game or voice downloading
This commit is contained in:
parent
fcd90315e6
commit
8497c9d13b
14 changed files with 296 additions and 49 deletions
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Launcher window
|
||||
launcher:
|
||||
# Progress bar
|
||||
progress:
|
||||
pause: Pausieren
|
||||
resume: Fortsetzen
|
||||
|
||||
# Game installation
|
||||
game:
|
||||
downloading: Spiel ist am herunterladen...
|
||||
unpacking: Spiel wird entpackt...
|
||||
deleting_outdated: Lösche veraltete dateien...
|
||||
|
||||
# Voice packages installation
|
||||
voice:
|
||||
deleting: Lösche Sprachpakete...
|
||||
downloading: Sprachpaket {voice} wird heruntergeladen...
|
||||
unpacking: Sprachpaket {voice} wird entpackt..
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# When the game should be installed or updated
|
||||
installation:
|
||||
|
|
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Launcher window
|
||||
launcher:
|
||||
# Progress bar
|
||||
progress:
|
||||
pause: Pause
|
||||
resume: Resume
|
||||
|
||||
# Game installation
|
||||
game:
|
||||
downloading: Downloading game...
|
||||
unpacking: Unpacking game...
|
||||
deleting_outdated: Deleting outdated files...
|
||||
|
||||
# Voice packages installation
|
||||
voice:
|
||||
deleting: Deleting voice packages...
|
||||
downloading: Downloading {voice} voice package...
|
||||
unpacking: Unpacking {voice} voice package...
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# When the game should be installed or updated
|
||||
installation:
|
||||
|
|
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Launcher window
|
||||
launcher:
|
||||
# Progress bar
|
||||
progress:
|
||||
pause: Pause
|
||||
resume: Continuer
|
||||
|
||||
# Game installation
|
||||
game:
|
||||
downloading: Téléchargement du jeu...
|
||||
unpacking: Décompression du jeu...
|
||||
deleting_outdated: Suppression des fichiers non à jour...
|
||||
|
||||
# Voice packages installation
|
||||
voice:
|
||||
deleting: Suppression des pack de voix...
|
||||
downloading: 'Téléchargement du pack de voix : {voice}...'
|
||||
unpacking: 'Décompression du pack de voix : {voice}...'
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# When the game should be installed or updated
|
||||
installation:
|
||||
|
|
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Launcher window
|
||||
launcher:
|
||||
# Progress bar
|
||||
progress:
|
||||
pause: Pause
|
||||
resume: Resume
|
||||
|
||||
# Game installation
|
||||
game:
|
||||
downloading: Downloading game...
|
||||
unpacking: Unpacking game...
|
||||
deleting_outdated: Deleting outdated files...
|
||||
|
||||
# Voice packages installation
|
||||
voice:
|
||||
deleting: Deleting voice packages...
|
||||
downloading: Downloading {voice} voice package...
|
||||
unpacking: Unpacking {voice} voice package...
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# When the game should be installed or updated
|
||||
installation:
|
||||
|
|
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Окно лаунчера
|
||||
launcher:
|
||||
# Прогресс бар
|
||||
progress:
|
||||
pause: Пауза
|
||||
resume: Продолжить
|
||||
|
||||
# Установка игры
|
||||
game:
|
||||
downloading: Скачивание игры...
|
||||
unpacking: Распаковка игры...
|
||||
deleting_outdated: Удаление устаревших файлов...
|
||||
|
||||
# Установка звуковых пакетов
|
||||
voice:
|
||||
deleting: Удаление звуковых пакетов...
|
||||
downloading: Скачивание звукового пакета {voice}...
|
||||
unpacking: Распаковка звукового пакета {voice}...
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# Когда игра должна быть установлена или обновлена
|
||||
installation:
|
||||
|
|
|
@ -14,6 +14,24 @@ splash:
|
|||
|
||||
# Launcher window
|
||||
launcher:
|
||||
# Progress bar
|
||||
progress:
|
||||
pause: pause
|
||||
resume: wesume
|
||||
|
||||
# Game installation
|
||||
game:
|
||||
downloading: downwoading game... -.-
|
||||
unpacking: unpacking g-game (o^▽^o)
|
||||
deleting_outdated: deweting outdated fiwes...
|
||||
|
||||
# Voice packages installation
|
||||
voice:
|
||||
deleting: deweting voice packages...
|
||||
downloading: downwoading {voice} voice package...
|
||||
unpacking: u-unpacking {voice} voice package...
|
||||
|
||||
# Launcher states
|
||||
states:
|
||||
# When the game should be installed or updated
|
||||
installation:
|
||||
|
|
|
@ -157,4 +157,5 @@
|
|||
</button>
|
||||
|
||||
<button class="button hint--top hint--large" aria-label="" id="launch">Launch</button>
|
||||
<button class="button" id="pause">Pause</button>
|
||||
</main>
|
||||
|
|
|
@ -40,7 +40,7 @@ img.background
|
|||
.button-blue:hover:not([disabled])
|
||||
background-color: #7284b6
|
||||
|
||||
#launch
|
||||
#launch, #pause
|
||||
position: absolute
|
||||
|
||||
width: 238px
|
||||
|
@ -51,6 +51,9 @@ img.background
|
|||
|
||||
font-size: 22px
|
||||
|
||||
#pause
|
||||
display: none
|
||||
|
||||
#predownload
|
||||
position: absolute
|
||||
display: none
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import constants from '../Constants';
|
||||
import Downloader from './Downloader';
|
||||
import Downloader, { Stream as DownloadStream } from './Downloader';
|
||||
import Archive from './Archive';
|
||||
import { DebugThread } from './Debug';
|
||||
|
||||
|
@ -12,6 +12,11 @@ export default abstract class Installer
|
|||
*/
|
||||
public downloadProgressInterval: number = 200;
|
||||
|
||||
/**
|
||||
* The interval in ms between checking was downloading resumed after pausing
|
||||
*/
|
||||
public downloadPauseInterval: number = 500;
|
||||
|
||||
/**
|
||||
* The interval in ms between progress event calls
|
||||
*/
|
||||
|
@ -32,6 +37,8 @@ export default abstract class Installer
|
|||
protected downloadFinished: boolean = false;
|
||||
protected unpackFinished: boolean = false;
|
||||
|
||||
protected downloadStream?: DownloadStream;
|
||||
|
||||
/**
|
||||
* @param uri URI to the archive we need to download
|
||||
* @param unpackDir path to unpack this archive to
|
||||
|
@ -94,7 +101,10 @@ export default abstract class Installer
|
|||
if (!alreadyDownloaded)
|
||||
{
|
||||
Downloader.download(uri, archivePath).then((stream) => {
|
||||
this.downloadStream = stream;
|
||||
|
||||
stream.progressInterval = this.downloadProgressInterval;
|
||||
stream.pauseInterval = this.downloadPauseInterval;
|
||||
|
||||
stream.start(() => {
|
||||
this.downloadStarted = true;
|
||||
|
@ -194,4 +204,20 @@ export default abstract class Installer
|
|||
if (this.unpackFinished)
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause downloading
|
||||
*/
|
||||
public pauseDownload()
|
||||
{
|
||||
this.downloadStream?.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume downloading
|
||||
*/
|
||||
public resumeDownload()
|
||||
{
|
||||
this.downloadStream?.resume();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,22 +17,20 @@ export default class Domain
|
|||
process.runningInterval = 500;
|
||||
process.outputInterval = 500;
|
||||
|
||||
const resolveInfo = (info: DomainInfo) => {
|
||||
process.outputInterval = null;
|
||||
process.runningInterval = null;
|
||||
|
||||
process.kill();
|
||||
|
||||
debugThread.log({ message: info });
|
||||
|
||||
resolve(info);
|
||||
};
|
||||
|
||||
let output = '';
|
||||
|
||||
process.output((outputPart) => {
|
||||
output += outputPart;
|
||||
|
||||
const resolveInfo = (info: DomainInfo) => {
|
||||
process.outputInterval = null;
|
||||
process.runningInterval = null;
|
||||
|
||||
process.kill();
|
||||
|
||||
debugThread.log({ message: info });
|
||||
|
||||
resolve(info);
|
||||
};
|
||||
|
||||
const processOutput = () => {
|
||||
if (output.includes('Name or service not known'))
|
||||
{
|
||||
resolveInfo({
|
||||
|
@ -55,7 +53,15 @@ export default class Domain
|
|||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
process.output((outputPart) => {
|
||||
output += outputPart;
|
||||
|
||||
processOutput();
|
||||
});
|
||||
|
||||
process.finish(() => processOutput());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,7 +21,13 @@ class Stream
|
|||
*/
|
||||
public progressInterval: number = 200;
|
||||
|
||||
/**
|
||||
* The interval in ms between checking was downloading resumed after pausing
|
||||
*/
|
||||
public pauseInterval: number = 500;
|
||||
|
||||
protected uri: string;
|
||||
protected output: string;
|
||||
protected total: number;
|
||||
protected previous: number = 0;
|
||||
|
||||
|
@ -30,15 +36,19 @@ class Stream
|
|||
protected onFinish?: () => void;
|
||||
|
||||
protected started: boolean = false;
|
||||
protected paused: boolean = true; // true because we call .resume() method at start
|
||||
protected finished: boolean = false;
|
||||
|
||||
protected debugThread: DebugThread;
|
||||
|
||||
public constructor(uri: string, output: string, total: number)
|
||||
{
|
||||
this.uri = uri;
|
||||
this.output = output;
|
||||
this.total = total;
|
||||
this.started = true;
|
||||
|
||||
const debugThread = new DebugThread('Downloader/Stream', {
|
||||
this.debugThread = new DebugThread('Downloader/Stream', {
|
||||
message: {
|
||||
'uri': uri,
|
||||
'output file': output,
|
||||
|
@ -49,39 +59,36 @@ class Stream
|
|||
if (this.onStart)
|
||||
this.onStart();
|
||||
|
||||
const command = `curl -s -L -N -o "${Process.addSlashes(output)}" "${uri}"`;
|
||||
|
||||
Neutralino.os.execCommand(command, {
|
||||
background: true
|
||||
}).then((result) => {
|
||||
this._id = result.pid;
|
||||
});
|
||||
|
||||
debugThread.log(`Downloading started with command: ${command}`);
|
||||
this.resume();
|
||||
|
||||
const updateProgress = () => {
|
||||
Neutralino.filesystem.getStats(output).then((stats) => {
|
||||
if (this.onProgress)
|
||||
this.onProgress(stats.size, this.total, stats.size - this.previous);
|
||||
if (!this.paused)
|
||||
{
|
||||
Neutralino.filesystem.getStats(output).then((stats) => {
|
||||
if (this.onProgress)
|
||||
this.onProgress(stats.size, this.total, stats.size - this.previous);
|
||||
|
||||
this.previous = stats.size;
|
||||
this.previous = stats.size;
|
||||
|
||||
if (stats.size >= this.total)
|
||||
{
|
||||
this.finished = true;
|
||||
if (stats.size >= this.total)
|
||||
{
|
||||
this.finished = true;
|
||||
|
||||
debugThread.log('Downloading finished');
|
||||
this.debugThread.log('Downloading finished');
|
||||
|
||||
if (this.onFinish)
|
||||
this.onFinish();
|
||||
}
|
||||
if (this.onFinish)
|
||||
this.onFinish();
|
||||
}
|
||||
|
||||
if (!this.finished)
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
}).catch(() => {
|
||||
if (!this.finished)
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
});
|
||||
if (!this.finished)
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
}).catch(() => {
|
||||
if (!this.finished)
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
});
|
||||
}
|
||||
|
||||
else setTimeout(updateProgress, this.pauseInterval);
|
||||
};
|
||||
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
|
@ -123,6 +130,42 @@ class Stream
|
|||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause downloading
|
||||
*/
|
||||
public pause()
|
||||
{
|
||||
if (!this.paused)
|
||||
{
|
||||
this.debugThread.log('Downloading paused');
|
||||
|
||||
this.close(true);
|
||||
|
||||
this.paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume downloading
|
||||
*/
|
||||
public resume()
|
||||
{
|
||||
if (this.paused)
|
||||
{
|
||||
const command = `curl -s -L -N -C - -o "${Process.addSlashes(this.output)}" "${this.uri}"`;
|
||||
|
||||
this.debugThread.log(`Downloading started with command: ${command}`);
|
||||
|
||||
Neutralino.os.execCommand(command, {
|
||||
background: true
|
||||
}).then((result) => {
|
||||
this._id = result.pid;
|
||||
});
|
||||
|
||||
this.paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close downloading stream
|
||||
*/
|
||||
|
|
|
@ -25,6 +25,7 @@ export default class State
|
|||
public launcher: Launcher;
|
||||
|
||||
public launchButton: HTMLElement;
|
||||
public pauseButton: HTMLElement;
|
||||
public predownloadButton: HTMLElement;
|
||||
public settingsButton: HTMLElement;
|
||||
|
||||
|
@ -51,6 +52,7 @@ export default class State
|
|||
this.launcher = launcher;
|
||||
|
||||
this.launchButton = <HTMLElement>document.getElementById('launch');
|
||||
this.pauseButton = <HTMLElement>document.getElementById('pause');
|
||||
this.predownloadButton = <HTMLElement>document.getElementById('predownload');
|
||||
this.settingsButton = <HTMLElement>document.getElementById('settings');
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { get as svelteget } from 'svelte/store';
|
||||
import { _ } from 'svelte-i18n';
|
||||
|
||||
import type Launcher from '../../Launcher';
|
||||
|
||||
import Game from '../../Game';
|
||||
|
@ -27,12 +30,35 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
Game.update(prevGameVersion).then((stream) => {
|
||||
launcher.progressBar?.init({
|
||||
label: 'Downloading game...',
|
||||
label: svelteget(_)('launcher.progress.game.downloading'),
|
||||
showSpeed: true,
|
||||
showEta: true,
|
||||
showPercents: true,
|
||||
showTotals: true
|
||||
});
|
||||
|
||||
// Show pause/resume button
|
||||
launcher.state!.pauseButton.style['display'] = 'block';
|
||||
|
||||
let paused = false;
|
||||
|
||||
launcher.state!.pauseButton.onclick = () => {
|
||||
if (!paused)
|
||||
{
|
||||
stream?.pauseDownload();
|
||||
|
||||
launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.resume');
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
stream?.resumeDownload();
|
||||
|
||||
launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.pause');
|
||||
}
|
||||
|
||||
paused = !paused;
|
||||
};
|
||||
|
||||
stream?.downloadStart(() => launcher.progressBar?.show());
|
||||
|
||||
|
@ -42,7 +68,7 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
stream?.unpackStart(() => {
|
||||
launcher.progressBar?.init({
|
||||
label: 'Unpacking game...',
|
||||
label: svelteget(_)('launcher.progress.game.unpacking'),
|
||||
showSpeed: true,
|
||||
showEta: true,
|
||||
showPercents: true,
|
||||
|
@ -70,7 +96,7 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
if (files.length > 0)
|
||||
{
|
||||
launcher.progressBar?.init({
|
||||
label: 'Deleting outdated files...',
|
||||
label: svelteget(_)('launcher.progress.game.deleting_outdated'),
|
||||
showSpeed: false,
|
||||
showEta: true,
|
||||
showPercents: true,
|
||||
|
@ -103,6 +129,9 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
// Download voice package when the game itself has been installed
|
||||
const installVoice = () => {
|
||||
// Hide pause/resume button
|
||||
launcher.state!.pauseButton.style['display'] = 'none';
|
||||
|
||||
import('./InstallVoice').then((module) => {
|
||||
module.default(launcher).then(() => resolve());
|
||||
});
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { get as svelteget } from 'svelte/store';
|
||||
import { _ } from 'svelte-i18n';
|
||||
|
||||
import type Launcher from '../../Launcher';
|
||||
import type { VoiceLang } from '../../types/Voice';
|
||||
|
||||
|
@ -25,7 +28,7 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
if (packagesToDelete.length > 0)
|
||||
{
|
||||
launcher.progressBar?.init({
|
||||
label: `Deleting voice packages...`,
|
||||
label: svelteget(_)('launcher.progress.voice.deleting'),
|
||||
showSpeed: false,
|
||||
showEta: false,
|
||||
showPercents: true,
|
||||
|
@ -50,12 +53,35 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
else Voice.update(selectedVoice, packagesVersions[selectedVoice] ?? null).then((stream) => {
|
||||
launcher.progressBar?.init({
|
||||
label: `Downloading ${selectedVoice} voice package...`,
|
||||
label: svelteget(_)('launcher.progress.voice.downloading', { values: { voice: selectedVoice } }),
|
||||
showSpeed: true,
|
||||
showEta: true,
|
||||
showPercents: true,
|
||||
showTotals: true
|
||||
});
|
||||
|
||||
// Show pause/resume button
|
||||
launcher.state!.pauseButton.style['display'] = 'block';
|
||||
|
||||
let paused = false;
|
||||
|
||||
launcher.state!.pauseButton.onclick = () => {
|
||||
if (!paused)
|
||||
{
|
||||
stream?.pauseDownload();
|
||||
|
||||
launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.resume');
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
stream?.resumeDownload();
|
||||
|
||||
launcher.state!.pauseButton.textContent = svelteget(_)('launcher.progress.pause');
|
||||
}
|
||||
|
||||
paused = !paused;
|
||||
};
|
||||
|
||||
stream?.downloadStart(() => launcher.progressBar?.show());
|
||||
|
||||
|
@ -65,7 +91,7 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
stream?.unpackStart(() => {
|
||||
launcher.progressBar?.init({
|
||||
label: `Unpacking ${selectedVoice} voice package...`,
|
||||
label: svelteget(_)('launcher.progress.voice.unpacking', { values: { voice: selectedVoice } }),
|
||||
showSpeed: true,
|
||||
showEta: true,
|
||||
showPercents: true,
|
||||
|
@ -84,6 +110,9 @@ export default (launcher: Launcher): Promise<void> => {
|
|||
|
||||
stream?.unpackFinish(() => {
|
||||
launcher.progressBar?.hide();
|
||||
|
||||
// Hide pause/resume button
|
||||
launcher.state!.pauseButton.style['display'] = 'none';
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue