Show message when YouTube comments are disabled

This commit is contained in:
zergzorg 2026-05-21 14:33:24 +03:00
parent 99390d065d
commit 4344d398d9
8 changed files with 81 additions and 6 deletions

View File

@ -52,7 +52,22 @@ function show_youtube_replies(event) {
target.setAttribute('data-sub-text', sub_text); target.setAttribute('data-sub-text', sub_text);
} }
function show_youtube_comments_disabled_message() {
var comments = document.getElementById('comments');
comments.innerHTML = ' \
<div id="youtube-comments-disabled-message" class="h-box v-box"> \
<p><b>{message}</b></p> \
</div>'.supplant({
message: video_data.youtube_comments_disabled_text
});
}
function get_youtube_comments() { function get_youtube_comments() {
if (!video_data.comments_enabled) {
show_youtube_comments_disabled_message();
return;
}
var comments = document.getElementById('comments'); var comments = document.getElementById('comments');
var fallback = comments.innerHTML; var fallback = comments.innerHTML;

View File

@ -182,6 +182,11 @@ addEventListener('load', function (e) {
if (video_data.plid) if (video_data.plid)
get_playlist(video_data.plid); get_playlist(video_data.plid);
var first_comments_source = video_data.params.comments[0] || video_data.params.comments[1];
if (!video_data.comments_enabled && first_comments_source === 'youtube') {
return;
}
if (video_data.params.comments[0] === 'youtube') { if (video_data.params.comments[0] === 'youtube') {
get_youtube_comments(); get_youtube_comments();
} else if (video_data.params.comments[0] === 'reddit') { } else if (video_data.params.comments[0] === 'reddit') {

View File

@ -220,6 +220,7 @@
"View Reddit comments": "View Reddit comments", "View Reddit comments": "View Reddit comments",
"Hide replies": "Hide replies", "Hide replies": "Hide replies",
"Show replies": "Show replies", "Show replies": "Show replies",
"youtube_comments_disabled_text": "Comments are turned off on this video.",
"Incorrect password": "Incorrect password", "Incorrect password": "Incorrect password",
"Wrong answer": "Wrong answer", "Wrong answer": "Wrong answer",
"Erroneous CAPTCHA": "Erroneous CAPTCHA", "Erroneous CAPTCHA": "Erroneous CAPTCHA",

View File

@ -40,6 +40,7 @@ Spectator.describe "parse_video_info" do
expect(info["keywords"].as_a).to be_empty expect(info["keywords"].as_a).to be_empty
expect(info["allowRatings"].as_bool).to be_true expect(info["allowRatings"].as_bool).to be_true
expect(info["commentsEnabled"].as_bool).to be_true
expect(info["isFamilyFriendly"].as_bool).to be_true expect(info["isFamilyFriendly"].as_bool).to be_true
expect(info["isListed"].as_bool).to be_true expect(info["isListed"].as_bool).to be_true
expect(info["isUpcoming"].as_bool).to be_false expect(info["isUpcoming"].as_bool).to be_false
@ -125,6 +126,7 @@ Spectator.describe "parse_video_info" do
).in_any_order ).in_any_order
expect(info["allowRatings"].as_bool).to be_true expect(info["allowRatings"].as_bool).to be_true
expect(info["commentsEnabled"].as_bool).to be_true
expect(info["isFamilyFriendly"].as_bool).to be_true expect(info["isFamilyFriendly"].as_bool).to be_true
expect(info["isListed"].as_bool).to be_true expect(info["isListed"].as_bool).to be_true
expect(info["isUpcoming"].as_bool).to be_false expect(info["isUpcoming"].as_bool).to be_false
@ -163,4 +165,23 @@ Spectator.describe "parse_video_info" do
expect(info["authorVerified"].as_bool).to be_false expect(info["authorVerified"].as_bool).to be_false
expect(info["subCountText"].as_s).to eq("3.11K") expect(info["subCountText"].as_s).to eq("3.11K")
end end
it "detects disabled YouTube comments" do
_player = load_mock("video/regular_no-description.player")
_next = load_mock("video/regular_no-description.next")
raw_data = _player.merge!(_next)
comments_section = raw_data.dig(
"contents", "twoColumnWatchNextResults",
"results", "results", "contents"
).as_a[3]["itemSectionRenderer"].as_h
comments_section["contents"] = JSON.parse(%([
{"messageRenderer":{"text":{"simpleText":"Comments are turned off."}}}
]))
info = parse_video_info("iuevw6218F0", raw_data)
expect(info["commentsEnabled"].as_bool).to be_false
end
end end

View File

@ -84,7 +84,9 @@ module Invidious::Routes::Watch
source = preferences.comments[1] source = preferences.comments[1]
end end
if source == "youtube" if source == "youtube" && !video.comments_enabled?
comment_html = ""
elsif source == "youtube"
begin begin
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"] comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
rescue ex rescue ex
@ -110,7 +112,9 @@ module Invidious::Routes::Watch
end end
end end
else else
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"] if video.comments_enabled?
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
end
end end
comment_html ||= "" comment_html ||= ""

View File

@ -15,7 +15,7 @@ struct Video
# NOTE: don't forget to bump this number if any change is made to # NOTE: don't forget to bump this number if any change is made to
# the `params` structure in videos/parser.cr!!! # the `params` structure in videos/parser.cr!!!
# #
SCHEMA_VERSION = 3 SCHEMA_VERSION = 4
property id : String property id : String
@ -192,6 +192,10 @@ struct Video
} }
end end
def comments_enabled? : Bool
info["commentsEnabled"]?.try &.as_bool || true
end
# Macros defining getters/setters for various types of data # Macros defining getters/setters for various types of data
private macro getset_string(name) private macro getset_string(name)

View File

@ -52,6 +52,18 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
} }
end end
private def detect_comments_enabled(primary_results : JSON::Any?) : Bool
primary_results.try &.as_a.each do |section|
item_section = section["itemSectionRenderer"]?
next if !item_section
next if item_section["sectionIdentifier"]?.try &.as_s != "comment-item-section"
return false if item_section["contents"]?.try &.as_a.any?(&.["messageRenderer"]?)
end
return true
end
def extract_video_info(video_id : String) def extract_video_info(video_id : String)
# Fetch data from the player endpoint # Fetch data from the player endpoint
player_response = YoutubeAPI.player(video_id: video_id) player_response = YoutubeAPI.player(video_id: video_id)
@ -160,7 +172,9 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
# Primary results are not available on Music videos # Primary results are not available on Music videos
# See: https://github.com/iv-org/invidious/pull/3238#issuecomment-1207193725 # See: https://github.com/iv-org/invidious/pull/3238#issuecomment-1207193725
if primary_results = main_results.dig?("results", "results", "contents") primary_results = main_results.dig?("results", "results", "contents")
if primary_results
video_primary_renderer = primary_results video_primary_renderer = primary_results
.as_a.find(&.["videoPrimaryInfoRenderer"]?) .as_a.find(&.["videoPrimaryInfoRenderer"]?)
.try &.["videoPrimaryInfoRenderer"] .try &.["videoPrimaryInfoRenderer"]
@ -231,6 +245,8 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
keywords = video_details["keywords"]? keywords = video_details["keywords"]?
.try &.as_a.map &.as_s || [] of String .try &.as_a.map &.as_s || [] of String
comments_enabled = detect_comments_enabled(primary_results)
# Related videos # Related videos
LOGGER.debug("extract_video_info: parsing related videos...") LOGGER.debug("extract_video_info: parsing related videos...")
@ -418,6 +434,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
"isFamilyFriendly" => JSON::Any.new(family_friendly || false), "isFamilyFriendly" => JSON::Any.new(family_friendly || false),
"isListed" => JSON::Any.new(is_listed || false), "isListed" => JSON::Any.new(is_listed || false),
"isUpcoming" => JSON::Any.new(is_upcoming || false), "isUpcoming" => JSON::Any.new(is_upcoming || false),
"commentsEnabled" => JSON::Any.new(comments_enabled),
"keywords" => JSON::Any.new(keywords.map { |v| JSON::Any.new(v) }), "keywords" => JSON::Any.new(keywords.map { |v| JSON::Any.new(v) }),
"isPostLiveDvr" => JSON::Any.new(post_live_dvr), "isPostLiveDvr" => JSON::Any.new(post_live_dvr),
# Related videos # Related videos

View File

@ -57,12 +57,14 @@ we're going to need to do it here in order to allow for translations.
"reddit_comments_text" => HTML.escape(I18n.translate(locale, "View Reddit comments")), "reddit_comments_text" => HTML.escape(I18n.translate(locale, "View Reddit comments")),
"reddit_permalink_text" => HTML.escape(I18n.translate(locale, "View more comments on Reddit")), "reddit_permalink_text" => HTML.escape(I18n.translate(locale, "View more comments on Reddit")),
"comments_text" => HTML.escape(I18n.translate(locale, "View `x` comments", "{commentCount}")), "comments_text" => HTML.escape(I18n.translate(locale, "View `x` comments", "{commentCount}")),
"youtube_comments_disabled_text" => HTML.escape(I18n.translate(locale, "youtube_comments_disabled_text")),
"hide_replies_text" => HTML.escape(I18n.translate(locale, "Hide replies")), "hide_replies_text" => HTML.escape(I18n.translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(I18n.translate(locale, "Show replies")), "show_replies_text" => HTML.escape(I18n.translate(locale, "Show replies")),
"params" => params, "params" => params,
"preferences" => preferences, "preferences" => preferences,
"premiere_timestamp" => video.premiere_timestamp.try &.to_unix, "premiere_timestamp" => video.premiere_timestamp.try &.to_unix,
"vr" => video.vr?, "vr" => video.vr?,
"comments_enabled" => video.comments_enabled?,
"projection_type" => video.projection_type, "projection_type" => video.projection_type,
"local_disabled" => CONFIG.disabled?("local"), "local_disabled" => CONFIG.disabled?("local"),
"support_reddit" => true, "support_reddit" => true,
@ -288,8 +290,14 @@ we're going to need to do it here in order to allow for translations.
<hr> <hr>
<% end %> <% end %>
<% first_comments_source = params.comments[0]? || "" %>
<% first_comments_source = params.comments[1]? || "" if first_comments_source.empty? %>
<div id="comments" class="comments"> <div id="comments" class="comments">
<% if nojs %> <% if !video.comments_enabled? && first_comments_source == "youtube" %>
<div id="youtube-comments-disabled-message" class="h-box v-box">
<p><b><%= I18n.translate(locale, "youtube_comments_disabled_text") %></b></p>
</div>
<% elsif nojs %>
<%= comment_html %> <%= comment_html %>
<% else %> <% else %>
<noscript> <noscript>