Files
motorsports/templates/index.html
T

197 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Torrent Vahti Ohjauspaneeli</title>
<link rel="icon" type="image/png" href="{{ url_for('static', filename='favicon.png') }}">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background-color: #f8f9fa; font-family: system-ui, -apple-system, sans-serif; }
.card { border: none; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
.nav-tabs .nav-link { color: #495057; font-weight: 500; }
.nav-tabs .nav-link.active { font-weight: 600; }
#loki-sisalto, #skripti-loki {
background-color: #212529;
color: #f8f9fa;
padding: 15px;
border-radius: 5px;
font-size: 0.85rem;
max-height: 400px;
overflow-y: auto;
white-space: pre-wrap;
}
</style>
</head>
<body>
<nav class="navbar navbar-dark bg-dark mb-4">
<div class="container">
<span class="navbar-brand mb-0 h1">🤖 Torrent Vahti Ohjauspaneeli</span>
<span id="tila-badge" class="badge bg-secondary">Ladataan...</span>
</div>
</nav>
<div class="container mb-5">
<div class="row">
<div class="col-12">
<ul class="nav nav-tabs mb-4" id="paneeliTabs" role="tablist">
<li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#haut-pane" type="button">📋 Hakujen Hallinta</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#historia-pane" type="button">⏳ Lataushistoria</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#asetukset-pane" type="button">⚙️ Järjestelmäasetukset</button></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="haut-pane">
<div class="card p-4 mb-4">
<h5> Lisää uusi haku</h5>
<form id="lisaa-form" class="row g-3">
<div class="col-md-6"><input type="text" id="haku-sana" class="form-control form-control-sm" placeholder="Haku" required></div>
<input type="hidden" id="haku-regex" value=".*">
<div class="col-md-5"><input type="text" id="haku-kansio" class="form-control form-control-sm" placeholder="Kansio" required></div>
<div class="col-md-12">
<label class="small text-muted">Aktiiviset päivät:</label><br>
<div class="btn-group btn-group-sm" role="group">
<input type="checkbox" class="btn-check" id="pv-0" checked><label class="btn btn-outline-secondary" for="pv-0">Ma</label>
<input type="checkbox" class="btn-check" id="pv-1" checked><label class="btn btn-outline-secondary" for="pv-1">Ti</label>
<input type="checkbox" class="btn-check" id="pv-2" checked><label class="btn btn-outline-secondary" for="pv-2">Ke</label>
<input type="checkbox" class="btn-check" id="pv-3" checked><label class="btn btn-outline-secondary" for="pv-3">To</label>
<input type="checkbox" class="btn-check" id="pv-4" checked><label class="btn btn-outline-secondary" for="pv-4">Pe</label>
<input type="checkbox" class="btn-check" id="pv-5" checked><label class="btn btn-outline-secondary" for="pv-5">La</label>
<input type="checkbox" class="btn-check" id="pv-6" checked><label class="btn btn-outline-secondary" for="pv-6">Su</label>
</div>
</div>
<div class="col-md-1"><button type="submit" class="btn btn-success btn-sm w-100">Lisää</button></div>
</form>
</div>
<div class="card p-4">
<h5>Aktiiviset haut</h5>
<table class="table table-hover align-middle"><tbody id="hakukohteet-lista"></tbody></table>
</div>
</div>
<div class="tab-pane fade" id="historia-pane">
<div class="card p-4">
<h5>Ladatut Torrentit</h5>
<div class="d-flex gap-2 mb-3">
<input type="text" id="historia-haku" class="form-control form-control-sm" placeholder="Suodata nimen mukaan..." oninput="paivitaNakyma()">
<button id="tyhjenna-loki-btn" class="btn btn-outline-danger btn-sm text-nowrap">Tyhjennä historia</button>
</div>
<div id="loki-sisalto">Ladataan...</div>
</div>
</div>
<div class="tab-pane fade" id="asetukset-pane">
<div class="card p-4">
<form id="asetukset-form">
<h6 class="fw-bold mb-3 text-primary">📡 Jackett Asetukset</h6>
<div class="mb-3"><input type="url" id="cfg-url" class="form-control form-control-sm" placeholder="Jackett URL"></div>
<div class="mb-4"><input type="text" id="cfg-apikey" class="form-control form-control-sm" placeholder="Jackett API-avain"></div>
<hr class="my-4">
<h6 class="fw-bold mb-3 text-success">🐾 qBittorrent Asetukset</h6>
<div class="mb-2"><input type="url" id="cfg-qbiturl" class="form-control form-control-sm" placeholder="Web UI URL"></div>
<div class="row mb-2">
<div class="col-sm-6"><input type="text" id="cfg-qbituser" class="form-control form-control-sm" placeholder="Käyttäjätunnus"></div>
<div class="col-sm-6"><input type="text" id="cfg-qbitpass" class="form-control form-control-sm" placeholder="Salasana/API"></div>
</div>
<button type="submit" class="btn btn-primary btn-sm mt-3">Tallenna kaikki asetukset</button>
</form>
<hr class="mt-5">
<h6 class="fw-bold mb-3 text-warning">🔍 Jackett Indexerit</h6>
<div class="input-group mb-3" style="max-width: 400px;">
<input type="text" id="uusi-indexer" class="form-control form-control-sm" placeholder="Indexer ID">
<button type="button" onclick="lisaaIndexer()" class="btn btn-outline-secondary btn-sm">Lisää</button>
</div>
<ul id="indexer-lista" class="list-group mb-3" style="max-width: 400px;"></ul>
</div>
</div>
</div>
<div class="card p-4 mt-4 bg-dark text-light">
<div class="d-flex justify-content-between"><h5>⚡ Järjestelmäloki</h5><button id="suorita-haku-btn" class="btn btn-success btn-sm">Suorita haku</button></div>
<pre id="skripti-loki">Ladataan...</pre>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
function rullaaLokiAlas() {
const lokit = ['loki-sisalto', 'skripti-loki'];
lokit.forEach(id => {
const el = document.getElementById(id);
if(el) el.scrollTop = el.scrollHeight;
});
}
function paivitaNakyma() {
fetch('/status').then(res => res.json()).then(data => {
document.getElementById('tila-badge').innerText = "Valmis";
document.getElementById('tila-badge').className = "badge bg-success";
const lista = document.getElementById('hakukohteet-lista');
lista.innerHTML = data.hakukohteet.map((k, i) => `<tr><td>${k.jackett_haku}</td><td>${k.kohdekansio}</td><td class="text-end"><button onclick="poistaKohde(${i})" class="btn btn-link text-danger btn-sm p-0">Poista</button></td></tr>`).join('');
const hakuTermi = document.getElementById('historia-haku').value.toLowerCase();
const lokiDiv = document.getElementById('loki-sisalto');
const kaikkiRivit = (data.loki_torrentit || '').split('\n').filter(r => r.trim() !== '');
lokiDiv.innerHTML = kaikkiRivit
.filter(r => r.toLowerCase().includes(hakuTermi))
.map((r) => {
// Suodatetaan magnet-linkin nimi näkyviin (poistetaan 'dn=' alku ja magnet: linkki)
let nimi = r;
if (r.includes('dn=')) {
nimi = decodeURIComponent(r.split('dn=')[1].split('&')[0].replace(/\+/g, ' '));
}
return `<div class="d-flex justify-content-between border-bottom py-1">
<span class="font-monospace small text-truncate" style="max-width: 80%;" title="${r}">${nimi}</span>
<button onclick="poistaHist('${r.replace(/'/g, "\\'")}')" class="btn btn-outline-danger btn-sm py-0">Poista</button>
</div>`;
}).join('');
const iList = document.getElementById('indexer-lista');
iList.innerHTML = (data.indeksorit || []).map((idx, i) => `<li class="list-group-item d-flex justify-content-between py-1">${idx}<button onclick="poistaIndexer(${i})" class="btn btn-danger btn-sm py-0">Poista</button></li>`).join('');
document.getElementById('skripti-loki').innerText = data.loki_skripti;
document.getElementById('cfg-url').value = data.asetukset.jackett_url || '';
document.getElementById('cfg-apikey').value = data.asetukset.jackett_api_key || '';
document.getElementById('cfg-qbiturl').value = data.asetukset.qbit_url || '';
document.getElementById('cfg-qbituser').value = data.asetukset.qbit_user || '';
document.getElementById('cfg-qbitpass').value = data.asetukset.qbit_pass || '';
rullaaLokiAlas();
});
}
function poistaHist(riviTeksti) {
if(confirm("Poistetaanko tämä rivi historiasta?")) {
fetch('/poista_historiarivi', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ rivi: riviTeksti })
}).then(() => paivitaNakyma());
}
}
function lisaaIndexer() { const val = document.getElementById('uusi-indexer').value; if(!val) return; fetch('/status').then(r => r.json()).then(d => { let l = d.indeksorit || []; l.push(val); fetch('/paivita_indeksorit', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({indeksorit:l})}).then(() => paivitaNakyma()); }); }
function poistaIndexer(i) { fetch('/status').then(r => r.json()).then(d => { let l = d.indeksorit; l.splice(i, 1); fetch('/paivita_indeksorit', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({indeksorit:l})}).then(() => paivitaNakyma()); }); }
function poistaKohde(i) { fetch(`/poista_kohde/${i}`, {method:'DELETE'}).then(() => paivitaNakyma()); }
document.getElementById('lisaa-form').addEventListener('submit', (e) => {
e.preventDefault();
const paivat = [0,1,2,3,4,5,6].filter(i => document.getElementById('pv-'+i).checked);
fetch('/lisaa_kohde', {
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({
jackett_haku: document.getElementById('haku-sana').value,
regex_suodatin: document.getElementById('haku-regex').value,
kohdekansio: document.getElementById('haku-kansio').value,
paivat: paivat
})
}).then(() => { e.target.reset(); paivitaNakyma(); });
});
document.getElementById('asetukset-form').addEventListener('submit', (e) => { e.preventDefault(); fetch('/tallenna_asetukset', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({jackett_url:document.getElementById('cfg-url').value, jackett_api_key:document.getElementById('cfg-apikey').value, qbit_url:document.getElementById('cfg-qbiturl').value, qbit_user:document.getElementById('cfg-qbituser').value, qbit_pass:document.getElementById('cfg-qbitpass').value})}).then(() => paivitaNakyma()); });
document.getElementById('suorita-haku-btn').addEventListener('click', () => fetch('/suorita_haku', {method:'POST'}));
document.getElementById('tyhjenna-loki-btn').addEventListener('click', () => fetch('/tyhjenna_loki', {method:'POST'}).then(() => paivitaNakyma()));
paivitaNakyma(); setInterval(paivitaNakyma, 5000);
</script>
</body>
</html>