Skip to content

Commit 324a416

Browse files
committed
initial support for base_url with invidious companion + proxy invidious_companion
1 parent 89c8b1b commit 324a416

File tree

7 files changed

+103
-29
lines changed

7 files changed

+103
-29
lines changed

config/config.example.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ db:
7575
## If you are using a reverse proxy then you will probably need to
7676
## configure the public_url to be the same as the domain used for Invidious.
7777
## Also apply when used from an external IP address (without a domain).
78-
## Examples: https://MYINVIDIOUSDOMAIN or http://192.168.1.100:8282
78+
## Examples: https://MYINVIDIOUSDOMAIN/companion or http://192.168.1.100:8282/companion
7979
##
8080
## Both parameter can have identical URL when Invidious is hosted in
8181
## an internal network or at home or locally (localhost).
@@ -84,8 +84,8 @@ db:
8484
## Default: <none>
8585
##
8686
#invidious_companion:
87-
# - private_url: "http://localhost:8282"
88-
# public_url: "http://localhost:8282"
87+
# - private_url: "http://localhost:8282/companion"
88+
# public_url: "http://localhost:8282/companion"
8989

9090
##
9191
## API key for Invidious companion, used for securing the communication

src/invidious/routes/companion.cr

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module Invidious::Routes::Companion
2+
# /companion
3+
def self.get_companion(env)
4+
url = env.request.path.lchop("/companion")
5+
6+
begin
7+
COMPANION_POOL.client &.get(url, env.request.header) do |resp|
8+
return self.proxy_companion(env, resp)
9+
end
10+
rescue ex
11+
end
12+
end
13+
14+
def self.options_companion(env)
15+
url = env.request.path.lchop("/companion")
16+
17+
begin
18+
COMPANION_POOL.client &.options(url, env.request.header) do |resp|
19+
return self.proxy_companion(env, resp)
20+
end
21+
rescue ex
22+
end
23+
end
24+
25+
private def self.proxy_companion(env, response)
26+
env.response.status_code = response.status_code
27+
response.headers.each do |key, value|
28+
env.response.headers[key] = value
29+
end
30+
31+
if response.status_code >= 300
32+
return env.response.headers.delete("Transfer-Encoding")
33+
end
34+
35+
return proxy_file(response, env)
36+
end
37+
end

src/invidious/routes/embed.cr

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,14 @@ module Invidious::Routes::Embed
209209

210210
if CONFIG.invidious_companion.present?
211211
invidious_companion = CONFIG.invidious_companion.sample
212+
invidious_companion_urls = CONFIG.invidious_companion.map do |companion|
213+
uri =
214+
"#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}"
215+
end.join(" ")
212216
env.response.headers["Content-Security-Policy"] =
213217
env.response.headers["Content-Security-Policy"]
214-
.gsub("media-src", "media-src #{invidious_companion.public_url}")
215-
.gsub("connect-src", "connect-src #{invidious_companion.public_url}")
218+
.gsub("media-src", "media-src #{invidious_companion_urls}")
219+
.gsub("connect-src", "connect-src #{invidious_companion_urls}")
216220
end
217221

218222
rendered "embed"

src/invidious/routes/watch.cr

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,14 @@ module Invidious::Routes::Watch
194194

195195
if CONFIG.invidious_companion.present?
196196
invidious_companion = CONFIG.invidious_companion.sample
197+
invidious_companion_urls = CONFIG.invidious_companion.map do |companion|
198+
uri =
199+
"#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}"
200+
end.join(" ")
197201
env.response.headers["Content-Security-Policy"] =
198202
env.response.headers["Content-Security-Policy"]
199-
.gsub("media-src", "media-src #{invidious_companion.public_url}")
200-
.gsub("connect-src", "connect-src #{invidious_companion.public_url}")
203+
.gsub("media-src", "media-src #{invidious_companion_urls}")
204+
.gsub("connect-src", "connect-src #{invidious_companion_urls}")
201205
end
202206

203207
templated "watch"

src/invidious/routing.cr

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ module Invidious::Routing
188188
end
189189

190190
# -------------------
191-
# Media proxy routes
191+
# Proxy routes
192192
# -------------------
193193

194194
def register_api_manifest_routes
@@ -223,6 +223,13 @@ module Invidious::Routing
223223
get "/vi/:id/:name", Routes::Images, :thumbnails
224224
end
225225

226+
def register_companion_routes
227+
if CONFIG.invidious_companion.present?
228+
get "/companion/*", Routes::Companion, :get_companion
229+
options "/companion/*", Routes::Companion, :options_companion
230+
end
231+
end
232+
226233
# -------------------
227234
# API routes
228235
# -------------------

src/invidious/yt_backend/connection_pool.cr

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,22 @@ struct YoutubeConnectionPool
4646
end
4747
end
4848

49+
class CompanionWrapper
50+
property client : HTTP::Client
51+
property companion : Config::CompanionConfig
52+
53+
def initialize(companion : Config::CompanionConfig)
54+
@companion = companion
55+
@client = HTTP::Client.new(companion.private_url)
56+
end
57+
58+
def close
59+
@client.close
60+
end
61+
end
62+
4963
struct CompanionConnectionPool
50-
property pool : DB::Pool(HTTP::Client)
64+
property pool : DB::Pool(CompanionWrapper)
5165

5266
def initialize(capacity = 5, timeout = 5.0)
5367
options = DB::Pool::Options.new(
@@ -57,26 +71,28 @@ struct CompanionConnectionPool
5771
checkout_timeout: timeout
5872
)
5973

60-
@pool = DB::Pool(HTTP::Client).new(options) do
74+
@pool = DB::Pool(CompanionWrapper).new(options) do
6175
companion = CONFIG.invidious_companion.sample
62-
next make_client(companion.private_url, use_http_proxy: false)
76+
client = make_client(companion.private_url, use_http_proxy: false)
77+
CompanionWrapper.new(companion: companion)
6378
end
6479
end
6580

6681
def client(&)
67-
conn = pool.checkout
82+
wrapper = pool.checkout
6883

6984
begin
70-
response = yield conn
85+
response = yield wrapper
7186
rescue ex
72-
conn.close
87+
wrapper.client.close
7388

7489
companion = CONFIG.invidious_companion.sample
75-
conn = make_client(companion.private_url, use_http_proxy: false)
90+
client = make_client(companion.private_url, use_http_proxy: false)
91+
wrapper = CompanionWrapper.new(companion: companion)
7692

77-
response = yield conn
93+
response = yield wrapper
7894
ensure
79-
pool.release(conn)
95+
pool.release(wrapper)
8096
end
8197

8298
response

src/invidious/yt_backend/youtube_api.cr

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -701,22 +701,28 @@ module YoutubeAPI
701701
# Send the POST request
702702

703703
begin
704-
response = COMPANION_POOL.client &.post(endpoint, headers: headers, body: data.to_json)
705-
body = response.body
706-
if (response.status_code != 200)
707-
raise Exception.new(
708-
"Error while communicating with Invidious companion: \
709-
status code: #{response.status_code} and body: #{body.dump}"
710-
)
704+
response_body = ""
705+
706+
COMPANION_POOL.client do |wrapper|
707+
companion_base_url = wrapper.companion.private_url.path
708+
puts "Using companion: #{wrapper.companion.private_url}"
709+
710+
response = wrapper.client.post(companion_base_url + endpoint, headers: headers, body: data.to_json)
711+
response_body = response.body
712+
713+
if response.status_code != 200
714+
raise Exception.new(
715+
"Error while communicating with Invidious companion: " \
716+
"status code: #{response.status_code} and body: #{response_body.dump}"
717+
)
718+
end
711719
end
720+
721+
# Convert result to Hash
722+
return JSON.parse(response_body).as_h
712723
rescue ex
713724
raise InfoException.new("Error while communicating with Invidious companion: " + (ex.message || "no extra info found"))
714725
end
715-
716-
# Convert result to Hash
717-
initial_data = JSON.parse(body).as_h
718-
719-
return initial_data
720726
end
721727

722728
####################################################################

0 commit comments

Comments
 (0)