2 import requests
, requests_cache
3 from flask
import Flask
, Blueprint
, request
, Response
, g
4 from flask_login
import current_user
5 from werkzeug
.exceptions
import Forbidden
7 from ..common
.common
import cf
9 frontend
= Blueprint('proxy', __name__
)
13 app
.register_blueprint(frontend
)
16 # https://github.com/psf/requests/issues/5612
17 def silence_errors(generator
):
20 except requests
.exceptions
.RequestException
:
23 @frontend.route("/videoplayback/<path:path>")
24 @frontend.route("/videoplayback")
25 def videoplayback(path
=None):
26 if path
is not None: # seg.ts URL
27 args
= path
.split("/")[0:-1]
28 host
= dict(zip(args
[::2], args
[1::2])).get('hls_chunk_host')
29 path
= "/" + path
.replace(';','%3B').replace('=','%3D')
31 fvip
= request
.args
.get("fvip", "3")
32 mn
= request
.args
.get("mn", "").split(",")[-1]
33 host
= f
"r{fvip}---{mn}.googlevideo.com"
36 REQUEST_HEADERS_WHITELIST
= {
42 RESPONSE_HEADERS_WHITELIST
= {
49 "x-content-type-options",
53 k
:v
for k
,v
in request
.headers
54 if k
.lower() in REQUEST_HEADERS_WHITELIST
56 with requests_cache
.disabled():
58 r
= requests
.get(f
"https://{host}/videoplayback{path}",
59 request
.args
.to_dict(),
62 except requests
.exceptions
.ConnectionError
:
63 return f
"unable to connect to {host}", 502
66 k
:v
for k
,v
in r
.headers
.items()
67 if k
.lower() in RESPONSE_HEADERS_WHITELIST
70 silence_errors(r
.iter_content(chunk_size
=8192)),
71 status
=r
.status_code
, headers
=resp_headers
)
72 response
.call_on_close(lambda: r
.close())
73 response
.headers
['Access-Control-Allow-Origin'] = cors_origin()
76 @frontend.route("/api/manifest/hls_playlist/<path:path>")
77 @frontend.route("/api/manifest/hls_variant/<path:path>")
78 def hls_manifest(path
):
79 path_fixed
= request
.path
.replace(';','%3B').replace('=','%3D')
80 with requests_cache
.disabled():
81 r
= requests
.get(f
"https://manifest.googlevideo.com{path_fixed}")
83 return "", r
.status_code
85 rv
= re
.sub(r
"^https://[a-z0-9-]+\.googlevideo\.com", "", r
.text
, flags
=re
.M
)
86 if "/api/manifest/hls_variant" in request
.path
:
87 rv
= rv
+ "\n#EXT-X-ENDLIST"
89 'Content-Type': 'application/x-mpegURL',
90 'Access-Control-Allow-Origin': cors_origin()
94 return f
"{request.environ.get('wsgi.url_scheme')}://{request.host}"
97 """ the proxy can be restricted to logged-in users by a config flag """
98 require_auth
= cf
.getboolean('proxy', 'require_auth', fallback
=False)
99 is_authd
= not current_user
.is_anonymous
100 return is_authd
or not require_auth
102 @frontend.before_request
104 if not proxy_allowed():
105 raise Forbidden("limited to authenticated users")
107 @frontend.before_app_request
108 def propagate_auth_requirement():
109 g
.proxy_on
= proxy_allowed()
112 if __name__
== '__main__':
113 app().run(debug
=True)