mirror of
https://gitea.invidious.io/iv-org/invidious-copy-2022-03-16.git
synced 2024-08-15 00:53:18 +00:00
Add administrator preferences
This commit is contained in:
parent
2fe545e19a
commit
a39b1583da
22 changed files with 616 additions and 454 deletions
|
@ -1,9 +1,9 @@
|
|||
class Config
|
||||
YAML.mapping({
|
||||
video_threads: Int32, # Number of threads to use for updating videos in cache (mostly non-functional)
|
||||
crawl_threads: Int32, # Number of threads to use for finding new videos from YouTube (used to populate "top" page)
|
||||
channel_threads: Int32, # Number of threads to use for crawling videos from channels (for updating subscriptions)
|
||||
feed_threads: Int32, # Number of threads to use for updating feeds
|
||||
video_threads: Int32, # Number of threads to use for updating videos in cache (mostly non-functional)
|
||||
db: NamedTuple( # Database configuration
|
||||
user: String,
|
||||
password: String,
|
||||
|
@ -11,11 +11,18 @@ user: String,
|
|||
port: Int32,
|
||||
dbname: String,
|
||||
),
|
||||
dl_api_key: String?, # DetectLanguage API Key (used to filter non-English results from "top" page), mostly non-functional
|
||||
https_only: Bool?, # Used to tell Invidious it is behind a proxy, so links to resources should be https://
|
||||
hmac_key: String?, # HMAC signing key for CSRF tokens
|
||||
full_refresh: Bool, # Used for crawling channels: threads should check all videos uploaded by a channel
|
||||
domain: String, # Domain to be used for links to resources on the site where an absolute URL is required
|
||||
full_refresh: Bool, # Used for crawling channels: threads should check all videos uploaded by a channel
|
||||
https_only: Bool?, # Used to tell Invidious it is behind a proxy, so links to resources should be https://
|
||||
hmac_key: String?, # HMAC signing key for CSRF tokens
|
||||
domain: String, # Domain to be used for links to resources on the site where an absolute URL is required
|
||||
dl_api_key: String?, # DetectLanguage API Key (used to filter non-English results from "top" page), mostly non-functional
|
||||
default_home: {type: String, default: "Top"},
|
||||
feed_menu: {type: Array(String), default: ["Popular", "Top", "Trending"]},
|
||||
top_enabled: {type: Bool, default: true},
|
||||
captcha_enabled: {type: Bool, default: true},
|
||||
login_enabled: {type: Bool, default: true},
|
||||
registration_enabled: {type: Bool, default: true},
|
||||
admins: {type: Array(String), default: [] of String},
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ def refresh_feeds(db, logger, max_threads = 1)
|
|||
rescue ex
|
||||
# Create view if it doesn't exist
|
||||
if ex.message.try &.ends_with? "does not exist"
|
||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
db.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
SELECT * FROM channel_videos WHERE \
|
||||
ucid = ANY ((SELECT subscriptions FROM users WHERE email = E'#{email.gsub("'", "\\'")}')::text[]) \
|
||||
ORDER BY published DESC;")
|
||||
|
@ -193,11 +193,11 @@ end
|
|||
|
||||
def pull_popular_videos(db)
|
||||
loop do
|
||||
subscriptions = PG_DB.query_all("SELECT channel FROM \
|
||||
subscriptions = db.query_all("SELECT channel FROM \
|
||||
(SELECT UNNEST(subscriptions) AS channel FROM users) AS d \
|
||||
GROUP BY channel ORDER BY COUNT(channel) DESC LIMIT 40", as: String)
|
||||
|
||||
videos = PG_DB.query_all("SELECT DISTINCT ON (ucid) * FROM \
|
||||
videos = db.query_all("SELECT DISTINCT ON (ucid) * FROM \
|
||||
channel_videos WHERE ucid IN (#{arg_array(subscriptions)}) \
|
||||
ORDER BY ucid, published DESC", subscriptions, as: ChannelVideo).sort_by { |video| video.published }.reverse
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ def get_user(sid, headers, db, refresh = true)
|
|||
|
||||
begin
|
||||
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
db.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
SELECT * FROM channel_videos WHERE \
|
||||
ucid = ANY ((SELECT subscriptions FROM users WHERE email = E'#{user.email.gsub("'", "\\'")}')::text[]) \
|
||||
ORDER BY published DESC;")
|
||||
|
@ -165,7 +165,7 @@ def get_user(sid, headers, db, refresh = true)
|
|||
|
||||
begin
|
||||
view_name = "subscriptions_#{sha256(user.email)[0..7]}"
|
||||
PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
db.exec("CREATE MATERIALIZED VIEW #{view_name} AS \
|
||||
SELECT * FROM channel_videos WHERE \
|
||||
ucid = ANY ((SELECT subscriptions FROM users WHERE email = E'#{user.email.gsub("'", "\\'")}')::text[]) \
|
||||
ORDER BY published DESC;")
|
||||
|
@ -247,7 +247,7 @@ def validate_response(challenge, token, user_id, operation, key, db, locale)
|
|||
raise translate(locale, "Invalid challenge")
|
||||
end
|
||||
|
||||
challenge = OpenSSL::HMAC.digest(:sha256, HMAC_KEY, challenge)
|
||||
challenge = OpenSSL::HMAC.digest(:sha256, key, challenge)
|
||||
challenge = Base64.urlsafe_encode(challenge)
|
||||
|
||||
if db.query_one?("SELECT EXISTS (SELECT true FROM nonces WHERE nonce = $1)", nonce, as: Bool)
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<div class="pure-u-1 pure-u-md-1-4"></div>
|
||||
<div class="pure-u-1 pure-u-md-1-2">
|
||||
<div class="pure-g">
|
||||
<% feeds = ["Popular", "Top", "Trending"] %>
|
||||
<% if env.get? "user" %>
|
||||
<% feeds << "Subscriptions" %>
|
||||
<% feed_menu = config.feed_menu.dup %>
|
||||
<% if !env.get?("user") %>
|
||||
<% feed_menu.reject! {|feed| feed == "Subscriptions"} %>
|
||||
<% end %>
|
||||
<% feeds.each do |feed| %>
|
||||
<div class="pure-u-1-2 pure-u-md-1-<%= feeds.size %>">
|
||||
<% feed_menu.each do |feed| %>
|
||||
<div class="pure-u-1-2 pure-u-md-1-<%= feed_menu.size %>">
|
||||
<a href="/feed/<%= feed.downcase %>" style="text-align:center;" class="pure-menu-heading">
|
||||
<%= translate(locale, feed) %>
|
||||
</a>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<% content_for "header" do %>
|
||||
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>">
|
||||
<title>Invidious</title>
|
||||
<% end %>
|
||||
|
||||
<%= rendered "components/feed_menu" %>
|
||||
|
||||
<div class="pure-g">
|
||||
<% top_videos.each_slice(4) do |slice| %>
|
||||
<% slice.each do |item| %>
|
||||
<%= rendered "components/item" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
|
@ -27,36 +27,40 @@
|
|||
|
||||
<label for="password"><%= translate(locale, "Password:") %></label>
|
||||
<input required class="pure-input-1" name="password" type="password" placeholder="Password">
|
||||
|
||||
<% if captcha_type == "image" %>
|
||||
<img style="width:100%" src='<%= captcha.not_nil![:image] %>'/>
|
||||
<input type="hidden" name="token" value="<%= captcha.not_nil![:token] %>">
|
||||
<input type="hidden" name="challenge" value="<%= captcha.not_nil![:challenge] %>">
|
||||
<label for="answer"><%= translate(locale, "Time (h:mm:ss):") %></label>
|
||||
<input required type="text" name="answer" type="text" placeholder="h:mm:ss">
|
||||
|
||||
<label>
|
||||
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious&captcha=text">
|
||||
<%= translate(locale, "Text CAPTCHA") %>
|
||||
</a>
|
||||
</label>
|
||||
<% else %>
|
||||
<% text_captcha.not_nil![:tokens].each_with_index do |token, i| %>
|
||||
<input type="hidden" name="text_challenge<%= i %>" value="<%= token[0] %>">
|
||||
<input type="hidden" name="text_token<%= i %>" value="<%= token[1] %>">
|
||||
<% end %>
|
||||
<label for="text_answer"><%= text_captcha.not_nil![:question] %></label>
|
||||
<input required type="text" name="text_answer" type="text" placeholder="Answer">
|
||||
|
||||
<label>
|
||||
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious">
|
||||
<%= translate(locale, "Image CAPTCHA") %>
|
||||
</a>
|
||||
</label>
|
||||
<% if config.captcha_enabled %>
|
||||
<% if captcha_type == "image" %>
|
||||
<img style="width:100%" src='<%= captcha.not_nil![:image] %>'/>
|
||||
<input type="hidden" name="token" value="<%= captcha.not_nil![:token] %>">
|
||||
<input type="hidden" name="challenge" value="<%= captcha.not_nil![:challenge] %>">
|
||||
<label for="answer"><%= translate(locale, "Time (h:mm:ss):") %></label>
|
||||
<input required type="text" name="answer" type="text" placeholder="h:mm:ss">
|
||||
|
||||
<label>
|
||||
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious&captcha=text">
|
||||
<%= translate(locale, "Text CAPTCHA") %>
|
||||
</a>
|
||||
</label>
|
||||
<% else %>
|
||||
<% text_captcha.not_nil![:tokens].each_with_index do |token, i| %>
|
||||
<input type="hidden" name="text_challenge<%= i %>" value="<%= token[0] %>">
|
||||
<input type="hidden" name="text_token<%= i %>" value="<%= token[1] %>">
|
||||
<% end %>
|
||||
<label for="text_answer"><%= text_captcha.not_nil![:question] %></label>
|
||||
<input required type="text" name="text_answer" type="text" placeholder="Answer">
|
||||
|
||||
<label>
|
||||
<a href="/login?referer=<%= URI.escape(referer) %>&type=invidious">
|
||||
<%= translate(locale, "Image CAPTCHA") %>
|
||||
</a>
|
||||
</label>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary"><%= translate(locale, "Sign In") %></button>
|
||||
<% if config.registration_enabled %>
|
||||
<button type="submit" name="action" value="register" class="pure-button pure-button-primary"><%= translate(locale, "Register") %></button>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
</form>
|
||||
<% elsif account_type == "google" %>
|
||||
|
@ -67,7 +71,7 @@
|
|||
|
||||
<label for="password"><%= translate(locale, "Password:") %></label>
|
||||
<input required class="pure-input-1" name="password" type="password" placeholder="Password">
|
||||
|
||||
|
||||
<% if tfa %>
|
||||
<label for="tfa"><%= translate(locale, "Google verification code:") %></label>
|
||||
<input required class="pure-input-1" name="tfa" type="text" placeholder="Google verification code">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<% content_for "header" do %>
|
||||
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>">
|
||||
<title><%= translate(locale, "Popular") %> - Invidious</title>
|
||||
<title><% if config.default_home != "Popular" %><%= translate(locale, "Popular") %> - <% end %>Invidious</title>
|
||||
<% end %>
|
||||
|
||||
<%= rendered "components/feed_menu" %>
|
||||
|
|
|
@ -58,45 +58,25 @@ function update_value(element) {
|
|||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="comments_0"><%= translate(locale, "Default comments: ") %></label>
|
||||
<select name="comments_0" id="comments_0">
|
||||
<label for="comments[0]"><%= translate(locale, "Default comments: ") %></label>
|
||||
<% preferences.comments.each_with_index do |comments, index| %>
|
||||
<select name="comments[<%= index %>]" id="comments[<%= index %>]">
|
||||
<% {"", "youtube", "reddit"}.each do |option| %>
|
||||
<option value="<%= option %>" <% if preferences.comments[0] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<option value="<%= option %>" <% if preferences.comments[index] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="comments_1"><%= translate(locale, "Fallback comments: ") %></label>
|
||||
<select name="comments_1" id="comments_1">
|
||||
<% {"", "youtube", "reddit"}.each do |option| %>
|
||||
<option value="<%= option %>" <% if preferences.comments[1] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="captions_0"><%= translate(locale, "Default captions: ") %></label>
|
||||
<select class="pure-u-1-5" name="captions_0" id="captions_0">
|
||||
<label for="captions[0]"><%= translate(locale, "Default captions: ") %></label>
|
||||
<% preferences.captions.each_with_index do |caption, index| %>
|
||||
<select class="pure-u-1-6" name="captions[<%= index %>]" id="captions[<%= index %>]">
|
||||
<% CAPTION_LANGUAGES.each do |option| %>
|
||||
<option value="<%= option %>" <% if preferences.captions[0] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<option value="<%= option %>" <% if preferences.captions[index] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="captions_fallback"><%= translate(locale, "Fallback captions: ") %></label>
|
||||
<select class="pure-u-1-5" name="captions_1" id="captions_1">
|
||||
<% CAPTION_LANGUAGES.each do |option| %>
|
||||
<option value="<%= option %>" <% if preferences.captions[1] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
|
||||
<select class="pure-u-1-5" name="captions_2" id="captions_2">
|
||||
<% CAPTION_LANGUAGES.each do |option| %>
|
||||
<option value="<%= option %>" <% if preferences.captions[2] == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
|
@ -167,13 +147,57 @@ function update_value(element) {
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if env.get?("user") && config.admins.includes? env.get?("user").as(User).email %>
|
||||
<legend><%= translate(locale, "Administrator preferences") %></legend>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="default_home"><%= translate(locale, "Default homepage: ") %></label>
|
||||
<select name="default_home" id="default_home">
|
||||
<% {"Popular", "Top", "Trending", "Subscriptions"}.each do |option| %>
|
||||
<option value="<%= option %>" <% if config.default_home == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="feed_menu"><%= translate(locale, "Feed menu: ") %></label>
|
||||
<% 4.times do |index| %>
|
||||
<select name="feed_menu[<%= index %>]" id="feed_menu[<%= index %>]">
|
||||
<% {"", "Popular", "Top", "Trending", "Subscriptions"}.each do |option| %>
|
||||
<option value="<%= option %>" <% if config.feed_menu[index]? == option %> selected <% end %>><%= translate(locale, option) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="top_enabled"><%= translate(locale, "Top enabled? ") %></label>
|
||||
<input name="top_enabled" id="top_enabled" type="checkbox" <% if config.top_enabled %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="captcha_enabled"><%= translate(locale, "CAPTCHA enabled? ") %></label>
|
||||
<input name="captcha_enabled" id="captcha_enabled" type="checkbox" <% if config.captcha_enabled %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="login_enabled"><%= translate(locale, "Login enabled? ") %></label>
|
||||
<input name="login_enabled" id="login_enabled" type="checkbox" <% if config.login_enabled %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="registration_enabled"><%= translate(locale, "Registration enabled? ") %></label>
|
||||
<input name="registration_enabled" id="registration_enabled" type="checkbox" <% if config.registration_enabled %>checked<% end %>>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if env.get? "user" %>
|
||||
<legend><%= translate(locale, "Data preferences") %></legend>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<a href="/clear_watch_history?referer=<%= URI.escape(referer) %>"><%= translate(locale, "Clear watch history") %></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="pure-control-group">
|
||||
<a href="/data_control?referer=<%= URI.escape(referer) %>"><%= translate(locale, "Import/Export data") %></a>
|
||||
</div>
|
||||
|
|
|
@ -89,12 +89,14 @@
|
|||
<i class="icon ion-ios-cog"></i>
|
||||
</a>
|
||||
</div>
|
||||
<% if config.login_enabled %>
|
||||
<div class="pure-u-1-3">
|
||||
<a href="/login?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
|
||||
<%= translate(locale, "Login") %>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= content %>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<% content_for "header" do %>
|
||||
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>">
|
||||
<title><%= translate(locale, "Top") %> - Invidious</title>
|
||||
<title><% if config.default_home != "Top" %><%= translate(locale, "Top") %> - <% end %>Invidious</title>
|
||||
<% end %>
|
||||
|
||||
<%= rendered "components/feed_menu" %>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<% content_for "header" do %>
|
||||
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>">
|
||||
<title><%= translate(locale, "Trending") %> - Invidious</title>
|
||||
<title><% if config.default_home != "Trending" %><%= translate(locale, "Trending") %> - <% end %>Invidious</title>
|
||||
<% end %>
|
||||
|
||||
<%= rendered "components/feed_menu" %>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue