Files
website/utils/download_resources.py

225 lines
8.2 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Dieses Skript lädt externe Ressourcen wie Font Awesome, Tailwind CSS und Alpine.js herunter
und installiert sie lokal, um die Abhängigkeit von externen CDNs zu vermeiden und
die Content Security Policy zu erfüllen.
"""
import os
import sys
import requests
import zipfile
import io
import shutil
import subprocess
from pathlib import Path
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# URLs für die Ressourcen
RESOURCES = {
'alpine.js': 'https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js',
'font_awesome': 'https://use.fontawesome.com/releases/v6.4.0/fontawesome-free-6.4.0-web.zip',
'inter_font_300': 'https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2',
'inter_font_400': 'https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2',
'inter_font_500': 'https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2',
'inter_font_600': 'https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2',
'inter_font_700': 'https://fonts.gstatic.com/s/inter/v18/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2',
'jetbrains_font_400': 'https://fonts.gstatic.com/s/jetbrainsmono/v20/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwg.woff2',
'jetbrains_font_500': 'https://fonts.gstatic.com/s/jetbrainsmono/v20/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwhsk.woff2',
'jetbrains_font_700': 'https://fonts.gstatic.com/s/jetbrainsmono/v20/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwhsk.woff2',
}
# Zielverzeichnisse
DIRECTORIES = {
'js': os.path.join(BASE_DIR, 'static', 'js'),
'css': os.path.join(BASE_DIR, 'static', 'css'),
'fonts': os.path.join(BASE_DIR, 'static', 'fonts'),
'webfonts': os.path.join(BASE_DIR, 'static', 'webfonts'),
}
def download_file(url, filepath):
"""Lädt eine Datei von einer URL herunter und speichert sie lokal."""
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(filepath, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f"✅ Heruntergeladen: {os.path.basename(filepath)}")
return True
else:
print(f"❌ Fehler beim Herunterladen von {url}: {response.status_code}")
return False
def extract_zip(zip_data, extract_to):
"""Extrahiert eine ZIP-Datei in das angegebene Verzeichnis."""
with zipfile.ZipFile(io.BytesIO(zip_data)) as zip_ref:
zip_ref.extractall(extract_to)
def setup_directories():
"""Erstellt die benötigten Verzeichnisse, falls sie nicht existieren."""
for directory in DIRECTORIES.values():
os.makedirs(directory, exist_ok=True)
print(f"📁 Verzeichnis erstellt/überprüft: {directory}")
def download_alpine():
"""Lädt Alpine.js herunter."""
url = RESOURCES['alpine.js']
filepath = os.path.join(DIRECTORIES['js'], 'alpine.min.js')
download_file(url, filepath)
def download_font_awesome():
"""Lädt Font Awesome herunter und extrahiert die Dateien."""
url = RESOURCES['font_awesome']
response = requests.get(url)
if response.status_code == 200:
# Temporäres Verzeichnis für die Extraktion
temp_dir = os.path.join(BASE_DIR, 'temp_fontawesome')
os.makedirs(temp_dir, exist_ok=True)
# ZIP-Datei extrahieren
extract_zip(response.content, temp_dir)
# CSS-Datei kopieren
fa_dir = os.path.join(temp_dir, 'fontawesome-free-6.4.0-web')
css_source = os.path.join(fa_dir, 'css', 'all.min.css')
css_dest = os.path.join(DIRECTORIES['css'], 'all.min.css')
shutil.copyfile(css_source, css_dest)
print(f"✅ Font Awesome CSS kopiert nach {css_dest}")
# Webfonts-Verzeichnis kopieren
webfonts_source = os.path.join(fa_dir, 'webfonts')
shutil.rmtree(DIRECTORIES['webfonts'], ignore_errors=True)
shutil.copytree(webfonts_source, DIRECTORIES['webfonts'])
print(f"✅ Font Awesome Webfonts kopiert nach {DIRECTORIES['webfonts']}")
# Temporäres Verzeichnis löschen
shutil.rmtree(temp_dir)
return True
else:
print(f"❌ Fehler beim Herunterladen von Font Awesome: {response.status_code}")
return False
def download_google_fonts():
"""Lädt die Google Fonts (Inter und JetBrains Mono) herunter."""
font_files = {
'inter-light.woff2': RESOURCES['inter_font_300'],
'inter-regular.woff2': RESOURCES['inter_font_400'],
'inter-medium.woff2': RESOURCES['inter_font_500'],
'inter-semibold.woff2': RESOURCES['inter_font_600'],
'inter-bold.woff2': RESOURCES['inter_font_700'],
'jetbrainsmono-regular.woff2': RESOURCES['jetbrains_font_400'],
'jetbrainsmono-medium.woff2': RESOURCES['jetbrains_font_500'],
'jetbrainsmono-bold.woff2': RESOURCES['jetbrains_font_700'],
}
for filename, url in font_files.items():
filepath = os.path.join(DIRECTORIES['fonts'], filename)
download_file(url, filepath)
def setup_tailwind():
"""Richtet Tailwind CSS ein."""
# Tailwind-Konfiguration erstellen, falls sie nicht existiert
tailwind_config = os.path.join(BASE_DIR, 'tailwind.config.js')
if not os.path.exists(tailwind_config):
with open(tailwind_config, 'w') as f:
f.write("""/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class',
content: [
"./templates/**/*.html",
"./static/**/*.js",
],
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'ui-sans-serif', 'system-ui', '-apple-system', 'sans-serif'],
mono: ['JetBrains Mono', 'ui-monospace', 'monospace']
},
colors: {
primary: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95'
},
secondary: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b'
},
dark: {
500: '#374151',
600: '#1f2937',
700: '#111827',
800: '#0e1220',
900: '#0a0e19'
}
}
}
},
plugins: [],
}
""")
print(f"✅ Tailwind-Konfiguration erstellt: {tailwind_config}")
# Input-CSS-Datei erstellen
input_css_dir = os.path.join(DIRECTORIES['css'], 'src')
os.makedirs(input_css_dir, exist_ok=True)
input_css = os.path.join(input_css_dir, 'input.css')
if not os.path.exists(input_css):
with open(input_css, 'w') as f:
f.write("""@tailwind base;
@tailwind components;
@tailwind utilities;
""")
print(f"✅ Tailwind Input-CSS erstellt: {input_css}")
# Hinweis zur Kompilierung anzeigen
print("\n📋 Um Tailwind CSS zu kompilieren, führe folgenden Befehl aus:")
print("npm install -D tailwindcss")
print(f"npx tailwindcss -i {input_css} -o {os.path.join(DIRECTORIES['css'], 'tailwind.min.css')} --minify")
def main():
"""Hauptfunktion: Lädt alle benötigten Ressourcen herunter."""
print("🚀 Starte den Download externer Ressourcen...")
setup_directories()
# Alpine.js herunterladen
print("\n📦 Lade Alpine.js herunter...")
download_alpine()
# Font Awesome herunterladen
print("\n📦 Lade Font Awesome herunter...")
download_font_awesome()
# Google Fonts herunterladen
print("\n📦 Lade Google Fonts herunter...")
download_google_fonts()
# Tailwind CSS einrichten
print("\n📦 Richte Tailwind CSS ein...")
setup_tailwind()
print("\n✅ Alle Ressourcen wurden erfolgreich heruntergeladen und eingerichtet!")
print("🔒 Die Webseite sollte nun ohne externe CDNs funktionieren und die Content Security Policy erfüllen.")
if __name__ == "__main__":
main()