]> git.gir.st - subscriptionfeed.git/blob - app/proxy/__init__.py
don't load livestreams through proxy for osx(?) devices
[subscriptionfeed.git] / app / proxy / __init__.py
1 import re
2 import requests, requests_cache
3 from flask import Flask, Blueprint, request, Response
4 from flask_login import current_user
5
6 frontend = Blueprint('proxy', __name__)
7
8 def app():
9 app = Flask(__name__)
10 app.register_blueprint(frontend)
11 return app
12
13 # https://github.com/psf/requests/issues/5612
14 def silence_errors(generator):
15 try:
16 yield from generator
17 except requests.exceptions.RequestException:
18 return None
19
20 @frontend.route("/videoplayback/<path:path>")
21 @frontend.route("/videoplayback")
22 def videoplayback(path=None):
23 if path is not None: # seg.ts URL
24 args = path.split("/")[0:-1]
25 host = dict(zip(args[::2], args[1::2])).get('hls_chunk_host')
26 path = "/" + path.replace(';','%3B').replace('=','%3D')
27 else:
28 fvip = request.args.get("fvip", "3")
29 mn = request.args.get("mn", "").split(",")[-1]
30 host = f"r{fvip}---{mn}.googlevideo.com"
31 path = ""
32
33 REQUEST_HEADERS_WHITELIST = {
34 "accept",
35 "accept-encoding",
36 "cache-control",
37 "range",
38 }
39 RESPONSE_HEADERS_WHITELIST = {
40 "accept-ranges",
41 "cache-control",
42 "content-length",
43 "content-range",
44 "content-type",
45 "expires",
46 "x-content-type-options",
47 }
48
49 req_headers = {
50 k:v for k,v in request.headers
51 if k.lower() in REQUEST_HEADERS_WHITELIST
52 }
53 with requests_cache.disabled():
54 r = requests.get(f"https://{host}/videoplayback{path}",
55 request.args.to_dict(),
56 headers=req_headers,
57 stream=True)
58
59 resp_headers = {
60 k:v for k,v in r.headers.items()
61 if k.lower() in RESPONSE_HEADERS_WHITELIST
62 }
63 response = Response(
64 silence_errors(r.iter_content(chunk_size=8192)),
65 status=r.status_code, headers=resp_headers)
66 response.call_on_close(lambda: r.close())
67 response.headers['Access-Control-Allow-Origin'] = cors_origin()
68 return response
69
70 @frontend.route("/api/manifest/hls_playlist/<path:path>")
71 @frontend.route("/api/manifest/hls_variant/<path:path>")
72 def hls_manifest(path):
73 path_fixed = request.path.replace(';','%3B').replace('=','%3D')
74 with requests_cache.disabled():
75 r = requests.get(f"https://manifest.googlevideo.com{path_fixed}")
76 if not r.ok:
77 return "", r.status_code
78
79 rv = re.sub(r"^https://[a-z0-9-]+\.googlevideo\.com", "", r.text, flags=re.M)
80 if "/api/manifest/hls_variant" in request.path:
81 rv = rv + "\n#EXT-X-ENDLIST"
82 return rv, {
83 'Content-Type': 'application/x-mpegURL',
84 'Access-Control-Allow-Origin': cors_origin()
85 }
86
87 def cors_origin():
88 return f"{request.environ.get('wsgi.url_scheme')}://{request.host}"
89
90
91 if __name__ == '__main__':
92 app().run(debug=True)
Imprint / Impressum