Document and reorganize code 4 chan's feat. chans
This commit is contained in:
parent
cc10675610
commit
a6f3c80b6b
@ -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)}
|
||||
# Continuation to load more channel catagories
|
||||
if continuation.is_a?(String)
|
||||
initial_data = request_youtube_api_browse(continuation)
|
||||
items = extract_items(initial_data)
|
||||
continuation_token = fetch_continuation_token(initial_data)
|
||||
# Fetches the featured channel categories of a channel
|
||||
#
|
||||
# Returned as an array of Category objects containing different channels.
|
||||
def fetch_channel_featured_channels(ucid) : Array(Category)
|
||||
initial_data = request_youtube_api_browse(ucid, "EghjaGFubmVscw%3D%3D")
|
||||
|
||||
return [Category.new({
|
||||
title: query_title.not_nil!, # If continuation contents is requested then the query_title has to be passed along.
|
||||
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"]?
|
||||
|
||||
# If the featured channel tabs lacks categories then that means the channel doesn't feature any other channels.
|
||||
if !submenu
|
||||
return [] of Category
|
||||
end
|
||||
|
||||
# Fetches the fallback title.
|
||||
submenu_data = submenu["channelSubMenuRenderer"]["contentTypeSubMenuItems"]
|
||||
fallback_title = submenu_data.as_a.select(&.["selected"].as_bool)[0]["title"].as_s
|
||||
|
||||
items = extract_items(initial_data)
|
||||
|
||||
category_array = [] of Category
|
||||
items.each do |category|
|
||||
# The items can either be an Array of Categories or an Array of channels.
|
||||
if !category.is_a?(Category)
|
||||
break
|
||||
end
|
||||
|
||||
# category.title = category.title.empty? ? fallback_title : category.title
|
||||
category_array << category
|
||||
end
|
||||
|
||||
# If the returned data is only an array of channels then it means that the featured channel tab only has one category.
|
||||
# This is due to the fact that InnerTube uses a "gridRenderer" (an array of items) when only one category is present.
|
||||
# However, as the InnerTube result is a "gridRenderer" and not an "shelfRenderer", an object representing an
|
||||
# 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
|
||||
# which we fetched above. We can then use all of these values together to produce a Category object.
|
||||
if category_array.empty?
|
||||
category_array << Category.new({
|
||||
title: fallback_title,
|
||||
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"])
|
||||
submenu = channels_tab["content"]["sectionListRenderer"]["subMenu"]?
|
||||
|
||||
# There's no submenu data if the channel doesn't feature any channels.
|
||||
if !submenu
|
||||
return {[] of Category, continuation_token}
|
||||
end
|
||||
|
||||
submenu_data = submenu["channelSubMenuRenderer"]["contentTypeSubMenuItems"]
|
||||
|
||||
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
|
||||
items.each do |category|
|
||||
# Tell compiler that the result from extract_items has to be an array of Categories
|
||||
if !category.is_a?(Category)
|
||||
next
|
||||
end
|
||||
|
||||
category_array << Category.new({
|
||||
title: category.title.empty? ? fallback_title : category.title,
|
||||
contents: category.contents,
|
||||
description_html: category.description_html,
|
||||
url: category.url,
|
||||
badges: nil,
|
||||
})
|
||||
end
|
||||
|
||||
# If no categories has been parsed then it means two things.
|
||||
# - We're currently viewing a specific channel category
|
||||
# - We're currently requesting the continuation contents for that specific category.
|
||||
# And since Youtube dyanmically loads more channels onto the page via JS, the data returned from InnerTube will only contains
|
||||
# channels. Thus, we'll just go ahead and create one for the template to use.
|
||||
if category_array.empty?
|
||||
category_array << Category.new({
|
||||
title: fallback_title,
|
||||
contents: items,
|
||||
description_html: "",
|
||||
url: url,
|
||||
badges: nil,
|
||||
})
|
||||
end
|
||||
|
||||
return category_array, continuation_token
|
||||
})
|
||||
end
|
||||
|
||||
return category_array
|
||||
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 = {
|
||||
"2:string" => "channels",
|
||||
"4:varint" => view,
|
||||
@ -90,3 +66,50 @@ def produce_featured_channel_browse_param(view : Int64, shelf_id : Int64)
|
||||
|
||||
return browse_params
|
||||
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,36 +116,33 @@ class Invidious::Routes::Channels < Invidious::Routes::BaseRoute
|
||||
|
||||
view = env.params.query["view"]?
|
||||
shelf_id = env.params.query["shelf_id"]?
|
||||
|
||||
# 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"]?
|
||||
if offset
|
||||
offset = offset.to_i
|
||||
else
|
||||
offset = 0
|
||||
end
|
||||
|
||||
# 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"]?
|
||||
|
||||
if continuation
|
||||
offset = env.params.query["offset"]?
|
||||
if offset
|
||||
offset = offset.to_i
|
||||
else
|
||||
offset = 0
|
||||
end
|
||||
|
||||
# Previous continuation
|
||||
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!
|
||||
featured_channel_categories, continuation_token = fetch_channel_featured_channels_category_continuation(continuation, current_category_title)
|
||||
elsif view && shelf_id
|
||||
offset = env.params.query["offset"]?
|
||||
if offset
|
||||
offset = offset.to_i
|
||||
else
|
||||
offset = 0
|
||||
end
|
||||
|
||||
featured_channel_categories, continuation_token = fetch_channel_featured_channels(ucid, "EghjaGFubmVscw%3D%3D", view, shelf_id, continuation, current_category_title).not_nil!
|
||||
featured_channel_categories, continuation_token = fetch_selected_channel_featuring_category(ucid, view, shelf_id)
|
||||
else
|
||||
previous_continuation = nil
|
||||
offset = 0
|
||||
continuation_token = nil
|
||||
featured_channel_categories = fetch_channel_featured_channels(ucid)
|
||||
end
|
||||
|
||||
featured_channel_categories, continuation_token = fetch_channel_featured_channels(ucid, "EghjaGFubmVscw%3D%3D", nil, nil, 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.
|
||||
if featured_channel_categories.is_a? Category
|
||||
featured_channel_categories = [featured_channel_categories]
|
||||
end
|
||||
|
||||
templated "channel/featured_channels", buffer_footer: true
|
||||
|
@ -91,6 +91,7 @@
|
||||
|
||||
<% if !featured_channel_categories.empty? %>
|
||||
<% base_url = "/channel/#{channel.ucid}/channels?view=#{view}&shelf_id=#{shelf_id}" %>
|
||||
|
||||
<div class="pure-g h-box">
|
||||
<div class="pure-u-1 pure-u-lg-1-5">
|
||||
<% if previous_continuation %>
|
||||
|
Loading…
Reference in New Issue
Block a user