From 71a55692513f14e4c47afd86995a0e4a33a8defa Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Sat, 24 Jan 2026 22:16:40 -0300
Subject: [PATCH] Set current companion using preferences and not a separate
cookie
---
config/config.example.yml | 9 ------
src/invidious/config.cr | 4 +--
src/invidious/routes/backend_switcher.cr | 17 ++++++++---
src/invidious/routes/before_all.cr | 39 +++++++++++++++---------
src/invidious/routes/preferences.cr | 2 +-
src/invidious/user/cookies.cr | 26 ++--------------
src/invidious/user/preferences.cr | 1 +
src/invidious/views/template.ecr | 8 ++---
8 files changed, 48 insertions(+), 58 deletions(-)
diff --git a/config/config.example.yml b/config/config.example.yml
index c7a7e1e8..cd92b55d 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -1163,15 +1163,6 @@ video_cache:
##
#max_dash_resolution: null
-##
-## The name of the cookie to hold the backend id that
-## the client is using.
-##
-## Accepted values: a string
-## Default: "COMPANION_ID"
-##
-#server_id_cookie_name: "COMPANION_ID"
-
##
## Checks if the companions in the `invidious_companion` list
## are alive using their `/healthz` endpoint.
diff --git a/src/invidious/config.cr b/src/invidious/config.cr
index b477b19c..4bc11fb2 100644
--- a/src/invidious/config.cr
+++ b/src/invidious/config.cr
@@ -60,6 +60,8 @@ struct ConfigPreferences
@[YAML::Field(ignore: true)]
property default_trending_type : Invidious::Routes::Feeds::TrendingTypes = Invidious::Routes::Feeds::TrendingTypes::Default
property show_community_backends : Bool = false
+ @[YAML::Field(ignore: true)]
+ property current_companion : Int32? = nil
def to_tuple
{% begin %}
@@ -223,8 +225,6 @@ class Config
property pubsub_domain : String = ""
- property server_id_cookie_name : String = "COMPANION_ID"
-
property video_cache : VideoCacheConfig = VideoCacheConfig.from_yaml("")
class VideoCacheConfig
diff --git a/src/invidious/routes/backend_switcher.cr b/src/invidious/routes/backend_switcher.cr
index e4702729..7d143e39 100644
--- a/src/invidious/routes/backend_switcher.cr
+++ b/src/invidious/routes/backend_switcher.cr
@@ -3,13 +3,22 @@
module Invidious::Routes::BackendSwitcher
def self.switch(env)
referer = get_referer(env, unroll: false)
- backend_id = env.params.query["backend_id"]?.try &.to_i
+ companion_id = env.params.query["companion_id"]?.try &.to_i
+ preferences = env.get("preferences").as(Preferences)
+ user = env.get? "user"
- if backend_id.nil?
- return error_template(400, "Backend ID is required")
+ if companion_id.nil?
+ return error_template(400, "Companion ID is required")
end
- env.response.cookies[CONFIG.server_id_cookie_name] = Invidious::User::Cookies.server_id(env.request.headers["Host"], backend_id)
+ if user
+ user = user.as(User)
+ user.preferences.current_companion = companion_id
+ Invidious::Database::Users.update_preferences(user)
+ else
+ preferences.current_companion = companion_id
+ env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(env.request.headers["Host"], preferences)
+ end
env.redirect referer
end
diff --git a/src/invidious/routes/before_all.cr b/src/invidious/routes/before_all.cr
index 2082eb72..297b7ce0 100644
--- a/src/invidious/routes/before_all.cr
+++ b/src/invidious/routes/before_all.cr
@@ -169,7 +169,6 @@ module Invidious::Routes::BeforeAll::Companion
companion_status : CompanionStatus,
preferences : Preferences,
)
- cookie_name = CONFIG.server_id_cookie_name
c_size = CONFIG.invidious_companion.size
current_companion = 0
@@ -181,20 +180,20 @@ module Invidious::Routes::BeforeAll::Companion
current_companion = index
else
# Set cookie if there is no cookie
- if !env.request.cookies.has_key?(cookie_name)
+ if !env.request.cookies.has_key?("PREFS")
current_companion = self.find_available_companion(env, host, nil, companion_status, preferences)
if current_companion
- self.set_cookie(env, host, current_companion)
+ self.set_companion(env, preferences, host, current_companion)
else
return ""
end
else
begin
- current_companion = get_cookie(env)
+ current_companion = get_companion(preferences)
current_companion = self.find_available_companion(env, host, current_companion, companion_status, preferences)
rescue
current_companion = rand(c_size)
- self.set_cookie(env, host, current_companion)
+ self.set_companion(env, preferences, host, current_companion)
end
end
@@ -219,18 +218,29 @@ module Invidious::Routes::BeforeAll::Companion
return companion_csp
end
- private def set_cookie(
+ private def set_companion(
env : HTTP::Server::Context,
+ preferences : Preferences,
host : String,
current_companion : Int32,
)
- cookie_name = CONFIG.server_id_cookie_name
- env.response.cookies[cookie_name] = Invidious::User::Cookies.server_id(host, current_companion)
+ user = env.get? "user"
+
+ if user
+ user = user.as(User)
+ user.preferences.current_companion = current_companion
+ Invidious::Database::Users.update_preferences(user)
+ else
+ preferences.current_companion = current_companion
+ env.set "preferences", preferences
+ env.response.cookies["PREFS"] = Invidious::User::Cookies.prefs(env.request.headers["Host"], preferences)
+ end
end
- private def get_cookie(env : HTTP::Server::Context)
- cookie_name = CONFIG.server_id_cookie_name
- return env.request.cookies[cookie_name].value.try &.to_i
+ private def get_companion(
+ preferences : Preferences,
+ )
+ return preferences.current_companion
end
private def find_available_companion(
@@ -260,7 +270,7 @@ module Invidious::Routes::BeforeAll::Companion
end
end
- current_companion = self.wrap_current_companion(env, host, current_companion, c_size, working_companions)
+ current_companion = self.wrap_current_companion(env, host, current_companion, c_size, working_companions, preferences)
if current_companion.nil?
return nil
end
@@ -271,7 +281,7 @@ module Invidious::Routes::BeforeAll::Companion
if alive_companion
current_companion = alive_companion
env.set "companion_switched", true
- self.set_cookie(env, host, current_companion)
+ self.set_companion(env, preferences, host, current_companion)
end
end
@@ -294,11 +304,12 @@ module Invidious::Routes::BeforeAll::Companion
current_companion : Int32,
invidious_companion_size : Int32,
working_companions : Array(Int32),
+ preferences : Preferences,
)
if (current_companion < 0) || current_companion >= invidious_companion_size
current_companion = self.get_available_companion(invidious_companion_size, working_companions)
if current_companion
- self.set_cookie(env, host, current_companion)
+ self.set_companion(env, preferences, host, current_companion)
else
current_companion = rand(invidious_companion_size)
end
diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr
index e42b68bc..55ffaff6 100644
--- a/src/invidious/routes/preferences.cr
+++ b/src/invidious/routes/preferences.cr
@@ -174,7 +174,7 @@ module Invidious::Routes::PreferencesRoute
show_community_backends = env.params.body["show_community_backends"]?.try &.as(String)
show_community_backends ||= "off"
- show_community_backends= show_community_backends == "on"
+ show_community_backends = show_community_backends == "on"
# Convert to JSON and back again to take advantage of converters used for compatibility
preferences = Preferences.from_json({
diff --git a/src/invidious/user/cookies.cr b/src/invidious/user/cookies.cr
index 605ead3a..37c64a5c 100644
--- a/src/invidious/user/cookies.cr
+++ b/src/invidious/user/cookies.cr
@@ -50,30 +50,8 @@ struct Invidious::User
expires: Time.utc + 2.years,
secure: @@secure,
http_only: false,
- samesite: HTTP::Cookie::SameSite::Lax
- )
- end
-
- # Backend (CONFIG.server_id_cookie_name) cookie
- # Parameter "domain" comes from the global config
- def server_id(domain : String?, server_id : Int32) : HTTP::Cookie
- # Strip the port from the domain if it's being accessed from another port
- # Browsers will reject the cookie if it contains the port number. This is
- # because `example.com:3000` is not the same as `example.com` on a cookie.
- domain = domain.split(":")[0]
- # Not secure if it's being accessed from I2P
- # Browsers expect the domain to include https. On I2P there is no HTTPS
- if domain.not_nil!.split(".").last == "i2p"
- @@secure = false
- end
- return HTTP::Cookie.new(
- name: CONFIG.server_id_cookie_name,
- domain: domain,
- path: "/",
- value: server_id.to_s,
- secure: @@secure,
- http_only: true,
- samesite: HTTP::Cookie::SameSite::Lax
+ samesite: HTTP::Cookie::SameSite::Lax,
+ path: "/"
)
end
end
diff --git a/src/invidious/user/preferences.cr b/src/invidious/user/preferences.cr
index 112200f8..c82f3712 100644
--- a/src/invidious/user/preferences.cr
+++ b/src/invidious/user/preferences.cr
@@ -60,6 +60,7 @@ struct Preferences
property default_trending_type : Invidious::Routes::Feeds::TrendingTypes = Invidious::Routes::Feeds::TrendingTypes::Default
property default_playlist : String? = nil
property show_community_backends : Bool = false
+ property current_companion : Int32? = nil
module BoolToString
def self.to_json(value : String, json : JSON::Builder)
diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr
index 2364d06e..ebcf6dc2 100644
--- a/src/invidious/views/template.ecr
+++ b/src/invidious/views/template.ecr
@@ -146,7 +146,7 @@
next if companion.i2p_public_url.host.nil? && using_i2p
backend_name_prefix = CONFIG.backend_name_prefix + (index + 1).to_s
%>
- display: inline-block;">
+ display: inline-block;">
<%= HTML.escape(backend_name_prefix) %> <%= HTML.escape(companion.note) %>
<% end %>
-
+
<% if CONFIG.instance_maintainer_email || CONFIG.modified_source_code_url || CONFIG.footer_instance_tos_link || CONFIG.footer_instance_privacy_policy_link %>