Simple bottle.py application to open a multitwitch (or similar site) for an SRL race
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from bottle import * | |
from urllib.request import urlopen | |
import json | |
import re | |
DEFAULT_HOSTS = ['multitwitch.tv', 'multistre.am', 'kadgar.net/live'] | |
SRL_API = "https://api.speedrunslive.com/races/" | |
SANITY_RE = re.compile('[0-9a-z]+') | |
RACE_STATE_COMPLETE = 4 # from the SRL API | |
HTML_INDEX_TEMPLATE = """ | |
<html> | |
<head> | |
<title>SRL Races</title> | |
</head> | |
<body> | |
% for race in races: | |
<div> | |
<a href="https://www.speedrunslive.com/race/?id={{race['id']}}">#srl-{{race['id']}} ({{race['statetext']}})</a> | |
<span> | |
{{race['game']['name']}} | |
{{' - ' + race['goal'] if race['goal'] else ''}} | |
</span> | |
</div> | |
<div> | |
% for i, entrant in enumerate(race['entrants'].values()): | |
<span> | |
{{'/' if i != 0 else ''}} | |
% if entrant['twitch']: | |
<a href="https://twitch.tv/{{entrant['twitch']}}">{{entrant['displayname']}}</a> | |
% else: | |
{{entrant['displayname']}} | |
% end | |
</span> | |
% end | |
</div> | |
% for j, host in enumerate(hosts): | |
{{'/' if j != 0 else ''}} | |
<a href="{{host}}/{{race['id']}}">{{host}}</a> | |
% end | |
<br/><br/> | |
% end | |
</body> | |
</html> | |
""" | |
def get_json(url): | |
req = urlopen(url) | |
reqdata = req.read().decode() | |
return json.loads(reqdata) | |
@route('/srlmulti') | |
@route('/') | |
def redirect_to_index(): | |
# we need trailing slash for relative urls | |
return redirect('/srlmulti/') | |
@route('/srlmulti/') | |
def index(): | |
data = get_json(SRL_API) | |
races = (r for r in data['races'] if r['state'] < RACE_STATE_COMPLETE) | |
return template(HTML_INDEX_TEMPLATE, races=races, hosts=DEFAULT_HOSTS) | |
@route('/srlmulti/<race_id>') | |
def showmulti(race_id): | |
return showmulti_with_host(DEFAULT_HOSTS[0], race_id) | |
@route('/srlmulti/<host:path>/<race_id>') | |
def showmulti_with_host(host, race_id): | |
race_id = race_id.strip() | |
if race_id.startswith('srl-'): | |
race_id = race_id[4:] | |
if not SANITY_RE.fullmatch(race_id): | |
abort(400, 'invalid format for race id') | |
# request might fail with exception, let it go through | |
data = get_json(SRL_API + race_id) | |
# srl api returns empty json object for invalid race id | |
if not data: | |
abort(404, "race id '" + race_id + "' not found") | |
streams = (v['twitch'] for v in data['entrants'].values() if v['twitch']) | |
return redirect('https://' + host + '/' + '/'.join(streams)) | |
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