add webtracker (also avalibal at stats.search.serverjonas.de

This commit is contained in:
2026-09-02 18:27:57 +02:00
parent 7d4773d06a
commit ca0f617f62
+246
View File
@@ -0,0 +1,246 @@
#!/usr/bin/env python3
import subprocess
import json
import time
import threading
from datetime import datetime
from pathlib import Path
from flask import Flask, jsonify, render_template_string
DB_DATA = Path("page_counts.json")
INTERVAL = 15 * 60 # 15 Minuten
app = Flask(__name__)
HTML = """
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JonasSearch – Pages</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body {
margin: 0;
background: #111;
color: #eee;
font-family: Arial, sans-serif;
}
.container {
max-width: 1200px;
margin: auto;
padding: 30px;
}
h1 {
margin-bottom: 5px;
}
.current {
font-size: 2.5rem;
margin: 20px 0;
}
.chart-container {
background: #1b1b1b;
padding: 20px;
border-radius: 15px;
}
</style>
</head>
<body>
<div class="container">
<h1>JonasSearch</h1>
<div>Indexed Pages</div>
<div class="current">
<span id="current">–</span> Pages
</div>
<div class="chart-container">
<canvas id="chart"></canvas>
</div>
</div>
<script>
let chart = null;
async function update() {
const response = await fetch("/api/data");
const data = await response.json();
document.getElementById("current").textContent =
data.values.length
? data.values[data.values.length - 1].count.toLocaleString("de-DE")
: "–";
const labels = data.values.map(x =>
new Date(x.timestamp).toLocaleString("de-DE")
);
const values = data.values.map(x => x.count);
if (chart) {
chart.data.labels = labels;
chart.data.datasets[0].data = values;
chart.update();
return;
}
chart = new Chart(document.getElementById("chart"), {
type: "line",
data: {
labels: labels,
datasets: [{
label: "Pages",
data: values,
tension: 0.25,
pointRadius: 2,
fill: true
}]
},
options: {
responsive: true,
scales: {
x: {
ticks: {
color: "#aaa"
}
},
y: {
beginAtZero: false,
ticks: {
color: "#aaa"
}
}
},
plugins: {
legend: {
labels: {
color: "#eee"
}
}
}
}
});
}
update();
// Browser alle 30 Sekunden aktualisieren
setInterval(update, 30000);
</script>
</body>
</html>
"""
def load_data():
if not DB_DATA.exists():
return []
try:
with DB_DATA.open("r", encoding="utf-8") as f:
return json.load(f)
except Exception:
return []
def save_data(data):
tmp = DB_DATA.with_suffix(".tmp")
with tmp.open("w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
tmp.replace(DB_DATA)
def get_page_count():
command = [
"sudo",
"-u",
"postgres",
"psql",
"-p",
"25432",
"-d",
"jonassearch",
"-t",
"-A",
"-c",
"SELECT COUNT(*) FROM pages;"
]
result = subprocess.run(
command,
capture_output=True,
text=True,
check=True
)
return int(result.stdout.strip())
def collect():
while True:
try:
count = get_page_count()
entry = {
"timestamp": datetime.now().isoformat(),
"count": count
}
data = load_data()
data.append(entry)
save_data(data)
print(
f"[{entry['timestamp']}] "
f"Pages: {count}"
)
except Exception as e:
print(f"Fehler beim Abrufen der Seitenzahl: {e}")
time.sleep(INTERVAL)
@app.route("/")
def index():
return render_template_string(HTML)
@app.route("/api/data")
def api_data():
return jsonify({
"values": load_data()
})
if __name__ == "__main__":
# Collector im Hintergrund starten
thread = threading.Thread(target=collect, daemon=True)
thread.start()
# Webserver
app.run(
host="0.0.0.0",
port=8081,
threaded=True
)