Plugin neuheiten: Web-Quellen-Crawler (4 Adapter, Rate-Limit, Dedup-Gate, Sync-UI)

This commit is contained in:
Flo Hartmann
2026-08-23 00:41:02 +00:00
parent 8c9f542b8c
commit 3b0626c774
18 changed files with 2247 additions and 18 deletions

View File

@@ -23,8 +23,12 @@
<tr class="hover:bg-slate-50">
<td class="px-4 py-3 font-medium">
{{ eintrag.titel }}
{% if eintrag.bgg_id %}
<a href="https://boardgamegeek.com/boardgame/{{ eintrag.bgg_id }}" target="_blank" rel="noopener"
class="ml-1 text-[10px] text-slate-400 hover:text-emerald-700 align-super">BGG&nbsp;{{ eintrag.bgg_id }}</a>
{% elif eintrag.quelle and eintrag.quelle != 'boardgamegeek' %}
<span class="ml-1 text-[10px] uppercase tracking-wide text-sky-600/70 align-super">{{ eintrag.quelle }}</span>
{% endif %}
</td>
<td class="px-4 py-3">{{ eintrag.verlag or '—' }}</td>
<td class="px-4 py-3">{{ eintrag.autor or '—' }}</td>

View File

@@ -41,6 +41,68 @@
</p>
</div>
<div class="mb-6 bg-white rounded-xl border border-slate-200 shadow-sm p-4">
<div class="flex flex-wrap items-center gap-2 mb-3">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500 mr-auto">Web-Quellen</h2>
{% if ist_redaktion %}
<form method="post" action="/neuheiten/quellen-sync">
<button type="submit"
class="bg-sky-600 hover:bg-sky-700 text-white font-medium px-3 py-1.5 rounded-lg text-xs whitespace-nowrap">
&#8635; Web-Quellen synchronisieren
</button>
</form>
{% endif %}
</div>
<div class="overflow-x-auto">
<table class="w-full text-xs">
<thead class="text-left text-slate-400">
<tr>
<th class="px-2 py-1.5 font-medium">Quelle</th>
<th class="px-2 py-1.5 font-medium">Status</th>
<th class="px-2 py-1.5 font-medium">Letzter Lauf</th>
<th class="px-2 py-1.5 font-medium text-right">Neu</th>
<th class="px-2 py-1.5 font-medium text-right">Aktualisiert</th>
<th class="px-2 py-1.5 font-medium text-right">Gefiltert</th>
<th class="px-2 py-1.5 font-medium">Hinweis</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{% for quelle in quellen_zeilen %}
<tr>
<td class="px-2 py-1.5">
<a href="{{ quelle.url }}" target="_blank" rel="noopener noreferrer"
class="font-medium text-slate-700 hover:text-emerald-700">{{ quelle.anzeigename }}</a>
<span class="ml-1 text-[10px] text-slate-300">{{ quelle.name }}</span>
</td>
<td class="px-2 py-1.5">
{% if quelle.aktiv %}<span class="inline-block px-2 py-0.5 rounded-full bg-emerald-50 text-emerald-700">an</span>
{% else %}<span class="inline-block px-2 py-0.5 rounded-full bg-slate-100 text-slate-400">aus</span>{% endif %}
</td>
<td class="px-2 py-1.5 whitespace-nowrap text-slate-500">
{{ quelle.letzte_laufzeit.strftime('%d.%m.%Y %H:%M') if quelle.letzte_laufzeit else '—' }}
{% if quelle.dauer_sekunden %}<span class="text-slate-300">({{ '%.1f' | format(quelle.dauer_sekunden) }}&nbsp;s)</span>{% endif %}
</td>
<td class="px-2 py-1.5 text-right">{{ quelle.neu }}</td>
<td class="px-2 py-1.5 text-right">{{ quelle.aktualisiert }}</td>
<td class="px-2 py-1.5 text-right">{{ quelle.gefiltert }}</td>
<td class="px-2 py-1.5">
{% if quelle.fehlermeldung %}<span class="text-red-600">{{ quelle.fehlermeldung }}</span>
{% elif quelle.unveraendert %}<span class="text-slate-400">unverändert (304) — übersprungen</span>
{% elif not quelle.aktiv %}<span class="text-slate-300">abgeschaltet</span>
{% else %}—{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<p class="mt-2 text-[11px] text-slate-400">
Quellen-Sync:
{% if quellen_sync_aktiv %}<span class="text-emerald-700 font-medium">täglich aktiv</span>{% else %}<span class="text-slate-500">ausgeschaltet</span>{% endif %}
&middot; max. 1 Anfrage/Sekunde je Quelle &middot; Duplikate gegen BGG werden per Titel-Match gefiltert
</p>
</div>
<form method="get" action="/neuheiten"
hx-get="/neuheiten" hx-target="#neuheiten-liste" hx-swap="outerHTML"
hx-trigger="input changed delay:300ms from:find input[name='q'], change from:find select[name='status']"