X-Git-Url: https://code.delx.au/youtube-cgi/blobdiff_plain/0353143a6d35c80ee24acd3cf8f3502743eaab56..7ee672be8998bfa85a8552f0e9c129d241e11f50:/youtube.cgi diff --git a/youtube.cgi b/youtube.cgi index b94febf..ef7b608 100755 --- a/youtube.cgi +++ b/youtube.cgi @@ -15,8 +15,7 @@ import urllib.parse import urllib.request -MAX_MEMORY_BYTES = 128 * 1024*1024 -USER_AGENT = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1" +USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0" MIMETYPES = { "video/mp4": "mp4", @@ -36,8 +35,11 @@ QUALITIES = { class VideoUnavailable(Exception): pass +class NotYouTube(Exception): + pass + def print_form(url="", msg=""): - script_url = "http://%s%s" % (os.environ["HTTP_HOST"], os.environ["REQUEST_URI"]) + script_url = "https://%s%s" % (os.environ["HTTP_HOST"], os.environ["REQUEST_URI"]) sys.stdout.write("Content-Type: text/html\r\n\r\n") sys.stdout.write(""" @@ -103,6 +105,16 @@ def urlopen(url, offset=None): assert start == offset return res +def validate_url(url): + parsed_url = urllib.parse.urlparse(url) + scheme_ok = parsed_url.scheme == "https" + host_ok = parsed_url.netloc.lstrip("www.") in ["youtube.com", "youtu.be"] + + if scheme_ok and host_ok: + return + else: + raise NotYouTube() + def parse_url(url, parser): f = urlopen(url) parser.feed(f.read().decode("utf-8")) @@ -214,6 +226,7 @@ def decode_signature(js_url, signature): p.stdin.close() transformed_signature = p.stdout.read().decode("utf-8").strip() + transformed_signature = urllib.parse.unquote(transformed_signature) if p.wait() != 0: raise Exception("js failed to execute: %d" % p.returncode) @@ -253,7 +266,8 @@ def get_best_video(player_config): signature = None if signature: - video_url = append_to_qs(video_url, {"signature": signature}) + sp = url_data.get("sp", ["signature"])[0] + video_url = append_to_qs(video_url, {sp: signature}) best_url = video_url best_quality = quality @@ -278,21 +292,24 @@ def get_video_url(page): if not video_url: return None, None - filename = sanitize_filename(page.title) - filename += "." + extension + title = player_config["args"].get("title", None) + if not title: + title = json.loads(player_config["args"]["player_response"])["videoDetails"]["title"] + if not title: + title = "Unknown title" + + filename = sanitize_filename(title) + "." + extension return video_url, filename class YouTubeVideoPageParser(html.parser.HTMLParser): def __init__(self): super().__init__() - self.title = None self.unavailable_message = None self.scripts = [] def handle_starttag(self, tag, attrs): attrs = dict(attrs) - self._handle_title(tag, attrs) self._handle_unavailable_message(tag, attrs) self._handle_script(tag, attrs) @@ -302,13 +319,6 @@ class YouTubeVideoPageParser(html.parser.HTMLParser): def _ignore_data(self, _): pass - def _handle_title(self, tag, attrs): - if tag == "title": - self.handle_data = self._handle_title_data - - def _handle_title_data(self, data): - self.title = data.strip() - def _handle_unavailable_message(self, tag, attrs): if attrs.get("id", None) == "unavailable-message": self.handle_data = self._handle_unavailable_message_data @@ -343,11 +353,12 @@ def cgimain(): try: url = args["url"][0] except: - print_form(url="http://www.youtube.com/watch?v=FOOBAR") + print_form(url="https://www.youtube.com/watch?v=FOOBAR") return try: page = YouTubeVideoPageParser() + validate_url(url) parse_url(url, page) video_url, filename = get_video_url(page) video_data = urlopen(video_url) @@ -356,10 +367,15 @@ def cgimain(): url=url, msg="

Sorry, there was an error: %s

" % cgi.escape(e.args[0]) ) + except NotYouTube: + print_form( + url=url, + msg="

Sorry, that does not look like a YouTube page!

" + ) except Exception as e: print_form( url=url, - msg="

Sorry, there was an error. Check your URL?

" + msg="

Sorry, there was an unknown error.

" ) return @@ -411,7 +427,7 @@ def main(): try: url = sys.argv[1] except: - print("Usage: %s http://youtube.com/watch?v=FOOBAR" % sys.argv[0], file=sys.stderr) + print("Usage: %s https://youtube.com/watch?v=FOOBAR" % sys.argv[0], file=sys.stderr) sys.exit(1) page = YouTubeVideoPageParser()