@ -211,6 +211,7 @@ def favorites_page():
@web.route ( " /users " )
def users ( ) :
import math
# ---- filters ----
q = ( request . args . get ( " q " ) or " " ) . lower ( ) . strip ( )
sort = request . args . get ( " sort " , " total_size " ) # user|site|total_size|video_count
@ -237,19 +238,19 @@ def users():
params [ " end " ] = end
where_sql = " AND " . join ( where )
# ---- ORDER BY ----
# ---- ORDER BY (use computed GB alias) ----
sort_map = {
" user " : " username " ,
" site " : " site " ,
" total_size " : " total_ bytes " ,
" total_size " : " total_ g b" , # <- sort by GB, not raw MB sum
" video_count " : " video_count " ,
}
order_col = sort_map . get ( sort , " total_ bytes " )
order_col = sort_map . get ( sort , " total_ g b" )
order_dir = " DESC " if reverse else " ASC "
# ---- pagination ----
page = max ( 1 , int ( request . args . get ( " page " , 1 ) ) )
per_page = 100 # or your DASHBOARD_PER_PAGE
per_page = 100
offset = ( page - 1 ) * per_page
# ---- count distinct (username, site) for pager ----
@ -262,16 +263,18 @@ def users():
) t ;
"""
# ---- aggregate page ----
# size is in **MB**, convert to GB:
# 1 GiB = 1024 MB → divide by 1024.0
# (If you really want decimal GB, change 1024.0 to 1000.0)
agg_sql = f """
SELECT
username ,
site ,
COUNT ( * ) AS video_count ,
SUM ( size ) AS total_ bytes ,
AVG ( size ) AS avg_ bytes ,
SUM ( size ) : : numeric / 10 00000000.0 AS total_gb ,
AVG ( size ) : : numeric / 10 00000000.0 AS avg_gb
SUM ( size ) AS total_ m b,
AVG ( size ) AS avg_ m b,
( SUM ( size ) : : numeric / 10 24.0) AS total_gb ,
( AVG ( size ) : : numeric / 10 24.0) AS avg_gb
FROM videos
WHERE { where_sql }
GROUP BY username , site
@ -290,9 +293,9 @@ def users():
cur . execute ( agg_sql , params )
rows = cur . fetchall ( )
# rows: (username, site, video_count, total_ bytes, avg_bytes )
# rows: (username, site, video_count, total_ mb, avg_mb, total_gb, avg_gb )
# ---- get recording sets (for status dots ) ----
# ---- online/recording status sets (optional ) ----
online_usernames : set [ str ] = set ( )
recording_offline_usernames : set [ str ] = set ( )
if show_online_first :
@ -309,7 +312,8 @@ def users():
except Exception :
pass
# ---- thumbnail subquery (only for current page) ----
# ---- thumbnail candidates per (user, site) ----
tcur = conn . cursor ( )
thumb_sql = """
SELECT thumbnail
FROM videos
@ -320,49 +324,39 @@ def users():
ORDER BY created_at DESC
LIMIT 3 ;
"""
tcur = conn . cursor ( )
def to_gb ( n ) : return ( n or 0 ) / 1_000_000_000.0
cards = [ ]
for ( username , site , video_count , total_ bytes , avg_ bytes , total_gb , avg_gb ) in rows :
# fetch up to 3 recent thumbnails (unchanged logic you already added)
for ( username , site , video_count , total_mb , avg_mb , total_gb , avg_gb ) in rows :
# fetch up to 3 recent thumbnails
thumb_urls = [ ]
try :
tcur . execute (
"""
SELECT thumbnail
FROM videos
WHERE username = % ( u ) s AND site = % ( s ) s
AND thumbnail IS NOT NULL AND thumbnail < > ' '
ORDER BY created_at DESC
LIMIT 3 ;
""" ,
{ " u " : username , " s " : site } ,
)
tcur . execute ( thumb_sql , { " u " : username , " s " : site } )
thumb_urls = [ r [ 0 ] for r in tcur . fetchall ( ) if r and r [ 0 ] ]
except Exception :
pass
# ---- PRE-FORMAT display strings here (avoid Jinja float filter entirely) ----
total_gb_val = float ( total_gb or 0 )
avg_gb_val = float ( avg_gb or 0 )
total_gb_val = float ( total_gb or 0.0 )
avg_gb_val = float ( avg_gb or 0.0 )
uname_low = ( username or " " ) . lower ( )
cards . append ( {
" user " : username ,
" site " : site ,
" total_size " : total_gb_val , # keep the raw number if you need it
" avg_size " : avg_gb_val , # keep raw
" total_size_display " : f " { total_gb_val : .2f } " , # <— use this in HTML
" avg_size_display " : f " { avg_gb_val : .2f } " , # <— use this in HTML
" video_count " : int ( video_count ) ,
# numeric
" total_size " : total_gb_val ,
" avg_size " : avg_gb_val ,
# preformatted strings for display
" total_size_display " : f " { total_gb_val : .2f } " ,
" avg_size_display " : f " { avg_gb_val : .2f } " ,
" thumb_urls " : thumb_urls ,
" is_online " : uname_low in online_usernames ,
" is_recording_offline " : ( uname_low in recording_offline_usernames ) and ( uname_low not in online_usernames ) ,
} )
# ---- optional: reorder with online-first grouping ----
if show_online_first :
online_cards = [ c for c in cards if c [ " is_online " ] ]
rec_off_cards = [ c for c in cards if c [ " is_recording_offline " ] and not c [ " is_online " ] ]
@ -380,7 +374,6 @@ def users():
the_rest . sort ( key = k , reverse = reverse )
cards = online_cards + rec_off_cards + the_rest
# ---- render users.html ----
return render_template (
" users.html " ,
cards = cards ,