Here is an app to stream MPEG-DASH MPD (Media Presentation Description) streams in Channels. Requires no configuration.
The MPDs can be provided directly or as an m3u8 list, non MPD urls in m3u8 lists are left unchanged
Requires python modules flask and streamlink, and ffmpeg binary in the path
Tested with python 3.11 on Debian 12
flask app
from flask import Flask, request, Response
import streamlink
import requests
import re
app = Flask(__name__)
def modify_m3u8_content(content):
def replace_mpd_urls(line):
if line.startswith("http") and ".mpd" in line:
scheme = request.scheme
host = request.host
return re.sub(r'^(https?://[^\s]+\.mpd)', lambda match: f'{scheme}://{host}/stream?url={match.group(1)}', line)
return line
return "\n".join(replace_mpd_urls(line) for line in content.splitlines())
@app.route('/playlist.m3u8')
def get_custom_m3u8():
url = request.args.get('url')
if not url:
return "Error: No URL provided", 400
response = requests.get(url)
if response.status_code != 200:
return "Error fetching M3U8 playlist", 500
modified_content = modify_m3u8_content(response.text)
return Response(modified_content, content_type='application/vnd.apple.mpegurl')
def generate_stream(url):
session = streamlink.Streamlink()
streams = session.streams(url)
if "best" not in streams:
raise ValueError("No valid stream found.")
stream = streams["best"]
fd = stream.open()
try:
while True:
chunk = fd.read(8192)
if not chunk:
break
yield chunk
finally:
fd.close()
@app.route('/')
def home():
return '''<h1>Streamlink Flask App</h1>
<form action="/stream" method="get">
<label for="url">Enter URL:</label>
<input type="text" id="url" name="url" required>
<button type="submit">Stream</button>
</form>'''
@app.route('/stream')
def stream():
url = request.args.get('url')
if not url:
return "Error: No URL provided", 400
try:
return Response(generate_stream(url), content_type='video/mp4')
except ValueError as e:
return f"Error: {e}", 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
also available as https://pastebin.com/eTBNbKQc
maybe it could be dockerized (put under WSGI) @bnhf
Let's say your favorite channel is in mpd format.
For example if your station is
Korean Central Television (KCTV) (576p)
which uses an MPD stream:
https://tv.nknews.org/tvdash/stream.mpd
contained in this M3U8 playlist:
https://iptv-org.github.io/iptv/countries/kp.m3u
Fire the app locally or elsewhere. For this example let's assume the app is running locally on the default port 5000. Prepend the original M3U8 url with
http://localhost:5000/playlist.m3u8?url=
and put this as the playlist source in custom streams
http://localhost:5000/playlist.m3u8?url=https://iptv-org.github.io/iptv/countries/kp.m3u
also set the type to MPEG -TS. You are done. The lists are identical except for the fact the MPD streams work.
There is also a home page to help stream single MPD streams.
it uses the /stream endpoint. E.g. for the original MPD
http://APP_IP:5000/stream?url=https://tv.nknews.org/tvdash/stream.mpd