update
This commit is contained in:
parent
db3497138b
commit
ae11e8e17d
117
dist/app/downloadDemoFile.js
vendored
117
dist/app/downloadDemoFile.js
vendored
@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.downloadDemoFile = downloadDemoFile;
|
exports.downloadDemoFile = downloadDemoFile;
|
||||||
// src/app/downloadDemoFile.ts
|
|
||||||
const fs_1 = __importDefault(require("fs"));
|
const fs_1 = __importDefault(require("fs"));
|
||||||
const path_1 = __importDefault(require("path"));
|
const path_1 = __importDefault(require("path"));
|
||||||
const https_1 = __importDefault(require("https"));
|
const https_1 = __importDefault(require("https"));
|
||||||
@ -13,8 +12,9 @@ const stream_1 = require("stream");
|
|||||||
const util_1 = require("util");
|
const util_1 = require("util");
|
||||||
const unbzip2_stream_1 = __importDefault(require("unbzip2-stream"));
|
const unbzip2_stream_1 = __importDefault(require("unbzip2-stream"));
|
||||||
const pipe = (0, util_1.promisify)(stream_1.pipeline);
|
const pipe = (0, util_1.promisify)(stream_1.pipeline);
|
||||||
// Kleiner In-Flight-Lock, um Doppel-Downloads bei gleichzeitigen Requests zu vermeiden
|
/**
|
||||||
const inflight = new Map();
|
* Entpackt eine .bz2-Datei mithilfe von Streams nach .dem
|
||||||
|
*/
|
||||||
async function extractBz2Safe(srcPath, destPath) {
|
async function extractBz2Safe(srcPath, destPath) {
|
||||||
try {
|
try {
|
||||||
await pipe(fs_1.default.createReadStream(srcPath), (0, unbzip2_stream_1.default)(), fs_1.default.createWriteStream(destPath));
|
await pipe(fs_1.default.createReadStream(srcPath), (0, unbzip2_stream_1.default)(), fs_1.default.createWriteStream(destPath));
|
||||||
@ -24,6 +24,9 @@ async function extractBz2Safe(srcPath, destPath) {
|
|||||||
throw new Error('Entpackung fehlgeschlagen');
|
throw new Error('Entpackung fehlgeschlagen');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Lädt eine Datei per HTTPS, speichert sie unter `dest`, zeigt optional Fortschritt.
|
||||||
|
*/
|
||||||
function downloadWithHttps(url, dest, onProgress, maxRetries = 3, retryDelay = 3000) {
|
function downloadWithHttps(url, dest, onProgress, maxRetries = 3, retryDelay = 3000) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
@ -86,18 +89,21 @@ function downloadWithHttps(url, dest, onProgress, maxRetries = 3, retryDelay = 3
|
|||||||
tryDownload();
|
tryDownload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function downloadDemoFile(match, steamId, outputBaseDir = 'demos', onProgress) {
|
/**
|
||||||
|
* Hauptfunktion: lädt und entpackt eine CS2-Demo (.bz2), mit Fortschrittsanzeige.
|
||||||
|
*/
|
||||||
|
async function downloadDemoFile(match, outputBaseDir = 'demos', onProgress) {
|
||||||
if (!outputBaseDir || outputBaseDir.trim() === '') {
|
if (!outputBaseDir || outputBaseDir.trim() === '') {
|
||||||
outputBaseDir = 'demos';
|
outputBaseDir = 'demos';
|
||||||
}
|
}
|
||||||
const appId = 730;
|
const appId = 730;
|
||||||
const matchId = match.matchid;
|
const matchId = match.matchid;
|
||||||
const timestamp = match.matchtime;
|
const timestamp = match.matchtime;
|
||||||
// Wenn du die Berliner TZ möchtest:
|
|
||||||
// const matchDate = new Date(timestamp * 1000).toLocaleDateString('sv-SE', { timeZone: 'Europe/Berlin' });
|
|
||||||
const matchDate = new Date(timestamp * 1000).toISOString().split('T')[0];
|
const matchDate = new Date(timestamp * 1000).toISOString().split('T')[0];
|
||||||
const lastRound = match.roundstatsall?.at(-1);
|
const lastRound = match.roundstatsall?.at(-1);
|
||||||
const demoUrl = typeof lastRound?.map === 'string' && lastRound.map.endsWith('.bz2') ? lastRound.map : undefined;
|
const demoUrl = typeof lastRound?.map === 'string' && lastRound.map.endsWith('.bz2')
|
||||||
|
? lastRound.map
|
||||||
|
: undefined;
|
||||||
const mapName = lastRound?.reservation?.map ||
|
const mapName = lastRound?.reservation?.map ||
|
||||||
lastRound?.mapname ||
|
lastRound?.mapname ||
|
||||||
match.watchablematchinfo?.game_map ||
|
match.watchablematchinfo?.game_map ||
|
||||||
@ -114,63 +120,48 @@ async function downloadDemoFile(match, steamId, outputBaseDir = 'demos', onProgr
|
|||||||
const finalDir = path_1.default.join(outputBaseDir, matchDate);
|
const finalDir = path_1.default.join(outputBaseDir, matchDate);
|
||||||
const finalFile = path_1.default.join(finalDir, `${baseName}.dem`);
|
const finalFile = path_1.default.join(finalDir, `${baseName}.dem`);
|
||||||
const finalFileName = path_1.default.basename(finalFile);
|
const finalFileName = path_1.default.basename(finalFile);
|
||||||
// 1) Bereits vorhanden? -> sofort zurück
|
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
||||||
if (fs_1.default.existsSync(finalFile)) {
|
fs_1.default.mkdirSync(finalDir, { recursive: true });
|
||||||
console.log(`♻️ Demo existiert bereits: ${finalFileName}`);
|
console.log(`📥 Lade Demo von ${demoUrl}...`);
|
||||||
return { path: finalFile, existed: true };
|
|
||||||
}
|
|
||||||
// 2) In-Flight-Lock prüfen
|
|
||||||
if (inflight.has(finalFile)) {
|
|
||||||
return inflight.get(finalFile);
|
|
||||||
}
|
|
||||||
// 3) Download-/Entpack-Job definieren und in Map eintragen
|
|
||||||
const job = (async () => {
|
|
||||||
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
|
||||||
fs_1.default.mkdirSync(finalDir, { recursive: true });
|
|
||||||
console.log(`📥 Lade Demo von ${demoUrl}...`);
|
|
||||||
try {
|
|
||||||
const success = await downloadWithHttps(demoUrl, tempFile, onProgress);
|
|
||||||
if (!success || !fs_1.default.existsSync(tempFile) || fs_1.default.statSync(tempFile).size === 0) {
|
|
||||||
try {
|
|
||||||
if (fs_1.default.existsSync(tempFile))
|
|
||||||
fs_1.default.unlinkSync(tempFile);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
throw new Error('Download fehlgeschlagen oder Datei leer');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
throw new Error(`❌ Fehler beim Download: ${err instanceof Error ? err.message : String(err)}`);
|
|
||||||
}
|
|
||||||
console.log(`✅ Gespeichert als ${tempFileName}`);
|
|
||||||
const entpackZeile = `🗜️ Entpacke ${finalFileName}...`;
|
|
||||||
process.stdout.write(entpackZeile);
|
|
||||||
await extractBz2Safe(tempFile, finalFile);
|
|
||||||
const successMessage = `✅ Entpackt: ${finalFileName}`;
|
|
||||||
const failMessage = `❌ Entpackung fehlgeschlagen – Datei nicht vorhanden`;
|
|
||||||
const maxLength = Math.max(entpackZeile.length, successMessage.length, failMessage.length);
|
|
||||||
if (!fs_1.default.existsSync(finalFile)) {
|
|
||||||
const paddedFail = failMessage.padEnd(maxLength, ' ');
|
|
||||||
process.stdout.write(`\r${paddedFail}\n`);
|
|
||||||
throw new Error(failMessage);
|
|
||||||
}
|
|
||||||
const paddedSuccess = successMessage.padEnd(maxLength, ' ');
|
|
||||||
process.stdout.write(`\r${paddedSuccess}\n`);
|
|
||||||
// Aufräumen
|
|
||||||
try {
|
|
||||||
fs_1.default.unlinkSync(tempFile);
|
|
||||||
console.log(`🧹 Gelöscht: ${tempFileName}`);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
console.log(`⚠️ Konnte temporäre Datei nicht löschen: ${tempFileName}`);
|
|
||||||
}
|
|
||||||
return { path: finalFile, existed: false };
|
|
||||||
})();
|
|
||||||
inflight.set(finalFile, job);
|
|
||||||
try {
|
try {
|
||||||
return await job;
|
const success = await downloadWithHttps(demoUrl, tempFile, onProgress);
|
||||||
|
if (!success || !fs_1.default.existsSync(tempFile) || fs_1.default.statSync(tempFile).size === 0) {
|
||||||
|
console.warn(`⚠️ Download fehlgeschlagen oder Datei leer – lösche ${tempFileName}`);
|
||||||
|
try {
|
||||||
|
if (fs_1.default.existsSync(tempFile))
|
||||||
|
fs_1.default.unlinkSync(tempFile);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
console.warn(`⚠️ Konnte leere Datei nicht löschen: ${tempFileName}`);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
catch (err) {
|
||||||
inflight.delete(finalFile);
|
throw new Error(`❌ Fehler beim Download: ${err instanceof Error ? err.message : err}`);
|
||||||
}
|
}
|
||||||
|
console.log(`✅ Gespeichert als ${tempFileName}`);
|
||||||
|
const entpackZeile = `🗜️ Entpacke ${finalFileName}...`;
|
||||||
|
process.stdout.write(entpackZeile);
|
||||||
|
await extractBz2Safe(tempFile, finalFile);
|
||||||
|
const successMessage = `✅ Entpackt: ${finalFileName}`;
|
||||||
|
const failMessage = `❌ Entpackung fehlgeschlagen – Datei nicht vorhanden`;
|
||||||
|
// Max-Zeichenlänge bestimmen
|
||||||
|
const maxLength = Math.max(entpackZeile.length, successMessage.length, failMessage.length);
|
||||||
|
if (!fs_1.default.existsSync(finalFile)) {
|
||||||
|
const paddedFail = failMessage.padEnd(maxLength, ' ');
|
||||||
|
process.stdout.write(`\r${paddedFail}\n`);
|
||||||
|
throw new Error(failMessage);
|
||||||
|
}
|
||||||
|
const paddedSuccess = successMessage.padEnd(maxLength, ' ');
|
||||||
|
process.stdout.write(`\r${paddedSuccess}\n`);
|
||||||
|
// Aufräumen
|
||||||
|
try {
|
||||||
|
fs_1.default.unlinkSync(tempFile);
|
||||||
|
console.log(`🧹 Gelöscht: ${tempFileName}`);
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
console.log(`⚠️ Konnte temporäre Datei nicht löschen: ${tempFileName}`);
|
||||||
|
}
|
||||||
|
return finalFile;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
dist/cs2-demo-downloader-linux
vendored
BIN
dist/cs2-demo-downloader-linux
vendored
Binary file not shown.
BIN
dist/cs2-demo-downloader-macos
vendored
BIN
dist/cs2-demo-downloader-macos
vendored
Binary file not shown.
BIN
dist/cs2-demo-downloader-win.exe
vendored
BIN
dist/cs2-demo-downloader-win.exe
vendored
Binary file not shown.
5
dist/main.js
vendored
5
dist/main.js
vendored
@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
// src/app/main.ts
|
|
||||||
const yargs_1 = __importDefault(require("yargs"));
|
const yargs_1 = __importDefault(require("yargs"));
|
||||||
const helpers_1 = require("yargs/helpers");
|
const helpers_1 = require("yargs/helpers");
|
||||||
const steamSession_1 = require("./app/steamSession");
|
const steamSession_1 = require("./app/steamSession");
|
||||||
@ -44,7 +43,7 @@ async function start() {
|
|||||||
const { shareCode, steamId } = JSON.parse(body);
|
const { shareCode, steamId } = JSON.parse(body);
|
||||||
console.log(`📦 ShareCode empfangen: ${shareCode}`);
|
console.log(`📦 ShareCode empfangen: ${shareCode}`);
|
||||||
const match = await (0, fetchMatchFromSharecode_1.fetchMatchFromShareCode)(shareCode, session);
|
const match = await (0, fetchMatchFromSharecode_1.fetchMatchFromShareCode)(shareCode, session);
|
||||||
const { path: demoFilePath, existed } = await (0, downloadDemoFile_1.downloadDemoFile)(match, steamId, resolvedDemoPath, (percent) => {
|
const demoFilePath = await (0, downloadDemoFile_1.downloadDemoFile)(match, resolvedDemoPath, (percent) => {
|
||||||
process.stdout.write(`📶 Fortschritt: ${percent}%\r`);
|
process.stdout.write(`📶 Fortschritt: ${percent}%\r`);
|
||||||
if (percent === 100) {
|
if (percent === 100) {
|
||||||
console.log('✅ Download abgeschlossen');
|
console.log('✅ Download abgeschlossen');
|
||||||
@ -58,7 +57,7 @@ async function start() {
|
|||||||
console.log(`📝 Match-Daten gespeichert unter: ${jsonFileName}`);
|
console.log(`📝 Match-Daten gespeichert unter: ${jsonFileName}`);
|
||||||
// Antwort an den Client
|
// Antwort an den Client
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify({ success: true, path: demoFilePath, existed }));
|
res.end(JSON.stringify({ success: true, path: demoFilePath }));
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.error('❌ Fehler:', err);
|
console.error('❌ Fehler:', err);
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// src/app/downloadDemoFile.ts
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import https from 'https';
|
import https from 'https';
|
||||||
@ -9,18 +8,25 @@ import bz2 from 'unbzip2-stream';
|
|||||||
|
|
||||||
const pipe = promisify(pipeline);
|
const pipe = promisify(pipeline);
|
||||||
|
|
||||||
// Kleiner In-Flight-Lock, um Doppel-Downloads bei gleichzeitigen Requests zu vermeiden
|
/**
|
||||||
const inflight = new Map<string, Promise<{ path: string; existed: boolean }>>();
|
* Entpackt eine .bz2-Datei mithilfe von Streams nach .dem
|
||||||
|
*/
|
||||||
async function extractBz2Safe(srcPath: string, destPath: string) {
|
async function extractBz2Safe(srcPath: string, destPath: string) {
|
||||||
try {
|
try {
|
||||||
await pipe(fs.createReadStream(srcPath), bz2(), fs.createWriteStream(destPath));
|
await pipe(
|
||||||
|
fs.createReadStream(srcPath),
|
||||||
|
bz2(),
|
||||||
|
fs.createWriteStream(destPath)
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('❌ Fehler beim Entpacken (pipe):', err);
|
console.log('❌ Fehler beim Entpacken (pipe):', err);
|
||||||
throw new Error('Entpackung fehlgeschlagen');
|
throw new Error('Entpackung fehlgeschlagen');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lädt eine Datei per HTTPS, speichert sie unter `dest`, zeigt optional Fortschritt.
|
||||||
|
*/
|
||||||
function downloadWithHttps(
|
function downloadWithHttps(
|
||||||
url: string,
|
url: string,
|
||||||
dest: string,
|
dest: string,
|
||||||
@ -30,6 +36,7 @@ function downloadWithHttps(
|
|||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
|
|
||||||
const tryDownload = () => {
|
const tryDownload = () => {
|
||||||
const file = fs.createWriteStream(dest);
|
const file = fs.createWriteStream(dest);
|
||||||
const client = url.startsWith('https') ? https : http;
|
const client = url.startsWith('https') ? https : http;
|
||||||
@ -100,93 +107,105 @@ function downloadWithHttps(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hauptfunktion: lädt und entpackt eine CS2-Demo (.bz2), mit Fortschrittsanzeige.
|
||||||
|
*/
|
||||||
export async function downloadDemoFile(
|
export async function downloadDemoFile(
|
||||||
match: any,
|
match: any,
|
||||||
steamId: string,
|
|
||||||
outputBaseDir = 'demos',
|
outputBaseDir = 'demos',
|
||||||
onProgress?: (percent: number) => void
|
onProgress?: (percent: number) => void
|
||||||
): Promise<{ path: string; existed: boolean; matchId: string; map?: string }> {
|
): Promise<string> {
|
||||||
if (!outputBaseDir || outputBaseDir.trim() === '') outputBaseDir = 'demos'
|
if (!outputBaseDir || outputBaseDir.trim() === '') {
|
||||||
|
outputBaseDir = 'demos';
|
||||||
|
}
|
||||||
|
|
||||||
const appId = 730
|
const appId = 730;
|
||||||
const matchId: string = String(match.matchid)
|
const matchId = match.matchid;
|
||||||
const timestamp = match.matchtime
|
const timestamp = match.matchtime;
|
||||||
const matchDate = new Date(timestamp * 1000).toISOString().split('T')[0]
|
const matchDate = new Date(timestamp * 1000).toISOString().split('T')[0];
|
||||||
|
|
||||||
const lastRound = match.roundstatsall?.at(-1)
|
const lastRound = match.roundstatsall?.at(-1);
|
||||||
|
const demoUrl =
|
||||||
|
typeof lastRound?.map === 'string' && lastRound.map.endsWith('.bz2')
|
||||||
|
? lastRound.map
|
||||||
|
: undefined;
|
||||||
|
|
||||||
// echte Demo-URL
|
const mapName =
|
||||||
const demoUrl = (typeof lastRound?.map === 'string' && lastRound.map.endsWith('.bz2'))
|
lastRound?.reservation?.map ||
|
||||||
? lastRound.map
|
lastRound?.mapname ||
|
||||||
: undefined
|
match.watchablematchinfo?.game_map ||
|
||||||
if (!demoUrl) throw new Error('❌ Keine Demo-URL im Match vorhanden')
|
'unknownmap';
|
||||||
|
|
||||||
// Mapnamen robust extrahieren
|
if (!demoUrl) {
|
||||||
const rawMap =
|
throw new Error('❌ Keine Demo-URL im Match vorhanden');
|
||||||
lastRound?.reservation?.map ??
|
}
|
||||||
lastRound?.reservation?.mapname ??
|
|
||||||
lastRound?.mapname ??
|
|
||||||
match.watchablematchinfo?.game_map ??
|
|
||||||
''
|
|
||||||
|
|
||||||
const mapName = (String(rawMap).trim() || 'unknownmap')
|
const isPremier = !!lastRound?.b_switched_teams;
|
||||||
.replace(/^maps[\\/]/i, '') // "maps/de_inferno" -> "de_inferno"
|
const matchType = isPremier ? 'premier' : 'competitive';
|
||||||
.split(/[\\/]/).pop() || 'unknownmap'
|
|
||||||
|
|
||||||
const isPremier = !!lastRound?.b_switched_teams
|
const tempDir = path.join(outputBaseDir, 'temp');
|
||||||
const matchType = isPremier ? 'premier' : 'competitive'
|
const tempFileName = `match${appId}_${mapName}_${matchId}_${matchType}.bz2`;
|
||||||
|
const baseName = path.parse(tempFileName).name;
|
||||||
|
const tempFile = path.join(tempDir, tempFileName);
|
||||||
|
|
||||||
const tempDir = path.join(outputBaseDir, 'temp')
|
const finalDir = path.join(outputBaseDir, matchDate);
|
||||||
// Dateiname darf sich ändern -> Consumer soll nicht auf Map im Namen bauen
|
const finalFile = path.join(finalDir, `${baseName}.dem`);
|
||||||
const tempFileName = `match${appId}_${mapName}_${matchId}_${matchType}.bz2`
|
|
||||||
const baseName = path.parse(tempFileName).name
|
|
||||||
const tempFile = path.join(tempDir, tempFileName)
|
|
||||||
|
|
||||||
const finalDir = path.join(outputBaseDir, matchDate)
|
|
||||||
const finalFile = path.join(finalDir, `${baseName}.dem`)
|
|
||||||
const finalFileName = path.basename(finalFile)
|
const finalFileName = path.basename(finalFile)
|
||||||
|
|
||||||
// schon vorhanden?
|
fs.mkdirSync(tempDir, { recursive: true });
|
||||||
try {
|
fs.mkdirSync(finalDir, { recursive: true });
|
||||||
fs.accessSync(finalFile)
|
|
||||||
console.log(`♻️ Demo existiert bereits: ${finalFileName}`)
|
|
||||||
return { path: path.normalize(finalFile), existed: true, matchId, map: mapName }
|
|
||||||
} catch {/* not exists */}
|
|
||||||
|
|
||||||
if (inflight.has(finalFile)) {
|
console.log(`📥 Lade Demo von ${demoUrl}...`);
|
||||||
return inflight.get(finalFile)! as any
|
|
||||||
|
try {
|
||||||
|
const success = await downloadWithHttps(demoUrl, tempFile, onProgress);
|
||||||
|
if (!success || !fs.existsSync(tempFile) || fs.statSync(tempFile).size === 0) {
|
||||||
|
console.warn(`⚠️ Download fehlgeschlagen oder Datei leer – lösche ${tempFileName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile);
|
||||||
|
} catch {
|
||||||
|
console.warn(`⚠️ Konnte leere Datei nicht löschen: ${tempFileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`❌ Fehler beim Download: ${err instanceof Error ? err.message : err}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const job = (async () => {
|
|
||||||
fs.mkdirSync(tempDir, { recursive: true })
|
|
||||||
fs.mkdirSync(finalDir, { recursive: true })
|
|
||||||
|
|
||||||
console.log(`📥 Lade Demo von ${demoUrl}...`)
|
console.log(`✅ Gespeichert als ${tempFileName}`);
|
||||||
const ok = await downloadWithHttps(demoUrl, tempFile, onProgress)
|
|
||||||
if (!ok || !fs.existsSync(tempFile) || fs.statSync(tempFile).size === 0) {
|
|
||||||
try { if (fs.existsSync(tempFile)) fs.unlinkSync(tempFile) } catch {}
|
|
||||||
throw new Error('Download fehlgeschlagen oder Datei leer')
|
|
||||||
}
|
|
||||||
|
|
||||||
const entpackInfo = `🗜️ Entpacke ${finalFileName}...`
|
const entpackZeile = `🗜️ Entpacke ${finalFileName}...`;
|
||||||
process.stdout.write(entpackInfo)
|
process.stdout.write(entpackZeile);
|
||||||
await extractBz2Safe(tempFile, finalFile)
|
|
||||||
|
|
||||||
if (!fs.existsSync(finalFile)) {
|
await extractBz2Safe(tempFile, finalFile);
|
||||||
process.stdout.write(`\r❌ Entpackung fehlgeschlagen – Datei nicht vorhanden\n`)
|
|
||||||
throw new Error('Entpackung fehlgeschlagen')
|
|
||||||
}
|
|
||||||
process.stdout.write(`\r✅ Entpackt: ${finalFileName}\n`)
|
|
||||||
|
|
||||||
try { fs.unlinkSync(tempFile) } catch {}
|
const successMessage = `✅ Entpackt: ${finalFileName}`;
|
||||||
|
const failMessage = `❌ Entpackung fehlgeschlagen – Datei nicht vorhanden`;
|
||||||
|
|
||||||
return { path: path.normalize(finalFile), existed: false, matchId, map: mapName }
|
// Max-Zeichenlänge bestimmen
|
||||||
})()
|
const maxLength = Math.max(entpackZeile.length, successMessage.length, failMessage.length);
|
||||||
|
|
||||||
inflight.set(finalFile, job)
|
if (!fs.existsSync(finalFile)) {
|
||||||
try {
|
const paddedFail = failMessage.padEnd(maxLength, ' ');
|
||||||
return await job
|
process.stdout.write(`\r${paddedFail}\n`);
|
||||||
} finally {
|
throw new Error(failMessage);
|
||||||
inflight.delete(finalFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const paddedSuccess = successMessage.padEnd(maxLength, ' ');
|
||||||
|
process.stdout.write(`\r${paddedSuccess}\n`);
|
||||||
|
|
||||||
|
// Aufräumen
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(tempFile);
|
||||||
|
console.log(`🧹 Gelöscht: ${tempFileName}`);
|
||||||
|
} catch {
|
||||||
|
console.log(`⚠️ Konnte temporäre Datei nicht löschen: ${tempFileName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalFile;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// src/app/main.ts
|
|
||||||
import yargs from 'yargs';
|
import yargs from 'yargs';
|
||||||
import { hideBin } from 'yargs/helpers';
|
import { hideBin } from 'yargs/helpers';
|
||||||
import { createSteamSession } from './app/steamSession';
|
import { createSteamSession } from './app/steamSession';
|
||||||
@ -46,9 +45,8 @@ async function start() {
|
|||||||
console.log(`📦 ShareCode empfangen: ${shareCode}`);
|
console.log(`📦 ShareCode empfangen: ${shareCode}`);
|
||||||
|
|
||||||
const match = await fetchMatchFromShareCode(shareCode, session);
|
const match = await fetchMatchFromShareCode(shareCode, session);
|
||||||
const { path: demoFilePath, existed } = await downloadDemoFile(
|
const demoFilePath = await downloadDemoFile(
|
||||||
match,
|
match,
|
||||||
steamId,
|
|
||||||
resolvedDemoPath,
|
resolvedDemoPath,
|
||||||
(percent: number) => {
|
(percent: number) => {
|
||||||
process.stdout.write(`📶 Fortschritt: ${percent}%\r`);
|
process.stdout.write(`📶 Fortschritt: ${percent}%\r`);
|
||||||
@ -68,7 +66,7 @@ async function start() {
|
|||||||
|
|
||||||
// Antwort an den Client
|
// Antwort an den Client
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify({ success: true, path: demoFilePath, existed }));
|
res.end(JSON.stringify({ success: true, path: demoFilePath }));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('❌ Fehler:', err);
|
console.error('❌ Fehler:', err);
|
||||||
res.writeHead(500, { 'Content-Type': 'application/json' });
|
res.writeHead(500, { 'Content-Type': 'application/json' });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user