From ac1319e7204200577eb8aba74655de8b3e2d4f0a Mon Sep 17 00:00:00 2001
From: James Taylor <user234683@users.noreply.github.com>
Date: Mon, 16 Jul 2018 02:05:46 -0700
Subject: Support for downloading video in all available formats

---
 youtube/shared.css     | 38 ++++++++++++++++++++++++++++++++------
 youtube/watch.py       | 48 ++++++++++++++++++++++++++++++++++--------------
 yt_watch_template.html |  6 ++++++
 3 files changed, 72 insertions(+), 20 deletions(-)

diff --git a/youtube/shared.css b/youtube/shared.css
index 33acb4f..6803e05 100644
--- a/youtube/shared.css
+++ b/youtube/shared.css
@@ -1,4 +1,4 @@
-h1, h2, h3, h4, h5, h6, div{
+h1, h2, h3, h4, h5, h6, div, button{
     margin:0;
     padding:0;
     
@@ -32,9 +32,6 @@ body{
         grid-row: 2;
     }
 
-button{
-    padding:0;  /* Fuck browser-specific styling. Fix your shit mozilla */
-}
 address{
     font-style:normal;
 }
@@ -126,7 +123,7 @@ address{
 
 .full-item{
     display: grid;
-    grid-template-rows: 0fr 0fr 0fr 0fr 0fr;
+    grid-template-rows: 0fr 0fr 0fr 0fr 20px 0fr 0fr;
     grid-template-columns: 1fr 1fr;
     align-content: start;
 }
@@ -372,4 +369,33 @@ address{
         border-width: 2px;
         font-weight: bold;
         text-align: center;
-    }
\ No newline at end of file
+    }
+
+
+.dropdown{
+    z-index:1;
+    justify-self:start;
+    min-width:0px;
+}
+
+    .dropdown-label{
+        background-color: #e9e9e9;
+        border-style: outset;
+        border-width: 2px;
+        font-weight: bold;
+    }
+
+    .dropdown-content{
+        display:none;
+        background-color: #e9e9e9;
+    }
+    .dropdown:hover .dropdown-content {
+        display: grid;
+        grid-auto-rows:30px;
+    }
+        .dropdown-content a{
+            white-space: nowrap;
+            display:grid;
+            grid-template-columns: 60px 90px auto;
+            max-height: 1.2em;
+        }
\ No newline at end of file
diff --git a/youtube/watch.py b/youtube/watch.py
index 5bf6ebb..94e1e78 100644
--- a/youtube/watch.py
+++ b/youtube/watch.py
@@ -211,22 +211,28 @@ def watch_page_related_playlist_info(item):
 
     
 def sort_formats(info):
-    info['formats'].sort(key=lambda x: default_multi_get(_formats, x['format_id'], 'height', default=0))
-    for index, format in enumerate(info['formats']):
+    sorted_formats = info['formats'].copy()
+    sorted_formats.sort(key=lambda x: default_multi_get(_formats, x['format_id'], 'height', default=0))
+    for index, format in enumerate(sorted_formats):
         if default_multi_get(_formats, format['format_id'], 'height', default=0) >= 360:
             break
-    info['formats'] = info['formats'][index:] + info['formats'][0:index]
-    info['formats'] = [format for format in info['formats'] if format['acodec'] != 'none' and format['vcodec'] != 'none']
-    
-def formats_html(info):
+    sorted_formats = sorted_formats[index:] + sorted_formats[0:index]
+    sorted_formats = [format for format in info['formats'] if format['acodec'] != 'none' and format['vcodec'] != 'none']
+    return sorted_formats
+
+source_tag_template = Template('''
+<source src="$src" type="$type">''')
+def formats_html(formats):
     result = ''
-    for format in info['formats']:
+    for format in formats:
         result += source_tag_template.substitute(
             src=format['url'],
             type='audio/' + format['ext'] if format['vcodec'] == "none" else 'video/' + format['ext'],
         )
     return result
-    
+
+
+
 def choose_format(info):
     suitable_formats = []
     with open('teste.txt', 'w', encoding='utf-8') as f:
@@ -279,14 +285,16 @@ def subtitles_html(info):
 
 
 more_comments_template = Template('''<a class="page-button more-comments" href="$url">More comments</a>''')
-source_tag_template = Template('''
-<source src="$src" type="$type">''')
+
+download_link_template = Template('''
+<a href="$url"> <span>$ext</span> <span>$resolution</span> <span>$note</span></a>''')
 
 def get_watch_page(query_string):
         id = urllib.parse.parse_qs(query_string)['v'][0]
+        downloader = YoutubeDL(params={'youtube_include_dash_manifest':False})
         tasks = (
             gevent.spawn(comments.video_comments, id ), 
-            gevent.spawn(YoutubeDL(params={'youtube_include_dash_manifest':False}).extract_info, "https://www.youtube.com/watch?v=" + id, download=False)
+            gevent.spawn(downloader.extract_info, "https://www.youtube.com/watch?v=" + id, download=False)
         )
         gevent.joinall(tasks)
         comments_info, info = tasks[0].value, tasks[1].value
@@ -300,7 +308,7 @@ def get_watch_page(query_string):
         #info = YoutubeDL().extract_info(url, download=False)
         
         #chosen_format = choose_format(info)
-        sort_formats(info)
+        sorted_formats = sort_formats(info)
         
         video_info = {
             "duration": common.seconds_to_timestamp(info["duration"]),
@@ -318,7 +326,18 @@ def get_watch_page(query_string):
             related_videos_html = get_related_items_html(info)
         else:
             related_videos_html = ''
-        
+
+
+
+        download_options = ''
+        for format in info['formats']:
+            download_options += download_link_template.substitute(
+                url        = html.escape(format['url']),
+                ext         = html.escape(format['ext']),
+                resolution  = html.escape(downloader.format_resolution(format)),
+                note        = html.escape(downloader._format_note(format)),
+            )
+
         page = yt_watch_template.substitute(
             video_title             = html.escape(info["title"]),
             page_title              = html.escape(info["title"]),
@@ -329,9 +348,10 @@ def get_watch_page(query_string):
             views           = (lambda x: '{:,}'.format(x) if x is not None else "")(info.get("view_count", None)),
             likes           = (lambda x: '{:,}'.format(x) if x is not None else "")(info.get("like_count", None)),
             dislikes        = (lambda x: '{:,}'.format(x) if x is not None else "")(info.get("dislike_count", None)),
+            download_options        = download_options,
             video_info              = html.escape(json.dumps(video_info)),
             description             = html.escape(info["description"]),
-            video_sources           = formats_html(info) + subtitles_html(info),
+            video_sources           = formats_html(sorted_formats) + subtitles_html(info),
             related                 = related_videos_html,
             comments                = comments_html,
             more_comments_button    = more_comments_button,
diff --git a/yt_watch_template.html b/yt_watch_template.html
index 515d953..58b3959 100644
--- a/yt_watch_template.html
+++ b/yt_watch_template.html
@@ -67,6 +67,12 @@ $video_sources
 
                     <time datetime="$upload_date">Published on $upload_date</time>
                     <span class="likes-dislikes">$likes likes $dislikes dislikes</span>
+                    <div class="dropdown">
+                        <button class="dropdown-label">Download</button>
+                        <div class="dropdown-content">
+$download_options
+                        </div>
+                    </div>
                     <input class="checkbox" name="video_info_list" value="$video_info" form="playlist-add" type="checkbox">
 
                     <span class="description">$description</span>
-- 
cgit v1.2.3