diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..1764c4b --- /dev/null +++ b/static/styles.css @@ -0,0 +1,186 @@ +/* ========================= + Theme / Base + ========================= */ +:root{ + --bg:#111; --card:#1a1a1a; --muted:#bbb; --text:#eee; --line:#333; + --chip:#181818; --link:#4af; --link-hover:#7bb7ff; +} + +*{box-sizing:border-box} +html,body{height:100%} +body{ + margin:0; + font-family:Arial,Helvetica,sans-serif; + background:var(--bg); + color:var(--text); +} +a{color:var(--link); text-decoration:none} +a:hover{color:var(--link-hover)} + +/* ========================= + Top Nav & Footer + ========================= */ +.topbar{ + position:sticky; top:0; z-index:100; + background:#0d0d0d; border-bottom:1px solid var(--line); +} +.nav{ + max-width:1200px; margin:0 auto; + display:flex; align-items:center; justify-content:space-between; + padding:12px 16px; +} +.nav .brand{color:#fff; font-weight:600} +.nav .links{display:flex; gap:14px; flex-wrap:wrap} +.nav .links a{color:var(--link)} +.nav .links a:hover{color:var(--link-hover)} + +.footer{ + margin-top:32px; border-top:1px solid var(--line); + padding:16px; text-align:center; color:var(--muted) +} + +/* ========================= + Layout Helpers + ========================= */ +.container{max-width:1200px; margin:24px auto; padding:0 16px} + +/* ========================= + Controls / Forms + ========================= */ +.controls{ + margin:10px 0; display:flex; gap:10px; + flex-wrap:wrap; justify-content:center +} +input[type="text"], input[type="date"], select{ + padding:8px; background:var(--chip); color:var(--text); + border:1px solid var(--line); border-radius:4px; +} +button{ + padding:8px 12px; background:var(--chip); color:var(--text); + border:1px solid var(--line); border-radius:4px; cursor:pointer +} +button:hover{background:#202020} + +/* ========================= + Table (Dashboard) + ========================= */ +.table-wrap{overflow:auto} +table{ + margin:auto; border-collapse:collapse; width:100%; + background:var(--card) +} +th,td{border:1px solid var(--line); padding:10px; text-align:left} +th{ + background:#222; position:sticky; top:48px; /* align with .topbar height */ + z-index:10 +} +tr:nth-child(even){background:#181818} + +/* ========================= + Pagination (shared macro) + ========================= */ +.pagination{margin:16px 0; text-align:center} +.pagination a,.pagination span{ + display:inline-block; background:var(--chip); color:var(--text); + border:1px solid var(--line); margin:0 5px; padding:6px 12px; text-decoration:none; + border-radius:4px; +} +.pagination .active{background:#333} + +/* ========================= + Status dots + ========================= */ +.status-dot{ + display:inline-block; width:10px; height:10px; + border-radius:50%; margin-left:6px; vertical-align:middle +} +.dot-online{background:#22c55e} +.dot-record{background:#ef4444} +.dot-offline{background:#666} + +/* ========================= + Grid container (shared) + ========================= */ +.grid{ + width:100%; + display:grid; + grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); + gap:14px; +} + +/* ========================= + Card base (shared) + ========================= */ +.card{ + background:var(--card); border:1px solid var(--line); + border-radius:8px; padding:10px; min-height:120px; +} + +/* ========================= + Users grid (users.html) + Two-column card with tall thumbnail + ========================= */ +.user-card{ + display:grid; + grid-template-columns:180px 1fr; + gap:12px; align-items:stretch; +} + +/* ========================= + Video grids (favorites, user_page) + Stacked card (thumb on top, meta below) + ========================= */ +.video-card{ + display:flex; + flex-direction:column; + gap:10px; +} + +/* Thumbnails (shared) */ +.thumb{ + position:relative; + height:100%; min-height:120px; + background:#222; border:1px solid var(--line); + border-radius:6px; overflow:hidden; +} +.thumb img,.thumb .fallback{ + position:absolute; inset:0; + width:100%; height:100%; object-fit:cover; display:block; +} +.thumb .fallback{ + display:none; align-items:center; justify-content:center; font-size:28px; +} + +/* Taller thumbs on video cards */ +.grid.videos .thumb{ min-height:140px; } + +/* Meta panel */ +.meta{ + display:flex; flex-direction:column; gap:6px; min-width:0; +} +.meta h3{margin:0; font-size:16px; display:flex; align-items:center; gap:6px} +.row{font-size:14px} +.muted{color:var(--muted)} + +/* Favorite star overlay (works for both grids) */ +.fav-btn{ + position:absolute; top:8px; right:8px; z-index:2; + font-size:18px; line-height:1; + border:none; border-radius:6px; padding:.25rem .45rem; cursor:pointer; + background:rgba(0,0,0,.55); color:#fff; backdrop-filter:blur(2px) +} +.fav-btn[aria-pressed="true"]{color:gold} +.fav-btn:hover{transform:scale(1.05)} + +/* ========================= + Responsive tweaks + ========================= */ +@media (max-width: 900px){ + .user-card{grid-template-columns:150px 1fr} + th{top:56px} +} +@media (max-width: 640px){ + .user-card{grid-template-columns:1fr} + .thumb{min-height:160px} + th{top:60px} +} diff --git a/templates/_pagination.html b/templates/_pagination.html new file mode 100644 index 0000000..1e3ebe6 --- /dev/null +++ b/templates/_pagination.html @@ -0,0 +1,33 @@ +{% macro pager(endpoint, page, total_pages, q=None, sort=None, dir=None, timeframe=None, start=None, end=None, username=None) -%} + {% if total_pages > 1 %} + + {% endif %} +{%- endmacro %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..6e46e9c --- /dev/null +++ b/templates/base.html @@ -0,0 +1,37 @@ + + + + + + {% block title %}Streamaster Finder{% endblock %} + + + {% block head %}{% endblock %} + + + +
+ +
+ +
+ {% block content %}{% endblock %} +
+ + + + {% block scripts %}{% endblock %} + + + \ No newline at end of file diff --git a/templates/favorites.html b/templates/favorites.html index cd52714..777db8a 100644 --- a/templates/favorites.html +++ b/templates/favorites.html @@ -1,173 +1,72 @@ - - - - - - ★ Favorites - - - - -

★ Favorites

- ⬅ Back to Dashboard - -
- {% for video in videos %} -
-
- - Thumbnail - - - -
-

{{ "%.2f"|format(video.size/1024) }} GB

-
- {% endfor %} +{% extends "base.html" %} +{% from "_pagination.html" import pager %} +{% block title %}★ Favorites{% endblock %} + +{% block content %} +

★ Favorites

+ +
+ {% for video in videos %} +
+
+ {% set thumb = video.thumbnail %} + + Thumbnail + + 🎞️ + +
- + {% endfor %} +
+ +{{ pager('web.favorites_page', page, total_pages) }} +{% endblock %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/templates/main.html b/templates/main.html index d0d6709..6ad084a 100644 --- a/templates/main.html +++ b/templates/main.html @@ -1,291 +1,112 @@ - - - - - - 📊 Video Storage Analytics - - - - - - - - - - -

📊 Video Storage Analytics

- -
- -
- - - - - - - - - -
- - -
- - - - - - - - - - - -
- - - - -
- - -
-
- - - - - {% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %} - {% set next_platform_dir = 'asc' if sort != 'platform' or dir == 'desc' else 'desc' %} - {% set next_total_dir = 'asc' if sort != 'total_size' or dir == 'desc' else 'desc' %} - {% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %} - {% set next_avg_dir = 'asc' if sort != 'avg_size' or dir == 'desc' else 'desc' %} - - - - - - - - - - {% for key, stats in storage_usage %} - {% set user, platform = key.split("::") %} - - + + + + + + {% endfor %} - - {% if page < total_pages %} Next » - {% else %} - Next » - {% endif %} - - {% endif %} - - - \ No newline at end of file + +
- - User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} - - - - Platform{% if sort=='platform' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} - - - - Total Storage (GB){% if sort=='total_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} - - - - Video Count{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} - - - - Avg Size per Video (GB){% if sort=='avg_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} - -
- {{ user }} - {% set uname = user.lower() %} - {% if uname in online_set %} +{% extends "base.html" %} +{% from "_pagination.html" import pager %} +{% block title %}📊 Video Storage Analytics{% endblock %} +{% block content %} +

📊 Video Storage Analytics

+ +
+
+ + + + + + + + +
+ +
+ + +
+
+ +
+ + + + {% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %} + {% set next_platform_dir = 'asc' if sort != 'platform' or dir == 'desc' else 'desc' %} + {% set next_total_dir = 'asc' if sort != 'total_size' or dir == 'desc' else 'desc' %} + {% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %} + {% set next_avg_dir = 'asc' if sort != 'avg_size' or dir == 'desc' else 'desc' %} + + + + + + + + + + {% for key, stats in storage_usage %} + {% set user, platform = key.split("::") %} + + - - - - - - {% endfor %} - -
+ User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} + Platform{% if sort=='platform' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} + Total Storage (GB){% if sort=='total_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} + Video Count{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} + Avg Size per Video (GB){% if sort=='avg_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} + Last Online{% if sort=='last_online' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %} +
+ {{ user }} + {% set uname = user.lower() %} + {% if uname in online_set %} - {% elif uname in recording_offline_set %} + {% elif uname in recording_offline_set %} - {% else %} + {% else %} - {% endif %} - - {{ platform }} - {{ "%.2f"|format(stats.total_size) }}{{ stats.video_count }}{{ "%.2f"|format(avg_sizes[key]) }}
- - - {% if total_pages > 1 %} -
{{ platform }}{{ "%.2f"|format(stats.total_size) }}{{ stats.video_count }}{{ "%.2f"|format(avg_sizes[key]) }} + {% if stats.last_online %} + {{ stats.last_online.strftime('%Y-%m-%d') }} + {% else %} + — + {% endif %} +
+
+ +{{ pager('web.dashboard', page, total_pages, q=query, sort=sort, dir=dir, timeframe=timeframe, start=start_date, end=end_str) }} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/user_page.html b/templates/user_page.html index 1109130..e546607 100644 --- a/templates/user_page.html +++ b/templates/user_page.html @@ -1,168 +1,83 @@ - - - - - - {{ username }}'s Videos - - - - -

🎥 Videos for {{ username }}

- ⬅ Back to Dashboard - -
- {% for video in videos %} -
-
- - Thumbnail - - - - -
- -

{{ "%.2f"|format(video.size/1024) }} GB

-
- {% endfor %} +{% extends "base.html" %} +{% from "_pagination.html" import pager %} +{% block title %}{{ username }} — Videos{% endblock %} + +{% block content %} +

📼 {{ username }}

+ +
+ {% for v in videos %} +
+
+ {% set thumb = v.thumbnail %} + + Thumbnail + + 🎞️ + +
- + {% endfor %} +
+ +{{ pager('web.user_page', page, total_pages, username=username) }} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/users.html b/templates/users.html index 8fd527b..611d088 100644 --- a/templates/users.html +++ b/templates/users.html @@ -1,181 +1,100 @@ - - - - - 👥 Users - - - - - - -

👥 Users

- -
- -
- - - - - - - -
- - - {% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %} - {% set next_site_dir = 'asc' if sort != 'site' or dir == 'desc' else 'desc' %} - {% set next_total_dir = 'asc' if sort != 'total_size' or dir == 'desc' else 'desc' %} - {% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %} - - - - -
- - - - - - - - - -
+{% extends "base.html" %} +{% from "_pagination.html" import pager %} +{% block title %}👥 Users{% endblock %} +{% block content %} +

👥 Users

+ +
+
+ + + + + + + +
+ + {% set next_user_dir = 'asc' if sort != 'user' or dir == 'desc' else 'desc' %} + {% set next_site_dir = 'asc' if sort != 'site' or dir == 'desc' else 'desc' %} + {% set next_total_dir = 'asc' if sort != 'total_size' or dir == 'desc' else 'desc' %} + {% set next_count_dir = 'asc' if sort != 'video_count' or dir == 'desc' else 'desc' %} + -
- {% for c in cards %} -
-
- {% if c.thumb_urls and c.thumb_urls|length %} - {# render all candidates; show first, hide the rest; each tries the next on error #} - {% for url in c.thumb_urls %} - {{ c.user }} - {% endfor %} - 🎞️ +
+ + + + + + + + +
+
+ +
+ {% for c in cards %} +
+
+ {% if c.thumb_urls and c.thumb_urls|length %} + {% for url in c.thumb_urls %} + {{ c.user }} + {% endfor %} + {% endif %} + 🎞️ +
+
+

+ {{ c.user }} + {% if c.is_online %} + + {% elif c.is_recording_offline %} + {% else %} - {# no thumbnails at all → show fallback by default #} - 🎞️ + {% endif %} -

- -
-

- {{ c.user }} - {% if c.is_online %} - - {% elif c.is_recording_offline %} - - {% else %} - - {% endif %} -

-
- Site: - {{ c.site }} -
-
Total size: {{ c.total_size_display }} GB
-
Videos: {{ c.video_count }}
-
+ + +
Total size: {{ c.total_size_display }} GB
+
Videos: {{ c.video_count }}
- {% endfor %}
- - {% if total_pages > 1 %} - - {% endif %} - - - + {% endfor %} +
+ +{{ pager('web.users', page, total_pages, q=query, sort=sort, dir=dir, timeframe=timeframe, start=start_date, end=end_date) }} +{% endblock %} + +{% block scripts %} + +{% endblock %}