2 import requests
, requests_cache
3 from flask
import Flask
, Blueprint
, request
, Response
4 from flask_login
import current_user
6 frontend
= Blueprint('proxy', __name__
)
10 app
.register_blueprint(frontend
)
13 # https://github.com/psf/requests/issues/5612
14 def silence_errors(generator
):
17 except requests
.exceptions
.RequestException
:
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 #host = request.args.get('__host__')
29 fvip
= request
.args
.get("fvip", "3")
30 mn
= request
.args
.get("mn", "").split(",")[-1]
31 host
= f
"r{fvip}---{mn}.googlevideo.com"
34 REQUEST_HEADERS_WHITELIST
= {
40 RESPONSE_HEADERS_WHITELIST
= {
47 "x-content-type-options",
51 k
:v
for k
,v
in request
.headers
52 if k
.lower() in REQUEST_HEADERS_WHITELIST
54 with requests_cache
.disabled():
55 r
= requests
.get(f
"https://{host}/videoplayback{path}", request
.args
.to_dict(), headers
=req_headers
, stream
=True)
58 k
:v
for k
,v
in r
.headers
.items()
59 if k
.lower() in RESPONSE_HEADERS_WHITELIST
61 response
= Response(silence_errors(r
.iter_content(chunk_size
=8192)), status
=r
.status_code
, headers
=resp_headers
)
62 response
.call_on_close(lambda: r
.close())
63 response
.headers
['Access-Control-Allow-Origin'] = '*'
66 @frontend.route("/api/manifest/hls_playlist/<path:path>")
67 @frontend.route("/api/manifest/hls_variant/<path:path>")
68 def hls_manifest(path
):
69 with requests_cache
.disabled():
70 path_fixed
= request
.path
.replace(';','%3B').replace('=','%3D')
71 r
= requests
.get(f
"https://manifest.googlevideo.com{path_fixed}", request
.args
.to_dict())
73 return "", r
.status_code
76 for line
in r
.text
.splitlines():
77 if line
.startswith('#'): lines
.append(line
)
78 elif line
.startswith('https://'):
79 scheme
, _
, host
, _path
= line
.split('/', 3)
80 assert '.googlevideo.com' in host
81 #lines.append("/" + _path + "?__host__=" + host)
82 lines
.append("/" + _path
)
83 else: raise StopIteration
84 #if line.startswith('https://manifest.googlevideo.com/'):
87 #rv = rv.replace("https://manifest.googlevideo.com/", f"https://{request.host}/")
88 #rv = re.sub(r"https://([a-z0-9-]+\.googlevideo\.com)", r"https://subscriptions.gir.st/ts-proxy/\1", rv)
89 return rv
, {'content-type': 'application/x-mpegURL', 'Access-Control-Allow-Origin': '*'}
92 @frontend.route("/x-hls/")
93 @frontend.route("/x-hls/<vid>")
94 def xxx(vid
="5qap5aO4i9A"):
95 from ..common
.common
import get_video_info
96 _
, map, _
, _
, _
= get_video_info(vid
, -1)
97 url
= map['hlsManifestUrl'].replace("https://manifest.googlevideo.com", "")
100 <meta charset="utf-8"/>
101 <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
103 video {{ width: 640px; height: 360px; }}
105 <video autoplay preload="none" controls="true">
106 <source src="{url}" type="application/x-mpegURL"/>
109 let vid = document.querySelector('video');
110 if (!vid.canPlayType('application/vnd.apple.mpegurl') && Hls.isSupported()) {{
112 hls.loadSource(document.querySelector("source").src);
113 hls.attachMedia(vid);
119 if __name__
== '__main__':
120 app().run(debug
=True)