This commit is contained in:
Richard Lora 2025-06-07 12:35:57 +00:00 committed by GitHub
commit 3629664d5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 143 additions and 71 deletions

View File

@ -311,12 +311,13 @@ https_only: false
# -----------------------------
##
## Enable/Disable the "Popular" tab on the main page.
## Enable/Disable specific pages on the main page.
##
## Accepted values: true, false
## Default: true
#pages_enabled:
# trending: true
# popular: true
# search: true
##
#popular_enabled: true
##
## Enable/Disable statstics (available at /api/v1/stats).

View File

@ -3,7 +3,8 @@
"Add to playlist: ": "Add to playlist: ",
"Answer": "Answer",
"Search for videos": "Search for videos",
"The Popular feed has been disabled by the administrator.": "The Popular feed has been disabled by the administrator.",
"popular_page_disabled": "The Popular feed has been disabled by the administrator.",
"trending_page_disabled": "The Trending feed has been disabled by the administrator.",
"generic_channels_count": "{{count}} channel",
"generic_channels_count_plural": "{{count}} channels",
"generic_views_count": "{{count}} view",
@ -500,7 +501,10 @@
"carousel_slide": "Slide {{current}} of {{total}}",
"carousel_skip": "Skip the Carousel",
"carousel_go_to": "Go to slide `x`",
"preferences_trending_enabled_label": "Trending enabled: ",
"preferences_search_enabled_label": "Search enabled: ",
"timeline_parse_error_placeholder_heading": "Unable to parse item",
"timeline_parse_error_placeholder_message": "Invidious encountered an error while trying to parse this item. For more information see below:",
"timeline_parse_error_show_technical_details": "Show technical details"
"timeline_parse_error_show_technical_details": "Show technical details",
"search_page_disabled": "Search has been disabled by the administrator."
}

View File

@ -191,7 +191,7 @@ if (CONFIG.use_pubsub_feeds.is_a?(Bool) && CONFIG.use_pubsub_feeds.as(Bool)) ||
Invidious::Jobs.register Invidious::Jobs::SubscribeToFeedsJob.new(PG_DB, HMAC_KEY)
end
if CONFIG.popular_enabled
if CONFIG.page_enabled?("popular")
Invidious::Jobs.register Invidious::Jobs::PullPopularVideosJob.new(PG_DB)
end

View File

@ -71,6 +71,37 @@ struct HTTPProxyConfig
property port : Int32
end
# Structure used for global per-page feature toggles
struct PagesEnabled
include YAML::Serializable
property trending : Bool = true
property popular : Bool = true
property search : Bool = true
def has_key?(key : String) : Bool
%w(trending popular search).includes?(key)
end
def [](key : String) : Bool
case key
when "trending" then @trending
when "popular" then @popular
when "search" then @search
else raise KeyError.new("Unknown page '#{key}'")
end
end
def []=(key : String, value : Bool)
case key
when "trending" then @trending = value
when "popular" then @popular = value
when "search" then @search = value
else raise KeyError.new("Unknown page '#{key}'")
end
end
end
class Config
include YAML::Serializable
@ -111,13 +142,25 @@ class Config
# Used to tell Invidious it is behind a proxy, so links to resources should be https://
property https_only : Bool?
# HMAC signing key for CSRF tokens and verifying pubsub subscriptions
property hmac_key : String = ""
# Domain to be used for links to resources on the site where an absolute URL is required
property domain : String?
# Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
property use_pubsub_feeds : Bool | Int32 = false
# —————————————————————————————————————————————————————————————————————————————————————
# DEPRECATED: use `pages_enabled["popular"]` instead.
@[Deprecated("`popular_enabled` will be removed in a future release; use pages_enabled[\"popular\"] instead")]
property popular_enabled : Bool = true
# Global per-page feature toggles.
# Valid keys: "trending", "popular", "search"
# If someone sets both `popular_enabled` and `pages_enabled["popular"]`, the latter takes precedence.
property pages_enabled : PagesEnabled = PagesEnabled.new
# —————————————————————————————————————————————————————————————————————————————————————
property captcha_enabled : Bool = true
property login_enabled : Bool = true
property registration_enabled : Bool = true
@ -188,13 +231,20 @@ class Config
when Bool
return disabled
when Array
if disabled.includes? option
return true
disabled.includes?(option)
else
return false
false
end
end
# Centralized page toggle with legacy fallback for `popular_enabled`
def page_enabled?(page : String) : Bool
if @pages_enabled.has_key?(page)
@pages_enabled[page]
elsif page == "popular"
@popular_enabled
else
return false
true
end
end

View File

@ -29,11 +29,6 @@ module Invidious::Routes::API::V1::Feeds
env.response.content_type = "application/json"
if !CONFIG.popular_enabled
error_message = {"error" => "Administrator has disabled this endpoint."}.to_json
haltf env, 403, error_message
end
JSON.build do |json|
json.array do
popular_videos.each do |video|

View File

@ -102,6 +102,28 @@ module Invidious::Routes::BeforeAll
preferences.locale = locale
env.set "preferences", preferences
path = env.request.path
page_key = case path
when "/feed/popular", "/api/v1/popular"
"popular"
when "/feed/trending", "/api/v1/trending"
"trending"
when "/search", "/api/v1/search"
"search"
else
nil
end
if page_key && !CONFIG.page_enabled?(page_key)
if path.starts_with?("/api/")
error_message = {error: "Administrator has disabled this endpoint."}.to_json
haltf env, 403, error_message
else
message = "#{page_key}_page_disabled"
return error_template(403, message)
end
end
# Allow media resources to be loaded from google servers
# TODO: check if *.youtube.com can be removed
#

View File

@ -33,18 +33,11 @@ module Invidious::Routes::Feeds
def self.popular(env)
locale = env.get("preferences").as(Preferences).locale
if CONFIG.popular_enabled
templated "feeds/popular"
else
message = translate(locale, "The Popular feed has been disabled by the administrator.")
templated "message"
end
end
def self.trending(env)
locale = env.get("preferences").as(Preferences).locale
trending_type = env.params.query["type"]?
trending_type ||= "Default"

View File

@ -199,9 +199,12 @@ module Invidious::Routes::PreferencesRoute
end
CONFIG.default_user_preferences.feed_menu = admin_feed_menu
popular_enabled = env.params.body["popular_enabled"]?.try &.as(String)
popular_enabled ||= "off"
CONFIG.popular_enabled = popular_enabled == "on"
pages_enabled = {
popular: (env.params.body["popular_enabled"]?.try &.as(String) || "on") == "on",
trending: (env.params.body["trending_enabled"]?.try &.as(String) || "on") == "on",
search: (env.params.body["search_enabled"]?.try &.as(String) || "on") == "on",
}
CONFIG.pages_enabled = pages_enabled
captcha_enabled = env.params.body["captcha_enabled"]?.try &.as(String)
captcha_enabled ||= "off"

View File

@ -40,33 +40,28 @@ module Invidious::Routes::Search
prefs = env.get("preferences").as(Preferences)
locale = prefs.locale
# otherwise, do a normal search
region = env.params.query["region"]? || prefs.region
query = Invidious::Search::Query.new(env.params.query, :regular, region)
# empty query → show homepage
if query.empty?
# Display the full page search box implemented in #1977
env.set "search", ""
templated "search_homepage", navbar_search: false
else
user = env.get? "user"
return templated "search_homepage", navbar_search: false
end
# An URL was copy/pasted in the search box.
# Redirect the user to the appropriate page.
# nonempty query → process it
user = env.get?("user")
if query.url?
return env.redirect UrlSanitizer.process(query.text).to_s
end
begin
if user
items = query.process(user.as(User))
else
items = query.process
end
items = user ? query.process(user.as(User)) : query.process
rescue ex : ChannelSearchException
return error_template(404, "Unable to find channel with id of '#{HTML.escape(ex.channel)}'. Are you sure that's an actual channel id? It should look like 'UC4QobU6STFB0P71PMvOGN5A'.")
return error_template 404, "Unable to find channel with id “#{HTML.escape(ex.channel)}”…"
rescue ex
return error_template(500, ex)
return error_template 500, ex
end
redirect_url = Invidious::Frontend::Misc.redirect_url(env)
@ -78,6 +73,7 @@ module Invidious::Routes::Search
show_next: (items.size >= 20)
)
# If it's a channel search, prefix the box; otherwise just show the text
if query.type == Invidious::Search::Query::Type::Channel
env.set "search", "channel:#{query.channel} #{query.text}"
else
@ -86,7 +82,6 @@ module Invidious::Routes::Search
templated "search"
end
end
def self.hashtag(env : HTTP::Server::Context)
locale = env.get("preferences").as(Preferences).locale

View File

@ -289,9 +289,18 @@
<div class="pure-control-group">
<label for="popular_enabled"><%= translate(locale, "Popular enabled: ") %></label>
<input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.popular_enabled %>checked<% end %>>
<input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.page_enabled?("popular") %>checked<% end %>>
</div>
<div class="pure-control-group">
<label for="trending_enabled"><%= translate(locale, "preferences_trending_enabled_label") %></label>
<input name="trending_enabled" id="trending_enabled" type="checkbox" <% if CONFIG.page_enabled?("trending") %>checked<% end %>>
</div>
<div class="pure-control-group">
<label for="search_enabled"><%= translate(locale, "preferences_search_enabled_label") %></label>
<input name="search_enabled" id="search_enabled" type="checkbox" <% if CONFIG.page_enabled?("search") %>checked<% end %>>
</div>
<div class="pure-control-group">
<label for="captcha_enabled"><%= translate(locale, "CAPTCHA enabled: ") %></label>