From de82812e30c96a3dae058a57760366463da3f445 Mon Sep 17 00:00:00 2001 From: MrUnknownDE Date: Tue, 5 May 2026 20:30:27 +0200 Subject: [PATCH] add seo optimization --- .env.example | 9 +- app.py | 46 ++++++++- static/style.css | 40 ++++++++ templates/index.html | 239 +++++++++++++++++++++++++++++-------------- 4 files changed, 250 insertions(+), 84 deletions(-) diff --git a/.env.example b/.env.example index c83ce31..f66af7b 100644 --- a/.env.example +++ b/.env.example @@ -25,9 +25,12 @@ S3_ENDPOINT_URL="https://dein-s3-endpoint.example.com" # Wasabi: https://s3..wasabisys.com// S3_PUBLIC_URL_BASE="https://dein-bucket-public-url.example.com/" -# Verlauf aktivieren/deaktivieren (true/false) -# Wenn deaktiviert, wird kein Verlauf angezeigt, gespeichert oder geladen. -ENABLE_HISTORY="true" +# SEO / Site metadata +# Öffentliche URL der Seite (ohne Trailing-Slash). Wird für Canonical, Sitemap und OG-Tags genutzt. +# Leer lassen wenn noch keine Domain konfiguriert ist. +SITE_URL="https://dl.example.com" +SITE_NAME="unknownMedien.dl" +# SITE_DESCRIPTION="..." # Optional: überschreibt den Standard-Beschreibungstext # Anzahl der Worker-Threads für gleichzeitige Downloads/Uploads. # WICHTIG: Die Statusanzeige im Frontend funktioniert nur korrekt mit MAX_WORKERS=1. diff --git a/app.py b/app.py index c48965c..003c8f0 100644 --- a/app.py +++ b/app.py @@ -13,7 +13,7 @@ from datetime import datetime import random import string import re -from flask import Flask, render_template, request, jsonify, Response, copy_current_request_context +from flask import Flask, render_template, request, jsonify, Response, copy_current_request_context, make_response import time # import queue # ALT import multiprocessing # NEU: Für prozessübergreifende Queue @@ -24,6 +24,12 @@ import traceback # NEU: Für detaillierte Fehlermeldungen # --- Konstanten --- STATS_FILE = "stats.json" + +# --- Site-Metadaten (für SSR / SEO) --- +SITE_NAME = os.getenv('SITE_NAME', 'unknownMedien.dl') +SITE_URL = os.getenv('SITE_URL', '').rstrip('/') +SITE_DESCRIPTION = os.getenv('SITE_DESCRIPTION', 'Free media downloader. Save audio and video from YouTube, SoundCloud, TikTok, Instagram and Twitter directly to your cloud storage.') +SITE_KEYWORDS = 'media downloader, youtube downloader, soundcloud downloader, tiktok downloader, instagram reels, mp3 download, mp4 download, s3 upload' RANDOM_NAME_LENGTH = 4 MAX_FILENAME_RETRIES = 10 ANSI_ESCAPE_REGEX = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') @@ -715,7 +721,43 @@ def index(): if not isinstance(job_statuses, type(manager.dict())): job_statuses = manager.dict() logging.warning("job_statuses wurde neu initialisiert (wahrscheinlich nach Reload).") - return render_template('index.html') + stats = load_stats() + ctx = { + 'site_name': SITE_NAME, + 'site_url': SITE_URL, + 'site_description': SITE_DESCRIPTION, + 'site_keywords': SITE_KEYWORDS, + 'platforms': SUPPORTED_PLATFORMS, + 'total_jobs': stats.get('total_jobs', 0), + 'successful_jobs': stats.get('successful_jobs', 0), + } + return render_template('index.html', **ctx) + +@app.route('/robots.txt') +def robots_txt(): + lines = [ + 'User-agent: *', + 'Allow: /', + f'Sitemap: {SITE_URL}/sitemap.xml' if SITE_URL else '', + ] + resp = make_response('\n'.join(filter(None, lines)), 200) + resp.headers['Content-Type'] = 'text/plain' + return resp + +@app.route('/sitemap.xml') +def sitemap_xml(): + url_root = SITE_URL or request.url_root.rstrip('/') + xml = f''' + + + {url_root}/ + weekly + 1.0 + +''' + resp = make_response(xml, 200) + resp.headers['Content-Type'] = 'application/xml' + return resp @app.route('/start_download', methods=['POST']) def start_download(): diff --git a/static/style.css b/static/style.css index e49ae2d..33dc06e 100644 --- a/static/style.css +++ b/static/style.css @@ -786,6 +786,46 @@ body { color: #fca5a5; } +/* =========================== + Footer + =========================== */ +.site-footer { + position: relative; z-index: 1; + padding: 1.5rem 2rem; + border-top: 1px solid rgba(255,255,255,0.05); + text-align: center; +} +.footer-inner { max-width: 840px; margin: 0 auto; } +.footer-platforms { + display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; + margin-bottom: 0.5rem; +} +.footer-platform { + font-size: 0.72rem; font-weight: 500; + letter-spacing: 0.06em; text-transform: uppercase; + color: rgba(255,255,255,0.2); + background: rgba(255,255,255,0.04); + border: 1px solid rgba(255,255,255,0.06); + padding: 3px 10px; + border-radius: 100px; +} +.footer-note { + font-size: 0.72rem; + color: rgba(255,255,255,0.15); + margin: 0; +} + +/* Accessibility */ +.sr-only { + position: absolute; + width: 1px; height: 1px; + padding: 0; margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + /* =========================== Scrollbar =========================== */ diff --git a/templates/index.html b/templates/index.html index bd76a73..4664f0c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,25 +1,66 @@ + - unknownMedien.dl + + + {{ site_name }} — Media Downloader + + + + + {% if site_url %} + + {% endif %} + + + + + + + {% if site_url %} + + {% endif %} + + + + + + + + + + - + -
-
-
-
-
-
- - -