mirror of
https://git.nadeko.net/Fijxu/invidious.git
synced 2025-12-14 09:05:09 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -99,7 +99,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Use ARM64 Dockerfile if ARM64
|
- name: Use ARM64 Dockerfile if ARM64
|
||||||
if: ${{ matrix.name }} == "ARM64"
|
if: ${{ matrix.name == 'ARM64' }}
|
||||||
run: sed -i 's/Dockerfile/Dockerfile.arm64/' docker-compose.yml
|
run: sed -i 's/Dockerfile/Dockerfile.arm64/' docker-compose.yml
|
||||||
|
|
||||||
- name: Build Docker
|
- name: Build Docker
|
||||||
|
|||||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v9
|
- uses: actions/stale@v10
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 730
|
days-before-stale: 730
|
||||||
|
|||||||
@@ -61,31 +61,32 @@ db:
|
|||||||
## When this setting is commented out, Invidious companion is not used.
|
## When this setting is commented out, Invidious companion is not used.
|
||||||
## Otherwise, Invidious will proxy the requests to Invidious companion.
|
## Otherwise, Invidious will proxy the requests to Invidious companion.
|
||||||
##
|
##
|
||||||
## Note: multiple URL can be configured. In this case, invidious will
|
## Note: multiple URL can be configured. In this case, Invidious will
|
||||||
## randomly pick one every time video data needs to be retrieved. This
|
## randomly pick one every time video data needs to be retrieved. This
|
||||||
## URL is then kept in the video metadata cache to allow video playback
|
## URL is then kept in the video metadata cache to allow video playback
|
||||||
## to work. Once said cache has expired, requesting that video's data
|
## to work. Once said cache has expired, requesting that video's data
|
||||||
## again will cause a new companion URL to be picked.
|
## again will cause a new companion URL to be picked.
|
||||||
##
|
##
|
||||||
## The parameter private_url needs to be configured for the internal
|
## The parameter private_url is required for the internal communication
|
||||||
## communication between the companion and Invidious.
|
## between Invidious companion and Invidious.
|
||||||
## And public_url is the public URL from which companion is listening
|
|
||||||
## to the requests from the user(s).
|
|
||||||
##
|
##
|
||||||
## If you are using a reverse proxy then you will probably need to
|
## The optional parameter public_url is the public URL from which
|
||||||
## configure the public_url to be the same as the domain used for Invidious.
|
## Invidious companion is listening to the requests from the user(s).
|
||||||
## Also apply when used from an external IP address (without a domain).
|
## When this setting is commented out, Invidious proxy all requests to
|
||||||
## Examples: https://MYINVIDIOUSDOMAIN or http://192.168.1.100:8282
|
## Invidious companion. Useful for simple setups.
|
||||||
##
|
## Otherwise, requests from the user(s) will reach Invidious companion directly.
|
||||||
## Both parameter can have identical URL when Invidious is hosted in
|
## And you will need to configure a reverse proxy with separate routes
|
||||||
## an internal network or at home or locally (localhost).
|
## for Invidious and Invidious companion.
|
||||||
|
## Read the post-install documentation for advanced reverse proxy
|
||||||
|
## documentation: https://docs.invidious.io/installation/#post-install-configuration
|
||||||
##
|
##
|
||||||
## Accepted values: "http(s)://<IP-HOSTNAME>:<Port>"
|
## Accepted values: "http(s)://<IP-HOSTNAME>:<Port>"
|
||||||
## Default: <none>
|
## Default: <none>
|
||||||
##
|
##
|
||||||
#invidious_companion:
|
#invidious_companion:
|
||||||
# - private_url: "http://localhost:8282"
|
# - private_url: "http://localhost:8282/companion"
|
||||||
# public_url: "http://localhost:8282"
|
# # Uncomment for advanced reverse proxy configuration (see above).
|
||||||
|
# # public_url: "http://localhost:8282/companion"
|
||||||
|
|
||||||
##
|
##
|
||||||
## API key for Invidious companion, used for securing the communication
|
## API key for Invidious companion, used for securing the communication
|
||||||
|
|||||||
@@ -125,6 +125,8 @@
|
|||||||
"preferences_hidden_channels": "Hidden channels",
|
"preferences_hidden_channels": "Hidden channels",
|
||||||
"preferences_hidden_channels_label": "(Experimental) Channel ID list separated by ENTER key. This only hides channels from the popular page for now. You can get the ID of the channel clicking on the channel and copying the part that starts with 'UC' in the channel link. Example: /channel/<b>UCw-aR42z5gUcarpPGN5OKfA</b>",
|
"preferences_hidden_channels_label": "(Experimental) Channel ID list separated by ENTER key. This only hides channels from the popular page for now. You can get the ID of the channel clicking on the channel and copying the part that starts with 'UC' in the channel link. Example: /channel/<b>UCw-aR42z5gUcarpPGN5OKfA</b>",
|
||||||
"preferences_default_trending_type": "Default trending page: ",
|
"preferences_default_trending_type": "Default trending page: ",
|
||||||
|
"preferences_default_playlist": "Default playlist: ",
|
||||||
|
"preferences_default_playlist_none": "No default playlist set",
|
||||||
"published": "published",
|
"published": "published",
|
||||||
"published - reverse": "published - reverse",
|
"published - reverse": "published - reverse",
|
||||||
"alphabetically": "alphabetically",
|
"alphabetically": "alphabetically",
|
||||||
|
|||||||
@@ -81,6 +81,8 @@
|
|||||||
"preferences_hidden_channels": "Canales ocultos",
|
"preferences_hidden_channels": "Canales ocultos",
|
||||||
"preferences_hidden_channels_label": "(Experimental) Lista de IDs de canales separados por la tecla ENTER. Por ahora, esto solo oculta canales de la pagina popular. Puedes conseguir la ID del canal entrando al canal y copiando la parte que empieza por 'UC' en el enlace. Ejemplo: /channel/<b>UCw-aR42z5gUcarpPGN5OKfA</b>",
|
"preferences_hidden_channels_label": "(Experimental) Lista de IDs de canales separados por la tecla ENTER. Por ahora, esto solo oculta canales de la pagina popular. Puedes conseguir la ID del canal entrando al canal y copiando la parte que empieza por 'UC' en el enlace. Ejemplo: /channel/<b>UCw-aR42z5gUcarpPGN5OKfA</b>",
|
||||||
"preferences_default_trending_type": "Página de tendencias por defecto: ",
|
"preferences_default_trending_type": "Página de tendencias por defecto: ",
|
||||||
|
"preferences_default_playlist": "Lista de reproducción por defecto: ",
|
||||||
|
"preferences_default_playlist_none": "Ninguna lista de reproducción por defecto establecida",
|
||||||
"published": "fecha de publicación",
|
"published": "fecha de publicación",
|
||||||
"published - reverse": "fecha de publicación: orden inverso",
|
"published - reverse": "fecha de publicación: orden inverso",
|
||||||
"alphabetically": "alfabéticamente",
|
"alphabetically": "alfabéticamente",
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ struct ConfigPreferences
|
|||||||
property vr_mode : Bool = true
|
property vr_mode : Bool = true
|
||||||
property show_nick : Bool = true
|
property show_nick : Bool = true
|
||||||
property save_player_pos : Bool = false
|
property save_player_pos : Bool = false
|
||||||
|
@[YAML::Field(ignore: true)]
|
||||||
|
property default_playlist : String? = nil
|
||||||
property enable_dearrow : Bool = false
|
property enable_dearrow : Bool = false
|
||||||
@[YAML::Field(ignore: true)]
|
@[YAML::Field(ignore: true)]
|
||||||
property hidden_channels : Array(String)? = nil
|
property hidden_channels : Array(String)? = nil
|
||||||
@@ -93,6 +95,9 @@ class Config
|
|||||||
|
|
||||||
property note : String = ""
|
property note : String = ""
|
||||||
property domain : Array(String) = [] of String
|
property domain : Array(String) = [] of String
|
||||||
|
|
||||||
|
# Indicates if this companion instance uses the built-in proxy
|
||||||
|
property builtin_proxy : Bool = false
|
||||||
end
|
end
|
||||||
|
|
||||||
# Number of threads to use for crawling videos from channels (for updating subscriptions)
|
# Number of threads to use for crawling videos from channels (for updating subscriptions)
|
||||||
@@ -399,6 +404,14 @@ class Config
|
|||||||
puts "Config: The value of 'invidious_companion_key' needs to be a size of 16 characters."
|
puts "Config: The value of 'invidious_companion_key' needs to be a size of 16 characters."
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Set public_url to built-in proxy path when omitted
|
||||||
|
config.invidious_companion.each do |companion|
|
||||||
|
if companion.public_url.to_s.empty?
|
||||||
|
companion.public_url = URI.parse("/companion")
|
||||||
|
companion.builtin_proxy = true
|
||||||
|
end
|
||||||
|
end
|
||||||
elsif config.signature_server
|
elsif config.signature_server
|
||||||
puts("WARNING: inv-sig-helper is deprecated. Please switch to Invidious companion: https://docs.invidious.io/companion-installation/")
|
puts("WARNING: inv-sig-helper is deprecated. Please switch to Invidious companion: https://docs.invidious.io/companion-installation/")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -61,28 +61,13 @@ class Kemal::ExceptionHandler
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class FilteredCompressHandler < Kemal::Handler
|
class FilteredCompressHandler < HTTP::CompressHandler
|
||||||
exclude ["/videoplayback", "/videoplayback/*", "/vi/*", "/sb/*", "/ggpht/*", "/api/v1/auth/notifications"]
|
exclude ["/videoplayback", "/videoplayback/*", "/vi/*", "/sb/*", "/ggpht/*", "/api/v1/auth/notifications"]
|
||||||
exclude ["/api/v1/auth/notifications", "/data_control"], "POST"
|
exclude ["/api/v1/auth/notifications", "/data_control"], "POST"
|
||||||
|
|
||||||
def call(env)
|
def call(context)
|
||||||
return call_next env if exclude_match? env
|
return call_next context if exclude_match? context
|
||||||
|
super
|
||||||
{% if flag?(:without_zlib) %}
|
|
||||||
call_next env
|
|
||||||
{% else %}
|
|
||||||
request_headers = env.request.headers
|
|
||||||
|
|
||||||
if request_headers.includes_word?("Accept-Encoding", "gzip")
|
|
||||||
env.response.headers["Content-Encoding"] = "gzip"
|
|
||||||
env.response.output = Compress::Gzip::Writer.new(env.response.output, sync_close: true)
|
|
||||||
elsif request_headers.includes_word?("Accept-Encoding", "deflate")
|
|
||||||
env.response.headers["Content-Encoding"] = "deflate"
|
|
||||||
env.response.output = Compress::Deflate::Writer.new(env.response.output, sync_close: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
call_next env
|
|
||||||
{% end %}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ module Invidious::Routes::BeforeAll
|
|||||||
"/videoplayback",
|
"/videoplayback",
|
||||||
"/latest_version",
|
"/latest_version",
|
||||||
"/download",
|
"/download",
|
||||||
|
"/companion/",
|
||||||
}.any? { |r| env.request.resource.starts_with? r }
|
}.any? { |r| env.request.resource.starts_with? r }
|
||||||
|
|
||||||
if env.request.cookies.has_key? "SID"
|
if env.request.cookies.has_key? "SID"
|
||||||
|
|||||||
47
src/invidious/routes/companion.cr
Normal file
47
src/invidious/routes/companion.cr
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
module Invidious::Routes::Companion
|
||||||
|
# /companion
|
||||||
|
def self.get_companion(env)
|
||||||
|
current_companion = env.get("current_companion").as(Int32)
|
||||||
|
|
||||||
|
url = env.request.path
|
||||||
|
if env.request.query
|
||||||
|
url += "?#{env.request.query}"
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
COMPANION_POOL[current_companion].client do |wrapper|
|
||||||
|
wrapper.client.get(url, env.request.headers) do |resp|
|
||||||
|
return self.proxy_companion(env, resp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue ex
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.options_companion(env)
|
||||||
|
current_companion = env.get("current_companion").as(Int32)
|
||||||
|
|
||||||
|
url = env.request.path
|
||||||
|
if env.request.query
|
||||||
|
url += "?#{env.request.query}"
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
COMPANION_POOL[current_companion].client do |wrapper|
|
||||||
|
wrapper.client.options(url, env.request.headers) do |resp|
|
||||||
|
return self.proxy_companion(env, resp)
|
||||||
|
end
|
||||||
|
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
|
||||||
|
|
||||||
|
return IO.copy response.body_io, env.response
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -210,6 +210,18 @@ module Invidious::Routes::Embed
|
|||||||
if CONFIG.invidious_companion.present?
|
if CONFIG.invidious_companion.present?
|
||||||
current_companion = env.get("current_companion").as(Int32)
|
current_companion = env.get("current_companion").as(Int32)
|
||||||
invidious_companion = CONFIG.invidious_companion[current_companion]
|
invidious_companion = CONFIG.invidious_companion[current_companion]
|
||||||
|
|
||||||
|
invidious_companion_urls = CONFIG.invidious_companion.reject(&.builtin_proxy).map do |companion|
|
||||||
|
uri =
|
||||||
|
"#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}"
|
||||||
|
end.join(" ")
|
||||||
|
|
||||||
|
if !invidious_companion_urls.empty?
|
||||||
|
env.response.headers["Content-Security-Policy"] =
|
||||||
|
env.response.headers["Content-Security-Policy"]
|
||||||
|
.gsub("media-src", "media-src #{invidious_companion_urls}")
|
||||||
|
.gsub("connect-src", "connect-src #{invidious_companion_urls}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
rendered "embed"
|
rendered "embed"
|
||||||
|
|||||||
@@ -144,6 +144,8 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
notifications_only ||= "off"
|
notifications_only ||= "off"
|
||||||
notifications_only = notifications_only == "on"
|
notifications_only = notifications_only == "on"
|
||||||
|
|
||||||
|
default_playlist = env.params.body["default_playlist"]?.try &.as(String)
|
||||||
|
|
||||||
hidden_channels = env.params.body["hidden_channels"]?.try &.as(String)
|
hidden_channels = env.params.body["hidden_channels"]?.try &.as(String)
|
||||||
if hidden_channels
|
if hidden_channels
|
||||||
hidden_channels = hidden_channels.split("\n")
|
hidden_channels = hidden_channels.split("\n")
|
||||||
@@ -171,6 +173,7 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
default_trending_type = env.params.body["default_trending_type"]?.try &.as(String)
|
default_trending_type = env.params.body["default_trending_type"]?.try &.as(String)
|
||||||
default_trending_type ||= Invidious::Routes::Feeds::TrendingTypes::Default
|
default_trending_type ||= Invidious::Routes::Feeds::TrendingTypes::Default
|
||||||
|
|
||||||
|
|
||||||
# Convert to JSON and back again to take advantage of converters used for compatibility
|
# Convert to JSON and back again to take advantage of converters used for compatibility
|
||||||
preferences = Preferences.from_json({
|
preferences = Preferences.from_json({
|
||||||
annotations: annotations,
|
annotations: annotations,
|
||||||
@@ -207,6 +210,7 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
vr_mode: vr_mode,
|
vr_mode: vr_mode,
|
||||||
show_nick: show_nick,
|
show_nick: show_nick,
|
||||||
save_player_pos: save_player_pos,
|
save_player_pos: save_player_pos,
|
||||||
|
default_playlist: default_playlist,
|
||||||
hidden_channels: hidden_channels,
|
hidden_channels: hidden_channels,
|
||||||
default_trending_type: default_trending_type,
|
default_trending_type: default_trending_type,
|
||||||
}.to_json)
|
}.to_json)
|
||||||
|
|||||||
@@ -279,6 +279,18 @@ module Invidious::Routes::Watch
|
|||||||
if CONFIG.invidious_companion.present?
|
if CONFIG.invidious_companion.present?
|
||||||
current_companion = env.get("current_companion").as(Int32)
|
current_companion = env.get("current_companion").as(Int32)
|
||||||
invidious_companion = CONFIG.invidious_companion[current_companion]
|
invidious_companion = CONFIG.invidious_companion[current_companion]
|
||||||
|
|
||||||
|
invidious_companion_urls = CONFIG.invidious_companion.reject(&.builtin_proxy).map do |companion|
|
||||||
|
uri =
|
||||||
|
"#{companion.public_url.scheme}://#{companion.public_url.host}#{companion.public_url.port ? ":#{companion.public_url.port}" : ""}"
|
||||||
|
end.join(" ")
|
||||||
|
|
||||||
|
if !invidious_companion_urls.empty?
|
||||||
|
env.response.headers["Content-Security-Policy"] =
|
||||||
|
env.response.headers["Content-Security-Policy"]
|
||||||
|
.gsub("media-src", "media-src #{invidious_companion_urls}")
|
||||||
|
.gsub("connect-src", "connect-src #{invidious_companion_urls}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
templated "watch"
|
templated "watch"
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ module Invidious::Routing
|
|||||||
self.register_api_v1_routes
|
self.register_api_v1_routes
|
||||||
self.register_api_manifest_routes
|
self.register_api_manifest_routes
|
||||||
self.register_video_playback_routes
|
self.register_video_playback_routes
|
||||||
|
self.register_companion_routes
|
||||||
end
|
end
|
||||||
|
|
||||||
# -------------------
|
# -------------------
|
||||||
@@ -191,7 +192,7 @@ module Invidious::Routing
|
|||||||
end
|
end
|
||||||
|
|
||||||
# -------------------
|
# -------------------
|
||||||
# Media proxy routes
|
# Proxy routes
|
||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
def register_api_manifest_routes
|
def register_api_manifest_routes
|
||||||
@@ -226,6 +227,13 @@ module Invidious::Routing
|
|||||||
get "/vi/:id/:name", Routes::Images, :thumbnails
|
get "/vi/:id/:name", Routes::Images, :thumbnails
|
||||||
end
|
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
|
# API routes
|
||||||
# -------------------
|
# -------------------
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ struct Preferences
|
|||||||
property save_player_pos : Bool = CONFIG.default_user_preferences.save_player_pos
|
property save_player_pos : Bool = CONFIG.default_user_preferences.save_player_pos
|
||||||
property hidden_channels : Array(String)? = nil
|
property hidden_channels : Array(String)? = nil
|
||||||
property default_trending_type : Invidious::Routes::Feeds::TrendingTypes = Invidious::Routes::Feeds::TrendingTypes::Default
|
property default_trending_type : Invidious::Routes::Feeds::TrendingTypes = Invidious::Routes::Feeds::TrendingTypes::Default
|
||||||
|
property default_playlist : String? = nil
|
||||||
|
|
||||||
module BoolToString
|
module BoolToString
|
||||||
def self.to_json(value : String, json : JSON::Builder)
|
def self.to_json(value : String, json : JSON::Builder)
|
||||||
|
|||||||
@@ -102,6 +102,9 @@ def extract_video_info(video_id : String, env : HTTP::Server::Context | Nil = ni
|
|||||||
# Don't fetch the next endpoint if the video is unavailable.
|
# Don't fetch the next endpoint if the video is unavailable.
|
||||||
if {"OK", "LIVE_STREAM_OFFLINE", "LOGIN_REQUIRED"}.any?(playability_status)
|
if {"OK", "LIVE_STREAM_OFFLINE", "LOGIN_REQUIRED"}.any?(playability_status)
|
||||||
next_response = YoutubeAPI.next({"videoId": video_id, "params": ""})
|
next_response = YoutubeAPI.next({"videoId": video_id, "params": ""})
|
||||||
|
# Remove the microformat returned by the /next endpoint on some videos
|
||||||
|
# to prevent player_response microformat from being overwritten.
|
||||||
|
next_response.delete("microformat")
|
||||||
player_response = player_response.merge(next_response)
|
player_response = player_response.merge(next_response)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -68,12 +68,18 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% preferred_captions.each do |caption| %>
|
<% preferred_captions.each do |caption|
|
||||||
<track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name %>" label="<%= caption.name %>">
|
api_captions_url = "/api/v1/captions/"
|
||||||
|
api_captions_url = invidious_companion.public_url.to_s + api_captions_url if (invidious_companion)
|
||||||
|
%>
|
||||||
|
<track kind="captions" src="<%= api_captions_url %><%= video.id %>?label=<%= caption.name %>" label="<%= caption.name %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% captions.each do |caption| %>
|
<% captions.each do |caption|
|
||||||
<track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name %>" label="<%= caption.name %>">
|
api_captions_url = "/api/v1/captions/"
|
||||||
|
api_captions_url = invidious_companion.public_url.to_s + api_captions_url if (invidious_companion)
|
||||||
|
%>
|
||||||
|
<track kind="captions" src="<%= api_captions_url %><%= video.id %>?label=<%= caption.name %>" label="<%= caption.name %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</video>
|
</video>
|
||||||
|
|||||||
@@ -129,6 +129,19 @@
|
|||||||
<input name="save_player_pos" id="save_player_pos" type="checkbox" <% if preferences.save_player_pos %>checked<% end %>>
|
<input name="save_player_pos" id="save_player_pos" type="checkbox" <% if preferences.save_player_pos %>checked<% end %>>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<% if user = env.get?("user").try &.as(User) %>
|
||||||
|
<% playlists = Invidious::Database::Playlists.select_user_created_playlists(user.email) %>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label for="default_playlist"><%= translate(locale, "preferences_default_playlist") %></label>
|
||||||
|
<select name="default_playlist" id="default_playlist">
|
||||||
|
<option value=""><%= translate(locale, "preferences_default_playlist_none") %></option>
|
||||||
|
<% playlists.each do |plid, playlist_title| %>
|
||||||
|
<option value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<legend><%= translate(locale, "preferences_category_visual") %></legend>
|
<legend><%= translate(locale, "preferences_category_visual") %></legend>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ we're going to need to do it here in order to allow for translations.
|
|||||||
<label for="playlist_id"><%= translate(locale, "Add to playlist: ") %></label>
|
<label for="playlist_id"><%= translate(locale, "Add to playlist: ") %></label>
|
||||||
<select style="width:100%" name="playlist_id" id="playlist_id">
|
<select style="width:100%" name="playlist_id" id="playlist_id">
|
||||||
<% playlists.each do |plid, playlist_title| %>
|
<% playlists.each do |plid, playlist_title| %>
|
||||||
<option data-plid="<%= plid %>" value="<%= plid %>"><%= HTML.escape(playlist_title) %></option>
|
<option data-plid="<%= plid %>" value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,11 +46,30 @@ struct YoutubeConnectionPool
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CompanionConnectionPool
|
# Packages a `HTTP::Client` to an Invidious companion instance alongside the configuration for that instance.
|
||||||
property pool : DB::Pool(HTTP::Client)
|
#
|
||||||
property companion : URI
|
# This is used as the resource for the `CompanionPool` as to allow the ability to
|
||||||
|
# proxy the requests to Invidious companion from Invidious directly.
|
||||||
|
# Instead of setting up routes in a reverse proxy.
|
||||||
|
struct CompanionWrapper
|
||||||
|
property client : HTTP::Client
|
||||||
|
property companion : Config::CompanionConfig
|
||||||
|
|
||||||
def initialize(companion, capacity = 5, timeout = 5.0)
|
def initialize(companion : Config::CompanionConfig)
|
||||||
|
@companion = companion
|
||||||
|
@client = make_client(companion.private_url, use_http_proxy: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
@client.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CompanionConnectionPool
|
||||||
|
property pool : DB::Pool(CompanionWrapper)
|
||||||
|
property companion : Config::CompanionConfig
|
||||||
|
|
||||||
|
def initialize(@companion, capacity = 5, timeout = 5.0)
|
||||||
options = DB::Pool::Options.new(
|
options = DB::Pool::Options.new(
|
||||||
initial_pool_size: 0,
|
initial_pool_size: 0,
|
||||||
max_pool_size: capacity,
|
max_pool_size: capacity,
|
||||||
@@ -58,26 +77,26 @@ class CompanionConnectionPool
|
|||||||
checkout_timeout: timeout
|
checkout_timeout: timeout
|
||||||
)
|
)
|
||||||
|
|
||||||
@companion = companion.private_url
|
@pool = DB::Pool(CompanionWrapper).new(options) do
|
||||||
|
make_client(@companion.private_url, use_http_proxy: false)
|
||||||
@pool = DB::Pool(HTTP::Client).new(options) do
|
CompanionWrapper.new(companion: @companion)
|
||||||
next make_client(@companion, use_http_proxy: false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def client(&)
|
def client(&)
|
||||||
conn = pool.checkout
|
wrapper = pool.checkout
|
||||||
|
|
||||||
begin
|
begin
|
||||||
response = yield conn
|
response = yield wrapper
|
||||||
rescue ex
|
rescue ex
|
||||||
conn.close
|
wrapper.close
|
||||||
|
|
||||||
conn = make_client(@companion, use_http_proxy: false)
|
make_client(@companion.private_url, use_http_proxy: false)
|
||||||
|
wrapper = CompanionWrapper.new(companion: @companion)
|
||||||
|
|
||||||
response = yield conn
|
response = yield wrapper
|
||||||
ensure
|
ensure
|
||||||
pool.release(conn)
|
pool.release(wrapper)
|
||||||
end
|
end
|
||||||
|
|
||||||
response
|
response
|
||||||
|
|||||||
@@ -709,22 +709,20 @@ module YoutubeAPI
|
|||||||
else
|
else
|
||||||
current_companion = env.get("current_companion").as(Int32)
|
current_companion = env.get("current_companion").as(Int32)
|
||||||
end
|
end
|
||||||
response = COMPANION_POOL[current_companion].client &.post(endpoint, headers: headers, body: data.to_json)
|
response_body = Hash(String, JSON::Any).new
|
||||||
body = response.body
|
|
||||||
if (response.status_code != 200)
|
COMPANION_POOL[current_companion].client do |wrapper|
|
||||||
raise Exception.new(
|
companion_base_url = wrapper.companion.private_url.path
|
||||||
"Error while communicating with Invidious companion: \
|
|
||||||
status code: #{response.status_code} and body: #{body.dump}"
|
wrapper.client.post("#{companion_base_url}#{endpoint}", headers: headers, body: data.to_json) do |response|
|
||||||
)
|
response_body = JSON.parse(response.body_io).as_h
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return response_body
|
||||||
rescue ex
|
rescue ex
|
||||||
raise InfoException.new("Error while communicating with Invidious companion: " + (ex.message || "no extra info found"))
|
raise InfoException.new("Error while communicating with Invidious companion: " + (ex.message || "no extra info found"))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert result to Hash
|
|
||||||
initial_data = JSON.parse(body).as_h
|
|
||||||
|
|
||||||
return initial_data
|
|
||||||
end
|
end
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|||||||
Reference in New Issue
Block a user