Moin an alle,
morgen sind Präsidentschaftswahlen in Polen. Dies nehme ich zum Anlass vorstellen, wie ich die englisch- bzw. polnischsprachigen Streams des öffentlich rechtlichen Fernsehens TVP aus Polen in TVHeadend einbinde. Vielleicht ist dies ja auch für andere von Interesse. Bevor ich zur Lösung komme, zunächst ein paar Infos, damit die Problemlage deutlich wird:
- Die Lösung bezieht sich nur auf die freien Sende von TVP. TVP hat auch PayTV-Sender.
- Ein Teil der TVP-Sender arbeitet mit Geo-Blocking. Drei Sender verzichten hierauf: TVP-World (englischsprachiger Nachrichtenkanal), TVP Polonia (der traditionelle polnischsprachige "Auslandskanal", gelegentlich mit englischsprachigen Untertiteln) und TVP Info (polnischsprachiger Nachrichtenkanal.Nur auf diese beziehe ich mich. Theoretisch ließe sich die Lösung auch auf die weiteren Sender ausweiten, wenn man in Polen lebt oder ein VPN benutzt.
- Einen Teil der TVP-Sender könnte man auch über Streamlink einbinden. Das funktioniert aber zumindest nicht für TVP World. Dieser Kanal ist mein Hauptinteresse. Dieser Sender macht sich u.a. mit einer besonders detaillierten Ukraine-Berichterstattung verdient.
- Die Streams wechseln mehrmals stündlich die Adresse. Man kann sie also nicht einfach direkt in TVHeadend (mit ffmpeg) einbinden. Es gibt aber eine API, von der man stets die aktuellen Streamadressen abfragen kann. Diese nutze ich in meiner Lösung unten.
- Damit das Mapping der Sender in TVHeadend stabil funktioniert, darf sich nicht ständig die Streaming-Adresse ändern. Deswegen erstelle ich für meine Lösung eine lokale M3U, die die Streams über einen lokalen Flask-Server anbietet.
- Die Programmierung hat der Bing Copilot für mich unternehmen. Die Lösung funktioniert bereits seit Wochen stabil. Ich hoffe, dies ändert sich nicht, wenn ich hier die Infos veröffentliche. Da es aber auch jede Menge unzulässige Möglichkeiten gibt, diese Sender zu schauen, ist dies hoffentlich TVP egal.
Unten nun zunächst für die Sender TVP World, TVP Info und TVP Polonia jeweils ein Python-Script. Ganz unten dann eine lokale M3U-Datei zur Einbindung in TVHeadend.
1. TVP World
Python
from flask import Flask, redirect
import requests
import threading
import time
app = Flask(__name__)
# Globale Variable, um die aktuelle Stream-URL zu speichern
current_stream_url = None
# API-URL
API_URL = "https://api.tvp.pl/tokenizer/token/51656539"
def update_stream_url():
global current_stream_url
while True:
try:
response = requests.get(API_URL)
response.raise_for_status()
data = response.json()
current_stream_url = data.get("url")
print(f"Aktualisierte Stream-URL: {current_stream_url}")
except Exception as e:
print(f"Fehler beim Abrufen der Stream-URL: {e}")
time.sleep(300) # Aktualisierung alle 5 Minuten
@app.route('/stream')
def stream():
if current_stream_url:
return redirect(current_stream_url)
return "Keine gültige Stream-URL verfügbar", 503
if __name__ == "__main__":
# Starte den Thread, um die URL regelmäßig zu aktualisieren
updater_thread = threading.Thread(target=update_stream_url, daemon=True)
updater_thread.start()
# Starte den Flask-Server
app.run(host="0.0.0.0", port=8000)
Alles anzeigen
2. TVP Polonia
Python
from flask import Flask, redirect
import requests
import threading
import time
app = Flask(__name__)
# Globale Variable, um die aktuelle Stream-URL zu speichern
current_stream_url = None
# API-URL für TVP Polonia
API_URL = "https://api.tvp.pl/tokenizer/token/51696824"
def update_stream_url():
global current_stream_url
while True:
try:
# Abrufen der aktuellen URL aus der API
response = requests.get(API_URL)
response.raise_for_status()
data = response.json()
stream_url = data.get("url")
if stream_url:
current_stream_url = stream_url
print(f"Aktualisierte Stream-URL: {current_stream_url}")
else:
print("Keine gültige Stream-URL erhalten.")
except Exception as e:
print(f"Fehler beim Abrufen der Stream-URL: {e}")
# Aktualisierung alle 5 Minuten
time.sleep(300)
@app.route('/stream')
def stream():
if current_stream_url:
return redirect(current_stream_url)
return "Keine gültige Stream-URL verfügbar", 503
if __name__ == "__main__":
# Starte den Thread, um die URL regelmäßig zu aktualisieren
updater_thread = threading.Thread(target=update_stream_url, daemon=True)
updater_thread.start()
# Starte den Flask-Server
app.run(host="0.0.0.0", port=8002)
Alles anzeigen
3. TVP Info
Python
from flask import Flask, redirect
import requests
import threading
import time
app = Flask(__name__)
# Globale Variable, um die aktuelle Stream-URL zu speichern
current_stream_url = None
# API-URL für TVP INFO
API_URL = "https://api.tvp.pl/tokenizer/token/51696820"
def update_stream_url():
global current_stream_url
while True:
try:
# Abrufen der aktuellen URL aus der API
response = requests.get(API_URL)
response.raise_for_status()
data = response.json()
stream_url = data.get("url")
if stream_url:
current_stream_url = stream_url
print(f"Aktualisierte Stream-URL: {current_stream_url}")
else:
print("Keine gültige Stream-URL erhalten.")
except Exception as e:
print(f"Fehler beim Abrufen der Stream-URL: {e}")
# Aktualisierung alle 5 Minuten
time.sleep(300)
@app.route('/stream')
def stream():
if current_stream_url:
return redirect(current_stream_url)
return "Keine gültige Stream-URL verfügbar", 503
if __name__ == "__main__":
# Starte den Thread, um die URL regelmäßig zu aktualisieren
updater_thread = threading.Thread(target=update_stream_url, daemon=True)
updater_thread.start()
# Starte den Flask-Server
app.run(host="0.0.0.0", port=8001)
Alles anzeigen
4. Lokale M3U:
Code
#EXTM3U
#EXTINF:-1 tvg-id="TVP World" tvg-logo="https://seeklogo.com/images/T/tvp-world-logo-3E1CF343B4-seeklogo.com.png" group-title="Nachrichten",TVP World
pipe://ffmpeg -loglevel fatal -i http://127.0.0.1:8000/stream -metadata service_name=TVP-World -vcodec copy -acodec copy -f mpegts pipe:1
#EXTINF:-1 tvg-id="TVP INFO" tvg-logo="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/TVP_Info_Logo.svg/512px-TVP_Info_Logo.svg.png" group-title="Nachrichten",TVP INFO
pipe://ffmpeg -loglevel fatal -i http://127.0.0.1:8001/stream -metadata service_name=TVP-Info -vcodec copy -acodec copy -f mpegts pipe:1
#EXTINF:-1 tvg-id="TVP Polonia" tvg-logo="https://seeklogo.com/images/T/tvp-polonia-logo-3E1CF343B4-seeklogo.com.png" group-title="Nachrichten",TVP Polonia
pipe://ffmpeg -loglevel fatal -i http://127.0.0.1:8002/stream -metadata service_name=TVP-Polonia -vcodec copy -acodec copy -f mpegts pipe:1