shelfy/templates/godownloader_download.pages.tmpl

168 lines
4.2 KiB
Cheetah
Raw Normal View History

2025-06-12 08:57:10 +00:00
<h1>Download</h1>
<div class="box">
2025-06-15 15:21:11 +00:00
<form
hx-post="/api/download/add"
hx-trigger="submit"
hx-swap="none"
hx-on="htmx:afterRequest: this.reset()"
class="mb-4"
>
2025-06-12 08:57:10 +00:00
<div class="field">
<label class="label">Lien à débrider</label>
<div class="control">
<input class="input" type="text" name="link" placeholder="https://..." required>
</div>
</div>
<div class="field">
<label class="label">Chemin d'enregistrement</label>
<div class="control">
<div class="select">
<select name="path_id">
{{range .paths}}<option value="{{.ID}}">{{.PathName}}</option>{{end}}
</select>
</div>
</div>
</div>
<div class="field is-grouped">
<div class="control">
<button class="button is-primary" type="submit">Ajouter</button>
</div>
</div>
</form>
2025-06-15 15:21:11 +00:00
<div
hx-ext="sse"
sse-connect="/api/download/stream"
hx-on="
htmx:sseOpen: console.log('✅ SSE ouvert');
htmx:sseError: console.error('❌ SSE erreur', event.detail.error);
htmx:sseMessage:console.log('📨 SSE reçu', event.detail);
"
>
<table
id="downloads-table"
class="table is-fullwidth is-striped"
hx-trigger="load,sse:jobs"
> <thead>
<tr>
<th>Fichier</th>
<th>Statut</th>
<th>Vitesse</th>
<th>Progress</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="test"></tbody>
</table>
2025-06-12 08:57:10 +00:00
</div>
2025-06-15 15:21:11 +00:00
</div>
<script>
2025-06-19 12:09:06 +00:00
if (typeof es === 'undefined') {
let es = new EventSource("/api/download/stream");
} else {
es = new EventSource("/api/download/stream");
}
2025-06-15 15:21:11 +00:00
es.addEventListener("jobs", async (e) => {
console.log("🧪 Event brut reçu es const:", e.data);
const tbody = document.getElementById("test");
if (!tbody) {
console.warn("❌ <tbody id='test'> non trouvé !");
return;
}
const url = `/api/download/all?t=${Date.now()}`;
console.log("🔁 Fetch direct :", url);
try {
const response = await fetch(url, {
headers: {
'HX-Request': 'true'
}
});
if (!response.ok) {
console.error("❌ Erreur serveur :", response.status);
return;
}
const html = await response.text();
tbody.innerHTML = html;
console.log("✅ Contenu injecté dans <tbody id='test'>");
} catch (err) {
console.error("❌ Erreur fetch :", err);
}
});
es.onerror = e => console.error("❌ Erreur EventSource", e);
es.onerror = e => console.error("❌ Erreur EventSource", e);
async function postJobAction(url) {
try {
const res = await fetch(url, {
method: "POST",
headers: { "HX-Request": "true" }
});
if (!res.ok) throw new Error("Échec POST : " + res.status);
console.log("✅ Action POST réussie :", url);
} catch (err) {
console.error("❌ Erreur action POST :", err);
}
}
// DELETE avec effet visuel
async function deleteJobAnimated(jobId) {
const row = document.getElementById(`job-${jobId}`);
if (!row) return;
try {
const res = await fetch(`/api/download/delete/${jobId}`, {
method: "DELETE",
headers: { "HX-Request": "true" }
});
if (!res.ok) throw new Error("Échec DELETE");
// Animation fade out
row.style.transition = "opacity 0.4s ease, height 0.4s ease";
row.style.opacity = "0";
row.style.height = "0px";
setTimeout(() => row.remove(), 400);
} catch (err) {
console.error("❌ Erreur suppression :", err);
}
}
// Dispatcher global
document.addEventListener("click", function (e) {
const btn = e.target.closest("button[data-action]");
if (!btn) return;
const action = btn.dataset.action;
const jobId = btn.dataset.id;
switch (action) {
case "start-job":
postJobAction(`/api/download/start/${jobId}`);
break;
case "pause-job":
postJobAction(`/api/download/pause/${jobId}`);
break;
case "resume-job":
postJobAction(`/api/download/resume/${jobId}`);
break;
case "delete-job":
deleteJobAnimated(jobId);
break;
}
});
</script>