import os import json import io import zipfile from flask import Flask, render_template_string, request, session, redirect, url_for, send_from_directory, send_file app = Flask(__name__) # WICHTIG: Ändere diesen Key für den produktiven Einsatz app.secret_key = '6a305032-9668-43c3-9a72-a407d5be988f' # Konfiguration PASSWORD = 'toniessindteuer' BASE_DIR = '/mnt/NAS/Toniebox/' # --------------------------------------------------------- # HTML & JS Template (Frontend) # --------------------------------------------------------- TEMPLATE = """ Tonieflix Abmelden

🎧 Tonieflix

{% for book in books %}
{% if book.has_cover %} Cover {% else %} Kein Cover {% endif %}
{{ book.name }}
{% endfor %}
""" LOGIN_TEMPLATE = """ Login - Toniboni

Toniboni Login

""" # --------------------------------------------------------- # Backend Logik & Routen # --------------------------------------------------------- @app.before_request def require_login(): if request.endpoint not in ['login'] and not session.get('logged_in'): return redirect(url_for('login')) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': if request.form.get('password') == PASSWORD: session['logged_in'] = True return redirect(url_for('index')) else: return "Falsches Passwort!", 403 return render_template_string(LOGIN_TEMPLATE) @app.route('/logout') def logout(): session.clear() return redirect(url_for('login')) @app.route('/') def index(): books = [] if os.path.exists(BASE_DIR): for item in sorted(os.listdir(BASE_DIR)): item_path = os.path.join(BASE_DIR, item) if os.path.isdir(item_path): files = os.listdir(item_path) tracks = sorted([f for f in files if f.lower().endswith(('.mp3', '.ogg'))]) has_cover = any(f.lower() == 'cover.jpg' for f in files) if tracks: books.append({ 'name': item, 'tracks': tracks, 'has_cover': has_cover }) return render_template_string(TEMPLATE, books=books) @app.route('/cover/') def serve_cover(book_name): book_path = os.path.join(BASE_DIR, book_name) return send_from_directory(book_path, 'cover.jpg') @app.route('/stream//') def serve_audio(book_name, track_name): book_path = os.path.join(BASE_DIR, book_name) return send_from_directory(book_path, track_name) @app.route('/download/') def download_book(book_name): book_path = os.path.join(BASE_DIR, book_name) # Sicherheitscheck: Existiert der Ordner? if not os.path.isdir(book_path): return "Hörbuch nicht gefunden", 404 # ZIP-Datei im Arbeitsspeicher erstellen memory_file = io.BytesIO() # ZIP_STORED nutzt keine Kompression (geht extrem schnell, gut für MP3s) with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_STORED) as zf: for root, dirs, files in os.walk(book_path): for file in files: file_path = os.path.join(root, file) # Schreibe Datei ins ZIP (nutzt Dateinamen ohne den absoluten NAS-Pfad) zf.write(file_path, arcname=file) memory_file.seek(0) # Datei an den Browser schicken return send_file( memory_file, download_name=f"{book_name}.zip", as_attachment=True, mimetype='application/zip' ) if __name__ == '__main__': app.run(host='0.0.0.0', port=5005)