BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2 或任何藍牙控制器,搭配 MyWhoosh、Rouvy、Zwift 等。iOS、Android、Windows、macOS 均可免費試用。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Basketballvereine in Deutschland finden — per Namenssuche oder Umkreissuche. Datenquelle: basketball-bund.net API
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Findet Basketballvereine und Teams in Deutschland — per Namens- oder Umkreissuche, mit aktuellen Tabellen und Spielplänen. Datenquelle: REST-API von basketball-bund.net. Beobachtungen zur API stehen in docs/bbb-api.md, die OpenAPI-Spezifikation liegt in einem eigenen Repository. Koordinaten stammen von Nominatim (OpenStreetMap).查看完整 README ↗
Findet Basketballvereine und Teams in Deutschland — per Namens- oder Umkreissuche, mit aktuellen Tabellen und Spielplänen.
Portal: https://olieder.github.io/basketball-vereinsregister-deutschland/
Datenquelle: REST-API von basketball-bund.net. Beobachtungen zur API stehen in docs/bbb-api.md, die OpenAPI-Spezifikation liegt in einem eigenen Repository. Koordinaten stammen von Nominatim (OpenStreetMap).
verein.html?id=<clubId>): Teams mit Liga und Tabellenplatz, Hallen mit Karte, Linksteam.html?id=<teamPermanentId>): Tabellenplatz, Bilanz, Form, nächstes Spiel, Tabelle und Spielplan (Alle/Heim/Auswärts); bei mehreren Wettbewerben (Liga, Pokal) ein Umschalterflowchart LR
BBB["basketball-bund.net<br/>REST-API"]
CR["Monthly Crawler<br/>(1. des Monats)"]
CJ["data/clubs.json<br/>Vereine, Teams, Hallen, Koordinaten"]
LV["Live-Crawl<br/>(alle 6 Stunden)"]
PG["GitHub Pages<br/>Portal + data/live/"]
BBB --> CR --> CJ --> PG
BBB --> LV --> PG
| Daten | Quelle | Aktualisierung | Ablage |
|---|---|---|---|
| Vereine, Teams, Hallen, Koordinaten | Monthly Crawler | monatlich | data/clubs.json (im Repo, wird committet) |
| Tabellen, Spielpläne | Live-Crawl pro Liga | alle 6 Stunden | data/live/ (nur im Pages-Artefakt, nicht im Repo) |
| Tabellen, Ergebnisse je Saison | Saison-Archiv aus den Live-Daten | täglich | Branch season-archive (<saison>/liga/<id>.json.gz) |
Der Live-Crawl holt pro Liga eine Anfrage (competition/spielplan/id/{ligaId}), die Spiele und Tabelle liefert, und schreibt liga/<id>.json, team-index.json (Team → Ligen) und index.json. Zwischen zwei Läufen bleiben die zuletzt gecachten Live-Daten erhalten, auch bei Portaländerungen. Beim Zusammenstellen des Artefakts entsteht außerdem hall-index.json (Club-ID → Heimhalle, crawler/hall-index.ts); die Team-Seite zeigt damit Spielort und Karte des nächsten Spiels. Der Ort gilt als voraussichtlich: bei Heimspielen die Heimhalle des eigenen Vereins, sonst die des gastgebenden Gegners.
Jede Team-Seite bietet das Abo für alle Spiele, nur Heimspiele oder nur Auswärtsspiele, mit den Wegen iPhone / Mac (webcal://), Android (Google Kalender), Link kopieren und Als Datei (.ics) sowie einer kurzen Erklärung. Die Dateien liegen unter ics/<teamPermanentId>.ics, -heim.ics und -auswaerts.ics und werden bei jedem Deploy (alle 6 Stunden) aus den Live-Daten erzeugt (crawler/ics.ts), inkrementell: nur Teams mit geänderten Eingaben werden neu gebaut, die übrigen Dateien kommen aus dem Cache des letzten Laufs. Spiele haben Halle und Koordinaten, sobald der Spielort aus matchInfo bekannt ist; abgesagte Spiele erscheinen als abgesagt.
Jede Halle hat eine Seite (/halle/<land>/<ort>/<halle>/) mit Adresse, dem Hallenzähler (Spiele dieser Saison mit gemeldeter Halle), den nächsten Spielen und den Vereinen, die dort spielen. Die Halle wird über die Spielfeld-ID aus clubs.json und den Spielorten (matchInfo) zusammengeführt. Der Zähler ist so vollständig wie die Spielorte im Branch data-store. Die Koordinaten der Hallen (für die Karte) erzeugt der Workflow „Hallen geokodieren“ (crawler/geocode-venues.ts, Nominatim, schrittweise, Ergebnis in data-store/hall-coords.json).
Auf Vereins- und Teamseiten gibt es die Schaltfläche Merken; gemerkte Teams und Vereine erscheinen auf der Startseite unter „Meine Teams und Vereine“ (mit dem nächsten Spiel). Sie liegen nur im Browser des Besuchers (localStorage), nichts wird übertragen. Fehler melden öffnet das GitHub-Formular „Datenfehler melden“ mit vorausgefüllter Seite; es legt ein Issue mit dem Label daten an (das Label bitte einmal im Repository anlegen).
| Workflow | Auslöser | Zweck |
|---|---|---|
| Monthly Crawler | 1. des Monats, manuell | crawl (Vereine/Teams, ohne Geocoding), danach geocode (fehlende Koordinaten); committet data/clubs.json |
| Deploy GitHub Pages | Push auf main, alle 6 Stunden, manuell | Live-Crawl (bei Zeitplan/manuell), baut das Pages-Artefakt aus portal/, data/clubs.json und data/live/, erzeugt die statischen Vereins- und Regionsseiten samt Sitemap (crawler/seo.ts, URL-Zuordnung im Branch url-store) und sichert Tabellen und Ergebnisse jeder Saison (crawler/archive.ts, Branch season-archive, einmal täglich) |
| Regeocode Clubs | manuell | berechnet verdächtige Koordinaten neu (scope=suspect|all); ohne apply nur Bericht auf dem Branch regeocode-report, mit apply wird clubs.json committet |
| Accessibility (WCAG 2.2) | Pull Requests auf portal/**, manuell | Playwright + axe-core gegen das Portal (Fixtures, Light/Dark) |
| Spielorte (matchInfo) | alle 6 Stunden, manuell | holt die Halle je Spiel aus matchInfo und legt sie dauerhaft im Branch data-store ab (Warteschlange mit Zeitbudget) |
| Probe Stats | manuell | prüft, welche Teamstatistik-Felder je Liga befüllt sind; Bericht auf dem Branch probe-stats-report |
| Render AsciiDoc Documentation | Änderungen an docs/**/*.adoc | erzeugt docs/arc42/README.adoc |
Node.js 24 (LTS), wie in allen Workflows; getestet wurde auch mit Node 22.
npm install
npm test # Vitest (TypeScript-Crawler) inkl. Portal-Logik
npm run typecheck # Typprüfung mit TypeScript 7 (nativer Compiler)
npx tsc --noEmit # Typprüfung
Daten holen (die BBB-API wird mit 1 Anfrage pro Sekunde angesprochen, ein voller Crawl dauert deshalb lange):
npm run crawl -- --skip-geocoding # Vereine und Teams → data/clubs.json
npm run geocode # fehlende Koordinaten (Nominatim)
npm run live -- --limit=50 # Live-Daten für 50 Ligen → _live/
Portal lokal ansehen — es braucht denselben Aufbau wie auf GitHub Pages:
mkdir -p _site/data
cp portal/* _site/
cp data/clubs.json _site/data/
[ -d _live ] && cp -r _live _site/data/live
python3 -m http.server -d _site 8080 # → http://localhost:8080
npm run api startet zusätzlich eine kleine Express-API mit Such-Endpunkten (/search, /clubs/:id, /health). Das Portal braucht sie nicht.
| Skript | Zweck |
|---|---|
npm run crawl | Verbände → Ligen → Tabellen, ergänzt Club-Details, optional Geocoding (--skip-geocoding) |
npm run geocode | geocodiert Vereine ohne Koordinaten (Kette siehe unten) |
npm run regeocode | berechnet verdächtige Koordinaten neu, --scope=suspect|all, --apply |
npm run region-check | listet Vereine, deren Koordinate weit außerhalb ihres Bezirks bzw. Landesverbands liegt (offline) |
npm run live | Live-Crawl pro Liga (--out, --concurrency, --delay, --limit) |
npm run test:a11y | Barrierefreiheits-Tests (einmalig npx playwright install chromium) |
npm run venues | Spielorte aus matchInfo holen, inkrementell (--source, --store, --budget-min, --max) |
npm run probe-stats | Erfassungstiefe der Teamstatistik je Liga prüfen |
npm run crawl-halls, geocode-halls, merge-halls | Hallen holen, geocodieren, in clubs.json übernehmen |
npm run backfill-team-details | holt teamNumber/teamAkj für Teams |
npm run fix-names | repariert Vereinsnamen und Orte aus den Club-Details |
Das Portal nutzt das DSS Design System: portal/dss/tokens.css (Kopie der Design-Tokens) und portal/dss/components.css (framework-freie Komponenten mit den Klassennamen dss-*), beide unverändert aus dem DSS kopiert (Stand: Commit 73cd19c, nach Version 0.9.0). Was das DSS (noch) nicht kennt, steht in portal/dss-local.css: Brotkrumen als Liste mit 44 px Zielgröße, Links in Tabellen und Spielzeilen, Seitennavigation als Pillen, der Vereinssitz-Pin der Karte. Beim nächsten Update diese Datei mit dem DSS abgleichen und, was dort inzwischen existiert, streichen.
Marke und Schrift sind die des DBB: <html data-brand="dbb" data-type="dbb"> auf allen Seiten (Vorlagen in portal/*.html und crawler/seo.ts). Die Schriften liegen selbst gehostet in portal/dss/fonts/ (Rubik, Barlow Condensed 600/700 als freier Ersatz für die lizenzpflichtige DBB-Display-Schrift Sucrose, JetBrains Mono; SIL OFL 1.1, Lizenztexte in portal/dss/fonts/licenses/); es gibt keine Anfrage mehr an Google. Wer eine Sucrose-Lizenz hat, bindet sie per @font-face unter dem Namen „Sucrose“ ein, dann greift sie vor Barlow Condensed. Zurück zur Standardmarke: beide Attribute entfernen und Sora, Manrope und JetBrains Mono aus dem DSS (fonts/fonts.css) einbinden. Eigene Seitenlayouts stehen in style.css, verein.css und team.css. Neue Bausteine entstehen zuerst in components.css und werden ins Design System zurückgegeben.
npm run test:a11y prüft Startseite, Vereins- und Team-Seiten (Light/Dark) mit axe-core:
tests/a11y/aaa-baseline.json festgehalten und dürfen nur steigen, wenn man sie bewusst akzeptiert. Aktuell ist die Baseline leer. Baseline neu schreiben: UPDATE_A11Y_BASELINE=1 npm run test:a11y.Für Vereine ohne Koordinaten gilt diese Reihenfolge (crawler/club-geocoder.ts):
Jeder Treffer wird gegen die Region des Vereins geprüft (Bezirk aus den Ligen, sonst Landesverband aus der Vereinsnummer); liegt er weit außerhalb, zählt er nicht und die nächste Quelle kommt an die Reihe. Orte, die sich nicht automatisch finden lassen, stehen mit PLZ und Ort in data/manual-locations.json und haben Vorrang.
Gleichnamige Club-IDs (z. B. ALBA Berlin) bekommen im Regeocode dieselbe Koordinate, sofern ihre Ergebnisse höchstens 15 km auseinander liegen. Eine von mehreren Club-IDs genutzte Halle ist nie ein Grund, eine Koordinate abzulehnen. Details: Kapitel 8 der Architekturdokumentation.
| Quelle | Verwendung | Lizenz / Hinweis |
|---|---|---|
| basketball-bund.net | Vereine, Teams, Ligen, Tabellen, Spielpläne, Spielorte | öffentlich einsehbare Daten der Website, Rechte beim DBB bzw. den jeweiligen Rechteinhabern |
| OpenStreetMap (Nominatim, Kartenkacheln) | Koordinaten, Kartendarstellung | © OpenStreetMap-Mitwirkende, ODbL |
| Bundesamt für Kartographie und Geodäsie | Länderpolygone für die Ortsprüfung (data/geo/laender.geojson, nicht Teil der Seitenanzeige) | siehe unten |
BKG, Verwaltungsgebiete 1:250 000 (VG250): © BKG (2026) dl-de/by-2-0 (Daten verändert), Datenquellen: https://sgx.geodatenzentrum.de/web_public/gdz/datenquellen/datenquellen_vg_nuts.pdf
Verwendung: Prüfung der Vereinskoordinaten und die Länderumrisse auf der Hubseite Vereine (weiter vereinfacht, Quellenvermerk auf der Seite).
Veränderungshinweis: Die Daten wurden bearbeitet: nur die Landflächen der 16 Länder, Geometrie vereinfacht, nach WGS84 (EPSG:4326) umgerechnet und auf Name und Länderschlüssel reduziert. Die Datei erzeugt der Workflow „Länderpolygone (BKG)“ (crawler/geo-laender.ts), Quellenvermerk und Änderungshinweis stehen auch in der Datei selbst.
Typprüfung und Ausführung sind getrennt: npm run typecheck prüft die Typen mit dem nativen Compiler von TypeScript 7 (tsc). Die Crawler-Skripte laufen über tsx und die Tests über Vitest; beide übersetzen die Dateien einzeln (esbuild) und prüfen dabei keine Typen. Die Typprüfung ist deshalb ein eigener Schritt. Zu den Einstellungen in der tsconfig.json: module/moduleResolution stehen auf node16 (node10 gibt es in TypeScript 7 nicht mehr), types ist ab TypeScript 6 leer und deshalb ausdrücklich ["node", "vitest/globals"], und isolatedModules passt zur Einzeldatei-Übersetzung.
crawler/ BBB-Crawler, Geocoding, Live-Crawl (TypeScript)
portal/ statisches Frontend (HTML/CSS/JS, kein Build-Schritt)
api/ optionale lokale Express-API
data/ clubs.json (versioniert), Schemas, clubs-enriched.json (nur für die API)
docs/arc42/ Architekturdokumentation (arc42, AsciiDoc)
tests/ Vitest-Tests
.github/ Workflows
docs/arc42