Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Search not showing next page button when a next page exists #4126

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/invidious/routes/api/v1/channels.cr
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ module Invidious::Routes::API::V1::Channels
query.channel = env.params.url["ucid"]

begin
search_results = query.process
search_results, _ = query.process
rescue ex
return error_json(400, ex)
end
Expand Down
2 changes: 1 addition & 1 deletion src/invidious/routes/api/v1/search.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Invidious::Routes::API::V1::Search
query = Invidious::Search::Query.new(env.params.query, :regular, region)

begin
search_results = query.process
search_results, _ = query.process
rescue ex
return error_json(400, ex)
end
Expand Down
6 changes: 4 additions & 2 deletions src/invidious/routes/playlists.cr
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,19 @@ module Invidious::Routes::Playlists

begin
query = Invidious::Search::Query.new(env.params.query, :playlist, region)
items = query.process.select(SearchVideo).map(&.as(SearchVideo))
processed_query, has_continuation = query.process
items = processed_query.select(SearchVideo).map(&.as(SearchVideo))
rescue ex
items = [] of SearchVideo
has_continuation = false
end

# Pagination
query_encoded = URI.encode_www_form(query.try &.text || "", space_to_plus: true)
page_nav_html = Frontend::Pagination.nav_numeric(locale,
base_url: "/add_playlist_items?list=#{playlist.id}&q=#{query_encoded}",
current_page: page,
show_next: (items.size >= 20)
show_next: has_continuation
)

env.set "add_playlist_items", plid
Expand Down
4 changes: 2 additions & 2 deletions src/invidious/routes/search.cr
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module Invidious::Routes::Search
user = env.get? "user"

begin
items = query.process
items, has_continuation = query.process
rescue ex : ChannelSearchException
return error_template(404, "Unable to find channel with id of '#{HTML.escape(ex.channel)}'. Are you sure that's an actual channel id? It should look like 'UC4QobU6STFB0P71PMvOGN5A'.")
rescue ex
Expand All @@ -65,7 +65,7 @@ module Invidious::Routes::Search
page_nav_html = Frontend::Pagination.nav_numeric(locale,
base_url: "/search?#{query.to_http_params}",
current_page: query.page,
show_next: (items.size >= 20)
show_next: has_continuation
)

if query.type == Invidious::Search::Query::Type::Channel
Expand Down
12 changes: 6 additions & 6 deletions src/invidious/search/processors.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ module Invidious::Search
extend self

# Regular search (`/search` endpoint)
def regular(query : Query) : Array(SearchItem)
def regular(query : Query) : {Array(SearchItem), Bool}
search_params = query.filters.to_yt_params(page: query.page)

client_config = YoutubeAPI::ClientConfig.new(region: query.region)
initial_data = YoutubeAPI.search(query.text, search_params, client_config: client_config)

items, _ = extract_items(initial_data)
return items.reject!(Category)
items, next_continuation = extract_items(initial_data)
return items.reject!(Category), next_continuation != nil
end

# Search a youtube channel
# TODO: clean code, and rely more on YoutubeAPI
def channel(query : Query) : Array(SearchItem)
def channel(query : Query) : {Array(SearchItem), Bool}
response = YT_POOL.client &.get("/channel/#{query.channel}")

if response.status_code == 404
Expand All @@ -31,8 +31,8 @@ module Invidious::Search
continuation = produce_channel_search_continuation(ucid, query.text, query.page)
response_json = YoutubeAPI.browse(continuation)

items, _ = extract_items(response_json, "", ucid)
return items.reject!(Category)
items, next_continuation = extract_items(response_json, "", ucid)
return items.reject!(Category), next_continuation != nil
end

# Search inside of user subscriptions
Expand Down
12 changes: 7 additions & 5 deletions src/invidious/search/query.cr
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,28 @@ module Invidious::Search

# Run the search query using the corresponding search processor.
# Returns either the results or an empty array of `SearchItem`.
def process(user : Invidious::User? = nil) : Array(SearchItem) | Array(ChannelVideo)
def process(user : Invidious::User? = nil) : {Array(SearchItem) | Array(ChannelVideo), Bool}
items = [] of SearchItem

has_continuation = false
# Don't bother going further if search query is empty
return items if self.empty_raw_query?
return items, has_continuation if self.empty_raw_query?

case @type
when .regular?, .playlist?
items = Processors.regular(self)
items, has_continuation = Processors.regular(self)
#
when .channel?
items = Processors.channel(self)
items, has_continuation = Processors.channel(self)
#
when .subscriptions?
if user
items = Processors.subscriptions(self, user.as(Invidious::User))
has_continuation = items.size >= 20
end
end

return items
return items, has_continuation
end

# Return the HTTP::Params corresponding to this Query (invidious format)
Expand Down
9 changes: 6 additions & 3 deletions src/invidious/yt_backend/extractors.cr
Original file line number Diff line number Diff line change
Expand Up @@ -717,11 +717,14 @@ private module Extractors
end

private def self.extract(target)
raw_items = [] of Array(JSON::Any)
raw_items = [] of JSON::Any

target.dig("primaryContents", "sectionListRenderer", "contents").as_a.each do |node|
if node = node["itemSectionRenderer"]?
raw_items << node["contents"].as_a
if new_node = node["itemSectionRenderer"]?
raw_items += new_node["contents"].as_a
elsif node["continuationItemRenderer"]?
# we put the node in an array so the ContinuationItemRendererParser is able to parse it
raw_items << node
end
end

Expand Down