def search(query, page = 1, search_params = build_search_params(content_type: "video")) client = make_client(YT_URL) html = client.get("/results?q=#{URI.escape(query)}&page=#{page}&sp=#{search_params}").body html = XML.parse_html(html) videos = [] of ChannelVideo html.xpath_nodes(%q(//ol[@class="item-section"]/li)).each do |item| root = item.xpath_node(%q(div[contains(@class,"yt-lockup-video")]/div)) if !root next end id = root.xpath_node(%q(.//div[contains(@class,"yt-lockup-thumbnail")]/a/@href)).not_nil!.content.lchop("/watch?v=") title = root.xpath_node(%q(.//div[@class="yt-lockup-content"]/h3/a)).not_nil!.content author = root.xpath_node(%q(.//div[@class="yt-lockup-content"]/div/a)).not_nil! ucid = author["href"].rpartition("/")[-1] author = author.content published = root.xpath_node(%q(.//ul[@class="yt-lockup-meta-info"]/li[1])).not_nil!.content published = decode_date(published) video = ChannelVideo.new(id, title, published, Time.now, ucid, author) videos << video end return videos end def build_search_params(sort_by = "relevance", date : String = "", content_type : String = "", duration : String = "", features : Array(String) = [] of String) head = "\x08" head += case sort_by when "relevance" "\x00" when "rating" "\x01" when "upload_date" "\x02" when "view_count" "\x03" else raise "No sort #{sort_by}" end body = "" body += case date when "hour" "\x08\x01" when "today" "\x08\x02" when "week" "\x08\x03" when "month" "\x08\x04" when "year" "\x08\x05" else "" end body += case content_type when "video" "\x10\x01" when "channel" "\x10\x02" when "playlist" "\x10\x03" when "movie" "\x10\x04" when "show" "\x10\x05" else "" end body += case duration when "short" "\x18\x01" when "long" "\x18\x02" else "" end features.each do |feature| body += case feature when "hd" "\x20\x01" when "subtitles" "\x28\x01" when "creative_commons" "\x30\x01" when "3d" "\x38\x01" when "live" "\x40\x01" when "purchased" "\x48\x01" when "4k" "\x70\x01" when "360" "\x78\x01" when "location" "\xb8\x01\x01" when "hdr" "\xc8\x01\x01" else raise "Unknown feature #{feature}" end end if body.size > 0 token = head + "\x12" + body.size.to_u8.unsafe_chr + body else token = head end token = Base64.urlsafe_encode(token) token = URI.escape(token) return token end