From c667ebd872fcc692df9cb7e4453f789455ce2520 Mon Sep 17 00:00:00 2001 From: Ethan Dalool Date: Wed, 23 Jan 2019 21:22:09 -0800 Subject: [PATCH] Batch requests & filterbox & update metadata - Download / Ignore on multiple videos is batched into a single request, like it should have been all along. - Text box at the top of the page lets you search for terms live instead of loading various ?q urls. - Doing a force refresh will actually update the metadata of old videos instead of skipping them. --- frontends/ycdl_flask/templates/channel.html | 116 +++++++++++++----- frontends/ycdl_flask/templates/channels.html | 2 +- frontends/ycdl_flask/ycdl_flask/ycdl_flask.py | 26 ++-- ycdl/ycdl.py | 46 ++++--- 4 files changed, 132 insertions(+), 58 deletions(-) diff --git a/frontends/ycdl_flask/templates/channel.html b/frontends/ycdl_flask/templates/channel.html index ed780e9..329fa59 100644 --- a/frontends/ycdl_flask/templates/channel.html +++ b/frontends/ycdl_flask/templates/channel.html @@ -12,10 +12,11 @@ { display: flex; flex-direction: column; - width: 1440px; + min-width: 200px; + width: 100%; + max-width: 1440px; margin-left: auto; margin-right: auto; - max-width: 100%; } .video_card { @@ -89,6 +90,9 @@ {% endif %} {{videos|length}} items +
+
{{videos|length}} items
+
{% for video in videos %}
- {{video['_published_str']}} - {{video['title']}} + {{video['_published_str']}} - {{video['title']}} ({{video['duration'] | seconds_to_hms}}) {% if channel is none %} (Chan) @@ -145,7 +149,38 @@ diff --git a/frontends/ycdl_flask/templates/channels.html b/frontends/ycdl_flask/templates/channels.html index 9d4c0a4..cd4d1d3 100644 --- a/frontends/ycdl_flask/templates/channels.html +++ b/frontends/ycdl_flask/templates/channels.html @@ -79,7 +79,7 @@ function _new_channel_submit() { if (box.value !== "") { - refresh_channel(box.value, false, function(){location.reload()}); + refresh_channel(box.value, true, function(){location.reload()}); } } diff --git a/frontends/ycdl_flask/ycdl_flask/ycdl_flask.py b/frontends/ycdl_flask/ycdl_flask/ycdl_flask.py index 6201429..d18b537 100644 --- a/frontends/ycdl_flask/ycdl_flask/ycdl_flask.py +++ b/frontends/ycdl_flask/ycdl_flask/ycdl_flask.py @@ -187,21 +187,26 @@ def get_channel(channel_id=None, download_filter=None): @site.route('/mark_video_state', methods=['POST']) def post_mark_video_state(): - if 'video_id' not in request.form or 'state' not in request.form: + if 'video_ids' not in request.form or 'state' not in request.form: flask.abort(400) - video_id = request.form['video_id'] + video_ids = request.form['video_ids'] state = request.form['state'] try: - youtube.mark_video_state(video_id, state) + video_ids = video_ids.split(',') + for video_id in video_ids: + youtube.mark_video_state(video_id, state, commit=False) + youtube.sql.commit() except ycdl.NoSuchVideo: + youtube.rollback() traceback.print_exc() flask.abort(404) except ycdl.InvalidVideoState: + youtube.rollback() flask.abort(400) - return make_json_response({'video_id': video_id, 'state': state}) + return make_json_response({'video_ids': video_ids, 'state': state}) @site.route('/refresh_all_channels', methods=['POST']) def post_refresh_all_channels(): @@ -232,15 +237,20 @@ def post_refresh_channel(): @site.route('/start_download', methods=['POST']) def post_start_download(): - if 'video_id' not in request.form: + if 'video_ids' not in request.form: flask.abort(400) - video_id = request.form['video_id'] + video_ids = request.form['video_ids'] try: - youtube.download_video(video_id) + video_ids = video_ids.split(',') + for video_id in video_ids: + youtube.download_video(video_id, commit=False) + youtube.sql.commit() + except ycdl.ytapi.VideoNotFound: + youtube.rollback() flask.abort(404) - return make_json_response({'video_id': video_id, 'state': 'downloaded'}) + return make_json_response({'video_ids': video_ids, 'state': 'downloaded'}) if __name__ == '__main__': pass diff --git a/ycdl/ycdl.py b/ycdl/ycdl.py index 77f72e3..6df4207 100644 --- a/ycdl/ycdl.py +++ b/ycdl/ycdl.py @@ -5,6 +5,9 @@ import sqlite3 from . import helpers from . import ytapi +from voussoirkit import sqlhelpers + + def YOUTUBE_DL_COMMAND(video_id): path = 'D:\\Incoming\\ytqueue\\{id}.ytqueue'.format(id=video_id) open(path, 'w') @@ -151,7 +154,7 @@ class YCDL: return None return fetch[SQL_CHANNEL['directory']] - def download_video(self, video, force=False): + def download_video(self, video, commit=True, force=False): ''' Execute the `YOUTUBE_DL_COMMAND`, within the channel's associated directory if applicable. @@ -194,7 +197,8 @@ class YCDL: os.chdir(current_directory) self.cur.execute('UPDATE videos SET download = "downloaded" WHERE id == ?', [video_id]) - self.sql.commit() + if commit: + self.sql.commit() def get_channel(self, channel_id): self.cur.execute('SELECT * FROM channels WHERE id == ?', [channel_id]) @@ -251,24 +255,36 @@ class YCDL: if add_channel: self.add_channel(video.author_id, get_videos=False, commit=False) self.cur.execute('SELECT * FROM videos WHERE id == ?', [video.id]) + fetch = self.cur.fetchone() - if fetch is not None: - return {'new': False, 'row': fetch} + existing = fetch is not None - data = [None] * len(SQL_VIDEO) - data[SQL_VIDEO['id']] = video.id - data[SQL_VIDEO['published']] = video.published - data[SQL_VIDEO['author_id']] = video.author_id - data[SQL_VIDEO['title']] = video.title - data[SQL_VIDEO['description']] = video.description - data[SQL_VIDEO['duration']] = video.duration - data[SQL_VIDEO['thumbnail']] = video.thumbnail['url'] - data[SQL_VIDEO['download']] = 'pending' + download_status = 'pending' if not existing else fetch[SQL_VIDEO['download']] + + data = { + 'id': video.id, + 'published': video.published, + 'author_id': video.author_id, + 'title': video.title, + 'description': video.description, + 'duration': video.duration, + 'thumbnail': video.thumbnail['url'], + 'download': download_status, + } + + if existing: + (qmarks, bindings) = sqlhelpers.update_filler(data, where_key='id') + query = f'UPDATE videos {qmarks}' + else: + (qmarks, bindings) = sqlhelpers.insert_filler(SQL_VIDEO_COLUMNS, data) + query = f'INSERT INTO videos VALUES({qmarks})' + + self.cur.execute(query, bindings) - self.cur.execute('INSERT INTO videos VALUES(?, ?, ?, ?, ?, ?, ?, ?)', data) if commit: self.sql.commit() - return {'new': True, 'row': data} + + return {'new': not existing, 'row': data} def mark_video_state(self, video_id, state, commit=True): '''