Add support for channel search

This commit is contained in:
Omar Roth 2018-09-13 17:47:31 -05:00
parent d4ee786cab
commit f7ca81c384
4 changed files with 95 additions and 11 deletions

View file

@ -432,32 +432,39 @@ get "/search" do |env|
page = env.params.query["page"]?.try &.to_i? page = env.params.query["page"]?.try &.to_i?
page ||= 1 page ||= 1
sort = "relevance" channel = nil
date = "" date = ""
duration = "" duration = ""
features = [] of String features = [] of String
sort = "relevance"
operators = query.split(" ").select { |a| a.match(/\w+:[\w,]+/) } operators = query.split(" ").select { |a| a.match(/\w+:[\w,]+/) }
operators.each do |operator| operators.each do |operator|
key, value = operator.split(":") key, value = operator.split(":")
case key case key
when "sort" when "channel", "user"
sort = value channel = value
when "date" when "date"
date = value date = value
when "duration" when "duration"
duration = value duration = value
when "features" when "features"
features = value.split(",") features = value.split(",")
when "sort"
sort = value
end end
end end
search_query = (query.split(" ") - operators).join(" ") search_query = (query.split(" ") - operators).join(" ")
if channel
count, videos = channel_search(search_query, page, channel)
else
search_params = build_search_params(sort: sort, date: date, content_type: "video", search_params = build_search_params(sort: sort, date: date, content_type: "video",
duration: duration, features: features) duration: duration, features: features)
count, videos = search(search_query, page, search_params).as(Tuple) count, videos = search(search_query, page, search_params).as(Tuple)
end
templated "search" templated "search"
end end
@ -1666,6 +1673,14 @@ get "/channel/:ucid" do |env|
auto_generated = true auto_generated = true
end end
if !auto_generated
if author.includes? " "
env.set "search", "channel:#{ucid} "
else
env.set "search", "channel:#{author.downcase} "
end
end
videos = [] of SearchVideo videos = [] of SearchVideo
2.times do |i| 2.times do |i|
url = produce_channel_videos_url(ucid, page * 2 + (i - 1), auto_generated: auto_generated) url = produce_channel_videos_url(ucid, page * 2 + (i - 1), auto_generated: auto_generated)

View file

@ -12,6 +12,43 @@ class SearchVideo
}) })
end end
def channel_search(query, page, channel)
client = make_client(YT_URL)
response = client.get("/user/#{channel}")
document = XML.parse_html(response.body)
canonical = document.xpath_node(%q(//link[@rel="canonical"]))
if !canonical
response = client.get("/channel/#{channel}")
document = XML.parse_html(response.body)
canonical = document.xpath_node(%q(//link[@rel="canonical"]))
end
if !canonical
return 0, [] of SearchVideo
end
ucid = canonical["href"].split("/")[-1]
url = produce_channel_search_url(ucid, query, page)
response = client.get(url)
json = JSON.parse(response.body)
if json["content_html"]? && !json["content_html"].as_s.empty?
document = XML.parse_html(json["content_html"].as_s)
nodeset = document.xpath_nodes(%q(//li[contains(@class, "feed-item-container")]))
count = nodeset.size
videos = extract_videos(nodeset)
else
count = 0
videos = [] of SearchVideo
end
return count, videos
end
def search(query, page = 1, search_params = build_search_params(content_type: "video")) def search(query, page = 1, search_params = build_search_params(content_type: "video"))
client = make_client(YT_URL) client = make_client(YT_URL)
if query.empty? if query.empty?
@ -124,3 +161,35 @@ def build_search_params(sort : String = "relevance", date : String = "", content
return token return token
end end
def produce_channel_search_url(ucid, query, page)
page = "#{page}"
meta = "\x12\x06search0\x02\x38\x01\x60\x01\x6a\x00\x7a"
meta += page.size.to_u8.unsafe_chr
meta += page
meta += "\xb8\x01\x00"
meta = Base64.urlsafe_encode(meta)
meta = URI.escape(meta)
continuation = "\x12"
continuation += ucid.size.to_u8.unsafe_chr
continuation += ucid
continuation += "\x1a"
continuation += meta.size.to_u8.unsafe_chr
continuation += meta
continuation += "\x5a"
continuation += query.size.to_u8.unsafe_chr
continuation += query
continuation = continuation.size.to_u8.unsafe_chr + continuation
continuation = "\xe2\xa9\x85\xb2\x02" + continuation
continuation = Base64.urlsafe_encode(continuation)
continuation = URI.escape(continuation)
url = "/browse_ajax?continuation=#{continuation}"
return url
end

View file

@ -18,7 +18,7 @@
</div> </div>
<div class="pure-u-1 pure-u-md-3-5"></div> <div class="pure-u-1 pure-u-md-3-5"></div>
<div style="text-align:right;" class="pure-u-1 pure-u-md-1-5"> <div style="text-align:right;" class="pure-u-1 pure-u-md-1-5">
<% if count == 20 %> <% if count >= 20 %>
<a href="/search?q=<%= query %>&page=<%= page + 1 %>">Next page</a> <a href="/search?q=<%= query %>&page=<%= page + 1 %>">Next page</a>
<% end %> <% end %>
</div> </div>

View file

@ -28,7 +28,7 @@
<div class="pure-u-1 pure-u-md-12-24 searchbar"> <div class="pure-u-1 pure-u-md-12-24 searchbar">
<form class="pure-form" action="/search" method="get"> <form class="pure-form" action="/search" method="get">
<fieldset> <fieldset>
<input type="search" style="width:100%;" name="q" placeholder="search" value="<%= env.params.query["q"]? %>"> <input type="search" style="width:100%;" name="q" placeholder="search" value="<%= env.params.query["q"]? || env.get? "search" %>">
</fieldset> </fieldset>
</form> </form>
</div> </div>