summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--assets/css/default.css4
-rw-r--r--config/sql/videos.sql1
-rw-r--r--src/invidious.cr3
-rw-r--r--src/invidious/channels.cr8
-rw-r--r--src/invidious/videos.cr26
-rw-r--r--src/invidious/views/channel.ecr73
-rw-r--r--src/invidious/views/watch.ecr53
7 files changed, 144 insertions, 24 deletions
diff --git a/assets/css/default.css b/assets/css/default.css
index e60b9da8..0582ea58 100644
--- a/assets/css/default.css
+++ b/assets/css/default.css
@@ -22,6 +22,10 @@ div {
padding-right: 10px;
}
+.pure-button-primary {
+ background: rgba(0, 182, 240, 1);
+}
+
/*
* Navbar
*/
diff --git a/config/sql/videos.sql b/config/sql/videos.sql
index 5241d7a0..2a02ccdf 100644
--- a/config/sql/videos.sql
+++ b/config/sql/videos.sql
@@ -22,6 +22,7 @@ CREATE TABLE public.videos
genre text COLLATE pg_catalog."default",
genre_url text COLLATE pg_catalog."default",
license text COLLATE pg_catalog."default",
+ sub_count_text text COLLATE pg_catalog."default",
CONSTRAINT videos_pkey PRIMARY KEY (id)
)
WITH (
diff --git a/src/invidious.cr b/src/invidious.cr
index 5d929996..74c70820 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -1739,7 +1739,7 @@ get "/channel/:ucid" do |env|
page ||= 1
begin
- author, ucid, auto_generated = get_about_info(ucid)
+ author, ucid, auto_generated, sub_count = get_about_info(ucid)
rescue ex
error_message = "User does not exist"
next templated "error"
@@ -2298,6 +2298,7 @@ get "/api/v1/videos/:id" do |env|
json.field "author", video.author
json.field "authorId", video.ucid
json.field "authorUrl", "/channel/#{video.ucid}"
+ json.field "subCountText", video.sub_count_text
json.field "lengthSeconds", video.info["length_seconds"].to_i
if video.info["allow_ratings"]?
diff --git a/src/invidious/channels.cr b/src/invidious/channels.cr
index 2e9e9fb3..42b0a69f 100644
--- a/src/invidious/channels.cr
+++ b/src/invidious/channels.cr
@@ -196,6 +196,12 @@ def get_about_info(ucid)
raise "User does not exist."
end
+ sub_count = about.xpath_node(%q(//span[contains(text(), "subscribers")]))
+ if sub_count
+ sub_count = sub_count.content.delete(", subscribers").to_i?
+ end
+ sub_count ||= 0
+
author = about.xpath_node(%q(//span[@class="qualified-channel-title-text"]/a)).not_nil!.content
ucid = about.xpath_node(%q(//link[@rel="canonical"])).not_nil!["href"].split("/")[-1]
@@ -207,5 +213,5 @@ def get_about_info(ucid)
auto_generated = true
end
- return {author, ucid, auto_generated}
+ return {author, ucid, auto_generated, sub_count}
end
diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr
index 9398943d..228aafbd 100644
--- a/src/invidious/videos.cr
+++ b/src/invidious/videos.cr
@@ -456,9 +456,10 @@ class Video
is_family_friendly: Bool,
genre: String,
genre_url: String,
- license: {
+ license: String,
+ sub_count_text: {
type: String,
- default: "",
+ default: "0",
},
})
end
@@ -490,11 +491,14 @@ def get_video(id, db, proxies = {} of String => Array({ip: String, port: Int32})
video = fetch_video(id, proxies)
video_array = video.to_a
+ # Migration point
+ video_array = video_array[0..-2]
+
args = arg_array(video_array[1..-1], 2)
db.exec("UPDATE videos SET (info,updated,title,views,likes,dislikes,wilson_score,\
- published,description,language,author,ucid, allowed_regions, is_family_friendly,\
- genre, genre_url, license)\
+ published,description,language,author,ucid,allowed_regions,is_family_friendly,\
+ genre,genre_url,license)\
= (#{args}) WHERE id = $1", video_array)
rescue ex
db.exec("DELETE FROM videos * WHERE id = $1", id)
@@ -505,6 +509,9 @@ def get_video(id, db, proxies = {} of String => Array({ip: String, port: Int32})
video = fetch_video(id, proxies)
video_array = video.to_a
+ # Migration point
+ video_array = video_array[0..-2]
+
args = arg_array(video_array)
db.exec("INSERT INTO videos VALUES (#{args}) ON CONFLICT (id) DO NOTHING", video_array)
@@ -662,11 +669,18 @@ def fetch_video(id, proxies)
if license
license = license.content
else
- license ||= ""
+ license = ""
+ end
+
+ sub_count_text = html.xpath_node(%q(//span[contains(@class, "yt-subscriber-count")]))
+ if sub_count_text
+ sub_count_text = sub_count_text["title"]
+ else
+ sub_count_text = "0"
end
video = Video.new(id, info, Time.now, title, views, likes, dislikes, wilson_score, published, description,
- nil, author, ucid, allowed_regions, is_family_friendly, genre, genre_url, license)
+ nil, author, ucid, allowed_regions, is_family_friendly, genre, genre_url, license, sub_count_text)
return video
end
diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr
index 2dbe1ce2..a73b9527 100644
--- a/src/invidious/views/channel.ecr
+++ b/src/invidious/views/channel.ecr
@@ -13,23 +13,32 @@
</div>
</div>
-<p class="h-box">
+<div class="h-box">
<% if user %>
<% if subscriptions.includes? ucid %>
- <a href="/subscription_ajax?action_remove_subscriptions=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>">
- <b>Unsubscribe from <%= author %></b>
- </a>
+ <p>
+ <a id="subscribe" onclick="unsubscribe()" class="pure-button pure-button-primary"
+ href="/subscription_ajax?action_remove_subscriptions=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>">
+ <b>Unsubscribe from <%= author %> <%= number_with_separator(sub_count) %></b>
+ </a>
+ </p>
<% else %>
- <a href="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>">
- <b>Subscribe to <%= author %></b>
- </a>
+ <p>
+ <a id="subscribe" onclick="subscribe()" class="pure-button pure-button-primary"
+ href="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>">
+ <b>Subscribe to <%= author %> <%= number_with_separator(sub_count) %></b>
+ </a>
+ </p>
<% end %>
<% else %>
- <a href="/login?referer=<%= env.get("current_page") %>">
- <b>Login to subscribe to <%= author %></b>
- </a>
+ <p>
+ <a id="subscribe" class="pure-button pure-button-primary"
+ href="/login?referer=<%= env.get("current_page") %>">
+ <b>Login to subscribe to <%= author %></b>
+ </a>
+ </p>
<% end %>
-</p>
+</div>
<p class="h-box">
<a href="https://www.youtube.com/channel/<%= ucid %>">View channel on YouTube</a>
@@ -56,3 +65,45 @@
<% end %>
</div>
</div>
+
+<script>
+document.getElementById("subscribe")["href"] = "javascript:void(0);"
+
+function subscribe() {
+ var url = "/subscription_ajax?action_create_subscription_to_channel=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>";
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = "json";
+ xhr.timeout = 20000;
+ xhr.open("GET", url, true);
+ xhr.send();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ subscribe_button = document.getElementById("subscribe");
+ subscribe_button.onclick = unsubscribe;
+ subscribe_button.innerHTML = '<b>Unsubscribe from <%= author %> <%= number_with_separator(sub_count + 1) %></b>'
+ }
+ }
+ }
+}
+
+function unsubscribe() {
+ var url = "/subscription_ajax?action_remove_subscriptions=1&c=<%= ucid %>&referer=<%= env.get("current_page") %>";
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = "json";
+ xhr.timeout = 20000;
+ xhr.open("GET", url, true);
+ xhr.send();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ subscribe_button = document.getElementById("subscribe");
+ subscribe_button.onclick = subscribe;
+ subscribe_button.innerHTML = '<b>Subscribe to <%= author %> <%= number_with_separator(sub_count) %></b>'
+ }
+ }
+ }
+}
+</script> \ No newline at end of file
diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr
index 27eb8a3e..16a8bd44 100644
--- a/src/invidious/views/watch.ecr
+++ b/src/invidious/views/watch.ecr
@@ -92,20 +92,23 @@
<% if user %>
<% if subscriptions.includes? video.ucid %>
<p>
- <a href="/subscription_ajax?action_remove_subscriptions=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>">
- <b>Unsubscribe from <%= video.author %></b>
+ <a id="subscribe" onclick="unsubscribe()" class="pure-button pure-button-primary"
+ href="/subscription_ajax?action_remove_subscriptions=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>">
+ <b>Unsubscribe from <%= video.author %> <%= video.sub_count_text %></b>
</a>
</p>
<% else %>
<p>
- <a href="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>">
- <b>Subscribe to <%= video.author %></b>
+ <a id="subscribe" onclick="subscribe()" class="pure-button pure-button-primary"
+ href="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>">
+ <b>Subscribe to <%= video.author %> <%= video.sub_count_text %></b>
</a>
</p>
<% end %>
<% else %>
<p>
- <a href="/login?referer=<%= env.get("current_page") %>">
+ <a id="subscribe" class="pure-button pure-button-primary"
+ href="/login?referer=<%= env.get("current_page") %>">
<b>Login to subscribe to <%= video.author %></b>
</a>
</p>
@@ -152,6 +155,46 @@
</div>
<script>
+document.getElementById("subscribe")["href"] = "javascript:void(0);"
+
+function subscribe() {
+ var url = "/subscription_ajax?action_create_subscription_to_channel=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>";
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = "json";
+ xhr.timeout = 20000;
+ xhr.open("GET", url, true);
+ xhr.send();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ subscribe_button = document.getElementById("subscribe");
+ subscribe_button.onclick = unsubscribe;
+ subscribe_button.innerHTML = '<b>Unsubscribe from <%= video.author %> <%= video.sub_count_text %></b>'
+ }
+ }
+ }
+}
+
+function unsubscribe() {
+ var url = "/subscription_ajax?action_remove_subscriptions=1&c=<%= video.ucid %>&referer=<%= env.get("current_page") %>";
+ var xhr = new XMLHttpRequest();
+ xhr.responseType = "json";
+ xhr.timeout = 20000;
+ xhr.open("GET", url, true);
+ xhr.send();
+
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState == 4) {
+ if (xhr.status == 200) {
+ subscribe_button = document.getElementById("subscribe");
+ subscribe_button.onclick = subscribe;
+ subscribe_button.innerHTML = '<b>Subscribe to <%= video.author %> <%= video.sub_count_text %></b>'
+ }
+ }
+ }
+}
+
<% if plid %>
function get_playlist() {
var plid = "<%= plid %>"