diff options
author | James Taylor <user234683@users.noreply.github.com> | 2019-08-10 00:09:03 -0700 |
---|---|---|
committer | James Taylor <user234683@users.noreply.github.com> | 2019-08-10 00:09:03 -0700 |
commit | 163814d35cbcad575d0deec54b31b94e2bbaaebb (patch) | |
tree | 103814ff10a19cfb165b3f8dda93bb2b40292a00 | |
parent | 2e75c6d9603f8a5edf6495f8d4fb3115a67d823c (diff) | |
download | yt-local-163814d35cbcad575d0deec54b31b94e2bbaaebb.tar.lz yt-local-163814d35cbcad575d0deec54b31b94e2bbaaebb.tar.xz yt-local-163814d35cbcad575d0deec54b31b94e2bbaaebb.zip |
Convert subscriptions page to flask framework
-rw-r--r-- | server.py | 2 | ||||
-rw-r--r-- | youtube/subscriptions.py | 160 | ||||
-rw-r--r-- | youtube/templates/subscriptions.html | 97 | ||||
-rw-r--r-- | yt_subscriptions_template.html | 82 |
4 files changed, 162 insertions, 179 deletions
@@ -6,7 +6,7 @@ from youtube import yt_app from youtube import util # these are just so the files get run - they import yt_app and add routes to it -from youtube import watch, search, playlist, channel, local_playlist, comments, post_comment +from youtube import watch, search, playlist, channel, local_playlist, comments, post_comment, subscriptions import settings diff --git a/youtube/subscriptions.py b/youtube/subscriptions.py index fdba114..a238ae4 100644 --- a/youtube/subscriptions.py +++ b/youtube/subscriptions.py @@ -1,21 +1,18 @@ -from youtube import util, yt_data_extract, html_common, channel +from youtube import util, yt_data_extract, channel +from youtube import yt_app import settings -from string import Template + import sqlite3 import os import time import gevent -import html import json import traceback import contextlib import defusedxml.ElementTree -with open('yt_subscriptions_template.html', 'r', encoding='utf-8') as f: - subscriptions_template = Template(f.read()) - -with open('yt_subscription_manager_template.html', 'r', encoding='utf-8') as f: - subscription_manager_template = Template(f.read()) +import flask +from flask import request thumbnails_directory = os.path.join(settings.data_dir, "subscription_thumbnails") @@ -272,16 +269,15 @@ def _get_upstream_videos(channel_id): videos = [] - json_channel_videos = channel.get_grid_items(channel.get_channel_tab(channel_id)[1]['response']) - for i, json_video in enumerate(json_channel_videos): - info = yt_data_extract.renderer_info(json_video['gridVideoRenderer']) - if 'description' not in info: - info['description'] = '' + channel_videos = channel.extract_info(json.loads(channel.get_channel_tab(channel_id)), 'videos')['items'] + for i, video_item in enumerate(channel_videos): + if 'description' not in video_item: + video_item['description'] = '' try: - info['time_published'] = youtube_timestamp_to_posix(info['published']) - i # subtract a few seconds off the videos so they will be in the right order + video_item['time_published'] = youtube_timestamp_to_posix(video_item['published']) - i # subtract a few seconds off the videos so they will be in the right order except KeyError: - print(info) - videos.append((channel_id, info['id'], info['title'], info['duration'], info['time_published'], info['description'])) + print(video_item) + videos.append((channel_id, video_item['id'], video_item['title'], video_item['duration'], video_item['time_published'], video_item['description'])) now = time.time() download_thumbnails_if_necessary(video[1] for video in videos if (now - video[4]) < 30*24*3600) # Don't download thumbnails from videos older than a month @@ -380,7 +376,7 @@ def import_subscriptions(env, start_response): -sub_list_item_template = Template(''' +"""sub_list_item_template = Template(''' <li class="sub-list-item $mute_class"> <input class="sub-list-checkbox" name="channel_ids" value="$channel_id" form="subscription-manager-form" type="checkbox"> <a href="$channel_url" class="sub-list-item-name" title="$channel_name">$channel_name</a> @@ -394,7 +390,7 @@ tag_group_template = Template(''' $sub_list </ol> </li> -''') +''')""" def get_subscription_manager_page(env, start_response): with open_database() as connection: with connection as cursor: @@ -473,8 +469,8 @@ def list_from_comma_separated_tags(string): return [tag.strip() for tag in string.split(',') if tag.strip()] -unsubscribe_list_item_template = Template(''' -<li><a href="$channel_url" title="$channel_name">$channel_name</a></li>''') +"""unsubscribe_list_item_template = Template(''' +<li><a href="$channel_url" title="$channel_name">$channel_name</a></li>''')""" def post_subscription_manager_page(env, start_response): params = env['parameters'] action = params['action'][0] @@ -531,97 +527,69 @@ def post_subscription_manager_page(env, start_response): return b'' - -sidebar_tag_item_template = Template(''' -<li class="sidebar-list-item"> - <span class="sidebar-item-name">$tag_name</span> - <form method="POST" class="sidebar-item-refresh"> - <input type="submit" value="Check"> - <input type="hidden" name="action" value="refresh"> - <input type="hidden" name="type" value="tag"> - <input type="hidden" name="tag_name" value="$tag_name"> - </form> -</li>''') - - -sidebar_channel_item_template = Template(''' -<li class="sidebar-list-item $mute_class"> - <a href="$channel_url" class="sidebar-item-name" title="$channel_name">$channel_name</a> - <form method="POST" class="sidebar-item-refresh"> - <input type="submit" value="Check"> - <input type="hidden" name="action" value="refresh"> - <input type="hidden" name="type" value="channel"> - <input type="hidden" name="channel_id" value="$channel_id"> - </form> -</li>''') - -def get_subscriptions_page(env, start_response): +@yt_app.route('/subscriptions', methods=['GET']) +@yt_app.route('/feed/subscriptions', methods=['GET']) +def get_subscriptions_page(): with open_database() as connection: with connection as cursor: - items_html = '''<nav class="item-grid">\n''' - - for item in _get_videos(cursor, 60, 0): - if item['id'] in downloading_thumbnails: - item['thumbnail'] = util.get_thumbnail_url(item['id']) + videos = [] + for video in _get_videos(cursor, 60, 0): + if video['id'] in downloading_thumbnails: + video['thumbnail'] = util.get_thumbnail_url(video['id']) else: - item['thumbnail'] = util.URL_ORIGIN + '/data/subscription_thumbnails/' + item['id'] + '.jpg' - items_html += html_common.video_item_html(item, html_common.small_video_item_template) - items_html += '''\n</nav>''' - + video['thumbnail'] = util.URL_ORIGIN + '/data/subscription_thumbnails/' + video['id'] + '.jpg' + video['type'] = 'video' + video['item_size'] = 'small' + videos.append(video) - tag_list_html = '' - for tag_name in _get_all_tags(cursor): - tag_list_html += sidebar_tag_item_template.substitute(tag_name = tag_name) + tags = _get_all_tags(cursor) - sub_list_html = '' + subscription_list = [] for channel_name, channel_id, muted in _get_subscribed_channels(cursor): - sub_list_html += sidebar_channel_item_template.substitute( - channel_url = util.URL_ORIGIN + '/channel/' + channel_id, - channel_name = html.escape(channel_name), - channel_id = channel_id, - mute_class = 'muted' if muted else '', - ) - - - - start_response('200 OK', [('Content-type','text/html'),]) - return subscriptions_template.substitute( - header = html_common.get_header(), - items = items_html, - tags = tag_list_html, - sub_list = sub_list_html, - page_buttons = '', - ).encode('utf-8') - -def post_subscriptions_page(env, start_response): - params = env['parameters'] - action = params['action'][0] + subscription_list.append({ + 'channel_url': util.URL_ORIGIN + '/channel/' + channel_id, + 'channel_name': channel_name, + 'channel_id': channel_id, + 'muted': muted, + }) + + return flask.render_template('subscriptions.html', + videos = videos, + tags = tags, + subscription_list = subscription_list, + ) + +@yt_app.route('/subscriptions', methods=['POST']) +@yt_app.route('/feed/subscriptions', methods=['POST']) +def post_subscriptions_page(): + action = request.values['action'] if action == 'subscribe': - if len(params['channel_id']) != len(params['channel_name']): - start_response('400 Bad Request', ()) - return b'400 Bad Request, length of channel_id != length of channel_name' - with_open_db(_subscribe, zip(params['channel_id'], params['channel_name'])) + if len(request.values.getlist('channel_id')) != len(request.values('channel_name')): + return '400 Bad Request, length of channel_id != length of channel_name', 400 + with_open_db(_subscribe, zip(request.values.getlist('channel_id'), request.values.getlist('channel_name'))) elif action == 'unsubscribe': - with_open_db(_unsubscribe, params['channel_id']) + with_open_db(_unsubscribe, request.values.getlist('channel_id')) elif action == 'refresh': - type = params['type'][0] + type = request.values['type'] if type == 'all': check_all_channels() elif type == 'tag': - check_tags(params['tag_name']) + check_tags(request.values.getlist('tag_name')) elif type == 'channel': - check_specific_channels(params['channel_id']) + check_specific_channels(request.values.getlist('channel_id')) else: - start_response('400 Bad Request', ()) - return b'400 Bad Request' - - start_response('204 No Content', ()) - return b'' + flask.abort(400) else: - start_response('400 Bad Request', ()) - return b'400 Bad Request' - start_response('204 No Content', ()) - return b'' + flask.abort(400) + + return '', 204 + + +@yt_app.route('/data/subscription_thumbnails/<thumbnail>') +def serve_subscription_thumbnail(thumbnail): + # .. is necessary because flask always uses the application directory at ./youtube, not the working directory + return flask.send_from_directory(os.path.join('..', thumbnails_directory), thumbnail) + diff --git a/youtube/templates/subscriptions.html b/youtube/templates/subscriptions.html new file mode 100644 index 0000000..a3227b1 --- /dev/null +++ b/youtube/templates/subscriptions.html @@ -0,0 +1,97 @@ +{% set page_title = 'Subscriptions' %} +{% extends "base.html" %} +{% import "common_elements.html" as common_elements %} + +{% block style %} + main{ + display:flex; + flex-direction: row; + } + .item-grid{ + flex-grow: 1; + } + .subscriptions-sidebar{ + flex-basis: 300px; + background-color: #dadada; + border-left: 2px; + } + .sidebar-links{ + display:flex; + justify-content: space-between; + padding-left:10px; + padding-right: 10px; + } + + .sidebar-list{ + list-style: none; + padding-left:10px; + padding-right: 10px; + } + .sidebar-list-item{ + display:flex; + justify-content: space-between; + margin-bottom: 5px; + } + .sub-refresh-list .sidebar-item-name{ + text-overflow: clip; + white-space: nowrap; + overflow: hidden; + max-width: 200px; + } + .muted{ + background-color: #888888; + } +{% endblock style %} + +{% block main %} + <nav class="item-grid"> + {% for video_info in videos %} + {{ common_elements.item(video_info, include_author=false) }} + {% endfor %} + </nav> + + <div class="subscriptions-sidebar"> + <div class="sidebar-links"> + <a href="/youtube.com/subscription_manager" class="sub-manager-link">Subscription Manager</a> + <form method="POST" class="refresh-all"> + <input type="submit" value="Check All"> + <input type="hidden" name="action" value="refresh"> + <input type="hidden" name="type" value="all"> + </form> + </div> + + <hr> + <ol class="sidebar-list tags"> + {% for tag in tags %} + <li class="sidebar-list-item"> + <span class="sidebar-item-name">{{ tag }}</span> + <form method="POST" class="sidebar-item-refresh"> + <input type="submit" value="Check"> + <input type="hidden" name="action" value="refresh"> + <input type="hidden" name="type" value="tag"> + <input type="hidden" name="tag_name" value="{{ tag }}"> + </form> + </li> + {% endfor %} + </ol> + + <ol class="sidebar-list sub-refresh-list"> + {% for subscription in subscription_list %} + <li class="sidebar-list-item {{ 'muted' if subscription['muted'] else '' }}"> + <a href="{{ subscription['channel_url'] }}" class="sidebar-item-name" title="{{ subscription['channel_name'] }}">{{ subscription['channel_name'] }}</a> + <form method="POST" class="sidebar-item-refresh"> + <input type="submit" value="Check"> + <input type="hidden" name="action" value="refresh"> + <input type="hidden" name="type" value="channel"> + <input type="hidden" name="channel_id" value="{{ subscription['channel_id'] }}"> + </form> + </li> + {% endfor %} + </ol> + + </div> + + <nav class="page-button-row"> + {# TODO #} + </nav> +{% endblock main %} diff --git a/yt_subscriptions_template.html b/yt_subscriptions_template.html deleted file mode 100644 index 41493e2..0000000 --- a/yt_subscriptions_template.html +++ /dev/null @@ -1,82 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <meta charset="utf-8"> - <title>Subscriptions</title> - <link href="/youtube.com/shared.css" type="text/css" rel="stylesheet"> - <link href="/youtube.com/favicon.ico" type="image/x-icon" rel="icon"> - <link title="Youtube local" href="/youtube.com/opensearch.xml" rel="search" type="application/opensearchdescription+xml"> - <style type="text/css"> - main{ - display:flex; - flex-direction: row; - } - .item-grid{ - flex-grow: 1; - } - .subscriptions-sidebar{ - flex-basis: 300px; - background-color: #dadada; - border-left: 2px; - } - .sidebar-links{ - display:flex; - justify-content: space-between; - padding-left:10px; - padding-right: 10px; - } - - .sidebar-list{ - list-style: none; - padding-left:10px; - padding-right: 10px; - } - .sidebar-list-item{ - display:flex; - justify-content: space-between; - margin-bottom: 5px; - } - .sub-refresh-list .sidebar-item-name{ - text-overflow: clip; - white-space: nowrap; - overflow: hidden; - max-width: 200px; - } - .muted{ - background-color: #888888; - } - </style> - </head> - <body> -$header - <main> - -$items - - <div class="subscriptions-sidebar"> - <div class="sidebar-links"> - <a href="/youtube.com/subscription_manager" class="sub-manager-link">Subscription Manager</a> - <form method="POST" class="refresh-all"> - <input type="submit" value="Check All"> - <input type="hidden" name="action" value="refresh"> - <input type="hidden" name="type" value="all"> - </form> - </div> - - <hr> - <ol class="sidebar-list tags"> -$tags - </ol> - - <ol class="sidebar-list sub-refresh-list"> -$sub_list - </ol> - - </div> - - <nav class="page-button-row"> -$page_buttons - </nav> - </main> - </body> -</html> |