validation

This commit is contained in:
2026-05-03 14:37:57 +03:00
parent 0f8707fe93
commit 672e199d3a
5 changed files with 398 additions and 1 deletions

View File

@@ -393,6 +393,7 @@ const state = {
currentUser: null, // {id, username, role}
authWarnings: {}, // source_slug → {source_slug, source_name}
metaUpdating: new Set(), // urls where meta refresh is in progress
validating: {}, // url → {checked, total} for in-progress validations
};
// ── Auth ─────────────────────────────────────
@@ -703,6 +704,31 @@ function handleEvent(msg) {
_updateMetaBtn(msg.url, msg.failed === -1 ? 'error' : 'done');
break;
case 'validate_started':
state.validating[msg.url] = {checked: 0, total: 0};
_updateValidateBtn(msg.url);
break;
case 'validate_progress':
if(state.validating[msg.url]) {
state.validating[msg.url].checked = msg.checked;
state.validating[msg.url].total = msg.total;
}
_updateValidateBtn(msg.url);
break;
case 'validate_done': {
delete state.validating[msg.url];
const result = msg.total_to_redownload > 0 || msg.new_chapters > 0 ? 'issues' : 'ok';
_updateValidateBtn(msg.url, result, msg);
break;
}
case 'validate_error':
delete state.validating[msg.url];
_updateValidateBtn(msg.url, 'error');
break;
case 'manga_meta_updated':
if(state.mangas[msg.url]) {
state.mangas[msg.url].title = msg.title;
@@ -1691,6 +1717,63 @@ async function refreshMetaModal(url) {
// Спиннер появится через WS meta_refresh_started, исчезнет через meta_refreshed
}
function _updateValidateBtn(url, result, data) {
const modal = document.getElementById('modal');
if(!modal || modal.classList.contains('hidden') || modal.dataset.currentUrl !== url) return;
const btn = document.getElementById('modal-validate-btn');
if(!btn) return;
const v = state.validating[url];
if(v !== undefined) {
const prog = v.total > 0 ? ` ${v.checked}/${v.total}` : '...';
btn.innerHTML = `<span class="meta-spinner"></span> Проверка${prog}`;
btn.disabled = true;
btn.style.color = '#94a3b8';
btn.style.borderColor = '#334155';
} else if(result === 'ok') {
btn.innerHTML = '✅ Всё в порядке';
btn.disabled = false;
btn.style.color = '#4ade80';
btn.style.borderColor = '#166534';
setTimeout(() => { btn.innerHTML = '🔍 Проверить целостность'; btn.style.color='#67e8f9'; btn.style.borderColor='#164e63'; btn.disabled=false; }, 3000);
} else if(result === 'issues') {
const n = data ? (data.total_to_redownload + data.new_chapters) : '?';
btn.innerHTML = `⚡ Найдено проблем: ${n} — поставлено в очередь`;
btn.disabled = true;
btn.style.color = '#fbbf24';
btn.style.borderColor = '#78350f';
setTimeout(() => { btn.innerHTML = '🔍 Проверить целостность'; btn.style.color='#67e8f9'; btn.style.borderColor='#164e63'; btn.disabled=false; }, 5000);
} else if(result === 'error') {
btn.innerHTML = '❌ Ошибка валидации';
btn.disabled = false;
btn.style.color = '#f87171';
btn.style.borderColor = '#7f1d1d';
setTimeout(() => { btn.innerHTML = '🔍 Проверить целостность'; btn.style.color='#67e8f9'; btn.style.borderColor='#164e63'; btn.disabled=false; }, 3000);
} else {
btn.innerHTML = '🔍 Проверить целостность';
btn.disabled = false;
btn.style.color = '#67e8f9';
btn.style.borderColor = '#164e63';
}
}
async function validateManga(url) {
const btn = document.getElementById('modal-validate-btn');
if(btn) {
btn.innerHTML = '<span class="meta-spinner"></span> Запуск...';
btn.disabled = true;
}
const r = await fetch('/api/mangas/validate?url='+encodeURIComponent(url), {method:'POST'});
if(!r.ok) {
const err = await r.json().catch(() => ({}));
if(btn) {
btn.innerHTML = '❌ ' + (err.detail || 'Ошибка');
btn.style.color = '#f87171';
btn.style.borderColor = '#7f1d1d';
setTimeout(() => { btn.innerHTML = '🔍 Проверить целостность'; btn.style.color='#67e8f9'; btn.style.borderColor='#164e63'; btn.disabled=false; }, 3000);
}
}
}
async function forceRedownload(url, closeModalAfter = false) {
if(!confirm('Скачать заново ВСЕ главы? Уже скачанные файлы будут перезаписаны.')) return;
const r = await fetch('/api/mangas/force_redownload?url='+encodeURIComponent(url), {method:'POST'});
@@ -2233,6 +2316,15 @@ function renderModalBody(data) {
📁 Переименовать папку
</button>` : ''}
${data.status === 'done' && canManage(data) ? `
<button id="modal-validate-btn" onclick="validateManga('${escHtml(data.url)}')"
class="flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-semibold transition-colors"
style="background:#0c1a2e;color:#67e8f9;border:1px solid #164e63"
${state.validating[data.url] !== undefined ? 'disabled' : ''}>
${state.validating[data.url] !== undefined
? `<span class="meta-spinner"></span> Проверка${state.validating[data.url].total > 0 ? ' '+state.validating[data.url].checked+'/'+state.validating[data.url].total : '...'}`
: '🔍 Проверить целостность'}
</button>` : ''}
${data.status === 'done' && canManage(data) ? `
<button id="modal-refresh-meta-btn" onclick="refreshMetaModal('${escHtml(data.url)}')"
class="flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-semibold transition-colors"
style="background:#1e1b4b;color:#a78bfa;border:1px solid #312e81">