Files
spotdl-py/templates/history.html
2026-03-21 00:43:49 +01:00

178 lines
8.2 KiB
HTML

{% extends "layout.html" %}
{% block title %}Historique - Spotify Downloader{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h4 class="mb-0"><i class="bi bi-clock-history me-2"></i>Historique des téléchargements</h4>
<span class="badge bg-secondary">{{ downloads|length }} téléchargement(s)</span>
</div>
<div class="card-body p-0">
{% if downloads %}
<div class="table-responsive">
<table class="table table-dark table-hover mb-0">
<thead>
<tr>
<th class="text-center" style="width: 80px;">Statut</th>
<th>URL</th>
<th style="width: 80px;">Format</th>
<th style="width: 100px;">Progression</th>
<th style="width: 150px;">Date</th>
<th style="width: 120px;">Actions</th>
</tr>
</thead>
<tbody>
{% for dl in downloads %}
<tr data-download-id="{{ dl.id }}">
<td class="text-center">
{% if dl.status == 'completed' %}
<span class="badge bg-success" title="Terminé">
<i class="bi bi-check-circle"></i>
</span>
{% elif dl.status == 'running' %}
<span class="badge bg-warning" title="En cours">
<i class="bi bi-arrow-repeat spin"></i>
</span>
{% elif dl.status == 'error' %}
<span class="badge bg-danger" title="Erreur">
<i class="bi bi-x-circle"></i>
</span>
{% elif dl.status == 'cancelled' %}
<span class="badge bg-secondary" title="Annulé">
<i class="bi bi-slash-circle"></i>
</span>
{% else %}
<span class="badge bg-info" title="En attente">
<i class="bi bi-clock"></i>
</span>
{% endif %}
</td>
<td>
<small class="text-break" style="max-width: 400px; display: inline-block;">
{{ dl.url[:80] }}{% if dl.url|length > 80 %}...{% endif %}
</small>
</td>
<td>
<span class="badge bg-dark">{{ dl.format_type|upper }}</span>
</td>
<td>
<div class="progress" style="height: 20px;">
<div class="progress-bar {{ 'bg-success' if dl.status == 'completed' else 'bg-warning' }}"
style="width: {{ dl.progress }}%">
{{ dl.progress }}%
</div>
</div>
</td>
<td>
<small>
{{ dl.created_at.strftime('%d/%m/%Y') }}<br>
<span class="text-muted">{{ dl.created_at.strftime('%H:%M') }}</span>
</small>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-light view-log" data-id="{{ dl.id }}" title="Voir les logs">
<i class="bi bi-file-text"></i>
</button>
{% if dl.status != 'running' %}
<button class="btn btn-outline-danger delete-download" data-id="{{ dl.id }}" title="Supprimer">
<i class="bi bi-trash"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-inbox fs-1 text-muted"></i>
<p class="text-muted mt-2">Aucun téléchargement pour le moment</p>
<a href="{{ url_for('index') }}" class="btn btn-spotify">
<i class="bi bi-download me-1"></i>Télécharger
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="modal fade" id="logModal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title"><i class="bi bi-terminal me-2"></i>Logs du téléchargement</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<pre id="logContent" class="output-box p-3 mb-0" style="white-space: pre-wrap; max-height: 500px; overflow-y: auto;"></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-light" data-bs-dismiss="modal">Fermer</button>
</div>
</div>
</div>
</div>
<style>
.spin {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const logModal = new bootstrap.Modal(document.getElementById('logModal'));
const logContent = document.getElementById('logContent');
document.querySelectorAll('.view-log').forEach(btn => {
btn.addEventListener('click', async function() {
const id = this.dataset.id;
try {
const response = await fetch(`/api/download/${id}`);
const data = await response.json();
logContent.textContent = data.log || 'Aucun log disponible';
logModal.show();
} catch (err) {
showToast('Erreur lors du chargement des logs', 'error');
}
});
});
document.querySelectorAll('.delete-download').forEach(btn => {
btn.addEventListener('click', async function() {
const id = this.dataset.id;
const row = this.closest('tr');
if (!confirm('Supprimer ce téléchargement de l\'historique ?')) return;
try {
const response = await fetch(`/api/download/${id}`, { method: 'DELETE' });
if (response.ok) {
row.remove();
showToast('Supprimé de l\'historique', 'success');
} else {
const data = await response.json();
showToast(data.error || 'Erreur', 'error');
}
} catch (err) {
showToast('Erreur réseau', 'error');
}
});
});
});
</script>
{% endblock %}