Initial curated chimera source from a8ae5b1db07fb49926c94585e2718e5130330974

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:38:08 +02:00
commit c737a37f71
531 files changed
+119270

No files matched your search

+164
View File
@@ -0,0 +1,164 @@
// ── Hash verification ──────────────────────────────────────────────────────────
let hashingInProgress = false;
window.pork.on('hash:progress', ({ percent }) => {
const fill = $('hash-progress-fill');
const label = $('hash-progress-label');
if (fill) fill.style.width = `${percent}%`;
if (label) label.textContent = `Hashing… ${percent}%`;
});
async function renderHashSection(game_id, backups) {
const section = $('modal-hash-section');
const badge = $('modal-hash-community-badge');
badge.hidden = true;
badge.className = 'hash-badge'; // reset class each render
// Include both local and backpork backups — all game files deserve verification.
if (!backups.length) { section.hidden = true; return; }
section.hidden = false;
const { localHashes, communityMatches, communityMismatch } = await window.pork.hashStatus(game_id);
const communitySet = new Set(communityMatches.map(h => h.file_hash));
// Badge above hash list: mismatch warning takes priority over verified check.
const allInCommunity = localHashes.length > 0 && communityMatches.length === localHashes.length;
if (communityMismatch && localHashes.length > 0) {
badge.hidden = false;
badge.className = 'hash-badge hash-mismatch';
badge.textContent = '⚠ Community Hash Mismatch — files may be modified or contain brick code';
} else if (allInCommunity) {
badge.hidden = false;
badge.className = 'hash-badge hash-community';
badge.textContent = 'Community Verified ✓';
}
// Each backup is a folder — show aggregate hash status for the whole folder.
$('modal-hash-list').innerHTML = backups.map(b => {
const folderName = b.backup_path.replace(/\\/g, '/').split('/').pop();
const hashedCount = localHashes.length;
const communityCount = communityMatches.length;
if (hashedCount === 0) {
return `
<div class="hash-entry">
<div class="hash-entry-info">
<span class="hash-filename">${escHtml(folderName)}</span>
<span class="hash-badge hash-none">Not hashed</span>
</div>
<div class="hash-entry-status">
<button class="btn btn-sm btn-teal hash-btn-add"
data-path="${escHtml(b.backup_path)}"
data-game="${escHtml(game_id)}"
data-source="${escHtml(b.source || 'local')}">Hash All Files</button>
</div>
</div>`;
}
const allCommunity = communityCount === hashedCount;
const statusBadge = allCommunity
? `<span class="hash-badge hash-community">${communityCount} file${communityCount !== 1 ? 's' : ''} community ✓</span>`
: communityMismatch
? `<span class="hash-badge hash-mismatch">⚠ Hash Mismatch — ${hashedCount} local hash${hashedCount !== 1 ? 'es' : ''} don't match community list</span>`
: `<span class="hash-badge hash-local">${hashedCount} file${hashedCount !== 1 ? 's' : ''} hashed</span>`
+ (communityCount > 0 ? ` <span class="hash-badge hash-community">${communityCount} community ✓</span>` : '');
return `
<div class="hash-entry">
<div class="hash-entry-info">
<span class="hash-filename">${escHtml(folderName)}</span>
${statusBadge}
</div>
<div class="hash-entry-status">
<button class="btn btn-sm hash-btn-reverify"
data-path="${escHtml(b.backup_path)}"
data-game="${escHtml(game_id)}"
data-source="${escHtml(b.source || 'local')}">Re-verify All</button>
</div>
</div>`;
}).join('');
}
async function runHash(backup_path, game_id, verified = 1, hash_type = 'game') {
if (hashingInProgress) return;
hashingInProgress = true;
// Disable all hash buttons while running
$('modal-hash-list').querySelectorAll('button').forEach(b => b.disabled = true);
const prog = $('modal-hash-progress');
const fill = $('hash-progress-fill');
fill.style.width = '0%';
prog.hidden = false;
try {
const { hashes } = await window.pork.hashCompute(backup_path, game_id);
let communityCount = 0;
for (const h of hashes) {
const { communityMatch } = await window.pork.hashAdd({
game_id, file_hash: h.file_hash, file_size: h.file_size, backup_path: h.backup_path, verified, hash_type,
});
if (communityMatch) communityCount++;
}
prog.hidden = true;
if (communityCount > 0) {
setStatus(`${hashes.length} file(s) hashed — ${communityCount} community match(es) ✓`, 'ok');
} else {
setStatus(`${hashes.length} file(s) hashed — will appear in the next community update`, 'ok');
}
// Re-render the hash section with fresh data
const backups = await window.pork.listBackups(game_id);
await renderHashSection(game_id, backups);
} catch (e) {
prog.hidden = true;
setStatus(`Hash failed: ${e.message}`, 'error');
// Re-enable buttons on error
$('modal-hash-list').querySelectorAll('button').forEach(b => b.disabled = false);
} finally {
hashingInProgress = false;
}
}
// Hash button delegation — attached once on the hash list container
$('modal-hash-list').addEventListener('click', async e => {
if (hashingInProgress) return;
// ── Hash & Add (not yet in DB) ─────────────────────────────────────────────
const addBtn = e.target.closest('.hash-btn-add');
if (addBtn) {
await runHash(addBtn.dataset.path, addBtn.dataset.game, 1, addBtn.dataset.source === 'backpork' ? 'backpork' : 'game');
return;
}
// ── Re-verify (already in DB) — show inline confirm first ─────────────────
const reverifyBtn = e.target.closest('.hash-btn-reverify');
if (reverifyBtn) {
const statusEl = reverifyBtn.closest('.hash-entry-status');
const path = reverifyBtn.dataset.path;
const game = reverifyBtn.dataset.game;
const source = reverifyBtn.dataset.source;
// Replace button with inline confirm
reverifyBtn.style.display = 'none';
const confirm = document.createElement('div');
confirm.className = 'hash-confirm';
confirm.innerHTML = `
<span class="hash-confirm-msg">Game works?</span>
<button class="btn btn-sm btn-teal hash-confirm-yes">Yes, verify</button>
<button class="btn btn-sm hash-confirm-no">Cancel</button>`;
statusEl.appendChild(confirm);
confirm.querySelector('.hash-confirm-yes').addEventListener('click', async () => {
confirm.remove();
await runHash(path, game, 1, source === 'backpork' ? 'backpork' : 'game');
});
confirm.querySelector('.hash-confirm-no').addEventListener('click', () => {
confirm.remove();
reverifyBtn.style.display = '';
});
return;
}
});