added favorite streamers feature

main
oscar 2 weeks ago
parent 4c6bc25398
commit f2de819f58

@ -70,4 +70,11 @@ def db_get_favorites(page: int, per_page: int):
total = cur.fetchone()[0]
cur.close(); conn.close()
return rows, total
return rows, total
def db_get_favorite_users():
conn, cur = get_local_db_connection()
cur.execute("SELECT username FROM favorite_users")
favorite_users = [r['username'] for r in cur.fetchall()]
cur.close(); conn.close()
return favorite_users

@ -91,3 +91,18 @@ def get_online():
for s in streamers:
s["is_online"] = (s.get("status") == "Channel online")
return jsonify(streamers)
@api.route("/api/favorite_user", methods=["POST"])
def favorite_user():
data = request.get_json(force=True)
username = data.get("username")
fav = bool(data.get("favorite"))
conn, cur = get_local_db_connection()
if fav:
cur.execute("INSERT INTO favorite_users (username) VALUES (%s) ON CONFLICT DO NOTHING", (username,))
else:
cur.execute("DELETE FROM favorite_users WHERE username = %s", (username,))
conn.commit()
cur.close(); conn.close()
return {"ok": True}

@ -1,7 +1,7 @@
from flask import Blueprint, render_template, request, send_file, jsonify
import math
from helpers.db import db_get_videos, db_get_video, db_get_recent
from helpers.favorites import mark_favorites, db_get_favorites, db_get_fav_set
from helpers.favorites import mark_favorites, db_get_favorites, db_get_fav_set, db_get_favorite_users
from helpers.cache import build_cache
from config import VIDEOS_PER_PAGE, DASHBOARD_PER_PAGE, get_local_db_connection
from datetime import date, datetime, timedelta
@ -120,6 +120,8 @@ def dashboard():
start_idx = (page - 1) * DASHBOARD_PER_PAGE
paginated = items[start_idx:start_idx + DASHBOARD_PER_PAGE]
favorite_users = db_get_favorite_users()
return render_template(
"main.html",
storage_usage=paginated,
@ -134,6 +136,7 @@ def dashboard():
end_date=end_str,
online_set=online_usernames,
recording_offline_set=recording_offline_usernames,
favorite_users=favorite_users,
)
@web.route("/user/<username>")

@ -172,6 +172,16 @@ tr:nth-child(even){background:#181818}
.fav-btn[aria-pressed="true"]{color:gold}
.fav-btn:hover{transform:scale(1.05)}
.user-fav {
position: static; /* no absolute positioning */
background: none;
padding: 0;
margin-right: 6px; /* little gap before username */
font-size: 16px;
backdrop-filter: none;
}
/* =========================
Responsive tweaks
========================= */

@ -51,7 +51,15 @@
{% for key, stats in storage_usage %}
{% set user, platform = key.split("::") %}
<tr data-username="{{ user|lower }}">
<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>
{% set uname = user.lower() %}
{% if uname in online_set %}
@ -62,10 +70,15 @@
<span class="status-dot dot-offline" title="Offline"></span>
{% endif %}
</td>
<td><a href="https://{{ platform }}.com/{{ user }}">{{ platform }}</a></td>
<td>{{ "%.2f"|format(stats.total_size) }}</td>
<td>{{ stats.video_count }}</td>
<td>{{ "%.2f"|format(avg_sizes[key]) }}</td>
<td>
{% if stats.last_online %}
{{ stats.last_online.strftime('%Y-%m-%d') }}
@ -73,6 +86,7 @@
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
@ -104,4 +118,32 @@ async function refreshStatusDots() {
}
refreshStatusDots(); setInterval(refreshStatusDots, 20000);
</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 %}

Loading…
Cancel
Save