Suchfunktion eingebaut

This commit is contained in:
2026-09-29 17:15:09 +02:00
parent ad9192674f
commit 7b570d1415
+125 -2
View File
@@ -668,6 +668,40 @@ h1 {
margin-bottom: 10px;
}
.filter-bar {
display: grid;
grid-template-columns: repeat(4, minmax(150px, 1fr));
gap: 10px;
margin-bottom: 14px;
}
.filter-bar label {
color: #aaa;
font-size: 13px;
}
.filter-bar input,
.filter-bar select {
width: 100%;
margin-top: 5px;
padding: 9px;
background: #111;
color: #eee;
border: 1px solid #555;
border-radius: 5px;
font-size: 15px;
}
.filter-bar .search {
grid-column: span 2;
}
.filter-info {
color: #999;
font-size: 13px;
margin-bottom: 10px;
}
table {
width: 100%;
border-collapse: collapse;
@@ -720,6 +754,16 @@ a.button:hover {
font-size: 13px;
}
@media (max-width: 900px) {
.filter-bar {
grid-template-columns: 1fr 1fr;
}
.filter-bar .search {
grid-column: span 2;
}
}
@media (max-width: 800px) {
body {
padding: 12px;
@@ -828,9 +872,32 @@ a.button:hover {
<h2>Fertige Aufnahmen</h2>
<div class="filter-bar">
<label>Zeitraum<select id="dateFilter">
<option value="all">Alle</option>
<option value="today">Heute</option>
<option value="yesterday">Gestern</option>
<option value="7">Letzte 7 Tage</option>
<option value="30">Letzte 30 Tage</option>
<option value="month">Dieser Monat</option>
<option value="lastmonth">Letzter Monat</option>
<option value="year">Dieses Jahr</option>
</select></label>
<label>Redner<select id="artistFilter">
<option value="">Alle Redner</option>
{% for artist in artists %}<option value="{{ artist }}">{{ artist }}</option>{% endfor %}
</select></label>
<label>Veranstaltung<select id="albumFilter">
<option value="">Alle Veranstaltungen</option>
{% for album in albums %}<option value="{{ album }}">{{ album }}</option>{% endfor %}
</select></label>
<label class="search">Beschreibung / Volltext<input id="textFilter" type="search" placeholder="Beschreibung, Redner, Veranstaltung, Dateiname …"></label>
</div>
<div class="filter-info" id="filterInfo"></div>
{% if recordings %}
<table>
<table id="finishedTable">
<thead>
<tr>
<th>Zeitpunkt</th>
@@ -846,7 +913,11 @@ a.button:hover {
<tbody>
{% for item in recordings %}
<tr>
<tr class="finished-row"
data-ts="{{ item.sort_ts }}"
data-artist="{{ item.artist }}"
data-album="{{ item.album }}"
data-search="{{ (item.filename ~ ' ' ~ item.artist ~ ' ' ~ item.title ~ ' ' ~ item.album)|lower }}">
<td>{{ item.datetime }}</td>
@@ -894,6 +965,51 @@ a.button:hover {
</div>
<script>
function applyFilters() {
const range = document.getElementById('dateFilter').value;
const artist = document.getElementById('artistFilter').value;
const album = document.getElementById('albumFilter').value;
const text = document.getElementById('textFilter').value.trim().toLowerCase();
const now = new Date();
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000;
const tomorrow = todayStart + 86400;
const yesterday = todayStart - 86400;
const week = todayStart - 6 * 86400;
const days30 = todayStart - 29 * 86400;
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).getTime() / 1000;
const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1).getTime() / 1000;
const lastMonthEnd = monthStart;
const yearStart = new Date(now.getFullYear(), 0, 1).getTime() / 1000;
let visible = 0;
document.querySelectorAll('.finished-row').forEach(row => {
const ts = Number(row.dataset.ts);
let dateOk = true;
if (range === 'today') dateOk = ts >= todayStart && ts < tomorrow;
else if (range === 'yesterday') dateOk = ts >= yesterday && ts < todayStart;
else if (range === '7') dateOk = ts >= week;
else if (range === '30') dateOk = ts >= days30;
else if (range === 'month') dateOk = ts >= monthStart;
else if (range === 'lastmonth') dateOk = ts >= lastMonthStart && ts < lastMonthEnd;
else if (range === 'year') dateOk = ts >= yearStart;
const artistOk = !artist || row.dataset.artist === artist;
const albumOk = !album || row.dataset.album === album;
const textOk = !text || row.dataset.search.includes(text);
const ok = dateOk && artistOk && albumOk && textOk;
row.style.display = ok ? '' : 'none';
if (ok) visible++;
});
const total = document.querySelectorAll('.finished-row').length;
document.getElementById('filterInfo').textContent = `${visible} von ${total} Aufnahmen`;
}
['dateFilter', 'artistFilter', 'albumFilter', 'textFilter'].forEach(id =>
document.getElementById(id)?.addEventListener('input', applyFilters)
);
applyFilters();
async function updateLiveSection() {
try {
const response = await fetch("/api/live", { cache: "no-store" });
@@ -943,7 +1059,12 @@ def render_index():
except FileNotFoundError:
continue
for item in files:
item["sort_ts"] = item["sort_date"]
files.sort(key=lambda item: item["sort_date"], reverse=True)
artists = sorted({item["artist"] for item in files if item["artist"]})
albums = sorted({item["album"] for item in files if item["album"]})
with state_lock:
process = ffmpeg_process
@@ -975,6 +1096,8 @@ def render_index():
return render_template_string(
HTML,
recordings=files,
artists=artists,
albums=albums,
recording=recording,
normalizing_filename=normalizing_filename,
status_error=status_error,