summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSamantaz Fox <coding@samantaz.fr>2023-07-16 17:23:23 +0200
committerSamantaz Fox <coding@samantaz.fr>2023-07-18 00:29:25 +0200
commitc1a69e4a4a8b581ec743b7b3f741097d6596cb3b (patch)
tree1946a8ad32bc4a64aadd53193072410985b585c2 /src
parent69e2eaccc017cbf0caed2f79fa789cdb0b2a2cdf (diff)
downloadinvidious-c1a69e4a4a8b581ec743b7b3f741097d6596cb3b.tar.gz
invidious-c1a69e4a4a8b581ec743b7b3f741097d6596cb3b.tar.bz2
invidious-c1a69e4a4a8b581ec743b7b3f741097d6596cb3b.zip
Channels: Use innertube to fetch the community tab
Diffstat (limited to 'src')
-rw-r--r--src/invidious/channels/community.cr56
-rw-r--r--src/invidious/yt_backend/extractors.cr26
2 files changed, 35 insertions, 47 deletions
diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr
index aac4bc8a..1a54a946 100644
--- a/src/invidious/channels/community.cr
+++ b/src/invidious/channels/community.cr
@@ -1,49 +1,31 @@
private IMAGE_QUALITIES = {320, 560, 640, 1280, 2000}
# TODO: Add "sort_by"
-def fetch_channel_community(ucid, continuation, locale, format, thin_mode)
- response = YT_POOL.client &.get("/channel/#{ucid}/community?gl=US&hl=en")
- if response.status_code != 200
- response = YT_POOL.client &.get("/user/#{ucid}/community?gl=US&hl=en")
- end
-
- if response.status_code != 200
- raise NotFoundException.new("This channel does not exist.")
- end
-
- ucid = response.body.match(/https:\/\/www.youtube.com\/channel\/(?<ucid>UC[a-zA-Z0-9_-]{22})/).not_nil!["ucid"]
-
- if !continuation || continuation.empty?
- initial_data = extract_initial_data(response.body)
- body = extract_selected_tab(initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"])["content"]["sectionListRenderer"]["contents"][0]["itemSectionRenderer"]
-
- if !body
- raise InfoException.new("Could not extract community tab.")
+def fetch_channel_community(ucid, cursor, locale, format, thin_mode)
+ if cursor.nil?
+ # Egljb21tdW5pdHk%3D is the protobuf object to load "community"
+ initial_data = YoutubeAPI.browse(ucid, params: "Egljb21tdW5pdHk%3D")
+
+ items = [] of JSON::Any
+ extract_items(initial_data) do |item|
+ items << item
end
else
- continuation = produce_channel_community_continuation(ucid, continuation)
-
- headers = HTTP::Headers.new
- headers["cookie"] = response.cookies.add_request_headers(headers)["cookie"]
-
- session_token = response.body.match(/"XSRF_TOKEN":"(?<session_token>[^"]+)"/).try &.["session_token"]? || ""
- post_req = {
- session_token: session_token,
- }
+ continuation = produce_channel_community_continuation(ucid, cursor)
+ initial_data = YoutubeAPI.browse(continuation: continuation)
- body = YoutubeAPI.browse(continuation)
+ container = initial_data.dig?("continuationContents", "itemSectionContinuation", "contents")
- body = body.dig?("continuationContents", "itemSectionContinuation") ||
- body.dig?("continuationContents", "backstageCommentsContinuation")
+ raise InfoException.new("Can't extract community data") if container.nil?
- if !body
- raise InfoException.new("Could not extract continuation.")
- end
+ items = container.as_a
end
- posts = body["contents"].as_a
+ return extract_channel_community(items, ucid: ucid, locale: locale, format: format, thin_mode: thin_mode)
+end
- if message = posts[0]["messageRenderer"]?
+def extract_channel_community(items, *, ucid, locale, format, thin_mode)
+ if message = items[0]["messageRenderer"]?
error_message = (message["text"]["simpleText"]? ||
message["text"]["runs"]?.try &.[0]?.try &.["text"]?)
.try &.as_s || ""
@@ -59,7 +41,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode)
json.field "authorId", ucid
json.field "comments" do
json.array do
- posts.each do |post|
+ items.each do |post|
comments = post["backstagePostThreadRenderer"]?.try &.["comments"]? ||
post["backstageCommentsContinuation"]?
@@ -242,7 +224,7 @@ def fetch_channel_community(ucid, continuation, locale, format, thin_mode)
end
end
end
- if cont = posts.dig?(-1, "continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token")
+ if cont = items.dig?(-1, "continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token")
json.field "continuation", extract_channel_community_cursor(cont.as_s)
end
end
diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr
index e5029dc5..8cf59d50 100644
--- a/src/invidious/yt_backend/extractors.cr
+++ b/src/invidious/yt_backend/extractors.cr
@@ -608,19 +608,25 @@ private module Extractors
private def self.unpack_section_list(contents)
raw_items = [] of JSON::Any
- contents.as_a.each do |renderer_container|
- renderer_container_contents = renderer_container["itemSectionRenderer"]["contents"][0]
-
- # Category extraction
- if items_container = renderer_container_contents["shelfRenderer"]?
- raw_items << renderer_container_contents
- next
- elsif items_container = renderer_container_contents["gridRenderer"]?
+ contents.as_a.each do |item|
+ if item_section_content = item.dig?("itemSectionRenderer", "contents")
+ raw_items += self.unpack_item_section(item_section_content)
else
- items_container = renderer_container_contents
+ raw_items << item
end
+ end
- items_container["items"]?.try &.as_a.each do |item|
+ return raw_items
+ end
+
+ private def self.unpack_item_section(contents)
+ raw_items = [] of JSON::Any
+
+ contents.as_a.each do |item|
+ # Category extraction
+ if container = item.dig?("gridRenderer", "items") || item.dig?("items")
+ raw_items += container.as_a
+ else
raw_items << item
end
end