diff --git a/src/invidious.cr b/src/invidious.cr index b151a090..c2e174a1 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -1399,44 +1399,18 @@ get "/feed/subscriptions" do |env| end get "/feed/channel/:ucid" do |env| + env.response.content_type = "text/xml" ucid = env.params.url["ucid"] + begin + author, ucid, auto_generated = get_about_info(ucid) + rescue ex + error_message = "User does not exist" + halt env, status_code: 404, response: error_message + end + client = make_client(YT_URL) - if !ucid.match(/UC[a-zA-Z0-9_-]{22}/) - rss = client.get("/feeds/videos.xml?user=#{ucid}") - rss = XML.parse_html(rss.body) - - ucid = rss.xpath_node("//feed/channelid") - if !ucid - error_message = "User does not exist." - halt env, status_code: 404, response: error_message - end - - ucid = ucid.content - author = rss.xpath_node("//author/name").not_nil!.content - 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 - - 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") || - {"Popular on YouTube", "Music", "Sports", "Gaming"}.includes? author - auto_generated = true - end - page = 1 videos = [] of SearchVideo @@ -1459,8 +1433,6 @@ get "/feed/channel/:ucid" do |env| end end - channel = get_channel(ucid, client, PG_DB, pull_all_videos: false) - host_url = make_host_url(Kemal.config.ssl || CONFIG.https_only, env.request.headers["Host"]?) path = env.request.path @@ -1470,11 +1442,11 @@ get "/feed/channel/:ucid" do |env| xml.element("link", rel: "self", href: "#{host_url}#{path}") xml.element("id") { xml.text "yt:channel:#{ucid}" } xml.element("yt:channelId") { xml.text ucid } - xml.element("title") { xml.text channel.author } + xml.element("title") { xml.text author } xml.element("link", rel: "alternate", href: "#{host_url}/channel/#{ucid}") xml.element("author") do - xml.element("name") { xml.text channel.author } + xml.element("name") { xml.text author } xml.element("uri") { xml.text "#{host_url}/channel/#{ucid}" } end @@ -1513,7 +1485,6 @@ get "/feed/channel/:ucid" do |env| end end - env.response.content_type = "text/xml" feed end @@ -1691,40 +1662,11 @@ get "/channel/:ucid" do |env| page = env.params.query["page"]?.try &.to_i? page ||= 1 - client = make_client(YT_URL) - - if !ucid.match(/UC[a-zA-Z0-9_-]{22}/) - rss = client.get("/feeds/videos.xml?user=#{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 - - ucid = ucid.content - author = rss.xpath_node("//author/name").not_nil!.content - next env.redirect "/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 - - 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") || - {"Popular on YouTube", "Music", "Sports", "Gaming"}.includes? author - auto_generated = true + begin + author, ucid, auto_generated = get_about_info(ucid) + rescue ex + error_message = "User does not exist" + next templated "error" end if !auto_generated @@ -1735,6 +1677,8 @@ get "/channel/:ucid" do |env| end end + client = make_client(YT_URL) + videos = [] of SearchVideo 2.times do |i| url = produce_channel_videos_url(ucid, page * 2 + (i - 1), auto_generated: auto_generated) @@ -2175,8 +2119,8 @@ get "/api/v1/videos/:id" do |env| video = get_video(id, PG_DB) rescue ex env.response.content_type = "application/json" - response = {"error" => ex.message}.to_json - halt env, status_code: 500, response: response + error_message = {"error" => ex.message}.to_json + halt env, status_code: 500, response: error_message end fmt_stream = video.fmt_stream(decrypt_function) @@ -2425,42 +2369,20 @@ get "/api/v1/top" do |env| end get "/api/v1/channels/:ucid" do |env| + env.response.content_type = "application/json" + ucid = env.params.url["ucid"] + begin + author, ucid, auto_generated = get_about_info(ucid) + rescue ex + puts ex.message + + error_message = {"error" => "User does not exist"}.to_json + halt env, status_code: 404, response: error_message + end + client = make_client(YT_URL) - if !ucid.match(/UC[a-zA-Z0-9_-]{22}/) - rss = client.get("/feeds/videos.xml?user=#{ucid}") - rss = XML.parse_html(rss.body) - - ucid = rss.xpath_node("//feed/channelid") - if !ucid - env.response.content_type = "application/json" - next {"error" => "User does not exist"}.to_json - end - - ucid = ucid.content - author = rss.xpath_node("//author/name").not_nil!.content - 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 - - 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") || - {"Popular on YouTube", "Music", "Sports", "Gaming"}.includes? author - auto_generated = true - end page = 1 @@ -2601,52 +2523,26 @@ get "/api/v1/channels/:ucid" do |env| end end - env.response.content_type = "application/json" channel_info end ["/api/v1/channels/:ucid/videos", "/api/v1/channels/videos/:ucid"].each do |route| get route do |env| + env.response.content_type = "application/json" + ucid = env.params.url["ucid"] page = env.params.query["page"]?.try &.to_i? page ||= 1 + begin + author, ucid, auto_generated = get_about_info(ucid) + rescue ex + error_message = {"error" => "User does not exist"}.to_json + halt env, status_code: 404, response: error_message + end + client = make_client(YT_URL) - if !ucid.match(/UC[a-zA-Z0-9_-]{22}/) - rss = client.get("/feeds/videos.xml?user=#{ucid}") - rss = XML.parse_html(rss.body) - - ucid = rss.xpath_node("//feed/channelid") - if !ucid - env.response.content_type = "application/json" - next {"error" => "User does not exist"}.to_json - end - - ucid = ucid.content - author = rss.xpath_node("//author/name").not_nil!.content - 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 - - 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") || - {"Popular on YouTube", "Music", "Sports", "Gaming"}.includes? author - auto_generated = true - end - videos = [] of SearchVideo 2.times do |i| url = produce_channel_videos_url(ucid, page * 2 + (i - 1), auto_generated: auto_generated) @@ -2700,7 +2596,6 @@ end end end - env.response.content_type = "application/json" result end end @@ -2826,6 +2721,7 @@ get "/api/v1/search" do |env| end get "/api/v1/playlists/:plid" do |env| + env.response.content_type = "application/json" plid = env.params.url["plid"] page = env.params.query["page"]?.try &.to_i? @@ -2834,9 +2730,8 @@ get "/api/v1/playlists/:plid" do |env| begin videos = extract_playlist(plid, page) rescue ex - env.response.content_type = "application/json" - response = {"error" => "Playlist is empty"}.to_json - halt env, status_code: 404, response: response + error_message = {"error" => "Playlist is empty"}.to_json + halt env, status_code: 404, response: error_message end playlist = fetch_playlist(plid) @@ -2881,7 +2776,6 @@ get "/api/v1/playlists/:plid" do |env| end end - env.response.content_type = "application/json" response end diff --git a/src/invidious/channels.cr b/src/invidious/channels.cr index 02e260ad..672d3c04 100644 --- a/src/invidious/channels.cr +++ b/src/invidious/channels.cr @@ -176,3 +176,32 @@ def produce_channel_videos_url(ucid, page = 1, auto_generated = nil) return url end + +def get_about_info(ucid) + client = make_client(YT_URL) + + about = client.get("/user/#{ucid}/about?disable_polymer=1") + about = XML.parse_html(about.body) + + if !about.xpath_node(%q(//span[@class="qualified-channel-title-text"]/a)) + about = client.get("/channel/#{ucid}/about?disable_polymer=1") + about = XML.parse_html(about.body) + end + + if !about.xpath_node(%q(//span[@class="qualified-channel-title-text"]/a)) + raise "User does not exist." + end + + author = about.xpath_node(%q(//span[@class="qualified-channel-title-text"]/a)).not_nil!.content + ucid = about.xpath_node(%q(//link[@rel="canonical"])).not_nil!["href"].split("/")[-1] + + # Auto-generated channels + # https://support.google.com/youtube/answer/2579942 + auto_generated = false + if about.xpath_node(%q(//ul[@class="about-custom-links"]/li/a[@title="Auto-generated by YouTube"])) || + about.xpath_node(%q(//span[@class="qualified-channel-title-badge"]/span[@title="Auto-generated by YouTube"])) + auto_generated = true + end + + return {author, ucid, auto_generated} +end