Upload via GUI (194 Dateien)
This commit is contained in:
+47
-8
@@ -299,6 +299,7 @@ async function modrinthResolveFile({ projectId, gameVersion, loader, art = 'mod'
|
||||
versionNumber: v.version_number,
|
||||
filename: file.filename,
|
||||
url: file.url,
|
||||
hashes: mrHashes(file),
|
||||
sha1: file.hashes && file.hashes.sha1,
|
||||
size: file.size,
|
||||
dependencies: v.dependencies || [],
|
||||
@@ -324,6 +325,7 @@ async function modrinthResolveFile({ projectId, gameVersion, loader, art = 'mod'
|
||||
versionNumber: v.version_number,
|
||||
filename: file.filename,
|
||||
url: file.url,
|
||||
hashes: mrHashes(file),
|
||||
sha1: file.hashes && file.hashes.sha1,
|
||||
size: file.size,
|
||||
dependencies: v.dependencies || [],
|
||||
@@ -350,23 +352,58 @@ async function modrinthResolveModpack({ projectId, gameVersion = '' } = {}) {
|
||||
name: v.name || v.version_number,
|
||||
filename: file.filename,
|
||||
url: file.url,
|
||||
hashes: mrHashes(file),
|
||||
size: file.size || 0,
|
||||
gameVersions: v.game_versions || [],
|
||||
loaders: v.loaders || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function downloadBuffer(url, extraHeaders) {
|
||||
const res = await fetch(url, { headers: Object.assign({ 'User-Agent': UA }, extraHeaders || {}) });
|
||||
if (!res.ok) throw new Error('Download fehlgeschlagen: HTTP ' + res.status);
|
||||
return Buffer.from(await res.arrayBuffer());
|
||||
/*
|
||||
* Prüfsumme eines Downloads kontrollieren. erwartet: { sha512?, sha1? } – die
|
||||
* Werte stammen aus der Modrinth- bzw. CurseForge-API. Ohne Angabe wird nichts
|
||||
* geprüft (z. B. Dateien, zu denen die Quelle keine Prüfsumme nennt).
|
||||
*/
|
||||
function pruefeDownload(buf, erwartet, name) {
|
||||
if (!erwartet) return;
|
||||
for (const algo of ['sha512', 'sha256', 'sha1']) {
|
||||
const soll = erwartet[algo] && String(erwartet[algo]).toLowerCase();
|
||||
if (!soll) continue;
|
||||
const ist = require('crypto').createHash(algo).update(buf).digest('hex');
|
||||
if (ist !== soll) {
|
||||
throw new Error(`Prüfsumme von ${name || 'Download'} stimmt nicht – Datei verworfen (beschädigt oder manipuliert).`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// extraHeaders: z. B. der CurseForge-API-Key, den das CDN seit Juli 2026 verlangt
|
||||
async function downloadFile(url, destPath, extraHeaders) {
|
||||
// CurseForge liefert Prüfsummen als Liste: algo 1 = SHA-1, 2 = MD5
|
||||
function cfHashes(datei) {
|
||||
const sha1 = ((datei && datei.hashes) || []).find((h) => h.algo === 1 && h.value);
|
||||
return sha1 ? { sha1: sha1.value } : null;
|
||||
}
|
||||
|
||||
// Modrinth: { sha512, sha1 }
|
||||
function mrHashes(datei) {
|
||||
const h = (datei && datei.hashes) || {};
|
||||
return h.sha512 || h.sha1 ? { sha512: h.sha512, sha1: h.sha1 } : null;
|
||||
}
|
||||
|
||||
async function downloadBuffer(url, extraHeaders, erwartet) {
|
||||
const res = await fetch(url, { headers: Object.assign({ 'User-Agent': UA }, extraHeaders || {}) });
|
||||
if (!res.ok) throw new Error('Download fehlgeschlagen: HTTP ' + res.status);
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
pruefeDownload(buf, erwartet, decodeURIComponent(String(url).split('/').pop() || ''));
|
||||
return buf;
|
||||
}
|
||||
|
||||
// extraHeaders: z. B. der CurseForge-API-Key, den das CDN seit Juli 2026 verlangt
|
||||
// erwartet: Prüfsummen (siehe pruefeDownload) – geschrieben wird nur, was passt
|
||||
async function downloadFile(url, destPath, extraHeaders, erwartet) {
|
||||
const res = await fetch(url, { headers: Object.assign({ 'User-Agent': UA }, extraHeaders || {}) });
|
||||
if (!res.ok) throw new Error('Download fehlgeschlagen: HTTP ' + res.status);
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
pruefeDownload(buf, erwartet, path.basename(destPath));
|
||||
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
||||
fs.writeFileSync(destPath, buf);
|
||||
return buf.length;
|
||||
@@ -383,7 +420,7 @@ async function modrinthInstall({ projectId, title, gameVersion, loader, modsDir,
|
||||
: `Keine passende Version für ${gameVersion} gefunden.` };
|
||||
}
|
||||
const dest = path.join(modsDir, file.filename);
|
||||
const bytes = await downloadFile(file.url, dest);
|
||||
const bytes = await downloadFile(file.url, dest, null, file.hashes);
|
||||
return {
|
||||
ok: true,
|
||||
dependencies: file.dependencies || [],
|
||||
@@ -738,6 +775,7 @@ async function curseforgePickFile(zugang, modId, gameVersion, loader, art) {
|
||||
fileId: match.id,
|
||||
filename: name,
|
||||
url: dl,
|
||||
hashes: cfHashes(match),
|
||||
versionNumber: match.displayName || match.fileName || String(match.id),
|
||||
dependencies: match.dependencies || [],
|
||||
};
|
||||
@@ -768,7 +806,7 @@ async function curseforgeInstall({ zugang, projectId, title, gameVersion, loader
|
||||
// Download: direkt mit Key oder über Weiterleitung
|
||||
const url = zugang.downloadAdresse ? zugang.downloadAdresse(file.url) : file.url;
|
||||
const headers = Object.assign({}, zugang.downloadKopfzeilen || {});
|
||||
const bytes = await downloadFile(url, dest, headers);
|
||||
const bytes = await downloadFile(url, dest, headers, file.hashes);
|
||||
|
||||
// Pflicht-Abhängigkeiten (relationType 3 = RequiredDependency)
|
||||
const depIds = (file.dependencies || [])
|
||||
@@ -826,6 +864,7 @@ async function curseforgeResolveFiles(zugang, files, onProgress) {
|
||||
map.set(Number(d.id), {
|
||||
fileName: d.fileName,
|
||||
url: zugang.downloadAdresse(roh),
|
||||
hashes: cfHashes(d),
|
||||
kopfzeilen: zugang.downloadKopfzeilen,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user