117 lines
4.5 KiB
Python
117 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Roku Web Remote - proxy server on port 7777."""
|
|
import http.server
|
|
import urllib.request
|
|
import urllib.error
|
|
import urllib.parse
|
|
import os
|
|
import json
|
|
|
|
ROKU = "http://10.0.1.93:8060"
|
|
HTML_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "roku-remote.html")
|
|
|
|
class RokuProxyHandler(http.server.BaseHTTPRequestHandler):
|
|
def do_GET(self):
|
|
if self.path == "/" or self.path == "/roku-remote.html":
|
|
self.serve_html()
|
|
elif self.path.startswith("/roku/icon/"):
|
|
self.proxy_icon()
|
|
elif self.path.startswith("/roku/query/"):
|
|
self.proxy_get(self.path.replace("/roku", "", 1))
|
|
elif self.path.startswith("/roku/"):
|
|
self.send_json(400, {"error": "Use POST for commands"})
|
|
else:
|
|
self.send_json(404, {"error": "Not found"})
|
|
|
|
def do_POST(self):
|
|
if self.path.startswith("/roku/"):
|
|
target = self.path.replace("/roku", "", 1)
|
|
self.proxy_post(target)
|
|
else:
|
|
self.send_json(404, {"error": "Not found"})
|
|
|
|
def serve_html(self):
|
|
try:
|
|
with open(HTML_PATH, "rb") as f:
|
|
content = f.read()
|
|
self.send_response(200)
|
|
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(content)
|
|
except FileNotFoundError:
|
|
self.send_json(500, {"error": "HTML file not found"})
|
|
|
|
def proxy_icon(self):
|
|
# /roku/icon/<encoded_full_url>
|
|
encoded = self.path[len("/roku/icon/"):]
|
|
url = urllib.parse.unquote(encoded)
|
|
try:
|
|
req = urllib.request.Request(url, method="GET")
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
body = resp.read()
|
|
self.send_response(resp.status)
|
|
ctype = resp.headers.get("Content-Type", "image/png")
|
|
self.send_header("Content-Type", ctype)
|
|
self.send_header("Cache-Control", "max-age=3600")
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(body)
|
|
except Exception as e:
|
|
self.send_json(502, {"error": str(e)})
|
|
|
|
def proxy_get(self, path):
|
|
url = f"{ROKU}{path}"
|
|
try:
|
|
req = urllib.request.Request(url, method="GET")
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
body = resp.read()
|
|
self.send_response(resp.status)
|
|
self.send_header("Content-Type", resp.headers.get("Content-Type", "application/xml"))
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(body)
|
|
except urllib.error.HTTPError as e:
|
|
self.send_json(e.code, {"error": str(e.reason)})
|
|
except Exception as e:
|
|
self.send_json(502, {"error": str(e)})
|
|
|
|
def proxy_post(self, path):
|
|
url = f"{ROKU}{path}"
|
|
try:
|
|
req = urllib.request.Request(url, method="POST", data=b"")
|
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
body = resp.read()
|
|
self.send_response(resp.status)
|
|
self.send_header("Content-Type", resp.headers.get("Content-Type", "text/plain"))
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(body)
|
|
except urllib.error.HTTPError as e:
|
|
self.send_json(e.code, {"error": str(e.reason)})
|
|
except Exception as e:
|
|
self.send_json(502, {"error": str(e)})
|
|
|
|
def send_json(self, code, data):
|
|
self.send_response(code)
|
|
self.send_header("Content-Type", "application/json")
|
|
self.send_header("Access-Control-Allow-Origin", "*")
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps(data).encode())
|
|
|
|
def log_message(self, fmt, *args):
|
|
msg = fmt % args
|
|
if "200" not in msg: # only log non-200
|
|
print(f"[roku-proxy] {self.client_address[0]} - {msg}")
|
|
|
|
if __name__ == "__main__":
|
|
port = 7777
|
|
server = http.server.HTTPServer(("0.0.0.0", port), RokuProxyHandler)
|
|
print(f"[roku-proxy] Serving on 0.0.0.0:{port}")
|
|
print(f"[roku-proxy] Access via http://10.10.10.1:{port}/ or http://10.0.1.49:{port}/")
|
|
try:
|
|
server.serve_forever()
|
|
except KeyboardInterrupt:
|
|
print("\n[roku-proxy] Shutting down")
|
|
server.server_close()
|