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",
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("""
<!DOCTYPE html>
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"))
navigator: {
userAgent: ''
},
+ XMLHttpRequest: class XMLHttpRequest {},
matchMedia: () => ({matches: () => {}, media: ''}),
signature: %(signature)s,
transformed_signature: null,
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)
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
if not video_url:
return None, None
- filename = sanitize_filename(page.title)
+ filename = sanitize_filename(player_config["args"]["title"])
filename += "." + 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)
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
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)
url=url,
msg="<p class='error'>Sorry, there was an error: %s</p>" % cgi.escape(e.args[0])
)
+ except NotYouTube:
+ print_form(
+ url=url,
+ msg="<p class='error'>Sorry, that does not look like a YouTube page!</p>"
+ )
except Exception as e:
print_form(
url=url,
- msg="<p class='error'>Sorry, there was an error. Check your URL?</p>"
+ msg="<p class='error'>Sorry, there was an unknown error.</p>"
)
return
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()