Skip to content

Feature: Reply Counts #5168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 74 additions & 15 deletions assets/js/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function show_youtube_replies(event) {
function get_youtube_comments() {
var comments = document.getElementById('comments');

var fallback = comments.innerHTML;
var originalHTML = comments.innerHTML;
comments.innerHTML = spinnerHTML;

var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
Expand All @@ -65,10 +65,10 @@ function get_youtube_comments() {
'&thin_mode=' + video_data.preferences.thin_mode;

if (video_data.ucid) {
url += '&ucid=' + video_data.ucid
url += '&ucid=' + video_data.ucid;
}

var onNon200 = function (xhr) { comments.innerHTML = fallback; };
var onNon200 = function (xhr) { comments.innerHTML = originalHTML; };
if (video_data.params.comments[1] === 'youtube')
onNon200 = function (xhr) {};

Expand Down Expand Up @@ -119,56 +119,115 @@ function get_youtube_comments() {
});
}

function format_count_load_more(content, current_count, total_count) {
var load_more_end_str = content.split('data-load-more');
if (load_more_end_str.length === 1)
return [content, false]; // no Load More button, return false for has_more_replies
load_more_end_str = load_more_end_str[1].split('\n')[0]; // ' >("Load more" translated string)</a>'
var slice_index = content.indexOf(load_more_end_str) + load_more_end_str.length - 4; // backtrace </a>
var num_remaining = total_count - current_count;
return [
// More replies may have been added since initally loading parent comment
content.slice(0, slice_index) + ' (+' + (num_remaining > 0 ? num_remaining : '?') + ')' + content.slice(slice_index),
true // Load More button present, return true for has_more_replies
];
}

function format_count_toggle_replies_button(toggle_reply_button, current_count, total_count, has_more_replies) {
if (!has_more_replies) {
// Accept the final current count as the total (comments may have been added or removed since loading)
total_count = current_count;
} else if (current_count >= total_count) {
// An unknown number of new replies have been added since retrieving data
total_count = '?';
}

['data-sub-text', 'data-inner-text'].forEach(attr => {
toggle_reply_button.setAttribute(attr,
toggle_reply_button.getAttribute(attr)
.replace(/\d+\/\d+/, total_count === current_count
? total_count
: current_count + '/' + total_count
)
);
});
toggle_reply_button.textContent = toggle_reply_button.title = toggle_reply_button.getAttribute('data-sub-text');
}

function get_youtube_replies(target, load_more, load_replies) {
var continuation = target.getAttribute('data-continuation');

var body = target.parentNode.parentNode;
var fallback = body.innerHTML;
var originalHTML = body.innerHTML;
body.innerHTML = spinnerHTML;
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
var baseUrl = video_data.base_url || '/api/v1/comments/' + video_data.id
var url = baseUrl +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode +
'&continuation=' + continuation;

if (video_data.ucid) {
url += '&ucid=' + video_data.ucid
url += '&ucid=' + video_data.ucid;
}
if (load_replies) url += '&action=action_get_comment_replies';

helpers.xhr('GET', url, {}, {
on200: function (response) {
var num_incoming_replies = response.contentHtml.split('channel-profile').length - 1;
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.insertAdjacentHTML('beforeend', response.contentHtml);
body.removeChild(body.lastElementChild); // Remove spinner

var toggle_replies_button = body.parentNode.firstChild.firstChild;
if (!toggle_replies_button) {
body.insertAdjacentHTML('beforeend', response.contentHtml); 
return;
}

var [prev_num_replies, num_total_replies] = toggle_replies_button.textContent.match(/\d+/g);
prev_num_replies -= 0; num_total_replies -= 0; // convert to integers
var num_current_replies = prev_num_replies + num_incoming_replies;

var [newHTML, has_more_replies] = format_count_load_more(response.contentHtml, num_current_replies, num_total_replies);
format_count_toggle_replies_button(toggle_replies_button, num_current_replies, num_total_replies, has_more_replies);

body.insertAdjacentHTML('beforeend', newHTML);
} else {
body.removeChild(body.lastElementChild);
// loads only once for each comment when first opening their replies
body.removeChild(body.lastElementChild); // Remove spinner

var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);

a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', video_data.hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text);
a.textContent = video_data.hide_replies_text;

var num_total_replies = originalHTML.split('data-load-replies')[1].match(/\d+/)[0] - 0;
// Replaced later with real counts
var num_replies_text = ' (0/0 ' + video_data.replies_loaded_text + ')';
var hide_replies_text = video_data.hide_replies_text + num_replies_text;
a.setAttribute('data-sub-text', hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text + num_replies_text);
a.textContent = hide_replies_text;

var div = document.createElement('div');
div.innerHTML = response.contentHtml;
var [newHTML, has_more_replies] = format_count_load_more(response.contentHtml, num_incoming_replies, num_total_replies);
format_count_toggle_replies_button(a, num_incoming_replies, num_total_replies, has_more_replies);

div.innerHTML = newHTML;

body.appendChild(p);
body.appendChild(div);
}
},
onNon200: function (xhr) {
body.innerHTML = fallback;
body.innerHTML = originalHTML;
},
onTimeout: function (xhr) {
console.warn('Pulling comments failed');
body.innerHTML = fallback;
body.innerHTML = originalHTML;
}
});
}
1 change: 1 addition & 0 deletions locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@
"View Reddit comments": "View Reddit comments",
"Hide replies": "Hide replies",
"Show replies": "Show replies",
"Replies loaded": "loaded",
"Incorrect password": "Incorrect password",
"Wrong answer": "Wrong answer",
"Erroneous CAPTCHA": "Erroneous CAPTCHA",
Expand Down
1 change: 1 addition & 0 deletions src/invidious/views/community.ecr
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")),
"replies_loaded_text" => HTML.escape(translate(locale, "Replies loaded")),
"preferences" => env.get("preferences").as(Preferences)
}.to_pretty_json
%>
Expand Down
1 change: 1 addition & 0 deletions src/invidious/views/post.ecr
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")),
"replies_loaded_text" => HTML.escape(translate(locale, "Replies loaded")),
"params" => {
"comments": ["youtube"]
},
Expand Down
1 change: 1 addition & 0 deletions src/invidious/views/watch.ecr
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ we're going to need to do it here in order to allow for translations.
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")),
"replies_loaded_text" => HTML.escape(translate(locale, "Replies loaded")),
"params" => params,
"preferences" => preferences,
"premiere_timestamp" => video.premiere_timestamp.try &.to_unix,
Expand Down