diff --git a/app/components/Flag.tsx b/app/components/Flag.tsx index 9d92f0b..d365a9d 100644 --- a/app/components/Flag.tsx +++ b/app/components/Flag.tsx @@ -1,15 +1,17 @@ "use client"; +import { useState } from "react"; import { Team } from "@/lib/types"; // Zeigt die Flagge/das Wappen eines Teams. Fällt auf ein neutrales Rund -// zurück, wenn keine crest-URL vorliegt. SVG-Crests (football-data) skalieren -// sauber; das Rendern als rundes Bild gibt den Flaggen-Look aus dem Screenshot. +// zurück, wenn keine crest-URL vorliegt oder das Bild nicht geladen werden kann. export default function Flag({ team, size = 22, }: { team?: Team; size?: number }) { + const [imgFailed, setImgFailed] = useState(false); const style = { width: size, height: size } as const; - if (team?.crest) { + + if (team?.crest && !imgFailed) { return ( setImgFailed(true)} /> ); } diff --git a/lib/feeds.ts b/lib/feeds.ts index d1a65c9..74cc72b 100644 --- a/lib/feeds.ts +++ b/lib/feeds.ts @@ -129,7 +129,7 @@ export async function fetchMatchesAndTeams(): Promise<{ matches: Match[]; teams: if (!teamMap.has(id)) { teamMap.set(id, { id, name: side.name, code: side.tla ?? "", group, - crest: side.crest ?? null, + crest: `/crests/${id}.svg`, localisedName: localisedTeamName(side.tla ?? "", side.name ?? ""), }); } diff --git a/package-lock.json b/package-lock.json index 0ec24e5..48c7758 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/node": "22.10.7", "@types/react": "19.0.7", "@types/react-dom": "19.0.3", + "tsx": "^4.22.4", "typescript": "5.7.3" } }, @@ -29,6 +30,448 @@ "tslib": "^2.4.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", @@ -668,6 +1111,63 @@ "node": ">=8" } }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/is-arrayish": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", @@ -918,6 +1418,25 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", diff --git a/package.json b/package.json index 7ef31fe..e403b17 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,10 @@ "react-dom": "19.0.0" }, "devDependencies": { - "typescript": "5.7.3", "@types/node": "22.10.7", "@types/react": "19.0.7", - "@types/react-dom": "19.0.3" + "@types/react-dom": "19.0.3", + "tsx": "^4.22.4", + "typescript": "5.7.3" } } diff --git a/public/crests/1060.svg b/public/crests/1060.svg new file mode 100644 index 0000000..45845f0 --- /dev/null +++ b/public/crests/1060.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/1836.svg b/public/crests/1836.svg new file mode 100644 index 0000000..d6ddb3f --- /dev/null +++ b/public/crests/1836.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/1930.svg b/public/crests/1930.svg new file mode 100644 index 0000000..1f61248 --- /dev/null +++ b/public/crests/1930.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/1934.svg b/public/crests/1934.svg new file mode 100644 index 0000000..862681e --- /dev/null +++ b/public/crests/1934.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/1935.svg b/public/crests/1935.svg new file mode 100644 index 0000000..7563a18 --- /dev/null +++ b/public/crests/1935.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/758.svg b/public/crests/758.svg new file mode 100644 index 0000000..a01a172 --- /dev/null +++ b/public/crests/758.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/759.svg b/public/crests/759.svg new file mode 100644 index 0000000..a42f059 --- /dev/null +++ b/public/crests/759.svg @@ -0,0 +1,6 @@ + +Flag of Germany + + + + diff --git a/public/crests/760.svg b/public/crests/760.svg new file mode 100644 index 0000000..760fe0d --- /dev/null +++ b/public/crests/760.svg @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/761.svg b/public/crests/761.svg new file mode 100644 index 0000000..7e41611 --- /dev/null +++ b/public/crests/761.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/762.svg b/public/crests/762.svg new file mode 100644 index 0000000..af454c2 Binary files /dev/null and b/public/crests/762.svg differ diff --git a/public/crests/763.svg b/public/crests/763.svg new file mode 100644 index 0000000..6017337 --- /dev/null +++ b/public/crests/763.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/crests/764.svg b/public/crests/764.svg new file mode 100644 index 0000000..a07bcf7 --- /dev/null +++ b/public/crests/764.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/765.svg b/public/crests/765.svg new file mode 100644 index 0000000..c3e79d1 --- /dev/null +++ b/public/crests/765.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/766.svg b/public/crests/766.svg new file mode 100644 index 0000000..6299e73 --- /dev/null +++ b/public/crests/766.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/crests/769.svg b/public/crests/769.svg new file mode 100644 index 0000000..018c462 --- /dev/null +++ b/public/crests/769.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/770.svg b/public/crests/770.svg new file mode 100644 index 0000000..52e2702 --- /dev/null +++ b/public/crests/770.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/crests/771.svg b/public/crests/771.svg new file mode 100644 index 0000000..9201215 --- /dev/null +++ b/public/crests/771.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/772.svg b/public/crests/772.svg new file mode 100644 index 0000000..cf5f3a6 Binary files /dev/null and b/public/crests/772.svg differ diff --git a/public/crests/773.svg b/public/crests/773.svg new file mode 100644 index 0000000..c43631e --- /dev/null +++ b/public/crests/773.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/774.svg b/public/crests/774.svg new file mode 100644 index 0000000..9fd94ac --- /dev/null +++ b/public/crests/774.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/778.svg b/public/crests/778.svg new file mode 100644 index 0000000..e1165a7 --- /dev/null +++ b/public/crests/778.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/779.svg b/public/crests/779.svg new file mode 100644 index 0000000..bab7eb4 --- /dev/null +++ b/public/crests/779.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/783.svg b/public/crests/783.svg new file mode 100644 index 0000000..db87a7f --- /dev/null +++ b/public/crests/783.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/788.svg b/public/crests/788.svg new file mode 100644 index 0000000..5ea9eea --- /dev/null +++ b/public/crests/788.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/791.svg b/public/crests/791.svg new file mode 100644 index 0000000..b673e6e --- /dev/null +++ b/public/crests/791.svg @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/792.svg b/public/crests/792.svg new file mode 100644 index 0000000..9223d14 --- /dev/null +++ b/public/crests/792.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/798.svg b/public/crests/798.svg new file mode 100644 index 0000000..db03aba --- /dev/null +++ b/public/crests/798.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/799.svg b/public/crests/799.svg new file mode 100644 index 0000000..39b2287 --- /dev/null +++ b/public/crests/799.svg @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/801.svg b/public/crests/801.svg new file mode 100644 index 0000000..d9a6ce8 --- /dev/null +++ b/public/crests/801.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/802.svg b/public/crests/802.svg new file mode 100644 index 0000000..a86d3d4 --- /dev/null +++ b/public/crests/802.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/crests/803.svg b/public/crests/803.svg new file mode 100644 index 0000000..7f55856 --- /dev/null +++ b/public/crests/803.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/crests/8030.svg b/public/crests/8030.svg new file mode 100644 index 0000000..b750f07 --- /dev/null +++ b/public/crests/8030.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/804.svg b/public/crests/804.svg new file mode 100644 index 0000000..7e34312 --- /dev/null +++ b/public/crests/804.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/8049.svg b/public/crests/8049.svg new file mode 100644 index 0000000..d0284e2 Binary files /dev/null and b/public/crests/8049.svg differ diff --git a/public/crests/805.svg b/public/crests/805.svg new file mode 100644 index 0000000..7caa698 --- /dev/null +++ b/public/crests/805.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/8062.svg b/public/crests/8062.svg new file mode 100644 index 0000000..f806fcb --- /dev/null +++ b/public/crests/8062.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/8070.svg b/public/crests/8070.svg new file mode 100644 index 0000000..b22b8fb Binary files /dev/null and b/public/crests/8070.svg differ diff --git a/public/crests/815.svg b/public/crests/815.svg new file mode 100644 index 0000000..9faffa1 --- /dev/null +++ b/public/crests/815.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/816.svg b/public/crests/816.svg new file mode 100644 index 0000000..a0a161d --- /dev/null +++ b/public/crests/816.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/crests/818.svg b/public/crests/818.svg new file mode 100644 index 0000000..6cb2061 --- /dev/null +++ b/public/crests/818.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/825.svg b/public/crests/825.svg new file mode 100644 index 0000000..e53e54a --- /dev/null +++ b/public/crests/825.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/828.svg b/public/crests/828.svg new file mode 100644 index 0000000..f03177d --- /dev/null +++ b/public/crests/828.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/836.svg b/public/crests/836.svg new file mode 100644 index 0000000..8fb20cf --- /dev/null +++ b/public/crests/836.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/840.svg b/public/crests/840.svg new file mode 100644 index 0000000..59b51b5 --- /dev/null +++ b/public/crests/840.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/crests/8601.svg b/public/crests/8601.svg new file mode 100644 index 0000000..baed368 --- /dev/null +++ b/public/crests/8601.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/crests/8872.svg b/public/crests/8872.svg new file mode 100644 index 0000000..4765e85 --- /dev/null +++ b/public/crests/8872.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/public/crests/8873.svg b/public/crests/8873.svg new file mode 100644 index 0000000..3c68d59 --- /dev/null +++ b/public/crests/8873.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/crests/9460.svg b/public/crests/9460.svg new file mode 100644 index 0000000..f2c9853 --- /dev/null +++ b/public/crests/9460.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/scripts/fetch-crests.ts b/scripts/fetch-crests.ts new file mode 100644 index 0000000..e17fed2 --- /dev/null +++ b/scripts/fetch-crests.ts @@ -0,0 +1,83 @@ +/** + * Einmal-Skript: Lädt alle Team-Crests von football-data.org herunter + * und speichert sie unter public/crests/{teamId}.svg. + * + * Ausführung: npx tsx --env-file=.env scripts/fetch-crests.ts + */ +import * as fs from "node:fs"; +import * as path from "node:path"; + +const CREST_BASE = "https://crests.football-data.org"; +const OUT_DIR = path.resolve(import.meta.dirname, "..", "public", "crests"); +const FD_BASE = "https://api.football-data.org/v4"; +const FD_COMP = "WC"; + +function fdHeaders(): Record { + const token = process.env.FOOTBALL_DATA_TOKEN; + if (!token) { + console.error("[fehler] FOOTBALL_DATA_TOKEN nicht gesetzt. Bitte .env prüfen."); + process.exit(1); + } + return { "X-Auth-Token": token }; +} + +interface FdTeam { + id: number; + name: string; + tla?: string | null; + crest?: string | null; +} + +async function main() { + console.log("[fetch-crests] Rufe Team-Daten von football-data.org ab…"); + + const res = await fetch(`${FD_BASE}/competitions/${FD_COMP}/teams`, { + headers: fdHeaders(), + }); + if (!res.ok) { + console.error(`[fehler] football-data API: ${res.status} ${res.statusText}`); + process.exit(1); + } + + const data = (await res.json()) as { teams: FdTeam[] }; + const teams = data.teams ?? []; + console.log(`[fetch-crests] ${teams.length} Teams gefunden.`); + + fs.mkdirSync(OUT_DIR, { recursive: true }); + + let ok = 0; + let failed = 0; + const failures: string[] = []; + + for (const t of teams) { + const id = String(t.id); + const url = t.crest ?? `${CREST_BASE}/${id}.svg`; + const outPath = path.join(OUT_DIR, `${id}.svg`); + + try { + const imgRes = await fetch(url); + if (!imgRes.ok) { + failed++; + failures.push(`${t.name} (id=${id}): HTTP ${imgRes.status}`); + continue; + } + const buf = Buffer.from(await imgRes.arrayBuffer()); + fs.writeFileSync(outPath, buf); + ok++; + } catch (err) { + failed++; + failures.push(`${t.name} (id=${id}): ${err instanceof Error ? err.message : String(err)}`); + } + } + + console.log(`\n[fetch-crests] Fertig: ${ok} geladen, ${failed} fehlgeschlagen.`); + if (failures.length > 0) { + console.log("[fetch-crests] Fehlgeschlagene:"); + for (const f of failures) console.log(` - ${f}`); + } +} + +main().catch((err) => { + console.error("[fehler]", err); + process.exit(1); +});