Add channel page

This commit is contained in:
Omar Roth 2018-06-02 19:52:58 -05:00
parent e865a801aa
commit 36ba69be1f
3 changed files with 140 additions and 0 deletions

View file

@ -670,3 +670,82 @@ def decode_time(string)
return time return time
end end
def produce_playlist_url(ucid, index)
ucid = ucid.lstrip("UC")
ucid = "VLUU" + ucid
continuation = write_var_int(index)
continuation.unshift(0x08_u8)
slice = continuation.to_unsafe.to_slice(continuation.size)
continuation = Base64.urlsafe_encode(slice, false)
continuation = "PT:" + continuation
continuation = continuation.bytes
continuation.unshift(0x7a_u8, continuation.size.to_u8)
slice = continuation.to_unsafe.to_slice(continuation.size)
continuation = Base64.urlsafe_encode(slice)
continuation = URI.escape(continuation)
continuation = continuation.bytes
continuation.unshift(continuation.size.to_u8)
continuation.unshift(ucid.size.to_u8)
continuation = ucid.bytes + continuation
continuation.unshift(0x12.to_u8, ucid.size.to_u8)
continuation.unshift(0xe2_u8, 0xa9_u8, 0x85_u8, 0xb2_u8, 2_u8, continuation.size.to_u8)
slice = continuation.to_unsafe.to_slice(continuation.size)
continuation = Base64.urlsafe_encode(slice)
continuation = URI.escape(continuation)
url = "/browse_ajax?action_continuation=1&continuation=#{continuation}"
return url
end
def read_var_int(bytes)
numRead = 0
result = 0
read = bytes[numRead]
if bytes.size == 1
result = bytes[0].to_i32
else
while ((read & 0b10000000) != 0)
read = bytes[numRead].to_u64
value = (read & 0b01111111)
result |= (value << (7 * numRead))
numRead += 1
if numRead > 5
raise "VarInt is too big"
end
end
end
return result
end
def write_var_int(value : Int)
bytes = [] of UInt8
value = value.to_u32
if value == 0
bytes = [0_u8]
else
while value != 0
temp = (value & 0b01111111).to_u8
value = value >> 7
if value != 0
temp |= 0b10000000
end
bytes << temp
end
end
return bytes
end

View file

@ -908,6 +908,41 @@ get "/videoplayback" do |env|
end end
end end
get "/channel/:ucid" do |env|
ucid = env.params.url["ucid"]
page = env.params.query["page"]?.try &.to_i
page ||= 1
client = make_client(YT_URL)
if !ucid.starts_with? "UC"
rss = client.get("/feeds/videos.xml?user=#{ucid}").body
rss = XML.parse_html(rss)
ucid = rss.xpath_node("//feed/channelid").not_nil!.content
env.redirect "/channel/#{ucid}"
end
url = produce_playlist_url(ucid, (page - 1) * 100)
response = client.get(url)
json = JSON.parse(response.body)
document = XML.parse_html(json["content_html"].as_s)
author = document.xpath_node(%q(//div[@class="pl-video-owner"]/a)).not_nil!.content
videos = [] of ChannelVideo
document.xpath_nodes(%q(//a[contains(@class,"pl-video-title-link")])).each do |item|
href = URI.parse(item["href"])
id = HTTP::Params.parse(href.query.not_nil!)["v"]
title = item.content
videos << ChannelVideo.new(id, title, Time.now, Time.now, ucid, author)
end
templated "channel"
end
options "/videoplayback" do |env| options "/videoplayback" do |env|
env.response.headers["Access-Control-Allow-Origin"] = "*" env.response.headers["Access-Control-Allow-Origin"] = "*"
env.response.headers["Access-Control-Allow-Methods"] = "GET" env.response.headers["Access-Control-Allow-Methods"] = "GET"

26
src/views/channel.ecr Normal file
View file

@ -0,0 +1,26 @@
<% content_for "header" do %>
<title><%= author %> - Invidious</title>
<% end %>
<h1><%= author %></h1>
<% videos.each_slice(4) do |slice| %>
<div class="pure-g">
<% slice.each do |video| %>
<%= rendered "components/video" %>
<% end %>
</div>
<% end %>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-5">
<% if page > 2 %>
<a href="/channel/<%= ucid %>?page=<%= page - 1 %>">Previous page</a>
<% else %>
<a href="/channel/<%= ucid %>">Previous page</a>
<% end %>
</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">
<a href="/channel/<%= ucid %>?page=<%= page + 1 %>">Next page</a>
</div>
</div>