#!/usr/bin/env python3 import streamlink import tornado.web import tornado.routing import requests import json import os import urllib.parse providers = {} providers["nrk"] = "https://tv.nrk.no" providers["svt"] = "https://svtplay.se" providers["youtube"] = "https://youtu.be" providers["twitch"] = "https://twitch.tv" proxies = {} proxies_raw = {} for key in providers: proxies[key] = streamlink.Streamlink() proxy = os.environ.get(key.upper() + "_PROXY") proxies[key].set_option("http-timeout", 2.0) if proxy is not None: proxies[key].set_option("https-proxy", proxy) splitted = proxy.split(":", 1) if len(splitted) == 2: proxies_raw[key] = splitted[1].lstrip("/") playlist = None icecast_server = os.environ.get("ICECAST_SERVER") stream_server = os.environ.get("STREAM_SERVER") proxy_server = os.environ.get("PROXY_SERVER") if icecast_server is not None and stream_server is not None: with open("/app/sources.json", "r") as f: data = json.loads(f.read()) playlist = "#EXTM3U\n" for key in data: current = data[key] name = current["name"] radio = current["radio"] if radio: playlist += f'#EXTINF:0 radio="true", {name}\n' playlist += icecast_server + key + "\n" else: playlist += f'#EXTINF:0 radio="false", {name}\n' playlist += stream_server + key + "\n" def rewrite(current, proxy): resp = requests.head(current) ctype = resp.headers.get("Content-Type", "text/plain").lower() if "mpegurl" not in ctype: return None resp = requests.get(current) ndata = None if resp.text is not None: ndata = "" for line in resp.text.splitlines(): if line.startswith("#"): ndata += line else: data = {} data["upstream"] = urllib.parse.urljoin(current, line) data["proxy"] = proxy if proxy is None or proxy_server is None: ndata += data["upstream"] else: presp = requests.post(proxy_server, json=data) ndata += presp.text ndata += "\n" return ndata class MainHandler(tornado.web.RequestHandler): def handle_any(self, write): provider = self.get_query_argument("provider", None) upstream = None proxy = None proxy_raw = None if provider is not None and provider in providers.keys(): proxy = proxies.get(provider) proxy_raw = proxies_raw.get(provider) src = providers[provider] + self.request.uri try: resp = requests.get(src) if resp is not None: src = resp.url except Exception as e: print(e) else: try: streams = proxy.streams(src) for key in reversed(streams): stream = streams.get(key) if hasattr(stream, "url"): upstream = stream.url break except Exception as e: print(str(e)) upstream = None if upstream is None: self.set_status(404) if write: self.write("stream not found") else: data = rewrite(upstream, proxy_raw) if data is None: self.redirect(upstream, status=303) else: self.set_header("Content-Type", "application/vnd.apple.mpegurl") self.write(data) def get(self): self.handle_any(True) def head(self): self.handle_any(False) class FileHandler(tornado.web.RequestHandler): def get(self): self.set_header("Content-Type", "text/plain; charset=utf-8") self.write(playlist) try: handlers = [] handlers.append((tornado.routing.PathMatches("/sources.m3u8"), FileHandler)) handlers.append((tornado.routing.AnyMatches(), MainHandler)) app_web = tornado.web.Application(handlers) app_web.listen(8080) tornado.ioloop.IOLoop.current().start() except KeyboardInterrupt: print()