refactor ciagl dalszy
This commit is contained in:
@@ -1,16 +1,216 @@
|
||||
<!-- templates/stats.html -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en" data-theme="dark">
|
||||
|
||||
<head>
|
||||
<title>Statistics</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Stats</title>
|
||||
<meta name="theme-color" content="#0f1115">
|
||||
<link rel="preload" href="{{ url_for('static', filename='css/main.css') }}" as="style">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Download Statistics</h1>
|
||||
<table>
|
||||
<tr><th>URL</th><th>Hits</th></tr>
|
||||
{% for url, count in stats.items() %}
|
||||
<tr><td>{{ url }}</td><td>{{ count }}</td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<header class="site-header">
|
||||
<div class="brand">
|
||||
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M4 4h16v4H4zM4 10h10v4H4zM4 16h16v4H4z" fill="currentColor" />
|
||||
</svg>
|
||||
<span>Hosts Converter</span>
|
||||
</div>
|
||||
<nav class="actions">
|
||||
<button class="btn ghost" type="button" data-action="toggle-theme" aria-label="Toggle theme">🌓</button>
|
||||
<a class="btn ghost" href="/" rel="nofollow">Home</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container container--wide">
|
||||
<!-- KPIs -->
|
||||
<section class="card kpi-card">
|
||||
<h2 class="section-title">Overview</h2>
|
||||
<div class="kpi-grid">
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Convert requests</div>
|
||||
<div class="kpi-value">{{ stats.get('stats:convert_requests', 0) }}</div>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Successful conversions</div>
|
||||
<div class="kpi-value">{{ stats.get('stats:conversions_success', 0) }}</div>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Errors 4xx</div>
|
||||
<div class="kpi-value">{{ stats.get('stats:errors_400', 0) }}</div>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Errors 5xx</div>
|
||||
<div class="kpi-value">{{ stats.get('stats:errors_500', 0) }}</div>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Avg processing (s)</div>
|
||||
<div class="kpi-value">{{ '%.3f' % detailed.processing_time_avg_sec }}</div>
|
||||
</div>
|
||||
<div class="kpi">
|
||||
<div class="kpi-label">Avg content (bytes)</div>
|
||||
<div class="kpi-value">{{ detailed.content_size_avg_bytes }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Recent converts -->
|
||||
<section class="card">
|
||||
<div class="section-head">
|
||||
<h2>Recent converts (latest {{ recent|length }})</h2>
|
||||
<div class="head-actions">
|
||||
<input class="table-filter" type="search" placeholder="Filter…" data-action="filter-table"
|
||||
data-target="#recent-table">
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table id="recent-table" class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>URL</th>
|
||||
<th>Target IP</th>
|
||||
<th>Client</th>
|
||||
<th>User agent</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in recent %}
|
||||
{% set q = row.get('url','') %}
|
||||
{% set parts = q.split('&ip=') %}
|
||||
{% set url = parts[0].replace('/convert?url=', '') | urlencode %}
|
||||
{% set ip = (parts[1] if parts|length > 1 else '') %}
|
||||
<tr>
|
||||
<td class="mono nowrap">{{ row.time|datetimeformat }}</td>
|
||||
<td class="mono ellipsis" title="{{ url|safe }}">
|
||||
{{ url|safe }}
|
||||
</td>
|
||||
<td class="mono">{{ ip }}</td>
|
||||
<td class="mono ellipsis" title="{{ row.hostname }} ({{ row.ip }})">
|
||||
{{ row.hostname }} ({{ row.ip }})
|
||||
</td>
|
||||
<td class="ellipsis" title="{{ row.user_agent }}">{{ row.user_agent }}</td>
|
||||
<td class="actions">
|
||||
<a class="btn tiny outline" href="{{ q }}" target="_blank" rel="noopener">Open</a>
|
||||
<button class="btn tiny" data-action="copy-text" data-text="{{ q }}">Copy</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Top tables -->
|
||||
<section class="card">
|
||||
<div class="section-head">
|
||||
<h2>Top sources</h2>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<h3 class="subhead">Source URLs</h3>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<th class="right">Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for u, c in url_requests.items()|sort(attribute=1, reverse=True) %}
|
||||
<tr>
|
||||
<td class="mono ellipsis" title="{{ u }}">{{ u }}</td>
|
||||
<td class="right">{{ c }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<h3 class="subhead">Target IPs</h3>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th class="right">Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ip, c in target_ips.items()|sort(attribute=1, reverse=True) %}
|
||||
<tr>
|
||||
<td class="mono">{{ ip }}</td>
|
||||
<td class="right">{{ c }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<h3 class="subhead">User agents</h3>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User agent</th>
|
||||
<th class="right">Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ua, c in user_agents.items()|sort(attribute=1, reverse=True) %}
|
||||
<tr>
|
||||
<td class="ellipsis" title="{{ ua }}">{{ ua }}</td>
|
||||
<td class="right">{{ c }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<h3 class="subhead">Client IPs</h3>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client IP</th>
|
||||
<th class="right">Hits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ip, c in client_ips.items()|sort(attribute=1, reverse=True) %}
|
||||
<tr>
|
||||
<td class="mono">{{ ip }}</td>
|
||||
<td class="right">{{ c }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
<div>© 2025 <a href="https://www.linuxiarz.pl" target="_blank" rel="noopener">linuxiarz.pl</a></div>
|
||||
<div class="meta">Your IP: <strong>{{ request.remote_addr }}</strong></div>
|
||||
</footer>
|
||||
|
||||
<div id="toast" role="status" aria-live="polite" aria-atomic="true"></div>
|
||||
<script defer src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
<script defer src="{{ url_for('static', filename='js/stats.js') }}"></script>
|
||||
<script>(function () { const t = localStorage.getItem('theme') || 'dark'; document.documentElement.setAttribute('data-theme', t); })();</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user