Add YouTube comments

This commit is contained in:
Omar Roth 2018-07-28 09:49:58 -05:00
parent 829ffdd466
commit 1eb7066c74
4 changed files with 190 additions and 48 deletions

View file

@ -504,7 +504,7 @@ get "/api/v1/comments/:id" do |env|
source ||= "youtube" source ||= "youtube"
format = env.params.query["format"]? format = env.params.query["format"]?
format ||= "html" format ||= "json"
if source == "youtube" if source == "youtube"
client = make_client(YT_URL) client = make_client(YT_URL)
@ -627,13 +627,20 @@ get "/api/v1/comments/:id" do |env|
end end
env.response.content_type = "application/json" env.response.content_type = "application/json"
next comments if format == "json"
next comments
else
comments = JSON.parse(comments)
content_html = template_youtube_comments(comments)
{"content_html" => content_html}.to_json
end
elsif source == "reddit" elsif source == "reddit"
client = make_client(REDDIT_URL) client = make_client(REDDIT_URL)
headers = HTTP::Headers{"User-Agent" => "web:invidio.us:v0.1.0 (by /u/omarroth)"} headers = HTTP::Headers{"User-Agent" => "web:invidio.us:v0.1.0 (by /u/omarroth)"}
begin begin
comments, reddit_thread = get_reddit_comments(id, client, headers) comments, reddit_thread = get_reddit_comments(id, client, headers)
content_html = template_comments(comments) content_html = template_reddit_comments(comments)
content_html = fill_links(content_html, "https", "www.reddit.com") content_html = fill_links(content_html, "https", "www.reddit.com")
content_html = add_alt_links(content_html) content_html = add_alt_links(content_html)
@ -1664,6 +1671,9 @@ post "/preferences" do |env|
volume = env.params.body["volume"]?.try &.as(String).to_i volume = env.params.body["volume"]?.try &.as(String).to_i
volume ||= 100 volume ||= 100
comments = env.params.body["comments"]?
comments ||= "youtube"
dark_mode = env.params.body["dark_mode"]?.try &.as(String) dark_mode = env.params.body["dark_mode"]?.try &.as(String)
dark_mode ||= "off" dark_mode ||= "off"
dark_mode = dark_mode == "on" dark_mode = dark_mode == "on"
@ -1688,6 +1698,7 @@ post "/preferences" do |env|
"speed" => speed, "speed" => speed,
"quality" => quality, "quality" => quality,
"volume" => volume, "volume" => volume,
"comments" => comments,
"dark_mode" => dark_mode, "dark_mode" => dark_mode,
"thin_mode" => thin_mode, "thin_mode" => thin_mode,
"max_results" => max_results, "max_results" => max_results,

View file

@ -23,6 +23,7 @@ DEFAULT_USER_PREFERENCES = Preferences.from_json({
"speed" => 1.0, "speed" => 1.0,
"quality" => "hd720", "quality" => "hd720",
"volume" => 100, "volume" => 100,
"comments" => "youtube",
"dark_mode" => false, "dark_mode" => false,
"thin_mode " => false, "thin_mode " => false,
"max_results" => 40, "max_results" => 40,
@ -157,8 +158,13 @@ class Preferences
speed: Float32, speed: Float32,
quality: String, quality: String,
volume: Int32, volume: Int32,
dark_mode: Bool, comments: {
thin_mode: { type: String,
nilable: true,
default: "youtube",
},
dark_mode: Bool,
thin_mode: {
type: Bool, type: Bool,
nilable: true, nilable: true,
default: false, default: false,
@ -500,7 +506,56 @@ def get_reddit_comments(id, client, headers)
return comments, thread return comments, thread
end end
def template_comments(root) def template_youtube_comments(comments)
html = ""
root = comments["comments"].as_a
root.each do |child|
if child["replies"]?
replies_html = <<-END_HTML
<div id="replies" class="pure-g">
<div class="pure-u-md-1-24"></div>
<div class="pure-u-md-23-24">
<p>
<a href="javascript:void(0)" data-continuation="#{child["replies"]["continuation"]}"
onclick="load_comments(this)">View #{child["replies"]["replyCount"]} replies</a>
</p>
</div>
END_HTML
end
html += <<-END_HTML
<div class="pure-g">
<div class="pure-u-1">
<p>
<a href="javascript:void(0)" onclick="toggle(this)">[ - ]</a> #{child["likeCount"]} <b>#{child["author"]}</b>
</p>
<div>
#{child["content"]}
#{replies_html}
</div>
</div>
</div>
END_HTML
end
if comments["continuation"]?
html += <<-END_HTML
<div class="pure-g">
<div class="pure-u-1">
<p>
<a href="javascript:void(0)" data-continuation="#{comments["continuation"]}"
onclick="load_comments(this)">Load more</a>
</p>
</div>
</div>
END_HTML
end
return html
end
def template_reddit_comments(root)
html = "" html = ""
root.each do |child| root.each do |child|
if child.data.is_a?(RedditComment) if child.data.is_a?(RedditComment)
@ -512,7 +567,7 @@ def template_comments(root)
replies_html = "" replies_html = ""
if child.replies.is_a?(RedditThing) if child.replies.is_a?(RedditThing)
replies = child.replies.as(RedditThing) replies = child.replies.as(RedditThing)
replies_html = template_comments(replies.data.as(RedditListing).children) replies_html = template_reddit_comments(replies.data.as(RedditListing).children)
end end
content = <<-END_HTML content = <<-END_HTML

View file

@ -47,6 +47,15 @@ function update_value(element) {
<span class="pure-form-message-inline" id="volume-value"><%= user.preferences.volume %></span> <span class="pure-form-message-inline" id="volume-value"><%= user.preferences.volume %></span>
</div> </div>
<div class="pure-control-group">
<label for="comments">Pull comments from: </label>
<select name="comments" id="comments">
<% ["youtube", "reddit"].each do |option| %>
<option <% if user.preferences.comments == option %> selected <% end %>><%= option %></option>
<% end %>
</select>
</div>
<legend>Visual preferences</legend> <legend>Visual preferences</legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="dark_mode">Dark mode: </label> <label for="dark_mode">Dark mode: </label>

View file

@ -124,28 +124,6 @@ player.offset({
end: <%= video_end %> end: <%= video_end %>
}); });
function toggle(target) {
body = target.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === '') {
target.innerHTML = '[ + ]';
body.style.display = 'none';
} else {
target.innerHTML = '[ - ]';
body.style.display = '';
}
};
function toggle_comments(target) {
body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === '') {
target.innerHTML = '[ + ]';
body.style.display = 'none';
} else {
target.innerHTML = '[ - ]';
body.style.display = '';
}
};
<% if !listen %> <% if !listen %>
var currentSources = player.currentSources(); var currentSources = player.currentSources();
for ( var i = 0; i < currentSources.length; i++ ) { for ( var i = 0; i < currentSources.length; i++ ) {
@ -158,12 +136,74 @@ for ( var i = 0; i < currentSources.length; i++ ) {
player.src(currentSources); player.src(currentSources);
<% end %> <% end %>
fetch("/api/v1/comments/<%= video.id %>?source=reddit") function toggle(target) {
body = target.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === "") {
target.innerHTML = "[ + ]";
body.style.display = "none";
} else {
target.innerHTML = "[ - ]";
body.style.display = "";
}
}
function toggle_comments(target) {
body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === "") {
target.innerHTML = "[ + ]";
body.style.display = "none";
} else {
target.innerHTML = "[ - ]";
body.style.display = "";
}
}
function timeout(ms, promise) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error("timeout"));
}, ms);
promise.then(resolve, reject);
});
}
function load_comments(target) {
var continuation = target.getAttribute("data-continuation");
var body = target.parentNode.parentNode;
var fallback = body.innerHTML;
body.innerHTML =
'<h3><center><i class="loading fas fa-spinner"></i></center></h3>';
var url =
"/api/v1/comments/<%= video.id %>?format=html&continuation=" + continuation;
timeout(5000, fetch(url))
.then(function(response) { .then(function(response) {
return response.json(); return response.json();
}) })
.then(function(jsonResponse) { .then(
comments = document.getElementById('comments'); function(jsonResponse) {
body.innerHTML = jsonResponse.content_html;
},
function(error) {
body.innerHTML = fallback;
console.log(response);
}
)
.catch(function(error) {
body.innerHTML = fallback;
console.log(error);
});
}
function get_reddit_comments() {
fetch("/api/v1/comments/<%= video.id %>?source=reddit")
.then(function(response) {
return response.json();
})
.then(
function(jsonResponse) {
comments = document.getElementById("comments");
comments.innerHTML = ` comments.innerHTML = `
<div> <div>
<h3> <h3>
@ -175,25 +215,52 @@ fetch("/api/v1/comments/<%= video.id %>?source=reddit")
</b> </b>
</div> </div>
<div>{content_html}</div> <div>{content_html}</div>
</div>
<hr style="margin-left:1em; margin-right:1em;">`.supplant({
title: jsonResponse.title,
permalink: jsonResponse.permalink,
content_html: jsonResponse.content_html
})
}, function(response){
comments.innerHTML = "";
});
String.prototype.supplant = function (o) { <hr style="margin-left:1em; margin-right:1em;">`.supplant({
return this.replace(/{([^{}]*)}/g, title: jsonResponse.title,
function (a, b) { permalink: jsonResponse.permalink,
var r = o[b]; content_html: jsonResponse.content_html
return typeof r === 'string' || typeof r === 'number' ? r : a; });
} },
function(response) {
get_youtube_comments();
}
); );
}
function get_youtube_comments() {
fetch("/api/v1/comments/<%= video.id %>?format=html")
.then(function(response) {
return response.json();
})
.then(
function(jsonResponse) {
comments = document.getElementById("comments");
comments.innerHTML = `
<div>{content_html}</div>
<hr style="margin-left:1em; margin-right:1em;">`.supplant({
content_html: jsonResponse.content_html
});
},
function(response) {
comments.innerHTML = "";
}
);
}
String.prototype.supplant = function(o) {
return this.replace(/{([^{}]*)}/g, function(a, b) {
var r = o[b];
return typeof r === "string" || typeof r === "number" ? r : a;
});
}; };
<% if preferences && preferences.comments == "reddit" %>
get_reddit_comments();
<% else %>
get_youtube_comments();
<% end %>
</script> </script>
<div class="h-box"> <div class="h-box">