225 lines
8.2 KiB
Python
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() |