You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
5.4 KiB
HTML
101 lines
5.4 KiB
HTML
{% extends "base.html" %}
|
|
{% from "_pagination.html" import pager %}
|
|
{% block title %}👥 Users{% endblock %}
|
|
{% block content %}
|
|
<h1>👥 Users</h1>
|
|
|
|
<div class="controls">
|
|
<form method="get" action="{{ url_for('web.users') }}">
|
|
<input type="text" name="q" placeholder="Search users..." value="{{ query or '' }}">
|
|
<input type="hidden" name="sort" value="{{ sort }}">
|
|
<input type="hidden" name="dir" value="{{ dir }}">
|
|
<input type="hidden" name="timeframe" value="{{ timeframe }}">
|
|
<input type="hidden" name="start" value="{{ start_date or '' }}">
|
|
<input type="hidden" name="end" value="{{ end_date or '' }}">
|
|
<button type="submit">Search</button>
|
|
</form>
|
|
<!-- sort links -->
|
|
{% 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' %}
|
|
<div class="controls">
|
|
<a href="{{ url_for('web.users', q=query, page=1, sort='user', dir=next_user_dir, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
|
<a href="{{ url_for('web.users', q=query, page=1, sort='site', dir=next_site_dir, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Site{% if sort=='site' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
|
<a href="{{ url_for('web.users', q=query, page=1, sort='total_size', dir=next_total_dir, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Total Size{% if sort=='total_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
|
<a href="{{ url_for('web.users', q=query, page=1, sort='video_count', dir=next_count_dir, timeframe=timeframe, start=start_date, end=end_date) }}">Sort: Videos{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a>
|
|
</div>
|
|
|
|
<form method="get" action="{{ url_for('web.users') }}">
|
|
<label>Timeframe:</label>
|
|
<select name="timeframe" onchange="this.form.submit()">
|
|
<option value="all" {{ 'selected' if timeframe=='all' else '' }}>All time</option>
|
|
<option value="week" {{ 'selected' if timeframe=='week' else '' }}>This week</option>
|
|
<option value="month" {{ 'selected' if timeframe=='month' else '' }}>Last 30 days</option>
|
|
<option value="year" {{ 'selected' if timeframe=='year' else '' }}>Last 365 days</option>
|
|
<option value="custom"{{ 'selected' if timeframe=='custom' else '' }}>Custom…</option>
|
|
</select>
|
|
<input type="date" name="start" value="{{ start_date or '' }}" />
|
|
<input type="date" name="end" value="{{ end_date or '' }}" />
|
|
<input type="hidden" name="q" value="{{ query or '' }}">
|
|
<input type="hidden" name="sort" value="{{ sort }}">
|
|
<input type="hidden" name="dir" value="{{ dir }}">
|
|
<button type="submit">Apply</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
{% for c in cards %}
|
|
<div class="card user-card" data-username="{{ c.user|lower }}">
|
|
<div class="thumb">
|
|
{% if c.thumb_urls and c.thumb_urls|length %}
|
|
{% for url in c.thumb_urls %}
|
|
<img src="{{ url }}" loading="lazy" decoding="async" alt="{{ c.user }}" {% if not loop.first %}style="display:none"{% endif %} onerror="this.style.display='none'; const n=this.nextElementSibling; if(n){ if(n.tagName==='IMG'){ n.style.display='block'; } else { n.style.display='flex'; } }">
|
|
{% endfor %}
|
|
{% endif %}
|
|
<span class="fallback">🎞️</span>
|
|
</div>
|
|
<div class="meta">
|
|
<h3>
|
|
<a href="{{ url_for('web.user_page', username=c.user) }}">{{ c.user }}</a>
|
|
{% if c.is_online %}
|
|
<span class="status-dot dot-online" title="Online"></span>
|
|
{% elif c.is_recording_offline %}
|
|
<span class="status-dot dot-record" title="Recording (offline)"></span>
|
|
{% else %}
|
|
<span class="status-dot dot-offline" title="Offline"></span>
|
|
{% endif %}
|
|
</h3>
|
|
<div class="row"><span class="muted">Site:</span> <a href="https://{{ c.site }}.com/{{ c.user }}" target="_blank" rel="noopener">{{ c.site }}</a></div>
|
|
<div class="row"><span class="muted">Total size:</span> {{ c.total_size_display }} GB</div>
|
|
<div class="row"><span class="muted">Videos:</span> {{ c.video_count }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
{{ pager('web.users', page, total_pages, q=query, sort=sort, dir=dir, timeframe=timeframe, start=start_date, end=end_date) }}
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
async function refreshStatus() {
|
|
try {
|
|
const resp = await fetch("/api/get_recording/"); if (!resp.ok) return;
|
|
const s = await resp.json();
|
|
const online = new Set(s.filter(x => x.is_online).map(x => (x.username||"").toLowerCase()));
|
|
const recOff = new Set(s.filter(x => !x.is_online).map(x => (x.username||"").toLowerCase()));
|
|
document.querySelectorAll('.card').forEach(card => {
|
|
const u = (card.dataset.username||"").toLowerCase();
|
|
const dot = card.querySelector('.status-dot'); if (!dot) return;
|
|
dot.classList.remove('dot-online','dot-record','dot-offline');
|
|
if (online.has(u)) dot.classList.add('dot-online');
|
|
else if (recOff.has(u)) dot.classList.add('dot-record');
|
|
else dot.classList.add('dot-offline');
|
|
});
|
|
} catch(e) {}
|
|
}
|
|
refreshStatus(); setInterval(refreshStatus, 20000);
|
|
</script>
|
|
{% endblock %}
|