Merge branch 'master' into optional_proxy_images

This commit is contained in:
James Taylor 2020-10-12 09:37:13 -07:00 committed by GitHub
commit fd253d9e07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 102 additions and 24 deletions

View File

@ -134,6 +134,13 @@ For security reasons, enabling this is not recommended.''',
'default': True, 'default': True,
'comment': '', 'comment': '',
}), }),
('use_comments_js', {
'label': 'Enable comments.js',
'type': bool,
'default': True,
'comment': '',
}),
('theme', { ('theme', {
'type': int, 'type': int,

View File

@ -5,6 +5,7 @@ import traceback
import re import re
from sys import exc_info from sys import exc_info
yt_app = flask.Flask(__name__) yt_app = flask.Flask(__name__)
yt_app.config['TEMPLATES_AUTO_RELOAD'] = True
yt_app.url_map.strict_slashes = False yt_app.url_map.strict_slashes = False
@ -25,6 +26,7 @@ theme_names = {
def inject_theme_preference(): def inject_theme_preference():
return { return {
'theme_path': '/youtube.com/static/' + theme_names[settings.theme] + '.css', 'theme_path': '/youtube.com/static/' + theme_names[settings.theme] + '.css',
'settings': settings,
} }
@yt_app.template_filter('commatize') @yt_app.template_filter('commatize')

View File

@ -150,7 +150,8 @@ def get_number_of_videos_channel(channel_id):
response = response.decode('utf-8') response = response.decode('utf-8')
match = re.search(r'"numVideosText":\s*{\s*"runs":\s*\[{"text":\s*"([\d,]*) videos"', response) # match = re.search(r'"numVideosText":\s*{\s*"runs":\s*\[{"text":\s*"([\d,]*) videos"', response)
match = re.search(r'"numVideosText".*?([,\d]+)', response)
if match: if match:
return int(match.group(1).replace(',','')) return int(match.group(1).replace(',',''))
else: else:
@ -209,7 +210,7 @@ def get_channel_page_general_url(base_url, tab, request, channel_id=None):
if tab == 'videos' and channel_id: if tab == 'videos' and channel_id:
tasks = ( tasks = (
gevent.spawn(get_number_of_videos_channel, channel_id), gevent.spawn(get_number_of_videos_channel, channel_id),
gevent.spawn(get_channel_tab, channel_id, page_number, sort, 'videos', view) gevent.spawn(get_channel_tab, channel_id, page_number, sort, 'videos', view)
) )
gevent.joinall(tasks) gevent.joinall(tasks)
@ -217,7 +218,7 @@ def get_channel_page_general_url(base_url, tab, request, channel_id=None):
number_of_videos, polymer_json = tasks[0].value, tasks[1].value number_of_videos, polymer_json = tasks[0].value, tasks[1].value
elif tab == 'videos': elif tab == 'videos':
tasks = ( tasks = (
gevent.spawn(get_number_of_videos_general, base_url), gevent.spawn(get_number_of_videos_general, base_url),
gevent.spawn(util.fetch_url, base_url + '/videos?pbj=1&view=0', headers_desktop, debug_name='gen_channel_videos') gevent.spawn(util.fetch_url, base_url + '/videos?pbj=1&view=0', headers_desktop, debug_name='gen_channel_videos')
) )
gevent.joinall(tasks) gevent.joinall(tasks)

View File

@ -27,7 +27,7 @@ from flask import request
def make_comment_ctoken(video_id, sort=0, offset=0, lc='', secret_key=''): def make_comment_ctoken(video_id, sort=0, offset=0, lc='', secret_key=''):
video_id = proto.as_bytes(video_id) video_id = proto.as_bytes(video_id)
secret_key = proto.as_bytes(secret_key) secret_key = proto.as_bytes(secret_key)
page_info = proto.string(4,video_id) + proto.uint(6, sort) page_info = proto.string(4,video_id) + proto.uint(6, sort)
offset_information = proto.nested(4, page_info) + proto.uint(5, offset) offset_information = proto.nested(4, page_info) + proto.uint(5, offset)
@ -41,11 +41,11 @@ def make_comment_ctoken(video_id, sort=0, offset=0, lc='', secret_key=''):
result = proto.nested(2, page_params) + proto.uint(3,6) + proto.nested(6, offset_information) result = proto.nested(2, page_params) + proto.uint(3,6) + proto.nested(6, offset_information)
return base64.urlsafe_b64encode(result).decode('ascii') return base64.urlsafe_b64encode(result).decode('ascii')
def comment_replies_ctoken(video_id, comment_id, max_results=500): def comment_replies_ctoken(video_id, comment_id, max_results=500):
params = proto.string(2, comment_id) + proto.uint(9, max_results) params = proto.string(2, comment_id) + proto.uint(9, max_results)
params = proto.nested(3, params) params = proto.nested(3, params)
result = proto.nested(2, proto.string(2, video_id)) + proto.uint(3,6) + proto.nested(6, params) result = proto.nested(2, proto.string(2, video_id)) + proto.uint(3,6) + proto.nested(6, params)
return base64.urlsafe_b64encode(result).decode('ascii') return base64.urlsafe_b64encode(result).decode('ascii')
@ -187,8 +187,10 @@ def get_comments_page():
'replying': replies, 'replying': replies,
} }
return flask.render_template('comments_page.html', return flask.render_template('comments_page.html',
comments_info = comments_info, comments_info = comments_info,
comment_posting_box_info = comment_posting_box_info, comment_posting_box_info = comment_posting_box_info,
slim = request.args.get('slim', False)
) )

View File

@ -1,4 +1,4 @@
from youtube import util, yt_data_extract, proto from youtube import util, yt_data_extract, proto, local_playlist
from youtube import yt_app from youtube import yt_app
import settings import settings
@ -115,6 +115,7 @@ def get_playlist_page():
video_count = 40 video_count = 40
return flask.render_template('playlist.html', return flask.render_template('playlist.html',
header_playlist_names = local_playlist.get_playlist_names(),
video_list = info.get('items', []), video_list = info.get('items', []),
num_pages = math.ceil(video_count/20), num_pages = math.ceil(video_count/20),
parameters_dictionary = request.args, parameters_dictionary = request.args,

View File

@ -0,0 +1,20 @@
function onClickReplies(e) {
var details = e.target.parentElement;
// e.preventDefault();
console.log("loading replies ..");
doXhr(details.getAttribute("src") + "&slim=1", (html) => {
var div = details.querySelector(".comment_page");
div.innerHTML = html;
});
details.removeEventListener('click', onClickReplies);
}
window.addEventListener('DOMContentLoaded', function() {
QA("details.replies").forEach(details => {
details.addEventListener('click', onClickReplies);
details.addEventListener('auxclick', (e) => {
if (e.target.parentElement !== details) return;
if (e.button == 1) window.open(details.getAttribute("src"));
});
});
});

View File

@ -1,4 +1,5 @@
Q = document.querySelector.bind(document); Q = document.querySelector.bind(document);
QA = document.querySelectorAll.bind(document);
function text(msg) { return document.createTextNode(msg); } function text(msg) { return document.createTextNode(msg); }
function clearNode(node) { while (node.firstChild) node.removeChild(node.firstChild); } function clearNode(node) { while (node.firstChild) node.removeChild(node.firstChild); }
function toTimestamp(seconds) { function toTimestamp(seconds) {
@ -36,6 +37,19 @@ function getDefaultTranscriptTrackIdx() {
return textTracks.length - 1; return textTracks.length - 1;
} }
function doXhr(url, callback=null) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = (e) => {
let ok = xhr.status >= 200 && xhr.status < 300;
if (ok) callback(e.currentTarget.response);
else alert(`${xhr.responseURL} status code: ${xhr.status}`);
}
xhr.send();
return xhr;
}
window.addEventListener('DOMContentLoaded', function() { window.addEventListener('DOMContentLoaded', function() {
cur_track_idx = getDefaultTranscriptTrackIdx(); cur_track_idx = getDefaultTranscriptTrackIdx();
}); });

View File

@ -20,7 +20,8 @@
<header> <header>
<a href="/youtube.com" id="home-link">Home</a> <a href="/youtube.com" id="home-link">Home</a>
<form id="site-search" action="/youtube.com/search"> <form id="site-search" action="/youtube.com/search">
<input type="search" name="query" class="search-box" value="{{ search_box_value }}"> <input type="search" name="query" class="search-box" value="{{ search_box_value }}"
{{ "autofocus" if request.path == "/" else "" }}>
<button type="submit" value="Search" class="search-button">Search</button> <button type="submit" value="Search" class="search-button">Search</button>
<div class="dropdown"> <div class="dropdown">
<button class="dropdown-label">Options</button> <button class="dropdown-label">Options</button>

View File

@ -22,7 +22,14 @@
<span class="likes">{{ comment['likes_text'] if comment['like_count'] else ''}}</span> <span class="likes">{{ comment['likes_text'] if comment['like_count'] else ''}}</span>
<div class="bottom-row"> <div class="bottom-row">
<a href="{{ comment['replies_url'] }}" class="replies">{{ comment['view_replies_text'] }}</a> {% if settings.use_comments_js and comment['reply_count'] %}
<details class="replies" src="{{ comment['replies_url'] }}">
<summary>{{ comment['view_replies_text'] }}</summary>
<div class="comment_page">loading..</div>
</details>
{% else %}
<a href="{{ comment['replies_url'] }}" class="replies">{{ comment['view_replies_text'] }}</a>
{% endif %}
{% if 'delete_url' is in comment %} {% if 'delete_url' is in comment %}
<a href="{{ comment['delete_url'] }}" target="_blank">Delete</a> <a href="{{ comment['delete_url'] }}" target="_blank">Delete</a>
{% endif %} {% endif %}

View File

@ -1,13 +1,16 @@
{% set page_title = ('Replies' if comments_info['is_replies'] else 'Comments page ' + comments_info['page_number']) %} {% set page_title = ('Replies' if comments_info['is_replies'] else 'Comments page ' + comments_info['page_number']) %}
{% extends "base.html" %} {% import "comments.html" as comments with context %}
{% import "comments.html" as comments %}
{% block style %} {% if not slim %}
.comments-area{ {% extends "base.html" %}
margin: auto;
width:640px; {% block style %}
} .comments-area{
{% endblock style %} margin: auto;
width:640px;
}
{% endblock style %}
{% endif %}
{% block main %} {% block main %}
@ -24,7 +27,9 @@
</section> </section>
{% endif %} {% endif %}
{{ comments.comment_posting_box(comment_posting_box_info) }} {% if not slim %}
{{ comments.comment_posting_box(comment_posting_box_info) }}
{% endif %}
{% if not comments_info['is_replies'] %} {% if not comments_info['is_replies'] %}
<div class="comment-links"> <div class="comment-links">
@ -36,13 +41,18 @@
<div class="comments"> <div class="comments">
{% for comment in comments_info['comments'] %} {% for comment in comments_info['comments'] %}
{{ comments.render_comment(comment, comments_info['include_avatars']) }} {{ comments.render_comment(comment, comments_info['include_avatars'], slim) }}
{% endfor %} {% endfor %}
</div> </div>
{% if 'more_comments_url' is in comments_info %} {% if 'more_comments_url' is in comments_info %}
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a> <a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
{% endif %} {% endif %}
</section> </section>
{% if settings.use_comments_js %}
<script src="/youtube.com/static/js/common.js"></script>
<script src="/youtube.com/static/js/comments.js"></script>
{% endif %}
{% endblock main %} {% endblock main %}

View File

@ -1,7 +1,7 @@
{% set page_title = title %} {% set page_title = title %}
{% extends "base.html" %} {% extends "base.html" %}
{% import "common_elements.html" as common_elements %} {% import "common_elements.html" as common_elements %}
{% import "comments.html" as comments %} {% import "comments.html" as comments with context %}
{% block style %} {% block style %}
details > summary{ details > summary{
background-color: var(--interface-color); background-color: var(--interface-color);
@ -14,6 +14,18 @@
text-decoration: underline; text-decoration: underline;
} }
details.replies > summary{
background-color: var(--interface-color);
border-style: outset;
border-width: 1px;
font-weight: bold;
padding-bottom: 0px;
}
details.replies .comment{
width: 600px;
}
.playability-error{ .playability-error{
height: 360px; height: 360px;
width: 640px; width: 640px;
@ -678,8 +690,11 @@ Reload without invidious (for usage of new identity button).</a>
{% endif %} {% endif %}
<script src="/youtube.com/static/js/common.js"></script> <script src="/youtube.com/static/js/common.js"></script>
<script src="/youtube.com/static/js/transcript-table.js"></script>
{% if settings.use_video_hotkeys %} {% if settings.use_video_hotkeys %}
<script src="/youtube.com/static/js/hotkeys.js"></script> <script src="/youtube.com/static/js/hotkeys.js"></script>
{% endif %} {% endif %}
<script src="/youtube.com/static/js/transcript-table.js"></script> {% if settings.use_comments_js %}
<script src="/youtube.com/static/js/comments.js"></script>
{% endif %}
{% endblock main %} {% endblock main %}

View File

@ -470,8 +470,6 @@ def get_watch_page(video_id=None):
comment_count = info['comment_count'], comment_count = info['comment_count'],
comments_disabled = info['comments_disabled'], comments_disabled = info['comments_disabled'],
settings = settings,
video_height = video_height, video_height = video_height,
video_width = video_width, video_width = video_width,
theater_video_target_width = theater_video_target_width, theater_video_target_width = theater_video_target_width,