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.

113 lines
5.5 KiB
HTML

{% extends "base.html" %}
{% from "_pagination.html" import pager %}
{% block title %}📊 Video Storage Analytics{% endblock %}
{% block content %}
<h1>📊 Video Storage Analytics</h1>
<div class="controls">
<form method="get" action="{{ url_for('web.dashboard') }}" style="display:inline-flex;gap:8px;align-items:center;">
<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 '' }}" placeholder="Start" />
<input type="date" name="end" value="{{ end_date or '' }}" placeholder="End" />
<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>
<form method="get" action="{{ url_for('web.dashboard') }}" style="display:inline-block;">
<input type="text" name="q" placeholder="Search users..." value="{{ query or '' }}">
<button type="submit">Search</button>
</form>
</div>
<div class="table-wrap">
<table id="analytics-table">
<thead>
<tr>
{% 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' %}
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='user', dir=next_user_dir) }}">
User{% if sort=='user' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a></th>
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='platform', dir=next_platform_dir) }}">
Platform{% if sort=='platform' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a></th>
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='total_size', dir=next_total_dir) }}">
Total Storage (GB){% if sort=='total_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a></th>
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='video_count', dir=next_count_dir) }}">
Video Count{% if sort=='video_count' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a></th>
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='avg_size', dir=next_avg_dir) }}">
Avg Size per Video (GB){% if sort=='avg_size' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}</a></th>
<th><a href="{{ url_for('web.dashboard', q=query, page=1, sort='last_online', dir='desc' if dir=='asc' else 'asc') }}">
Last Online{% if sort=='last_online' %} {{ '▲' if dir=='asc' else '▼' }}{% endif %}
</tr>
</thead>
<tbody>
{% for key, stats in storage_usage %}
{% set user, platform = key.split("::") %}
<tr data-username="{{ user|lower }}">
<td>
<a href="/user/{{ user }}">{{ user }}</a>
{% set uname = user.lower() %}
{% if uname in online_set %}
<span class="status-dot dot-online" title="Online"></span>
{% elif uname in recording_offline_set %}
<span class="status-dot dot-record" title="Recording (offline)"></span>
{% else %}
<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') }}
{% else %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{{ pager('web.dashboard', page, total_pages, q=query, sort=sort, dir=dir, timeframe=timeframe, start=start_date, end=end_str) }}
{% endblock %}
{% block scripts %}
<script>
async function refreshStatusDots() {
try {
const resp = await fetch("/api/get_recording/");
if (!resp.ok) return;
const streamers = await resp.json();
const online = new Set(streamers.filter(s => s.is_online).map(s => (s.username||"").toLowerCase()));
const recOff = new Set(streamers.filter(s => !s.is_online).map(s => (s.username||"").toLowerCase()));
document.querySelectorAll('#analytics-table tbody tr').forEach(tr => {
const uname = (tr.dataset.username || "").toLowerCase();
const dot = tr.querySelector('.status-dot'); if (!dot) return;
dot.classList.remove('dot-online','dot-record','dot-offline');
if (online.has(uname)) { dot.classList.add('dot-online'); dot.title='Online'; }
else if (recOff.has(uname)) { dot.classList.add('dot-record'); dot.title='Recording (offline)'; }
else { dot.classList.add('dot-offline'); dot.title='Offline'; }
});
} catch(e) { console.error('status refresh failed:', e); }
}
refreshStatusDots(); setInterval(refreshStatusDots, 20000);
</script>
{% endblock %}