Document and reorganize code 4 chan's feat. chans

pull/2059/head
syeopite 4 years ago
parent cc10675610
commit a6f3c80b6b
No known key found for this signature in database
GPG Key ID: 6FA616E5A5294A82

@ -1,82 +1,58 @@
def fetch_channel_featured_channels(ucid, params, view = nil, shelf_id = nil, continuation = nil, query_title = nil) : {Array(Category), (String | Nil)} # Fetches the featured channel categories of a channel
# Continuation to load more channel catagories #
if continuation.is_a?(String) # Returned as an array of Category objects containing different channels.
initial_data = request_youtube_api_browse(continuation) def fetch_channel_featured_channels(ucid) : Array(Category)
items = extract_items(initial_data) initial_data = request_youtube_api_browse(ucid, "EghjaGFubmVscw%3D%3D")
continuation_token = fetch_continuation_token(initial_data)
return [Category.new({
title: query_title.not_nil!, # If continuation contents is requested then the query_title has to be passed along.
contents: items,
description_html: "",
url: nil,
badges: nil,
})], continuation_token
else
url = nil
if view && shelf_id
url = "/channel/#{ucid}/channels?view=#{view}&shelf_id=#{shelf_id}"
params = produce_featured_channel_browse_param(view.to_i64, shelf_id.to_i64)
initial_data = request_youtube_api_browse(ucid, params)
continuation_token = fetch_continuation_token(initial_data)
else
initial_data = request_youtube_api_browse(ucid, params)
continuation_token = nil
end
channels_tab = extract_selected_tab(initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]) channels_tab = extract_selected_tab(initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"])
# The submenu is the content type menu, and is used to select which categories to view fully.
# As a result, it contains the category title which we'll use as a fallback, since Innertube doesn't
# return the title when the channel only has one featured channel category.
submenu = channels_tab["content"]["sectionListRenderer"]["subMenu"]? submenu = channels_tab["content"]["sectionListRenderer"]["subMenu"]?
# There's no submenu data if the channel doesn't feature any channels. # If the featured channel tabs lacks categories then that means the channel doesn't feature any other channels.
if !submenu if !submenu
return {[] of Category, continuation_token} return [] of Category
end end
# Fetches the fallback title.
submenu_data = submenu["channelSubMenuRenderer"]["contentTypeSubMenuItems"] submenu_data = submenu["channelSubMenuRenderer"]["contentTypeSubMenuItems"]
fallback_title = submenu_data.as_a.select(&.["selected"].as_bool)[0]["title"].as_s
items = extract_items(initial_data) items = extract_items(initial_data)
fallback_title = submenu_data.as_a.select(&.["selected"].as_bool)[0]["title"].as_s
# Although extract_items parsed everything into the right structs, we still have
# to fill in the title (if missing) attribute since Youtube doesn't return it when requesting
# a full category (initial)
category_array = [] of Category category_array = [] of Category
items.each do |category| items.each do |category|
# Tell compiler that the result from extract_items has to be an array of Categories # The items can either be an Array of Categories or an Array of channels.
if !category.is_a?(Category) if !category.is_a?(Category)
next break
end end
category_array << Category.new({ # category.title = category.title.empty? ? fallback_title : category.title
title: category.title.empty? ? fallback_title : category.title, category_array << category
contents: category.contents,
description_html: category.description_html,
url: category.url,
badges: nil,
})
end end
# If no categories has been parsed then it means two things. # If the returned data is only an array of channels then it means that the featured channel tab only has one category.
# - We're currently viewing a specific channel category # This is due to the fact that InnerTube uses a "gridRenderer" (an array of items) when only one category is present.
# - We're currently requesting the continuation contents for that specific category. # However, as the InnerTube result is a "gridRenderer" and not an "shelfRenderer", an object representing an
# And since Youtube dyanmically loads more channels onto the page via JS, the data returned from InnerTube will only contains # category or section on youtube, we'll lack the category title. But, the good news is that the title of the category is still stored within the submenu
# channels. Thus, we'll just go ahead and create one for the template to use. # which we fetched above. We can then use all of these values together to produce a Category object.
if category_array.empty? if category_array.empty?
category_array << Category.new({ category_array << Category.new({
title: fallback_title, title: fallback_title,
contents: items, contents: items,
description_html: "", description_html: "",
url: url, url: nil,
badges: nil, badges: nil,
}) })
end end
return category_array, continuation_token return category_array
end
end end
def produce_featured_channel_browse_param(view : Int64, shelf_id : Int64) # Produces the InnerTube parameter for requesting the contents of a specific channel featuring category
private def produce_featured_channel_browse_param(view : Int64, shelf_id : Int64)
object = { object = {
"2:string" => "channels", "2:string" => "channels",
"4:varint" => view, "4:varint" => view,
@ -90,3 +66,50 @@ def produce_featured_channel_browse_param(view : Int64, shelf_id : Int64)
return browse_params return browse_params
end end
# Fetches the first set of channels from a selected channel featuring category
def fetch_selected_channel_featuring_category(ucid, view, shelf_id) : Tuple(Category, String | Nil)
category_url = "/channel/#{ucid}/channels?view=#{view}&shelf_id=#{shelf_id}"
params = produce_featured_channel_browse_param(view.to_i64, shelf_id.to_i64)
initial_data = request_youtube_api_browse(ucid, params)
channels_tab = extract_selected_tab(initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"])
continuation_token = fetch_continuation_token(initial_data)
# Fetches the fallback title
submenu = channels_tab["content"]["sectionListRenderer"]["subMenu"]
submenu_data = submenu["channelSubMenuRenderer"]["contentTypeSubMenuItems"]
fallback_title = submenu_data.as_a.select(&.["selected"].as_bool)[0]["title"].as_s
items = extract_items(initial_data)
# Since the returned items from InnerTube is an array of channels, (See explanation at the end of the fetch_channel_featured_channels function)
# we lack the category title attribute. However, it is still stored as a submenu data which we fetched above. We can then use all of these
# values together to produce a Category object.
return Category.new({
title: fallback_title,
contents: items,
description_html: "",
url: category_url,
badges: nil,
}), continuation_token
end
# Fetches the next set of channels within the selected channel featuring category.
# Requires the continuation token and the query_title.
#
# TODO: The query_title here is really only used for frontend rendering.
# And since it's a URL parameter we should be able to just request it directly within the template files.
def fetch_channel_featured_channels_category_continuation(continuation, query_title) : Tuple(Category, String | Nil)
initial_data = request_youtube_api_browse(continuation)
items = extract_items(initial_data)
continuation_token = fetch_continuation_token(initial_data)
return Category.new({
title: query_title.not_nil!, # If continuation contents is requested then the query_title has to be passed along.
contents: items,
description_html: "",
url: nil,
badges: nil,
}), continuation_token
end

@ -116,11 +116,8 @@ class Invidious::Routes::Channels < Invidious::Routes::BaseRoute
view = env.params.query["view"]? view = env.params.query["view"]?
shelf_id = env.params.query["shelf_id"]? shelf_id = env.params.query["shelf_id"]?
# Category title isn't returned when requesting a specific category or continuation data
# so we have it in through a url param
current_category_title = env.params.query["title"]?
if continuation # The offset is mainly to check if we're at the first page or not and in turn whether we should have a "previous page" button or not.
offset = env.params.query["offset"]? offset = env.params.query["offset"]?
if offset if offset
offset = offset.to_i offset = offset.to_i
@ -128,24 +125,24 @@ class Invidious::Routes::Channels < Invidious::Routes::BaseRoute
offset = 0 offset = 0
end end
# Previous continuation # Category title isn't returned when requesting a specific category or continuation data
# so we have it in through a url param
current_category_title = env.params.query["title"]?
previous_continuation = env.params.query["previous"]? previous_continuation = env.params.query["previous"]?
featured_channel_categories, continuation_token = fetch_channel_featured_channels(ucid, "EghjaGFubmVscw%3D%3D", nil, nil, continuation, current_category_title).not_nil! if continuation
featured_channel_categories, continuation_token = fetch_channel_featured_channels_category_continuation(continuation, current_category_title)
elsif view && shelf_id elsif view && shelf_id
offset = env.params.query["offset"]? featured_channel_categories, continuation_token = fetch_selected_channel_featuring_category(ucid, view, shelf_id)
if offset
offset = offset.to_i
else else
offset = 0 continuation_token = nil
featured_channel_categories = fetch_channel_featured_channels(ucid)
end end
featured_channel_categories, continuation_token = fetch_channel_featured_channels(ucid, "EghjaGFubmVscw%3D%3D", view, shelf_id, continuation, current_category_title).not_nil! # If we only got a single category we'll go ahead and wrap it within an array for easier processing in the template.
else if featured_channel_categories.is_a? Category
previous_continuation = nil featured_channel_categories = [featured_channel_categories]
offset = 0
featured_channel_categories, continuation_token = fetch_channel_featured_channels(ucid, "EghjaGFubmVscw%3D%3D", nil, nil, current_category_title).not_nil!
end end
templated "channel/featured_channels", buffer_footer: true templated "channel/featured_channels", buffer_footer: true

@ -91,6 +91,7 @@
<% if !featured_channel_categories.empty? %> <% if !featured_channel_categories.empty? %>
<% base_url = "/channel/#{channel.ucid}/channels?view=#{view}&shelf_id=#{shelf_id}" %> <% base_url = "/channel/#{channel.ucid}/channels?view=#{view}&shelf_id=#{shelf_id}" %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1 pure-u-lg-1-5"> <div class="pure-u-1 pure-u-lg-1-5">
<% if previous_continuation %> <% if previous_continuation %>

Loading…
Cancel
Save