diff --git a/assets/js/comments.js b/assets/js/comments.js index 35ffa96e..86ec1543 100644 --- a/assets/js/comments.js +++ b/assets/js/comments.js @@ -10,6 +10,14 @@ String.prototype.supplant = function (o) { }); }; +function updateReplyLinks() { + document.querySelectorAll("a[href^='/comment_viewer']").forEach(function (replyLink) { + replyLink.setAttribute("href", "javascript:void(0)"); + replyLink.removeAttribute("target"); + }); +} +updateReplyLinks() + function toggle_comments(event) { var target = event.target; var body = target.parentNode.parentNode.parentNode.children[1]; @@ -104,6 +112,7 @@ function get_youtube_comments() { }) }); comments.innerHTML = commentInnerHtml; + updateReplyLinks() comments.children[0].children[0].children[0].onclick = toggle_comments; if (video_data.support_reddit) { comments.children[0].children[1].children[0].onclick = swap_comments; @@ -143,6 +152,7 @@ function get_youtube_replies(target, load_more, load_replies) { body = body.parentNode.parentNode; body.removeChild(body.lastElementChild); body.insertAdjacentHTML('beforeend', response.contentHtml); + updateReplyLinks() } else { body.removeChild(body.lastElementChild); @@ -161,6 +171,7 @@ function get_youtube_replies(target, load_more, load_replies) { body.appendChild(p); body.appendChild(div); + updateReplyLinks() } }, onNon200: function (xhr) { diff --git a/assets/js/community.js b/assets/js/community.js index 32fe4ebc..f076af9a 100644 --- a/assets/js/community.js +++ b/assets/js/community.js @@ -1,37 +1,20 @@ 'use strict'; var community_data = JSON.parse(document.getElementById('community_data').textContent); -function hide_youtube_replies(event) { - var target = event.target; +// first page of community posts are loaded without javascript so we need to update the Load more button +var initialLoadMore = document.querySelector('a[data-onclick="get_youtube_replies"]'); +initialLoadMore.setAttribute('href', 'javascript:void(0);'); +initialLoadMore.removeAttribute('target'); - var sub_text = target.getAttribute('data-inner-text'); - var inner_text = target.getAttribute('data-sub-text'); - - var body = target.parentNode.parentNode.children[1]; - body.style.display = 'none'; - - target.innerHTML = sub_text; - target.onclick = show_youtube_replies; - target.setAttribute('data-inner-text', inner_text); - target.setAttribute('data-sub-text', sub_text); +function updateReplyLinks() { + document.querySelectorAll("a[href^='/comment_viewer']").forEach(function (replyLink) { + replyLink.setAttribute("href", "javascript:void(0)"); + replyLink.removeAttribute("target"); + }); } +updateReplyLinks() -function show_youtube_replies(event) { - var target = event.target; - - var sub_text = target.getAttribute('data-inner-text'); - var inner_text = target.getAttribute('data-sub-text'); - - var body = target.parentNode.parentNode.children[1]; - body.style.display = ''; - - target.innerHTML = sub_text; - target.onclick = hide_youtube_replies; - target.setAttribute('data-inner-text', inner_text); - target.setAttribute('data-sub-text', sub_text); -} - -function get_youtube_replies(target, load_more) { +function get_youtube_replies(target) { var continuation = target.getAttribute('data-continuation'); var body = target.parentNode.parentNode; @@ -47,29 +30,10 @@ function get_youtube_replies(target, load_more) { helpers.xhr('GET', url, {}, { on200: function (response) { - if (load_more) { - body = body.parentNode.parentNode; - body.removeChild(body.lastElementChild); - body.innerHTML += response.contentHtml; - } else { - body.removeChild(body.lastElementChild); - - 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', community_data.hide_replies_text); - a.setAttribute('data-inner-text', community_data.show_replies_text); - a.textContent = community_data.hide_replies_text; - - var div = document.createElement('div'); - div.innerHTML = response.contentHtml; - - body.appendChild(p); - body.appendChild(div); - } + body = body.parentNode.parentNode; + body.removeChild(body.lastElementChild); + body.insertAdjacentHTML('beforeend', response.contentHtml); + updateReplyLinks() }, onNon200: function (xhr) { body.innerHTML = fallback; diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr index 49ffd990..bdfbc27c 100644 --- a/src/invidious/channels/community.cr +++ b/src/invidious/channels/community.cr @@ -279,7 +279,7 @@ def extract_channel_community(items, *, ucid, locale, format, thin_mode, is_sing if format == "html" response = JSON.parse(response) - content_html = IV::Frontend::Comments.template_youtube(response, locale, thin_mode) + content_html = IV::Frontend::Comments.template_youtube(response, locale, thin_mode, ucid, "community") response = JSON.build do |json| json.object do diff --git a/src/invidious/comments/youtube.cr b/src/invidious/comments/youtube.cr index 185d8e43..1b394f32 100644 --- a/src/invidious/comments/youtube.cr +++ b/src/invidious/comments/youtube.cr @@ -57,7 +57,7 @@ module Invidious::Comments return initial_data end - def parse_youtube(id, response, format, locale, thin_mode, sort_by = "top", isPost = false) + def parse_youtube(id, response, format, locale, thin_mode, sort_by = "top", type = "video", ucid = nil) contents = nil if on_response_received_endpoints = response["onResponseReceivedEndpoints"]? @@ -113,7 +113,11 @@ module Invidious::Comments json.field "commentCount", comment_count end - if isPost + if !ucid.nil? + json.field "authorId", ucid + end + + if type == "post" json.field "postId", id else json.field "videoId", id @@ -235,7 +239,7 @@ module Invidious::Comments if format == "html" response = JSON.parse(response) - content_html = Frontend::Comments.template_youtube(response, locale, thin_mode) + content_html = Frontend::Comments.template_youtube(response, locale, thin_mode, id, type) response = JSON.build do |json| json.object do diff --git a/src/invidious/frontend/comments_youtube.cr b/src/invidious/frontend/comments_youtube.cr index aecac87f..96a0b089 100644 --- a/src/invidious/frontend/comments_youtube.cr +++ b/src/invidious/frontend/comments_youtube.cr @@ -1,7 +1,7 @@ module Invidious::Frontend::Comments extend self - def template_youtube(comments, locale, thin_mode, is_replies = false) + def template_youtube(comments, locale, thin_mode, id, type = "video", is_replies = false) String.build do |html| root = comments["comments"].as_a root.each do |child| @@ -13,17 +13,17 @@ module Invidious::Frontend::Comments ) replies_html = <<-END_HTML -
+
END_HTML - elsif comments["authorId"]? && !comments["singlePost"]? + elsif comments["authorId"]? && !comments["singlePost"]? && type != "post" # for posts we should display a link to the post replies_count_text = translate_count(locale, "comments_view_x_replies", @@ -147,7 +147,12 @@ module Invidious::Frontend::Comments | END_HTML - if comments["videoId"]? + if type == "post" && !comments["singlePost"]? + html << <<-END_HTML + [YT] + | + END_HTML + elsif comments["videoId"]? html << <<-END_HTML [YT] | @@ -196,7 +201,7 @@ module Invidious::Frontend::Comments
diff --git a/src/invidious/routes/api/v1/channels.cr b/src/invidious/routes/api/v1/channels.cr index 67018660..1a20b66e 100644 --- a/src/invidious/routes/api/v1/channels.cr +++ b/src/invidious/routes/api/v1/channels.cr @@ -385,15 +385,23 @@ module Invidious::Routes::API::V1::Channels format ||= "json" continuation = env.params.query["continuation"]? + ucid = env.params.query["ucid"]? + + if ucid.nil? + response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}") + return error_json(400, "Invalid post ID") if response["error"]? + ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s + else + ucid = ucid.to_s + end case continuation when nil, "" - ucid = env.params.query["ucid"] comments = Comments.fetch_community_post_comments(ucid, id) else comments = YoutubeAPI.browse(continuation: continuation) end - return Comments.parse_youtube(id, comments, format, locale, thin_mode, isPost: true) + return Comments.parse_youtube(id, comments, format, locale, thin_mode, type: "post", ucid: ucid) end def self.channels(env) diff --git a/src/invidious/routes/channels.cr b/src/invidious/routes/channels.cr index d4d8b1c1..67bddf38 100644 --- a/src/invidious/routes/channels.cr +++ b/src/invidious/routes/channels.cr @@ -231,7 +231,7 @@ module Invidious::Routes::Channels if nojs comments = Comments.fetch_community_post_comments(ucid, id) - comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, isPost: true))["contentHtml"] + comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, type: "post", ucid: ucid))["contentHtml"] end templated "post" end diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index aabe8dfc..ad64f53f 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -332,4 +332,53 @@ module Invidious::Routes::Watch return error_template(400, "Invalid label or itag") end end + + # used for fetching replies/ fetching more comments when js is disabled. + def self.comments(env) + locale = env.get("preferences").as(Preferences).locale + region = env.params.query["region"]? + + id = env.params.query["id"] + continuation = env.params.query["continuation"]? + + source = env.params.query["source"]? || "youtube" + + thin_mode = env.params.query["thin_mode"]? == "true" + comment_type = env.params.query["type"]? || "video" + + parent_comment = nil + if comment_type == "community" + # community posts + comment_html = JSON.parse(fetch_channel_community(id, continuation, locale, "html", thin_mode))["contentHtml"] + elsif comment_type == "post" + # replies to a community post + ucid = env.params.query["ucid"]? + if ucid.nil? + response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}") + return error_json(400, "Invalid post ID") if response["error"]? + ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s + else + ucid = ucid.to_s + end + case continuation + when nil, "" + comments = Comments.fetch_community_post_comments(ucid, id) + else + comments = YoutubeAPI.browse(continuation: continuation) + end + comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, type: "post", ucid: ucid))["contentHtml"] + else + # video comments + if source == "youtube" + comment_html = JSON.parse(Comments.fetch_youtube(id, continuation, "html", locale, thin_mode, region))["contentHtml"] + elsif source == "reddit" + comments, reddit_thread = Comments.fetch_reddit(id) + comment_html = Frontend::Comments.template_reddit(comments, locale) + + comment_html = Comments.fill_links(comment_html, "https", "www.reddit.com") + comment_html = Comments.replace_links(comment_html) + end + end + templated "comments_no_js" + end end diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index ba05da19..f16d8a4c 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -170,6 +170,8 @@ module Invidious::Routing get "/embed/", Routes::Embed, :redirect get "/embed/:id", Routes::Embed, :show + # currently only for fetching continuations when js is disabled. + get "/comment_viewer", Routes::Watch, :comments end def register_yt_playlist_routes diff --git a/src/invidious/views/comments_no_js.ecr b/src/invidious/views/comments_no_js.ecr new file mode 100644 index 00000000..f9c25432 --- /dev/null +++ b/src/invidious/views/comments_no_js.ecr @@ -0,0 +1,9 @@ +<% content_for "header" do %> +Invidious + +<% end %> + + +
+ <%= comment_html %> +
\ No newline at end of file diff --git a/src/invidious/views/community.ecr b/src/invidious/views/community.ecr index d2a305d3..d79580cd 100644 --- a/src/invidious/views/community.ecr +++ b/src/invidious/views/community.ecr @@ -13,6 +13,7 @@ <% content_for "header" do %> <%= author %> - Invidious + <% end %> <%= rendered "components/channel_info" %> @@ -27,7 +28,7 @@
<% else %>
- <%= IV::Frontend::Comments.template_youtube(items.not_nil!, locale, thin_mode) %> + <%= IV::Frontend::Comments.template_youtube(items.not_nil!, locale, thin_mode, ucid, "community") %>
<% end %> diff --git a/src/invidious/views/post.ecr b/src/invidious/views/post.ecr index fb03a44c..d4133ffe 100644 --- a/src/invidious/views/post.ecr +++ b/src/invidious/views/post.ecr @@ -1,10 +1,11 @@ <% content_for "header" do %> Invidious + <% end %>
- <%= IV::Frontend::Comments.template_youtube(post_response.not_nil!, locale, thin_mode) %> + <%= IV::Frontend::Comments.template_youtube(post_response.not_nil!, locale, thin_mode, id, "post") %>
<% if nojs %> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 7a1cf2c3..12235965 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -42,6 +42,7 @@ we're going to need to do it here in order to allow for translations. content: "<%= translate(locale, "Show less") %>" } + <% end %>