mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-03-19 14:39:59 +03:00
Added Archive.unpack
method
This commit is contained in:
parent
7a5a0e572b
commit
944b70e926
5 changed files with 297 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
.lite_workspace.lua
|
||||
yarn.lock
|
||||
Audio_English(US)_2.3.0.zip
|
||||
|
||||
/bin
|
||||
/dist
|
||||
|
|
|
@ -3,6 +3,7 @@ import * as Vue from 'vue/dist/vue.esm-bundler';
|
|||
import Window from '../ts/neutralino/Window';
|
||||
|
||||
import Downloader from '../ts/Downloader';
|
||||
import Archive from '../ts/Archive';
|
||||
|
||||
const app = Vue.createApp({
|
||||
data: () => ({
|
||||
|
@ -16,7 +17,15 @@ const app = Vue.createApp({
|
|||
mounted: () => {
|
||||
Window.current.show();
|
||||
|
||||
Downloader.download('https://autopatchhk.yuanshen.com/client_app/download/pc_zip/20211117173404_G0gLRnxvOd4PvSu9/Audio_English(US)_2.3.0.zip').then((stream) => {
|
||||
/*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'));
|
||||
});*/
|
||||
|
||||
/*Downloader.download('https://autopatchhk.yuanshen.com/client_app/download/pc_zip/20211117173404_G0gLRnxvOd4PvSu9/Audio_English(US)_2.3.0.zip').then((stream) => {
|
||||
stream.progress((current: number, total: number) => {
|
||||
document.getElementById('progress').innerHTML = `${Math.round(current / total * 100)}%`;
|
||||
});
|
||||
|
@ -24,7 +33,7 @@ const app = Vue.createApp({
|
|||
stream.finish(() => {
|
||||
console.log('finished');
|
||||
});
|
||||
});
|
||||
});*/
|
||||
}
|
||||
});
|
||||
|
||||
|
|
256
src/ts/Archive.ts
Normal file
256
src/ts/Archive.ts
Normal file
|
@ -0,0 +1,256 @@
|
|||
import type {
|
||||
ArchiveType,
|
||||
Size,
|
||||
File,
|
||||
ArchiveInfo
|
||||
} from './types/Archive';
|
||||
|
||||
class Stream
|
||||
{
|
||||
/**
|
||||
* The interval in ms between progress event calls
|
||||
*/
|
||||
public progressInterval: number = 500;
|
||||
|
||||
protected path: string;
|
||||
protected unpackDir: string|null;
|
||||
protected unpacked: number = 0;
|
||||
|
||||
protected archive: ArchiveInfo;
|
||||
|
||||
protected onProgress?: (current: number, total: number, difference: number) => void;
|
||||
protected onFinish?: () => void;
|
||||
protected onError?: () => void;
|
||||
|
||||
protected finished: boolean = false;
|
||||
protected throwedError: boolean = false;
|
||||
|
||||
/**
|
||||
* @param path path to archive
|
||||
* @param unpackDir directory to unpack
|
||||
*/
|
||||
public constructor(path: string, unpackDir: string|null = null)
|
||||
{
|
||||
this.path = path;
|
||||
this.unpackDir = unpackDir;
|
||||
|
||||
Archive.getInfo(path).then((info) => {
|
||||
if (info === null)
|
||||
{
|
||||
this.throwedError = true;
|
||||
|
||||
if (this.onError)
|
||||
this.onError();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
this.archive = info;
|
||||
|
||||
const command = {
|
||||
tar: `tar -xvf "${path}"${unpackDir ? ` -C "${unpackDir}"` : ''}`,
|
||||
zip: `unzip -o "${path}"${unpackDir ? ` -d "${unpackDir}"` : ''}`
|
||||
}[this.archive.type];
|
||||
|
||||
let remainedFiles = this.archive.files;
|
||||
|
||||
// @ts-expect-error
|
||||
const baseDir = unpackDir ?? NL_CWD;
|
||||
|
||||
// @ts-expect-error
|
||||
Neutralino.os.execCommand(command, {
|
||||
background: true
|
||||
});
|
||||
|
||||
const updateProgress = async () => {
|
||||
let difference: number = 0;
|
||||
|
||||
remainedFiles.forEach((file) => {
|
||||
if (file.path != '#unpacked#')
|
||||
{
|
||||
// @ts-expect-error
|
||||
Neutralino.filesystem.getStats(`${baseDir}/${file.path}`)
|
||||
.then(() => {
|
||||
this.unpacked += file.size.uncompressed;
|
||||
difference += file.size.uncompressed;
|
||||
|
||||
file.path = '#unpacked#';
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
});
|
||||
|
||||
remainedFiles = remainedFiles.filter((file) => file.path != '#unpacked#');
|
||||
|
||||
if (this.onProgress)
|
||||
this.onProgress(this.unpacked, this.archive.size.uncompressed, difference);
|
||||
|
||||
if (this.unpacked >= this.archive.size.uncompressed)
|
||||
{
|
||||
this.finished = true;
|
||||
|
||||
if (this.onFinish)
|
||||
this.onFinish();
|
||||
}
|
||||
|
||||
if (!this.finished)
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
};
|
||||
|
||||
setTimeout(updateProgress, this.progressInterval);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify event that will be called every [this.progressInterval] ms during archive unpacking
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public progress(callback: (current: number, total: number, difference: number) => void)
|
||||
{
|
||||
this.onProgress = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify event that will be called after the archive will be unpacked
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public finish(callback: () => void)
|
||||
{
|
||||
this.onFinish = callback;
|
||||
|
||||
if (this.finished)
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify event that will be called if archive can't be unpacked
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
public error(callback: () => void)
|
||||
{
|
||||
this.onError = callback;
|
||||
|
||||
if (this.throwedError)
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
export default class Archive
|
||||
{
|
||||
/**
|
||||
* Get type of archive
|
||||
*
|
||||
* @param path path to archive
|
||||
* @returns ArchiveType|null
|
||||
*/
|
||||
public static getType(path: string): ArchiveType|null
|
||||
{
|
||||
if (path.substring(path.length - 4) == '.zip')
|
||||
return 'zip';
|
||||
|
||||
else if (path.substring(path.length - 7, path.length - 2) == '.tar.')
|
||||
return 'tar';
|
||||
|
||||
else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get archive info
|
||||
*
|
||||
* @param path path to archive
|
||||
* @returns Promise<ArchiveInfo|null>
|
||||
*/
|
||||
public static getInfo(path: string): Promise<ArchiveInfo|null>
|
||||
{
|
||||
return new Promise(async (resolve) => {
|
||||
let archive: ArchiveInfo = {
|
||||
size: {
|
||||
compressed: null,
|
||||
uncompressed: null
|
||||
},
|
||||
type: this.getType(path),
|
||||
files: []
|
||||
};
|
||||
|
||||
switch (archive.type)
|
||||
{
|
||||
case 'tar':
|
||||
// @ts-expect-error
|
||||
const tarOutput = await Neutralino.os.execCommand(`tar -tvf "${path}"`);
|
||||
|
||||
for (const match of tarOutput.stdOut.matchAll(/^[dwxr\-]+ [\w/]+[ ]+(\d+) [0-9\-]+ [0-9\:]+ (.+)/gm))
|
||||
{
|
||||
let fileSize = parseInt(match[1]);
|
||||
|
||||
archive.size.uncompressed += fileSize;
|
||||
|
||||
archive.files.push({
|
||||
path: match[2],
|
||||
size: {
|
||||
compressed: null,
|
||||
uncompressed: fileSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resolve(archive);
|
||||
|
||||
break;
|
||||
|
||||
case 'zip':
|
||||
// @ts-expect-error
|
||||
const zipOutput = await Neutralino.os.execCommand(`unzip -v "${path}"`);
|
||||
|
||||
for (const match of zipOutput.stdOut.matchAll(/^(\d+) [a-zA-Z\:]+[ ]+(\d+)[ ]+[0-9\-]+% [0-9\-]+ [0-9\:]+ [a-f0-9]{8} (.+)/gm))
|
||||
{
|
||||
let uncompressedSize = parseInt(match[1]),
|
||||
compressedSize = parseInt(match[2]);
|
||||
|
||||
archive.size.compressed += compressedSize;
|
||||
archive.size.uncompressed += uncompressedSize;
|
||||
|
||||
archive.files.push({
|
||||
path: match[3],
|
||||
size: {
|
||||
compressed: compressedSize,
|
||||
uncompressed: uncompressedSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resolve(archive);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
resolve(null);
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack archive
|
||||
*
|
||||
* @param path path to archive
|
||||
* @param unpackDir directory to unpack
|
||||
*/
|
||||
public static unpack(path: string, unpackDir: string|null = null): Promise<Stream>
|
||||
{
|
||||
return new Promise((resolve) => resolve(new Stream(path, unpackDir)));
|
||||
}
|
||||
}
|
||||
|
||||
export { Stream };
|
||||
|
||||
export type {
|
||||
ArchiveType,
|
||||
File,
|
||||
Size,
|
||||
ArchiveInfo
|
||||
};
|
|
@ -1,5 +1,8 @@
|
|||
class Stream
|
||||
{
|
||||
/**
|
||||
* The interval in ms between progress event calls
|
||||
*/
|
||||
public progressInterval: number = 200;
|
||||
|
||||
protected uri: string;
|
||||
|
|
26
src/ts/types/Archive.d.ts
vendored
Normal file
26
src/ts/types/Archive.d.ts
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
type ArchiveType =
|
||||
| 'tar'
|
||||
| 'zip';
|
||||
|
||||
type Size = {
|
||||
compressed?: number;
|
||||
uncompressed?: number;
|
||||
};
|
||||
|
||||
type File = {
|
||||
path: string;
|
||||
size: Size;
|
||||
};
|
||||
|
||||
type ArchiveInfo = {
|
||||
size: Size;
|
||||
type: ArchiveType;
|
||||
files: File[];
|
||||
};
|
||||
|
||||
export type {
|
||||
ArchiveType,
|
||||
Size,
|
||||
File,
|
||||
ArchiveInfo
|
||||
};
|
Loading…
Add table
Reference in a new issue