From 7757eca92c2c3eee7342bb2335741c33eaa945da Mon Sep 17 00:00:00 2001
From: Omar Roth <omarroth@hotmail.com>
Date: Sat, 31 Mar 2018 09:51:14 -0500
Subject: [PATCH] Add subscribe and unsubscribe button

---
 src/invidious.cr    | 85 ++++++++++++++++++++++++++++++++++++++++-----
 src/views/watch.ecr | 15 ++++++++
 2 files changed, 91 insertions(+), 9 deletions(-)

diff --git a/src/invidious.cr b/src/invidious.cr
index dfa0aadf..f4d7f791 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -209,14 +209,24 @@ get "/watch" do |env|
     env.params.query.delete_all("listen")
   end
 
-  yt_client = get_client(youtube_pool)
+  client = get_client(youtube_pool)
+
+  authorized = env.get? "authorized"
+  if authorized
+    sid = env.request.cookies["SID"].value
+
+    subscriptions = PG_DB.query_one("SELECT subscriptions FROM users WHERE id = $1", sid, as: Array(String))
+  else
+    subscriptions = [] of String
+  end
+
   begin
-    video = get_video(id, yt_client, PG_DB)
+    video = get_video(id, client, PG_DB)
   rescue ex
     error_message = ex.message
     next templated "error"
   ensure
-    youtube_pool << yt_client
+    youtube_pool << client
   end
 
   fmt_stream = [] of HTTP::Params
@@ -611,13 +621,13 @@ get "/enable_notifications" do |env|
     headers["content-type"] = "application/x-www-form-urlencoded"
     subs = XML.parse_html(subs.body)
     subs.xpath_nodes(%q(//a[@class="subscription-title yt-uix-sessionlink"]/@href)).each do |channel|
-      channel_id = channel.content.lstrip("/channel/")
+      channel_id = channel.content.lstrip("/channel/").not_nil!
 
       channel_req = {
-        "channel_id"           => channel_id.not_nil!,
+        "channel_id"           => channel_id,
         "receive_all_updates"  => "true",
         "receive_post_updates" => "true",
-        "session_token"        => session_token.not_nil!,
+        "session_token"        => session_token,
       }
 
       channel_req = HTTP::Params.encode(channel_req)
@@ -651,14 +661,14 @@ get "/disable_notifications" do |env|
     headers["content-type"] = "application/x-www-form-urlencoded"
     subs = XML.parse_html(subs.body)
     subs.xpath_nodes(%q(//a[@class="subscription-title yt-uix-sessionlink"]/@href)).each do |channel|
-      channel_id = channel.content.lstrip("/channel/")
+      channel_id = channel.content.lstrip("/channel/").not_nil!
 
       channel_req = {
-        "channel_id"           => channel_id.not_nil!,
+        "channel_id"           => channel_id,
         "receive_all_updates"  => "false",
         "receive_no_updates"   => "false",
         "receive_post_updates" => "true",
-        "session_token"        => session_token.not_nil!,
+        "session_token"        => session_token,
       }
 
       channel_req = HTTP::Params.encode(channel_req)
@@ -672,6 +682,63 @@ get "/disable_notifications" do |env|
   env.redirect "/"
 end
 
+get "/subscription_ajax" do |env|
+  authorized = env.get? "authorized"
+  referer = env.request.headers["referer"]?
+  referer ||= "/"
+
+  if authorized
+    if env.params.query["action_create_subscription_to_channel"]?
+      action = "action_create_subscription_to_channel"
+    elsif env.params.query["action_remove_subscriptions"]?
+      action = "action_remove_subscriptions"
+    else
+      action = ""
+      env.redirect referer
+    end
+
+    channel_id = env.params.query["c"]?
+    channel_id ||= ""
+
+    headers = HTTP::Headers.new
+    headers["Cookie"] = env.request.headers["Cookie"]
+
+    client = get_client(youtube_pool)
+    subs = client.get("/subscription_manager?disable_polymer=1", headers)
+    headers["Cookie"] += "; " + subs.cookies.add_request_headers(headers)["Cookie"]
+    match = subs.body.match(/'XSRF_TOKEN': "(?<session_token>[A-Za-z0-9\_\-\=]+)"/)
+    if match
+      session_token = match["session_token"]
+    else
+      next env.redirect "/"
+    end
+
+    headers["content-type"] = "application/x-www-form-urlencoded"
+
+    post_req = {
+      "session_token" => session_token,
+    }
+    post_req = HTTP::Params.encode(post_req)
+    post_url = "/subscription_ajax?#{action}=1&c=#{channel_id}"
+
+    # Update user
+    if client.post(post_url, headers, post_req).status_code == 200
+      sid = env.request.cookies["SID"].value
+
+      case action
+      when .starts_with? "action_create"
+        PG_DB.exec("UPDATE users SET subscriptions = array_append(subscriptions,$1) WHERE id = $2", channel_id, sid)
+      when .starts_with? "action_remove"
+        PG_DB.exec("UPDATE users SET subscriptions = array_remove(subscriptions,$1) WHERE id = $2", channel_id, sid)
+      end
+    end
+
+    youtube_pool << client
+  end
+
+  env.redirect referer
+end
+
 error 404 do |env|
   error_message = "404 Page not found"
   templated "error"
diff --git a/src/views/watch.ecr b/src/views/watch.ecr
index 5f251160..010f13a1 100644
--- a/src/views/watch.ecr
+++ b/src/views/watch.ecr
@@ -132,6 +132,21 @@ function toggle_comments(target) {
                     <h3><%= video.info["author"] %></h3>
                 </a>
             </p>
+        <% if authorized %>
+            <% if subscriptions.includes? video.info["ucid"] %>
+            <p>
+                <a href="/subscription_ajax?action_remove_subscriptions=1&c=<%= video.info["ucid"] %>">
+                    <b>Unsubscribe from <%= video.info["author"] %></b>
+                </a>
+            </p>
+            <% else %>
+            <p>
+                <a href="/subscription_ajax?action_create_subscription_to_channel=1&c=<%= video.info["ucid"] %>">
+                    <b>Subscribe to <%= video.info["author"] %></b>
+                </a>
+            </p>
+            <% end %>
+        <% end %>
             <p>
                 <b>Shared <%= video.published.to_s("%B %-d, %Y") %></b>
             </p>