From d418f505760cbf4bfce2b3280608e944dec3cb61 Mon Sep 17 00:00:00 2001 From: Omar Roth Date: Mon, 1 Oct 2018 19:01:44 -0500 Subject: [PATCH] Make geo-bypass more robust --- src/invidious.cr | 88 ++++++++++++++++++++++------------------- src/invidious/videos.cr | 83 +++++++++++++++++++++++--------------- 2 files changed, 100 insertions(+), 71 deletions(-) diff --git a/src/invidious.cr b/src/invidious.cr index 073ed354..37a68d20 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -1874,27 +1874,30 @@ get "/api/v1/comments/:id" do |env| proxies.each do |region, list| spawn do - begin - proxy_client = HTTPClient.new(YT_URL) - proxy_client.read_timeout = 10.seconds - proxy_client.connect_timeout = 10.seconds - - proxy = list.sample(1)[0] - proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) - proxy_client.set_proxy(proxy) - - proxy_html = proxy_client.get("/watch?v=#{id}&bpctr=#{Time.new.epoch + 2000}&gl=US&hl=en&disable_polymer=1") - proxy_headers = HTTP::Headers.new - proxy_headers["cookie"] = proxy_html.cookies.add_request_headers(headers)["cookie"] - proxy_html = proxy_html.body - - if proxy_html.match(//) - bypass_channel.send(nil) - else - bypass_channel.send({proxy_html, proxy_client, proxy_headers}) + list.each do |proxy| + begin + proxy_client = HTTPClient.new(YT_URL) + proxy_client.read_timeout = 10.seconds + proxy_client.connect_timeout = 10.seconds + + proxy = list.sample(1)[0] + proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) + proxy_client.set_proxy(proxy) + + proxy_html = proxy_client.get("/watch?v=#{id}&bpctr=#{Time.new.epoch + 2000}&gl=US&hl=en&disable_polymer=1") + proxy_headers = HTTP::Headers.new + proxy_headers["cookie"] = proxy_html.cookies.add_request_headers(headers)["cookie"] + proxy_html = proxy_html.body + + if proxy_html.match(//) + bypass_channel.send(nil) + else + bypass_channel.send({proxy_html, proxy_client, proxy_headers}) + end + + break + rescue ex end - rescue ex - bypass_channel.send(nil) end end end @@ -3227,34 +3230,39 @@ get "/videoplayback" do |env| host = "https://r#{fvip}---#{mn}.googlevideo.com" url = "/videoplayback?#{query_params.to_s}" - client = make_client(URI.parse(host)) - response = client.head(url) - - if response.status_code == 403 - ip = query_params["ip"] - proxy = proxies.values.flatten.select { |proxy| proxy[:ip] == ip } - if proxy.empty? - halt env, status_code: 403 - end + if query_params["region"]? + client = make_client(URI.parse(host)) + response = HTTP::Client::Response.new(status_code: 403) - proxy = proxy[0] - # Try to find proxy in same region - proxy = proxies.select { |region, list| list.includes? proxy }.values[0].sample(1)[0] - if proxy.empty? + if !proxies[query_params["region"]]? halt env, status_code: 403 end - client = HTTPClient.new(URI.parse(host)) - client.read_timeout = 10.seconds - client.connect_timeout = 10.seconds + proxies[query_params["region"]].each do |proxy| + begin + client = HTTPClient.new(URI.parse(host)) + client.read_timeout = 10.seconds + client.connect_timeout = 10.seconds - proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) - client.set_proxy(proxy) + proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) + client.set_proxy(proxy) + response = client.head(url) + if response.status_code == 200 + # For whatever reason the proxy needs to be set again + client.set_proxy(proxy) + break + end + rescue ex + end + end + else + client = make_client(URI.parse(host)) response = client.head(url) + end - # For whatever reason the proxy needs to be set again - client.set_proxy(proxy) + if response.status_code != 200 + halt env, status_code: 403 end if response.headers["Location"]? diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index acaef4c1..cc69ceef 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -273,6 +273,12 @@ class Video streams.each { |s| s.add("label", "#{s["quality"]} - #{s["type"].split(";")[0].split("/")[1]}") } streams = streams.uniq { |s| s["label"] } + if self.info["region"]? + streams.each do |fmt| + fmt["url"] += "®ion=" + self.info["region"] + end + end + if streams[0]? && streams[0]["s"]? streams.each do |fmt| fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) @@ -362,6 +368,12 @@ class Video end end + if self.info["region"]? + adaptive_fmts.each do |fmt| + fmt["url"] += "®ion=" + self.info["region"] + end + end + if adaptive_fmts[0]? && adaptive_fmts[0]["s"]? adaptive_fmts.each do |fmt| fmt["url"] += "&signature=" + decrypt_signature(fmt["s"], decrypt_function) @@ -527,47 +539,56 @@ def fetch_video(id, proxies) info = info_channel.receive if info["reason"]? && info["reason"].includes? "your country" - bypass_channel = Channel({HTTP::Params | Nil, XML::Node | Nil}).new + bypass_channel = Channel(HTTPProxy | Nil).new proxies.each do |region, list| spawn do - begin - client = HTTPClient.new(YT_URL) - client.read_timeout = 10.seconds - client.connect_timeout = 10.seconds - - proxy = list.sample(1)[0] - proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) - client.set_proxy(proxy) - - proxy_info = client.get("/get_video_info?video_id=#{id}&el=detailpage&ps=default&eurl=&gl=US&hl=en&disable_polymer=1") - proxy_info = HTTP::Params.parse(proxy_info.body) - - if proxy_info["reason"]? - proxy_info = client.get("/get_video_info?video_id=#{id}&ps=default&eurl=&gl=US&hl=en&disable_polymer=1") - proxy_info = HTTP::Params.parse(proxy_info.body) - end - - if !proxy_info["reason"]? - proxy_html = client.get("/watch?v=#{id}&bpctr=#{Time.new.epoch + 2000}&gl=US&hl=en&disable_polymer=1") - proxy_html = XML.parse_html(proxy_html.body) + list.each do |proxy| + begin + client = HTTPClient.new(YT_URL) + client.read_timeout = 10.seconds + client.connect_timeout = 10.seconds + + proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) + client.set_proxy(proxy) + + response = client.head("/get_video_info?video_id=#{id}&el=detailpage&ps=default&eurl=&gl=US&hl=en&disable_polymer=1") + if response.status_code == 200 + bypass_channel.send(proxy) + else + bypass_channel.send(nil) + end - bypass_channel.send({proxy_info, proxy_html}) - else - bypass_channel.send({nil, nil}) + break + rescue ex end - rescue ex - bypass_channel.send({nil, nil}) end end end proxies.size.times do - response = bypass_channel.receive - if response[0] || response[1] - info = response[0].not_nil! - html = response[1].not_nil! - break + proxy = bypass_channel.receive + if proxy + client = HTTPClient.new(YT_URL) + client.read_timeout = 10.seconds + client.connect_timeout = 10.seconds + client.set_proxy(proxy) + + proxy = {ip: proxy.proxy_host, port: proxy.proxy_port} + region = proxies.select { |region, list| list.includes? proxy }.keys[0] + + html = client.get("/watch?v=#{id}&bpctr=#{Time.new.epoch + 2000}&gl=US&hl=en&disable_polymer=1") + html = XML.parse_html(html.body) + + info = client.get("/get_video_info?video_id=#{id}&el=detailpage&ps=default&eurl=&gl=US&hl=en&disable_polymer=1") + info = HTTP::Params.parse(info.body) + + if info["reason"]? + info = client.get("/get_video_info?video_id=#{id}&ps=default&eurl=&gl=US&hl=en&disable_polymer=1") + info = HTTP::Params.parse(info.body) + end + + info["region"] = region end end end