|
|
|
@ -51,7 +51,15 @@
|
|
|
|
{% for key, stats in storage_usage %}
|
|
|
|
{% for key, stats in storage_usage %}
|
|
|
|
{% set user, platform = key.split("::") %}
|
|
|
|
{% set user, platform = key.split("::") %}
|
|
|
|
<tr data-username="{{ user|lower }}">
|
|
|
|
<tr data-username="{{ user|lower }}">
|
|
|
|
|
|
|
|
|
|
|
|
<td>
|
|
|
|
<td>
|
|
|
|
|
|
|
|
<!-- ⭐ favorite star on the left -->
|
|
|
|
|
|
|
|
<button class="fav-btn user-fav"
|
|
|
|
|
|
|
|
data-username="{{ user }}"
|
|
|
|
|
|
|
|
aria-pressed="{{ 'true' if user in favorite_users else 'false' }}">
|
|
|
|
|
|
|
|
★
|
|
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<a href="/user/{{ user }}">{{ user }}</a>
|
|
|
|
<a href="/user/{{ user }}">{{ user }}</a>
|
|
|
|
{% set uname = user.lower() %}
|
|
|
|
{% set uname = user.lower() %}
|
|
|
|
{% if uname in online_set %}
|
|
|
|
{% if uname in online_set %}
|
|
|
|
@ -62,10 +70,15 @@
|
|
|
|
<span class="status-dot dot-offline" title="Offline"></span>
|
|
|
|
<span class="status-dot dot-offline" title="Offline"></span>
|
|
|
|
{% endif %}
|
|
|
|
{% endif %}
|
|
|
|
</td>
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
|
|
<td><a href="https://{{ platform }}.com/{{ user }}">{{ platform }}</a></td>
|
|
|
|
<td><a href="https://{{ platform }}.com/{{ user }}">{{ platform }}</a></td>
|
|
|
|
|
|
|
|
|
|
|
|
<td>{{ "%.2f"|format(stats.total_size) }}</td>
|
|
|
|
<td>{{ "%.2f"|format(stats.total_size) }}</td>
|
|
|
|
|
|
|
|
|
|
|
|
<td>{{ stats.video_count }}</td>
|
|
|
|
<td>{{ stats.video_count }}</td>
|
|
|
|
|
|
|
|
|
|
|
|
<td>{{ "%.2f"|format(avg_sizes[key]) }}</td>
|
|
|
|
<td>{{ "%.2f"|format(avg_sizes[key]) }}</td>
|
|
|
|
|
|
|
|
|
|
|
|
<td>
|
|
|
|
<td>
|
|
|
|
{% if stats.last_online %}
|
|
|
|
{% if stats.last_online %}
|
|
|
|
{{ stats.last_online.strftime('%Y-%m-%d') }}
|
|
|
|
{{ stats.last_online.strftime('%Y-%m-%d') }}
|
|
|
|
@ -73,6 +86,7 @@
|
|
|
|
—
|
|
|
|
—
|
|
|
|
{% endif %}
|
|
|
|
{% endif %}
|
|
|
|
</td>
|
|
|
|
</td>
|
|
|
|
|
|
|
|
|
|
|
|
</tr>
|
|
|
|
</tr>
|
|
|
|
{% endfor %}
|
|
|
|
{% endfor %}
|
|
|
|
</tbody>
|
|
|
|
</tbody>
|
|
|
|
@ -104,4 +118,32 @@ async function refreshStatusDots() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
refreshStatusDots(); setInterval(refreshStatusDots, 20000);
|
|
|
|
refreshStatusDots(); setInterval(refreshStatusDots, 20000);
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
|
|
document.addEventListener("click", async (e) => {
|
|
|
|
|
|
|
|
if (e.target.classList.contains("fav-btn")) {
|
|
|
|
|
|
|
|
const btn = e.target;
|
|
|
|
|
|
|
|
const username = btn.dataset.username;
|
|
|
|
|
|
|
|
const videoId = btn.dataset.videoId;
|
|
|
|
|
|
|
|
const isFav = btn.getAttribute("aria-pressed") === "true";
|
|
|
|
|
|
|
|
const newState = !isFav;
|
|
|
|
|
|
|
|
btn.setAttribute("aria-pressed", newState);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
if (username) {
|
|
|
|
|
|
|
|
await fetch("/api/favorite_user", {
|
|
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
|
|
body: JSON.stringify({ username, favorite: newState })
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else if (videoId) {
|
|
|
|
|
|
|
|
await fetch(`/api/fav/toggle/${videoId}`, { method: "POST" });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
|
|
console.error("Favorite toggle failed:", err);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
{% endblock %}
|
|
|
|
{% endblock %}
|
|
|
|
|