diff --git a/server/utils/spielklassen-tables-import.js b/server/utils/spielklassen-tables-import.js index 8fab970..bd15bea 100644 --- a/server/utils/spielklassen-tables-import.js +++ b/server/utils/spielklassen-tables-import.js @@ -7,6 +7,33 @@ import { parseDelimitedLine } from './spielplan-data.js' const OUTPUT_DIR = getServerDataPath('spielplan-import') const DEFAULT_ASSOCIATION = 'HeTTV' +function normalizeHeaderName(value) { + return String(value || '').trim().toLowerCase() +} + +function toUrlOrNull(value) { + const raw = String(value || '').trim() + if (!raw) return null + + try { + return new URL(raw) + } catch { + return null + } +} + +function isSupportedTableUrl(urlValue) { + const parsed = toUrlOrNull(urlValue) + if (!parsed) return false + + const host = parsed.hostname.toLowerCase() + if (host !== 'www.mytischtennis.de' && host !== 'mytischtennis.de' && host !== 'click-tt.de' && host !== 'www.click-tt.de') { + return false + } + + return parsed.pathname.includes('/tabelle/') +} + async function fileExists(filePath) { try { await fs.access(filePath) @@ -73,7 +100,11 @@ function getTableRoutePayload(loaderData) { function normalizeTableData(url, routeKey, payload) { const data = payload?.data || {} - const leagueTable = Array.isArray(data.league_table) ? data.league_table : [] + if (!Array.isArray(data.league_table)) { + throw new Error('Ungueltige Tabellenstruktur: league_table fehlt') + } + + const leagueTable = data.league_table return { url, @@ -91,7 +122,6 @@ function normalizeTableData(url, routeKey, payload) { gamesPerSet: data.games_per_set ?? null, leagueTtrAvg: data.league_ttr_avg ?? null, subTableInfo: data.sub_table_info ?? null, - meetingsExcerpt: data.meetings_excerpt ?? null, rowCount: leagueTable.length, leagueTable } @@ -119,18 +149,28 @@ async function resolveMannschaftenCsvPath() { function extractRowsWithTableUrl(csvContent) { const lines = csvContent.split(/\r?\n/).filter((line) => line.trim() !== '') + if (lines.length < 2) return [] + + const headers = parseDelimitedLine(lines[0], ',').map(normalizeHeaderName) + const teamIdx = headers.indexOf('mannschaft') + const leagueIdx = headers.indexOf('liga') + const infoLinkIdx = headers.indexOf('weitere informationen link') + + if (infoLinkIdx === -1) { + throw new Error('CSV-Spalte weitere_informationen_link nicht gefunden') + } + const rows = [] - for (const line of lines) { - if (!line.includes('mytischtennis.de')) continue - + for (const line of lines.slice(1)) { const values = parseDelimitedLine(line, ',') - const tableUrl = values.find((value) => /^https?:\/\/www\.mytischtennis\.de\//.test(value)) + const tableUrl = values[infoLinkIdx] ? String(values[infoLinkIdx]).trim() : '' if (!tableUrl) continue + if (!isSupportedTableUrl(tableUrl)) continue rows.push({ - teamName: values[0] || null, - leagueName: values[1] || null, + teamName: teamIdx >= 0 ? (values[teamIdx] || null) : null, + leagueName: leagueIdx >= 0 ? (values[leagueIdx] || null) : null, tableUrl }) }