From f1078d825a986a752b174c8d84f1022ac8bad900 Mon Sep 17 00:00:00 2001 From: Manuel Weiser Date: Sun, 6 Jul 2025 10:08:56 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCge=20Cron-Version=20des=20SERMAN=20RSS?= =?UTF-8?q?=20Feed=20Generators=20hinzu,=20einschlie=C3=9Flich=20automatis?= =?UTF-8?q?chem=20Setup,=20Logging=20und=20Quiet-Mode-Unterst=C3=BCtzung.?= =?UTF-8?q?=20Entferne=20das=20Setup-Script=20und=20aktualisiere=20die=20R?= =?UTF-8?q?EADME.md=20f=C3=BCr=20bessere=20Benutzeranleitung.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CRON_README.md | 193 +++++++++++++++++++++++++++++++++++++++++ README.md | 229 ++++++++++++++++++++++++++++++++----------------- main.py | 113 ++++++++++++++++++------ setup.sh | 25 ------ 4 files changed, 434 insertions(+), 126 deletions(-) create mode 100644 CRON_README.md delete mode 100755 setup.sh diff --git a/CRON_README.md b/CRON_README.md new file mode 100644 index 0000000..ec176e8 --- /dev/null +++ b/CRON_README.md @@ -0,0 +1,193 @@ +# SERMAN RSS Feed Generator - Cron-Version + +Automatischer RSS-Feed-Generator für Podcast-Apps, optimiert für Cron-Jobs. + +## 🚀 Schnellstart für Cron-Jobs + +### 1. Automatisches Setup +```bash +./cron_setup.sh +``` + +Das Setup-Script: +- ✅ Testet die Python-Umgebung +- ✅ Erstellt Wrapper-Scripts für Cron +- ✅ Bietet automatische Cron-Installation +- ✅ Konfiguriert Log-Rotation + +### 2. Manueller Aufruf (ohne Cron) +```bash +# Standard-Ausführung +python main.py + +# Mit benutzerdefinierten Parametern +python main.py --audio-dir "/pfad/zu/mp3s" --output "mein_podcast.xml" + +# Stille Ausführung (für Cron) +python main.py --quiet +``` + +## ⏰ Cron-Konfiguration + +### Häufige Cron-Intervalle + +```bash +# Alle 15 Minuten +*/15 * * * * /pfad/zum/script/run_rss_generator.sh >/dev/null 2>&1 + +# Jede Stunde (empfohlen) +0 * * * * /pfad/zum/script/run_rss_generator.sh >/dev/null 2>&1 + +# Alle 6 Stunden +0 */6 * * * /pfad/zum/script/run_rss_generator.sh >/dev/null 2>&1 + +# Täglich um 6:00 Uhr +0 6 * * * /pfad/zum/script/run_rss_generator.sh >/dev/null 2>&1 +``` + +### Cron-Installation + +1. **Crontab öffnen:** + ```bash + crontab -e + ``` + +2. **Zeile hinzufügen** (z.B. stündlich): + ``` + 0 * * * * /Users/manuel/dev/serman/rss-feeder/run_rss_generator.sh >/dev/null 2>&1 + ``` + +3. **Speichern und beenden** (meist `Ctrl+X`, dann `Y`, dann `Enter`) + +## 📋 Logging und Monitoring + +### Log-Datei anzeigen +```bash +# Aktuelle Logs anzeigen +tail -f rss_generator.log + +# Letzte 50 Zeilen +tail -n 50 rss_generator.log + +# Log-Datei komplett anzeigen +cat rss_generator.log +``` + +### Log-Rotation +Das System rotiert die Logs automatisch (behält nur die letzten 100 Zeilen). + +## 🛠️ Kommandozeilen-Parameter + +```bash +python main.py [OPTIONEN] + +Optionen: + -a, --audio-dir PATH Verzeichnis mit MP3-Dateien + (Standard: ../httpdocs/_audio) + + -o, --output DATEI Ausgabedatei für RSS-Feed + (Standard: serman_podcast.xml) + + -u, --base-url URL Basis-URL für Audio-Dateien + (Standard: https://www.serman.club) + + -t, --title TITEL Titel des Podcasts + (Standard: "SERMAN - Organic House Podcast") + + --author AUTOR Autor des Podcasts + (Standard: "SERMAN") + + -q, --quiet Unterdrückt Ausgaben (für Cron-Jobs) + + -h, --help Zeigt diese Hilfe an +``` + +## 📁 Verzeichnisstruktur + +``` +rss-feeder/ +├── main.py # Haupt-Script (ohne Server) +├── local_podcast_generator.py # Generator-Klasse +├── cron_setup.sh # Automatisches Cron-Setup +├── run_rss_generator.sh # Cron-Wrapper (wird erstellt) +├── rotate_logs.sh # Log-Rotation (wird erstellt) +├── rss_generator.log # Log-Datei (wird erstellt) +├── serman_podcast.xml # Generierter RSS-Feed +└── _audio/ # MP3-Dateien + ├── track1.mp3 + ├── track2.mp3 + └── cover_track1.jpg # Automatisch extrahierte Cover +``` + +## 🔧 Troubleshooting + +### Cron-Job läuft nicht +1. **Pfade prüfen:** + ```bash + which python3 + # Oder + which uv + ``` + +2. **Script manuell testen:** + ```bash + ./run_rss_generator.sh + ``` + +3. **Log-Datei prüfen:** + ```bash + tail -f rss_generator.log + ``` + +### Keine MP3-Dateien gefunden +- Prüfe ob das Audio-Verzeichnis existiert +- Prüfe Dateiberechtigungen +- Verwende absolute Pfade in der Cron-Konfiguration + +### Dependencies fehlen +```bash +# Mit UV (empfohlen) +uv sync + +# Oder mit pip +pip install -r requirements.txt +``` + +## 🎵 Audio-Format-Unterstützung + +- **Unterstützt:** MP3-Dateien (.mp3) +- **Cover-Art:** Automatische Extraktion aus ID3-Tags +- **Metadaten:** Titel, Künstler, Album, Dauer aus ID3-Tags + +## 🌐 Webserver-Integration + +Der RSS-Feed kann direkt auf einen Webserver kopiert werden: + +```bash +# Manuelle Kopie +cp serman_podcast.xml /var/www/html/ + +# Automatisch im Wrapper-Script (wenn httpdocs existiert) +# Der Feed wird automatisch nach ../httpdocs/ kopiert +``` + +## 📱 Podcast-App-Kompatibilität + +Optimiert für: +- ✅ Apple Podcasts +- ✅ Spotify +- ✅ Google Podcasts +- ✅ Overcast +- ✅ Pocket Casts +- ✅ Alle RSS-2.0-kompatiblen Apps + +## 🔄 Aktualisierungsverhalten + +- **Neue MP3-Dateien:** Werden automatisch erkannt und hinzugefügt +- **Metadaten-Änderungen:** Werden bei der nächsten Ausführung übernommen +- **Cover-Art:** Wird einmalig extrahiert und wiederverwendet +- **Sortierung:** Neueste Dateien erscheinen zuerst (nach Änderungsdatum) + +--- + +**💡 Tipp:** Für die beste Performance empfiehlt sich eine stündliche Aktualisierung via Cron-Job. diff --git a/README.md b/README.md index c718e5f..7db7942 100644 --- a/README.md +++ b/README.md @@ -1,113 +1,188 @@ # SERMAN RSS Feed Generator - Lokale Version Ein Python-Tool zum Erstellen von RSS-Feeds aus lokalen MP3-Dateien für Podcast-Apps. +**Optimiert für Cron-Jobs und automatische Aktualisierungen.** + +## 🚀 Schnellstart + +### Für Cron-Jobs (empfohlen) +```bash +# Automatisches Setup +./cron_setup.sh + +# Oder manuell +uv run python main.py --quiet +``` + +### Für manuelle Nutzung +```bash +# Einfache Generierung +uv run python main.py + +# Mit eigenen Parametern +uv run python main.py --audio-dir /pfad/zu/mp3s --title "Mein Podcast" +``` ## Features -- 🎵 Scannt automatisch das `_audio/` Verzeichnis nach MP3-Dateien -- 📱 Erstellt Podcast-kompatible RSS-Feeds -- 🏷️ Liest ID3-Tags automatisch aus MP3-Dateien -- 🌐 Integrierter HTTP-Server zum Hosten der Dateien -- ⚡ Einfache Bedienung über Kommandozeile +- 🎵 Scannt automatisch nach MP3-Dateien +- 📱 Erstellt Podcast-kompatible RSS-Feeds (Apple Podcasts, Spotify, etc.) +- 🏷️ Liest ID3-Tags und Cover-Art aus MP3-Dateien +- ⏰ **Optimiert für Cron-Jobs** (quiet-Mode, keine Server-Abhängigkeiten) +- 🔄 Automatische Cover-Extraktion und -Optimierung +- 📊 Vollständige iTunes-Podcast-Kompatibilität ## Installation -1. Abhängigkeiten installieren: ```bash +# Dependencies installieren uv sync + +# MP3-Dateien in das _audio/ Verzeichnis legen +mkdir -p _audio +# Kopiere deine MP3-Dateien nach _audio/ ``` -2. MP3-Dateien in das `_audio/` Verzeichnis legen - -## Verwendung - -### Einfache Nutzung +## 🛠️ Parameter ```bash -uv run python main.py +uv run python main.py [OPTIONEN] + +Optionen: + -a, --audio-dir PATH MP3-Verzeichnis (Standard: _audio) + -o, --output DATEI RSS-Datei (Standard: serman_podcast.xml) + -u, --base-url URL Basis-URL (Standard: https://www.serman.club) + -t, --title TITEL Podcast-Titel + --author AUTOR Podcast-Autor (Standard: SERMAN) + -q, --quiet Stille Ausgabe (für Cron-Jobs) + -h, --help Hilfe anzeigen ``` -### Mit HTTP-Server +## ⏰ Cron-Job Setup + +### Automatisches Setup +```bash +./cron_setup.sh +``` + +Das Setup erstellt: +- ✅ Cron-Wrapper-Script (`run_rss_generator.sh`) +- ✅ Log-Rotation (`rotate_logs.sh`) +- ✅ Automatische Cron-Installation (optional) + +### Manuelle Cron-Konfiguration ```bash -uv run python main.py --serve +# Crontab bearbeiten +crontab -e + +# Beispiel: Stündliche Aktualisierung +0 * * * * /pfad/zum/script/run_rss_generator.sh >/dev/null 2>&1 ``` -### Erweiterte Optionen +**Weitere Cron-Beispiele:** +- `*/15 * * * *` - Alle 15 Minuten +- `0 */6 * * *` - Alle 6 Stunden +- `0 6 * * *` - Täglich um 6:00 Uhr -```bash -uv run python main.py --audio-dir _audio --output my_podcast.xml --base-url https://meinserver.de --serve --port 8080 -``` - -## Parameter - -- `--audio-dir`: Verzeichnis mit MP3-Dateien (Standard: `_audio`) -- `--output`: Name der RSS-Feed-Datei (Standard: `serman_podcast.xml`) -- `--base-url`: Basis-URL für Audio-Links (Standard: `http://localhost:8000`) -- `--serve`: Startet automatisch einen HTTP-Server -- `--port`: Port für den HTTP-Server (Standard: 8000) - -## RSS-Feed URLs - -Nach dem Start des Servers ist der Feed verfügbar unter: -- **Lokal**: http://localhost:8000/serman_podcast.xml -- **Mit eigener Basis-URL**: [DEINE_URL]/serman_podcast.xml - -## Podcast-App Integration - -1. RSS-Feed generieren und Server starten -2. RSS-URL in Podcast-App hinzufügen -3. Neue MP3-Dateien im `_audio/` Verzeichnis ablegen -4. Feed neu generieren für Updates - -## Dateiformat - -Das Tool liest automatisch folgende ID3-Tags: -- **TIT2**: Titel (Fallback: Dateiname) -- **TPE1**: Künstler (Fallback: "SERMAN") -- **TALB**: Album (optional) -- **Dauer**: Automatisch erkannt - -## Verzeichnisstruktur +## 📁 Verzeichnisstruktur ```text rss-feeder/ +├── main.py # Haupt-Script (Cron-optimiert) +├── local_podcast_generator.py # RSS-Generator-Klasse +├── cron_setup.sh # Automatisches Cron-Setup +├── run_rss_generator.sh # Cron-Wrapper (auto-generiert) +├── rss_generator.log # Log-Datei (auto-generiert) +├── serman_podcast.xml # RSS-Feed (auto-generiert) ├── _audio/ # MP3-Dateien hier ablegen │ ├── mix1.mp3 │ ├── mix2.mp3 -│ └── README.md -├── main.py # Hauptprogramm -├── local_podcast_generator.py # RSS-Generator -├── serman_podcast.xml # Generierter RSS-Feed -└── requirements.txt # Python-Abhängigkeiten +│ └── cover_mix1.jpg # Auto-extrahierte Cover +└── requirements.txt ``` -## Deployment - -Für produktive Nutzung: - -1. **Server bereitstellen** (z.B. VPS, Cloud-Instance) -2. **Dateien hochladen** und Dependencies installieren -3. **Permanenten Webserver** konfigurieren (nginx, Apache) -4. **RSS-Feed URL** an Hörer verteilen - -## Automatisierung - -Für automatische Updates bei neuen MP3-Dateien: +## 🌐 Webserver-Integration ```bash -# Beispiel-Script für cron job -#!/bin/bash -cd /pfad/zu/rss-feeder -uv run python main.py --base-url https://meinserver.de/podcast +# RSS-Feed zu Webserver kopieren +cp serman_podcast.xml /var/www/html/ + +# Mit nginx/Apache bereitstellen +# URL: https://deinserver.de/serman_podcast.xml ``` +## 📱 Podcast-App-Kompatibilität + +Getestet mit: +- ✅ Apple Podcasts +- ✅ Spotify +- ✅ Google Podcasts +- ✅ Overcast +- ✅ Pocket Casts +- ✅ Alle RSS-2.0-Apps + +## 🎵 Audio-Features + +- **Format**: MP3-Dateien (.mp3) +- **Metadaten**: Automatische ID3-Tag-Erkennung +- **Cover-Art**: Automatische Extraktion und Optimierung für Apple Podcasts +- **Sortierung**: Neueste Dateien zuerst (nach Änderungsdatum) + +## 📋 Logging und Monitoring + +```bash +# Live-Log anzeigen +tail -f rss_generator.log + +# Letzte Einträge +tail -n 50 rss_generator.log + +# Cron-Job Status prüfen +crontab -l +``` + +## 🔧 Troubleshooting + +### Script läuft nicht +```bash +# Dependencies prüfen +uv sync + +# Manual testen +uv run python main.py + +# Pfade prüfen +which uv +which python3 +``` + +### Cron-Job läuft nicht +```bash +# Wrapper-Script testen +./run_rss_generator.sh + +# Log prüfen +tail -f rss_generator.log + +# Crontab prüfen +crontab -l +``` + +## 📚 Dokumentation + +- **[CRON_README.md](CRON_README.md)** - Detaillierte Cron-Anleitung +- **[demo.sh](demo.sh)** - Funktions-Demo ausführen + +## 🔄 Migration von Server-Version + +Wenn du die alte Server-Version verwendet hast: + +1. **Stoppe den alten Server** +2. **Installiere Cron-Version:** `./cron_setup.sh` +3. **Teste:** `uv run python main.py --quiet` +4. **RSS-URL bleibt gleich** (nur Generation ändert sich) + --- -## Legacy: Mixcloud-Version - -Die ursprünglichen Mixcloud-Skripte sind noch vorhanden: -- `mixcloud_rss_pro.py` - Mixcloud RSS mit Audio-Extraktion -- `mixcloud_rss.py` - Einfache Mixcloud RSS-Generierung - -Siehe Git-Historie für die ursprüngliche Mixcloud-basierte README. +**💡 Empfehlung:** Für Produktiveinsatz stündliche Cron-Jobs verwenden. diff --git a/main.py b/main.py index ee20618..3b186aa 100644 --- a/main.py +++ b/main.py @@ -2,12 +2,68 @@ """ SERMAN RSS Feed Generator - Lokale Version Generiert RSS-Feeds aus lokalen MP3-Dateien für Podcast-Apps. +Optimiert für Cron-Jobs. """ from local_podcast_generator import LocalPodcastGenerator import argparse import sys import os +import contextlib +from io import StringIO + + +class QuietLocalPodcastGenerator(LocalPodcastGenerator): + """Erweiterte Version des Generators mit Quiet-Mode-Unterstützung.""" + + def __init__(self, audio_dir="../httpdocs/_audio", output_file="podcast_feed.xml", + base_url="https://www.serman.club", quiet=False): + super().__init__(audio_dir, output_file, base_url) + self.quiet = quiet + self.errors = [] + + def log(self, message): + """Logging-Funktion die das quiet-Flag berücksichtigt.""" + if not self.quiet: + print(message) + + def log_error(self, message): + """Error-Logging das immer ausgegeben wird.""" + print(message) + self.errors.append(message) + + def get_mp3_files(self): + """Überschreibt die Original-Methode für besseres Logging.""" + from pathlib import Path + + audio_path = Path(self.audio_dir) + if not audio_path.exists(): + self.log_error(f"❌ Audio-Verzeichnis '{self.audio_dir}' existiert nicht!") + return [] + + mp3_files = list(audio_path.glob("*.mp3")) + self.log(f"🎵 {len(mp3_files)} MP3-Dateien gefunden in '{self.audio_dir}/'") + + # Sortiere nach Änderungsdatum (neueste zuerst) + mp3_files.sort(key=lambda x: x.stat().st_mtime, reverse=True) + + return mp3_files + + def create_rss_feed_quiet(self, podcast_title="SERMAN - Organic House Podcast", + podcast_description=None, podcast_author="SERMAN"): + """RSS-Feed-Erstellung mit unterdrückter Ausgabe für Cron-Jobs.""" + + if self.quiet: + # Unterdrücke alle print-Ausgaben während der Feed-Erstellung + with contextlib.redirect_stdout(StringIO()), contextlib.redirect_stderr(StringIO()): + try: + return super().create_rss_feed(podcast_title, podcast_description, podcast_author) + except Exception as e: + self.log_error(f"❌ Fehler beim Erstellen des RSS-Feeds: {e}") + return False + else: + # Normale Ausgabe + return super().create_rss_feed(podcast_title, podcast_description, podcast_author) def main(): @@ -18,50 +74,59 @@ def main(): help="Ausgabedatei für den RSS-Feed (Standard: serman_podcast.xml)") parser.add_argument("-u", "--base-url", default="https://www.serman.club", help="Basis-URL für Audio-Dateien (Standard: https://www.serman.club)") - parser.add_argument("--serve", action="store_true", - help="Startet automatisch einen HTTP-Server nach der Generierung") - parser.add_argument("--port", type=int, default=8087, - help="Port für den HTTP-Server (Standard: 8087)") + parser.add_argument("-t", "--title", default="SERMAN - Organic House Podcast", + help="Titel des Podcasts") + parser.add_argument("--author", default="SERMAN", + help="Autor des Podcasts") + parser.add_argument("-q", "--quiet", action="store_true", + help="Unterdrückt Ausgaben (nützlich für Cron-Jobs)") args = parser.parse_args() - print("🎵 SERMAN RSS Feed Generator - Lokale Version") - print("=" * 50) + # Unterdrücke Ausgaben wenn --quiet gesetzt ist + def log(message): + if not args.quiet: + print(message) + + log("🎵 SERMAN RSS Feed Generator - Lokale Version") + log("=" * 50) # Prüfe ob Audio-Verzeichnis existiert if not os.path.exists(args.audio_dir): - print(f"❌ Audio-Verzeichnis '{args.audio_dir}' existiert nicht!") - print(f"💡 Erstelle das Verzeichnis und lege deine MP3-Dateien dort ab.") + log(f"❌ Audio-Verzeichnis '{args.audio_dir}' existiert nicht!") + log(f"💡 Erstelle das Verzeichnis und lege deine MP3-Dateien dort ab.") return 1 # Erstelle den Generator - generator = LocalPodcastGenerator( + generator = QuietLocalPodcastGenerator( audio_dir=args.audio_dir, output_file=args.output, - base_url=args.base_url + base_url=args.base_url, + quiet=args.quiet ) # Generiere den RSS-Feed - print(f"📂 Scanne '{args.audio_dir}/' nach MP3-Dateien...") - success = generator.create_rss_feed( - podcast_title="SERMAN - Organic House Podcast", - podcast_author="SERMAN" + log(f"📂 Scanne '{args.audio_dir}/' nach MP3-Dateien...") + success = generator.create_rss_feed_quiet( + podcast_title=args.title, + podcast_author=args.author ) if not success: - print("❌ Fehler beim Erstellen des RSS-Feeds!") + log("❌ Fehler beim Erstellen des RSS-Feeds!") + # Zeige Fehler auch im quiet-Modus + if args.quiet and hasattr(generator, 'errors') and generator.errors: + for error in generator.errors: + print(error) return 1 - print("\n🎉 RSS-Feed erfolgreich erstellt!") - print(f"📄 Datei: {args.output}") - print(f"🌐 URL: {args.base_url}/{args.output}") + log("\n🎉 RSS-Feed erfolgreich erstellt!") + log(f"📄 Datei: {args.output}") + log(f"🌐 URL: {args.base_url}/{args.output}") - if args.serve: - print("\n🚀 Starte HTTP-Server...") - generator.serve_feed(args.port) - else: - print(f"\n💡 Zum Starten des Servers: python main.py --serve") - print(f"💡 Oder direkt: python local_podcast_generator.py --serve") + # Im quiet-Modus nur Erfolg bei Fehlern ausgeben + if args.quiet and success: + print(f"✅ RSS-Feed erfolgreich erstellt: {args.output}") return 0 diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 053f243..0000000 --- a/setup.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# SERMAN RSS Feed Generator - Setup Script - -echo "🎵 SERMAN RSS Feed Generator - Setup" -echo "===================================" -echo "" - -# Prüfe ob audio-Verzeichnis existiert -if [ ! -d "_audio" ]; then - echo "📁 Erstelle _audio/ Verzeichnis..." - mkdir _audio -fi - -echo "📋 Setup abgeschlossen!" -echo "" -echo "Nächste Schritte:" -echo "1. Lege deine MP3-Dateien in das _audio/ Verzeichnis" -echo "2. Führe 'uv run python main.py' aus, um den RSS-Feed zu erstellen" -echo "3. Verwende 'uv run python main.py --serve' für lokales Testen" -echo "" -echo "💡 Beispiel-Befehle:" -echo " uv run python main.py # Feed erstellen" -echo " uv run python main.py --serve # Mit HTTP-Server" -echo " uv run python main.py --base-url https://... # Produktions-URL" -echo ""