mirror of
				https://github.com/iv-org/invidious.git
				synced 2025-10-31 12:42:09 +00:00 
			
		
		
		
	initial support for base_url with invidious companion + proxy invidious_companion
This commit is contained in:
		| @@ -75,7 +75,7 @@ db: | ||||
| ## If you are using a reverse proxy then you will probably need to | ||||
| ## configure the public_url to be the same as the domain used for Invidious. | ||||
| ## Also apply when used from an external IP address (without a domain). | ||||
| ## Examples: https://MYINVIDIOUSDOMAIN or http://192.168.1.100:8282 | ||||
| ## Examples: https://MYINVIDIOUSDOMAIN/companion or http://192.168.1.100:8282/companion | ||||
| ## | ||||
| ## Both parameter can have identical URL when Invidious is hosted in | ||||
| ## an internal network or at home or locally (localhost). | ||||
| @@ -84,8 +84,8 @@ db: | ||||
| ## Default: <none> | ||||
| ## | ||||
| #invidious_companion: | ||||
| #  - private_url: "http://localhost:8282" | ||||
| #    public_url: "http://localhost:8282" | ||||
| #  - private_url: "http://localhost:8282/companion" | ||||
| #    public_url: "http://localhost:8282/companion" | ||||
|  | ||||
| ## | ||||
| ## API key for Invidious companion, used for securing the communication | ||||
|   | ||||
							
								
								
									
										37
									
								
								src/invidious/routes/companion.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/invidious/routes/companion.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| module Invidious::Routes::Companion | ||||
|   # /companion | ||||
|   def self.get_companion(env) | ||||
|     url = env.request.path.lchop("/companion") | ||||
|  | ||||
|     begin | ||||
|       COMPANION_POOL.client &.get(url, env.request.header) do |resp| | ||||
|         return self.proxy_companion(env, resp) | ||||
|       end | ||||
|     rescue ex | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def self.options_companion(env) | ||||
|     url = env.request.path.lchop("/companion") | ||||
|  | ||||
|     begin | ||||
|       COMPANION_POOL.client &.options(url, env.request.header) do |resp| | ||||
|         return self.proxy_companion(env, resp) | ||||
|       end | ||||
|     rescue ex | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   private def self.proxy_companion(env, response) | ||||
|     env.response.status_code = response.status_code | ||||
|     response.headers.each do |key, value| | ||||
|       env.response.headers[key] = value | ||||
|     end | ||||
|  | ||||
|     if response.status_code >= 300 | ||||
|       return env.response.headers.delete("Transfer-Encoding") | ||||
|     end | ||||
|  | ||||
|     return proxy_file(response, env) | ||||
|   end | ||||
| end | ||||
| @@ -209,10 +209,14 @@ module Invidious::Routes::Embed | ||||
|  | ||||
|     if CONFIG.invidious_companion.present? | ||||
|       invidious_companion = CONFIG.invidious_companion.sample | ||||
|       invidious_companion_urls = CONFIG.invidious_companion.map do |companion| | ||||
|         uri = | ||||
|           "#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}" | ||||
|       end.join(" ") | ||||
|       env.response.headers["Content-Security-Policy"] = | ||||
|         env.response.headers["Content-Security-Policy"] | ||||
|           .gsub("media-src", "media-src #{invidious_companion.public_url}") | ||||
|           .gsub("connect-src", "connect-src #{invidious_companion.public_url}") | ||||
|           .gsub("media-src", "media-src #{invidious_companion_urls}") | ||||
|           .gsub("connect-src", "connect-src #{invidious_companion_urls}") | ||||
|     end | ||||
|  | ||||
|     rendered "embed" | ||||
|   | ||||
| @@ -194,10 +194,14 @@ module Invidious::Routes::Watch | ||||
|  | ||||
|     if CONFIG.invidious_companion.present? | ||||
|       invidious_companion = CONFIG.invidious_companion.sample | ||||
|       invidious_companion_urls = CONFIG.invidious_companion.map do |companion| | ||||
|         uri = | ||||
|           "#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}" | ||||
|       end.join(" ") | ||||
|       env.response.headers["Content-Security-Policy"] = | ||||
|         env.response.headers["Content-Security-Policy"] | ||||
|           .gsub("media-src", "media-src #{invidious_companion.public_url}") | ||||
|           .gsub("connect-src", "connect-src #{invidious_companion.public_url}") | ||||
|           .gsub("media-src", "media-src #{invidious_companion_urls}") | ||||
|           .gsub("connect-src", "connect-src #{invidious_companion_urls}") | ||||
|     end | ||||
|  | ||||
|     templated "watch" | ||||
|   | ||||
| @@ -188,7 +188,7 @@ module Invidious::Routing | ||||
|   end | ||||
|  | ||||
|   # ------------------- | ||||
|   #  Media proxy routes | ||||
|   #  Proxy routes | ||||
|   # ------------------- | ||||
|  | ||||
|   def register_api_manifest_routes | ||||
| @@ -223,6 +223,13 @@ module Invidious::Routing | ||||
|     get "/vi/:id/:name", Routes::Images, :thumbnails | ||||
|   end | ||||
|  | ||||
|   def register_companion_routes | ||||
|     if CONFIG.invidious_companion.present? | ||||
|       get "/companion/*", Routes::Companion, :get_companion | ||||
|       options "/companion/*", Routes::Companion, :options_companion | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   # ------------------- | ||||
|   #  API routes | ||||
|   # ------------------- | ||||
|   | ||||
| @@ -46,8 +46,22 @@ struct YoutubeConnectionPool | ||||
|   end | ||||
| end | ||||
|  | ||||
| class CompanionWrapper | ||||
|   property client : HTTP::Client | ||||
|   property companion : Config::CompanionConfig | ||||
|  | ||||
|   def initialize(companion : Config::CompanionConfig) | ||||
|     @companion = companion | ||||
|     @client = HTTP::Client.new(companion.private_url) | ||||
|   end | ||||
|  | ||||
|   def close | ||||
|     @client.close | ||||
|   end | ||||
| end | ||||
|  | ||||
| struct CompanionConnectionPool | ||||
|   property pool : DB::Pool(HTTP::Client) | ||||
|   property pool : DB::Pool(CompanionWrapper) | ||||
|  | ||||
|   def initialize(capacity = 5, timeout = 5.0) | ||||
|     options = DB::Pool::Options.new( | ||||
| @@ -57,26 +71,28 @@ struct CompanionConnectionPool | ||||
|       checkout_timeout: timeout | ||||
|     ) | ||||
|  | ||||
|     @pool = DB::Pool(HTTP::Client).new(options) do | ||||
|     @pool = DB::Pool(CompanionWrapper).new(options) do | ||||
|       companion = CONFIG.invidious_companion.sample | ||||
|       next make_client(companion.private_url, use_http_proxy: false) | ||||
|       client = make_client(companion.private_url, use_http_proxy: false) | ||||
|       CompanionWrapper.new(companion: companion) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def client(&) | ||||
|     conn = pool.checkout | ||||
|     wrapper = pool.checkout | ||||
|  | ||||
|     begin | ||||
|       response = yield conn | ||||
|       response = yield wrapper | ||||
|     rescue ex | ||||
|       conn.close | ||||
|       wrapper.client.close | ||||
|  | ||||
|       companion = CONFIG.invidious_companion.sample | ||||
|       conn = make_client(companion.private_url, use_http_proxy: false) | ||||
|       client = make_client(companion.private_url, use_http_proxy: false) | ||||
|       wrapper = CompanionWrapper.new(companion: companion) | ||||
|  | ||||
|       response = yield conn | ||||
|       response = yield wrapper | ||||
|     ensure | ||||
|       pool.release(conn) | ||||
|       pool.release(wrapper) | ||||
|     end | ||||
|  | ||||
|     response | ||||
|   | ||||
| @@ -701,22 +701,28 @@ module YoutubeAPI | ||||
|     # Send the POST request | ||||
|  | ||||
|     begin | ||||
|       response = COMPANION_POOL.client &.post(endpoint, headers: headers, body: data.to_json) | ||||
|       body = response.body | ||||
|       if (response.status_code != 200) | ||||
|         raise Exception.new( | ||||
|           "Error while communicating with Invidious companion: \ | ||||
|           status code: #{response.status_code} and body: #{body.dump}" | ||||
|         ) | ||||
|       response_body = "" | ||||
|  | ||||
|       COMPANION_POOL.client do |wrapper| | ||||
|         companion_base_url = wrapper.companion.private_url.path | ||||
|         puts "Using companion: #{wrapper.companion.private_url}" | ||||
|  | ||||
|         response = wrapper.client.post(companion_base_url + endpoint, headers: headers, body: data.to_json) | ||||
|         response_body = response.body | ||||
|  | ||||
|         if response.status_code != 200 | ||||
|           raise Exception.new( | ||||
|             "Error while communicating with Invidious companion: " \ | ||||
|             "status code: #{response.status_code} and body: #{response_body.dump}" | ||||
|           ) | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # Convert result to Hash | ||||
|       return JSON.parse(response_body).as_h | ||||
|     rescue ex | ||||
|       raise InfoException.new("Error while communicating with Invidious companion: " + (ex.message || "no extra info found")) | ||||
|     end | ||||
|  | ||||
|     # Convert result to Hash | ||||
|     initial_data = JSON.parse(body).as_h | ||||
|  | ||||
|     return initial_data | ||||
|   end | ||||
|  | ||||
|   #################################################################### | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Emilien
					Emilien