Skip to content

Instantly share code, notes, and snippets.

@mooware mooware/
Last active Jul 18, 2019

What would you like to do?
Simple application to play streams through HTML5 video
# uses as web framework, livestreamer for getting the stream URL
# and hls.js to play the HLS stream in an HTML5 video tag
from bottle import *
from livestreamer import Livestreamer
import sys, re, json
if sys.version_info.major >= 3:
from urllib.request import urlopen
def u(s):
if isinstance(s, str):
return s
return s.decode()
from urllib2 import urlopen
def u(s):
return s.decode('utf-8')
LOCAL_SERVER_PREFIX = 'http://_insert_server_here_/twitch-redirect/rewrite/'
# get oauth token from "livestreamer --twitch-oauth-authenticate"
TWITCH_OAUTH_TOKEN = '_insert_token_here_'
SANITIZE_RE = re.compile('[^a-zA-Z0-9_]')
TWITCH_SERVER_RE = re.compile(r'^http://[^/]+\.hls\.ttvnw\.net/')
<h2>currently online</h2>
%for (channel, name, status, game) in streams:
<a href="{{channel}}">{{name}}</a>
<span>(playing {{game}})</span>
<title>twitch-redirect {{channel}}</title>
<video id="video" controls></video>
<script src=""></script>
if (Hls.isSupported()) {
var url = '{{url}}';
var video = document.getElementById('video');
var hls = new Hls();
hls.on(Hls.Events.MANIFEST_PARSED,function() {;
} else {
var newNode = document.createElement('h1');
newNode.appendChild(document.createTextNode('Error: hls.js does not support your browser!'));
def get_online_streams():
"""return a lazy list of [name, displayname, status, game]
for each online followed stream"""
resp = urlopen(url)
data = json.loads(u(
fields = ('name', 'display_name', 'status', 'game')
for stream in data[u('streams')]:
ch = stream[u('channel')]
item = [ch[u(f)] for f in fields]
yield item
def get_stream_url(channel, quality):
"""return an HLS url for the given channel and quality, or None"""
livestreamer = Livestreamer()
livestreamer.set_plugin_option("twitch", "oauth_token", TWITCH_OAUTH_TOKEN)
# sanitize both params
channel = SANITIZE_RE.sub('', channel)
quality = SANITIZE_RE.sub('', quality)
url = '' + channel
streams = livestreamer.streams(url)
if not streams:
stream = streams.get(quality)
if not stream:
return stream.url
def redirect_to_index():
# we need trailing slash for relative urls
return redirect('/twitch-redirect/')
def index():
streams = get_online_streams()
return template(HTML_STREAMS_TEMPLATE, streams=streams)
def rewrite_stream(url):
# sanity check, only take twitch video server urls
url = 'http://' + url
if not TWITCH_SERVER_RE.match(url):
abort(404, "Invalid url")
resp = urlopen(url)
response.content_type = resp.getheader('Content-Type')
# rewrite playlists to redirect them through this server
if url.endswith('.m3u8'):
data = u(
new_data = data.replace('http://', LOCAL_SERVER_PREFIX)
return new_data
return resp
def stream_player(channel):
quality = request.query.quality or DEFAULT_QUALITY
url_only = bool(request.query.url)
url = get_stream_url(channel, quality)
if not url:
abort(404, "Unknown channel or quality")
if url_only:
return url
# redirect through this server
url = url.replace('http://', LOCAL_SERVER_PREFIX)
return template(HTML_PLAYER_TEMPLATE, url=url, channel=channel)
if __name__ == '__main__':
run(host='localhost', port=8080)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.