Add support for genre channels

This commit is contained in:
Omar Roth 2018-09-04 21:04:40 -05:00
parent e1bf7fa6cc
commit 5632e58636
3 changed files with 93 additions and 32 deletions

View file

@ -1382,24 +1382,40 @@ get "/feed/channel/:ucid" do |env|
end end
ucid = ucid.content ucid = ucid.content
author = rss.xpath_node("//author/name").not_nil!.content
next env.redirect "/feed/channel/#{ucid}" next env.redirect "/feed/channel/#{ucid}"
else
rss = client.get("/feeds/videos.xml?channel_id=#{ucid}")
rss = XML.parse_html(rss.body)
ucid = rss.xpath_node("//feed/channelid")
if !ucid
error_message = "User does not exist."
next templated "error"
end end
url = produce_channel_videos_url(ucid) ucid = ucid.content
author = rss.xpath_node("//author/name").not_nil!.content
end
# Auto-generated channels
# https://support.google.com/youtube/answer/2579942
if author.ends_with? " - Topic"
auto_generated = true
end
url = produce_channel_videos_url(ucid, auto_generated: auto_generated)
response = client.get(url) response = client.get(url)
json = JSON.parse(response.body) json = JSON.parse(response.body)
if json["content_html"].as_s.empty? if json["content_html"]? && !json["content_html"].as_s.empty?
if response.status_code == 500 document = XML.parse_html(json["content_html"].as_s)
error_message = "This channel does not exist." nodeset = document.xpath_nodes(%q(//li[contains(@class, "feed-item-container")]))
halt env, status_code: 404, response: error_message
else
next ""
end
end
content_html = json["content_html"].as_s videos = extract_videos(nodeset, ucid)
document = XML.parse_html(content_html) else
videos = [] of SearchVideo
end
channel = get_channel(ucid, client, PG_DB, pull_all_videos: false) channel = get_channel(ucid, client, PG_DB, pull_all_videos: false)
@ -1420,8 +1436,7 @@ get "/feed/channel/:ucid" do |env|
xml.element("uri") { xml.text "#{host_url}/channel/#{ucid}" } xml.element("uri") { xml.text "#{host_url}/channel/#{ucid}" }
end end
nodeset = document.xpath_nodes(%q(//li[contains(@class, "feed-item-container")])) videos.each do |video|
extract_videos(nodeset, ucid).each do |video|
xml.element("entry") do xml.element("entry") do
xml.element("id") { xml.text "yt:video:#{video.id}" } xml.element("id") { xml.text "yt:video:#{video.id}" }
xml.element("yt:videoId") { xml.text video.id } xml.element("yt:videoId") { xml.text video.id }
@ -1605,24 +1620,39 @@ get "/channel/:ucid" do |env|
end end
ucid = ucid.content ucid = ucid.content
author = rss.xpath_node("//author/name").not_nil!.content
next env.redirect "/channel/#{ucid}" next env.redirect "/channel/#{ucid}"
end else
rss = client.get("/feeds/videos.xml?channel_id=#{ucid}") rss = client.get("/feeds/videos.xml?channel_id=#{ucid}")
if rss.status_code == 404 rss = XML.parse_html(rss.body)
error_message = "This channel does not exist."
ucid = rss.xpath_node("//feed/channelid")
if !ucid
error_message = "User does not exist."
next templated "error" next templated "error"
end end
rss = XML.parse_html(rss.body) ucid = ucid.content
author = rss.xpath_node("//feed/author/name").not_nil!.content author = rss.xpath_node("//author/name").not_nil!.content
end
begin # Auto-generated channels
videos = extract_playlist(ucid, page) # https://support.google.com/youtube/answer/2579942
videos.each { |a| a.playlists.clear } if author.ends_with? " - Topic"
rescue ex auto_generated = true
error_message = ex.message end
next templated "error"
url = produce_channel_videos_url(ucid, page, auto_generated: auto_generated)
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")]))
videos = extract_videos(nodeset, ucid)
else
videos = [] of SearchVideo
end end
templated "channel" templated "channel"
@ -2236,11 +2266,29 @@ get "/api/v1/channels/:ucid" do |env|
end end
ucid = ucid.content ucid = ucid.content
url = "/api/v1/channels/#{ucid}" author = rss.xpath_node("//author/name").not_nil!.content
next env.redirect url next env.redirect "/api/v1/channels/#{ucid}"
else
rss = client.get("/feeds/videos.xml?channel_id=#{ucid}")
rss = XML.parse_html(rss.body)
ucid = rss.xpath_node("//feed/channelid")
if !ucid
error_message = "User does not exist."
next templated "error"
end end
url = produce_channel_videos_url(ucid, 1) ucid = ucid.content
author = rss.xpath_node("//author/name").not_nil!.content
end
# Auto-generated channels
# https://support.google.com/youtube/answer/2579942
if author.ends_with? " - Topic"
auto_generated = true
end
url = produce_channel_videos_url(ucid, 1, auto_generated)
response = client.get(url) response = client.get(url)
json = JSON.parse(response.body) json = JSON.parse(response.body)

View file

@ -131,10 +131,23 @@ def fetch_channel(ucid, client, db, pull_all_videos = true)
return channel return channel
end end
def produce_channel_videos_url(ucid, page = 1) def produce_channel_videos_url(ucid, page = 1, auto_generated = nil)
page = "#{page}" if auto_generated
seed = Time.epoch(1525757349)
meta = "\x12\x06videos \x00\x30\x02\x38\x01\x60\x01\x6a\x00\x7a" until seed >= Time.now
seed += 1.month
end
timestamp = seed - (page - 1).months
page = "#{timestamp.epoch}"
switch = "\x36"
else
page = "#{page}"
switch = "\x00"
end
meta = "\x12\x06videos #{switch}\x30\x02\x38\x01\x60\x01\x6a\x00\x7a"
meta += page.size.to_u8.unsafe_chr meta += page.size.to_u8.unsafe_chr
meta += page meta += page
meta += "\xb8\x01\x00" meta += "\xb8\x01\x00"

View file

@ -51,7 +51,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 videos.size == 100 %> <% if videos.size == 100 || auto_generated %>
<a href="/channel/<%= ucid %>?page=<%= page + 1 %>">Next page</a> <a href="/channel/<%= ucid %>?page=<%= page + 1 %>">Next page</a>
<% end %> <% end %>
</div> </div>