diff options
| -rw-r--r-- | Makefile | 44 | ||||
| -rw-r--r-- | config/config.example.yml | 10 | ||||
| -rw-r--r-- | docker-compose.yml | 57 | ||||
| -rw-r--r-- | locales/en-US.json | 1 | ||||
| -rw-r--r-- | locales/es.json | 3 | ||||
| -rw-r--r-- | locales/is.json | 3 | ||||
| -rw-r--r-- | locales/pl.json | 35 | ||||
| -rw-r--r-- | locales/tr.json | 3 | ||||
| -rw-r--r-- | src/invidious.cr | 87 | ||||
| -rw-r--r-- | src/invidious/config.cr | 1 | ||||
| -rw-r--r-- | src/invidious/routes/api/v1/authenticated.cr | 10 | ||||
| -rw-r--r-- | src/invidious/routes/api/v1/videos.cr | 2 | ||||
| -rw-r--r-- | src/invidious/routes/channels.cr | 33 | ||||
| -rw-r--r-- | src/invidious/routes/login.cr | 7 | ||||
| -rw-r--r-- | src/invidious/routes/playlists.cr | 11 | ||||
| -rw-r--r-- | src/invidious/routes/preferences.cr | 5 | ||||
| -rw-r--r-- | src/invidious/routes/watch.cr | 2 | ||||
| -rw-r--r-- | src/invidious/routing.cr | 4 | ||||
| -rw-r--r-- | src/invidious/user/preferences.cr | 1 | ||||
| -rw-r--r-- | src/invidious/views/user/preferences.ecr | 5 |
20 files changed, 186 insertions, 138 deletions
@@ -89,28 +89,28 @@ distclean: clean # ----------------------- help: - echo "Targets available in this Makefile:" - echo "" - echo "get-libs Fetch Crystal libraries" - echo "invidious Build Invidious" - echo "run Launch Invidious" - echo "" - echo "format Run the Crystal formatter" - echo "test Run tests" - echo "verify Just make sure that the code compiles, but without" - echo " generating any binaries. Useful to search for errors" - echo "" - echo "clean Remove build artifacts" - echo "distclean Remove build artifacts and libraries" - echo "" - echo "" - echo "Build options available for this Makefile:" - echo "" - echo "RELEASE Make a release build (Default: 1)" - echo "STATIC Link libraries statically (Default: 0)" - echo "" - echo "DISABLE_QUIC Disable support for QUIC (Default: 0)" - echo "NO_DBG_SYMBOLS Strip debug symbols (Default: 0)" + @echo "Targets available in this Makefile:" + @echo "" + @echo " get-libs Fetch Crystal libraries" + @echo " invidious Build Invidious" + @echo " run Launch Invidious" + @echo "" + @echo " format Run the Crystal formatter" + @echo " test Run tests" + @echo " verify Just make sure that the code compiles, but without" + @echo " generating any binaries. Useful to search for errors" + @echo "" + @echo " clean Remove build artifacts" + @echo " distclean Remove build artifacts and libraries" + @echo "" + @echo "" + @echo "Build options available for this Makefile:" + @echo "" + @echo " RELEASE Make a release build (Default: 1)" + @echo " STATIC Link libraries statically (Default: 0)" + @echo "" + @echo " DISABLE_QUIC Disable support for QUIC (Default: 0)" + @echo " NO_DBG_SYMBOLS Strip debug symbols (Default: 0)" diff --git a/config/config.example.yml b/config/config.example.yml index 59cb486b..e9f0e8f1 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -847,3 +847,13 @@ default_user_preferences: ## Default: false ## #automatic_instance_redirect: false + + ## + ## Show the entire video description by default (when set to 'false', + ## only the first few lines of the description are shown and a + ## "show more" button allows to expand it). + ## + ## Accepted values: true, false + ## Default: false + ## + #extend_desc: false diff --git a/docker-compose.yml b/docker-compose.yml index c76c314c..cd1df4ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,12 @@ -version: '3' +# Warning: This docker-compose file is made for development purposes. +# Using it will build an image from the locally cloned repository. +# +# If you want to use Invidious in production, see the docker-compose.yml file provided +# in the installation documentation: https://docs.invidious.io/Installation.md + +version: "3" services: - postgres: - image: postgres:10 - restart: unless-stopped - volumes: - - postgresdata:/var/lib/postgresql/data - - ./config/sql:/config/sql - - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh - environment: - POSTGRES_DB: invidious - POSTGRES_PASSWORD: kemal - POSTGRES_USER: kemal - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + invidious: build: context: . @@ -21,27 +15,42 @@ services: ports: - "127.0.0.1:3000:3000" environment: - # Adapted from ./config/config.yml + # Please read the following file for a comprehensive list of all available + # configuration options and their associated syntax: + # https://github.com/iv-org/invidious/blob/master/config/config.example.yml INVIDIOUS_CONFIG: | - channel_threads: 1 - check_tables: true - feed_threads: 1 db: + dbname: invidious user: kemal password: kemal - host: postgres + host: invidious-db port: 5432 - dbname: invidious - full_refresh: false - https_only: false - domain: + check_tables: true + # external_port: + # domain: + # https_only: false + # statistics_enabled: false healthcheck: test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1 interval: 30s timeout: 5s retries: 2 depends_on: - - postgres + - invidious-db + + invidious-db: + image: docker.io/library/postgres:14 + restart: unless-stopped + volumes: + - postgresdata:/var/lib/postgresql/data + - ./config/sql:/config/sql + - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh + environment: + POSTGRES_DB: invidious + POSTGRES_USER: kemal + POSTGRES_PASSWORD: kemal + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] volumes: postgresdata: diff --git a/locales/en-US.json b/locales/en-US.json index c924c8aa..1335d384 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -65,6 +65,7 @@ "preferences_continue_autoplay_label": "Autoplay next video: ", "preferences_listen_label": "Listen by default: ", "preferences_local_label": "Proxy videos: ", + "preferences_watch_history_label": "Enable watch history: ", "preferences_speed_label": "Default speed: ", "preferences_quality_label": "Preferred video quality: ", "preferences_quality_option_dash": "DASH (adaptative quality)", diff --git a/locales/es.json b/locales/es.json index 24f8dbdf..fbdb13ac 100644 --- a/locales/es.json +++ b/locales/es.json @@ -458,5 +458,6 @@ "Chinese (China)": "Chino (China)", "Korean (auto-generated)": "Coreano (generados automáticamente)", "Spanish (Mexico)": "Español (Méjico)", - "Spanish (auto-generated)": "Español (generados automáticamente)" + "Spanish (auto-generated)": "Español (generados automáticamente)", + "preferences_watch_history_label": "Habilitar historial de reproducciones: " } diff --git a/locales/is.json b/locales/is.json index 9258154e..99bd6574 100644 --- a/locales/is.json +++ b/locales/is.json @@ -318,5 +318,6 @@ "Videos": "Myndbönd", "Playlists": "Spilunarlistar", "Community": "Samfélag", - "Current version: ": "Núverandi útgáfa: " + "Current version: ": "Núverandi útgáfa: ", + "preferences_watch_history_label": "Virkja áhorfssögu: " } diff --git a/locales/pl.json b/locales/pl.json index 5c4667f0..0f4e0927 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -21,15 +21,15 @@ "No": "Nie", "Import and Export Data": "Import i eksport danych", "Import": "Import", - "Import Invidious data": "Importuj dane Invidious", - "Import YouTube subscriptions": "Importuj subskrybcje z YouTube", + "Import Invidious data": "Importuj dane JSON Invidious", + "Import YouTube subscriptions": "Importuj subskrybcje z YouTube/OPML", "Import FreeTube subscriptions (.db)": "Importuj subskrybcje z FreeTube (.db)", "Import NewPipe subscriptions (.json)": "Importuj subskrybcje z NewPipe (.json)", "Import NewPipe data (.zip)": "Importuj dane NewPipe (.zip)", "Export": "Eksport", "Export subscriptions as OPML": "Eksportuj subskrybcje jako OPML", "Export subscriptions as OPML (for NewPipe & FreeTube)": "Eksportuj subskrybcje jako OPML (dla NewPipe i FreeTube)", - "Export data as JSON": "Eksportuj dane jako JSON", + "Export data as JSON": "Eksportuj dane Invidious jako JSON", "Delete account?": "Usunąć konto?", "History": "Historia", "An alternative front-end to YouTube": "Alternatywny front-end dla YouTube", @@ -66,7 +66,7 @@ "preferences_related_videos_label": "Pokaż powiązane filmy? ", "preferences_annotations_label": "Domyślnie pokazuj adnotacje: ", "preferences_extend_desc_label": "Automatycznie rozwijaj opisy filmów: ", - "preferences_vr_mode_label": "Interaktywne filmy 360 stopni: ", + "preferences_vr_mode_label": "Interaktywne filmy 360 stopni (wymaga WebGL): ", "preferences_category_visual": "Preferencje Wizualne", "preferences_player_style_label": "Styl odtwarzacza: ", "Dark mode: ": "Ciemny motyw: ", @@ -446,12 +446,35 @@ "Video unavailable": "Film niedostępny", "preferences_save_player_pos_label": "Zapisz pozycję odtwarzania: ", "preferences_region_label": "Region zawartości: ", - "Released under the AGPLv3 on Github.": "Wydane na licencji AGPLv3 na Github'ie.", + "Released under the AGPLv3 on Github.": "Wydany na licencji AGPLv3 na Github.", "short": "Krótkie (< 4 minutes)", "long": "Długie (> 20 minutes)", "footer_documentation": "Dokumentacja", "footer_source_code": "Kod źródłowy", "footer_modfied_source_code": "Zmodyfikowany Kod źródłowy", "footer_original_source_code": "Oryginalny kod źródłowy", - "adminprefs_modified_source_code_url_label": "Adres URL do repozytorium z zmodyfikowanym kodem źródłowym" + "adminprefs_modified_source_code_url_label": "Adres URL do repozytorium z zmodyfikowanym kodem źródłowym", + "English (United Kingdom)": "angielski (Wielka Brytania)", + "English (United States)": "angielski (Stany Zjednoczone)", + "Cantonese (Hong Kong)": "kantoński (Hong Kong)", + "Chinese": "chiński", + "Chinese (China)": "chiński (Chiny)", + "Chinese (Hong Kong)": "chiński (Hong Kong)", + "Chinese (Taiwan)": "chiński (Tajwan)", + "Dutch (auto-generated)": "niderlandzki (wygenerowany automatycznie)", + "French (auto-generated)": "francuski (wygenerowany automatycznie)", + "German (auto-generated)": "niemiecki (wygenerowany automatycznie)", + "Indonesian (auto-generated)": "indonezyjski (wygenerowany automatycznie)", + "Interlingue": "interlingue", + "Italian (auto-generated)": "włoski (wygenerowany automatycznie)", + "Korean (auto-generated)": "koreański (wygenerowany automatycznie)", + "Spanish (auto-generated)": "hiszpański (wygenerowany automatycznie)", + "Spanish (Mexico)": "hiszpański (Meksyk)", + "Spanish (Spain)": "hiszpański (Hiszpania)", + "Turkish (auto-generated)": "turecki (wygenerowany automatycznie)", + "Vietnamese (auto-generated)": "wietnamski (wygenerowany automatycznie)", + "Japanese (auto-generated)": "japoński (wygenerowany automatycznie)", + "Russian (auto-generated)": "rosyjski (wygenerowany automatycznie)", + "Portuguese (auto-generated)": "portugalski (wygenerowany automatycznie)", + "Portuguese (Brazil)": "portugalski (Brazylia)" } diff --git a/locales/tr.json b/locales/tr.json index 65648fd7..094728fa 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -460,5 +460,6 @@ "German (auto-generated)": "Almanca (otomatik oluşturuldu)", "Portuguese (auto-generated)": "Portekizce (otomatik oluşturuldu)", "Spanish (Spain)": "İspanyolca (İspanya)", - "Vietnamese (auto-generated)": "Vietnamca (otomatik oluşturuldu)" + "Vietnamese (auto-generated)": "Vietnamca (otomatik oluşturuldu)", + "preferences_watch_history_label": "İzleme geçmişini etkinleştir: " } diff --git a/src/invidious.cr b/src/invidious.cr index d1c3ac83..1bdf3097 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -156,8 +156,8 @@ if CONFIG.popular_enabled Invidious::Jobs.register Invidious::Jobs::PullPopularVideosJob.new(PG_DB) end -connection_channel = Channel({Bool, Channel(PQ::Notification)}).new(32) -Invidious::Jobs.register Invidious::Jobs::NotificationJob.new(connection_channel, CONFIG.database_url) +CONNECTION_CHANNEL = Channel({Bool, Channel(PQ::Notification)}).new(32) +Invidious::Jobs.register Invidious::Jobs::NotificationJob.new(CONNECTION_CHANNEL, CONFIG.database_url) Invidious::Jobs.start_all @@ -327,6 +327,9 @@ end Invidious::Routing.get "/channel/:ucid/playlists", Invidious::Routes::Channels, :playlists Invidious::Routing.get "/channel/:ucid/community", Invidious::Routes::Channels, :community Invidious::Routing.get "/channel/:ucid/about", Invidious::Routes::Channels, :about + Invidious::Routing.get "/channel/:ucid/live", Invidious::Routes::Channels, :live + Invidious::Routing.get "/user/:user/live", Invidious::Routes::Channels, :live + Invidious::Routing.get "/c/:user/live", Invidious::Routes::Channels, :live ["", "/videos", "/playlists", "/community", "/about"].each do |path| # /c/LinusTechTips @@ -365,6 +368,7 @@ end Invidious::Routing.post "/playlist_ajax", Invidious::Routes::Playlists, :playlist_ajax Invidious::Routing.get "/playlist", Invidious::Routes::Playlists, :show Invidious::Routing.get "/mix", Invidious::Routes::Playlists, :mix + Invidious::Routing.get "/watch_videos", Invidious::Routes::Playlists, :watch_videos Invidious::Routing.get "/opensearch.xml", Invidious::Routes::Search, :opensearch Invidious::Routing.get "/results", Invidious::Routes::Search, :results @@ -411,85 +415,6 @@ define_v1_api_routes() define_api_manifest_routes() define_video_playback_routes() -# Channels - -{"/channel/:ucid/live", "/user/:user/live", "/c/:user/live"}.each do |route| - get route do |env| - locale = env.get("preferences").as(Preferences).locale - - # Appears to be a bug in routing, having several routes configured - # as `/a/:a`, `/b/:a`, `/c/:a` results in 404 - value = env.request.resource.split("/")[2] - body = "" - {"channel", "user", "c"}.each do |type| - response = YT_POOL.client &.get("/#{type}/#{value}/live?disable_polymer=1") - if response.status_code == 200 - body = response.body - end - end - - video_id = body.match(/'VIDEO_ID': "(?<id>[a-zA-Z0-9_-]{11})"/).try &.["id"]? - if video_id - params = [] of String - env.params.query.each do |k, v| - params << "#{k}=#{v}" - end - params = params.join("&") - - url = "/watch?v=#{video_id}" - if !params.empty? - url += "&#{params}" - end - - env.redirect url - else - env.redirect "/channel/#{value}" - end - end -end - -# Authenticated endpoints - -# The notification APIs can't be extracted yet -# due to the requirement of the `connection_channel` -# used by the `NotificationJob` - -get "/api/v1/auth/notifications" do |env| - env.response.content_type = "text/event-stream" - - topics = env.params.query["topics"]?.try &.split(",").uniq.first(1000) - topics ||= [] of String - - create_notification_stream(env, topics, connection_channel) -end - -post "/api/v1/auth/notifications" do |env| - env.response.content_type = "text/event-stream" - - topics = env.params.body["topics"]?.try &.split(",").uniq.first(1000) - topics ||= [] of String - - create_notification_stream(env, topics, connection_channel) -end - -get "/Captcha" do |env| - headers = HTTP::Headers{":authority" => "accounts.google.com"} - response = YT_POOL.client &.get(env.request.resource, headers) - env.response.headers["Content-Type"] = response.headers["Content-Type"] - response.body -end - -# Undocumented, creates anonymous playlist with specified 'video_ids', max 50 videos -get "/watch_videos" do |env| - response = YT_POOL.client &.get(env.request.resource) - if url = response.headers["Location"]? - url = URI.parse(url).request_target - next env.redirect url - end - - env.response.status_code = response.status_code -end - error 404 do |env| if md = env.request.path.match(/^\/(?<id>([a-zA-Z0-9_-]{11})|(\w+))$/) item = md["id"] diff --git a/src/invidious/config.cr b/src/invidious/config.cr index 72e145da..280de702 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -23,6 +23,7 @@ struct ConfigPreferences property listen : Bool = false property local : Bool = false property locale : String = "en-US" + property watch_history : Bool = true property max_results : Int32 = 40 property notifications_only : Bool = false property player_style : String = "invidious" diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index c27853ca..b559a01a 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -397,4 +397,14 @@ module Invidious::Routes::API::V1::Authenticated env.response.status_code = 204 end + + def self.notifications(env) + env.response.content_type = "text/event-stream" + + raw_topics = env.params.body["topics"]? || env.params.query["topics"]? + topics = raw_topics.try &.split(",").uniq.first(1000) + topics ||= [] of String + + create_notification_stream(env, topics, CONNECTION_CHANNEL) + end end diff --git a/src/invidious/routes/api/v1/videos.cr b/src/invidious/routes/api/v1/videos.cr index 8bca6930..a9f891f5 100644 --- a/src/invidious/routes/api/v1/videos.cr +++ b/src/invidious/routes/api/v1/videos.cr @@ -140,7 +140,7 @@ module Invidious::Routes::API::V1::Videos # # See: https://github.com/iv-org/invidious/issues/2391 webvtt = YT_POOL.client &.get("#{url}&format=vtt").body - .gsub(/([0-9:.]+ --> [0-9:.]+).+/, "\\1") + .gsub(/([0-9:.]{12} --> [0-9:.]{12}).+/, "\\1") end if title = env.params.query["title"]? diff --git a/src/invidious/routes/channels.cr b/src/invidious/routes/channels.cr index 6cb1e1f7..cd2e3323 100644 --- a/src/invidious/routes/channels.cr +++ b/src/invidious/routes/channels.cr @@ -147,6 +147,39 @@ module Invidious::Routes::Channels end end + def self.live(env) + locale = env.get("preferences").as(Preferences).locale + + # Appears to be a bug in routing, having several routes configured + # as `/a/:a`, `/b/:a`, `/c/:a` results in 404 + value = env.request.resource.split("/")[2] + body = "" + {"channel", "user", "c"}.each do |type| + response = YT_POOL.client &.get("/#{type}/#{value}/live?disable_polymer=1") + if response.status_code == 200 + body = response.body + end + end + + video_id = body.match(/'VIDEO_ID': "(?<id>[a-zA-Z0-9_-]{11})"/).try &.["id"]? + if video_id + params = [] of String + env.params.query.each do |k, v| + params << "#{k}=#{v}" + end + params = params.join("&") + + url = "/watch?v=#{video_id}" + if !params.empty? + url += "&#{params}" + end + + env.redirect url + else + env.redirect "/channel/#{value}" + end + end + private def self.fetch_basic_information(env) locale = env.get("preferences").as(Preferences).locale diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr index 65b337d1..99fc13a2 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -481,4 +481,11 @@ module Invidious::Routes::Login env.redirect referer end + + def self.captcha(env) + headers = HTTP::Headers{":authority" => "accounts.google.com"} + response = YT_POOL.client &.get(env.request.resource, headers) + env.response.headers["Content-Type"] = response.headers["Content-Type"] + response.body + end end diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr index 1ed29e79..dbeb4f97 100644 --- a/src/invidious/routes/playlists.cr +++ b/src/invidious/routes/playlists.cr @@ -443,4 +443,15 @@ module Invidious::Routes::Playlists templated "mix" end + + # Undocumented, creates anonymous playlist with specified 'video_ids', max 50 videos + def self.watch_videos(env) + response = YT_POOL.client &.get(env.request.resource) + if url = response.headers["Location"]? + url = URI.parse(url).request_target + return env.redirect url + end + + env.response.status_code = response.status_code + end end diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index 68d61fd1..570cba69 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -47,6 +47,10 @@ module Invidious::Routes::PreferencesRoute local ||= "off" local = local == "on" + watch_history = env.params.body["watch_history"]?.try &.as(String) + watch_history ||= "off" + watch_history = watch_history == "on" + speed = env.params.body["speed"]?.try &.as(String).to_f32? speed ||= CONFIG.default_user_preferences.speed @@ -149,6 +153,7 @@ module Invidious::Routes::PreferencesRoute latest_only: latest_only, listen: listen, local: local, + watch_history: watch_history, locale: locale, max_results: max_results, notifications_only: notifications_only, diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index 94148bc0..867ffa6a 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -75,7 +75,7 @@ module Invidious::Routes::Watch end env.params.query.delete_all("iv_load_policy") - if watched && !watched.includes? id + if watched && preferences.watch_history && !watched.includes? id Invidious::Database::Users.mark_watched(user.as(User), id) end diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 5efe1bd8..bd72c577 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -15,6 +15,7 @@ macro define_user_routes Invidious::Routing.get "/login", Invidious::Routes::Login, :login_page Invidious::Routing.post "/login", Invidious::Routes::Login, :login Invidious::Routing.post "/signout", Invidious::Routes::Login, :signout + Invidious::Routing.get "/Captcha", Invidious::Routes::Login, :captcha # User preferences Invidious::Routing.get "/preferences", Invidious::Routes::PreferencesRoute, :show @@ -95,6 +96,9 @@ macro define_v1_api_routes Invidious::Routing.post "/api/v1/auth/tokens/register", {{namespace}}::Authenticated, :register_token Invidious::Routing.post "/api/v1/auth/tokens/unregister", {{namespace}}::Authenticated, :unregister_token + Invidious::Routing.get "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications + Invidious::Routing.post "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications + # Misc Invidious::Routing.get "/api/v1/stats", {{namespace}}::Misc, :stats Invidious::Routing.get "/api/v1/playlists/:plid", {{namespace}}::Misc, :get_playlist diff --git a/src/invidious/user/preferences.cr b/src/invidious/user/preferences.cr index bf7ea401..8ecbe7a0 100644 --- a/src/invidious/user/preferences.cr +++ b/src/invidious/user/preferences.cr @@ -23,6 +23,7 @@ struct Preferences property latest_only : Bool = CONFIG.default_user_preferences.latest_only property listen : Bool = CONFIG.default_user_preferences.listen property local : Bool = CONFIG.default_user_preferences.local + property watch_history : Bool = CONFIG.default_user_preferences.watch_history property vr_mode : Bool = CONFIG.default_user_preferences.vr_mode property show_nick : Bool = CONFIG.default_user_preferences.show_nick diff --git a/src/invidious/views/user/preferences.ecr b/src/invidious/views/user/preferences.ecr index 3606d140..dbb5e9db 100644 --- a/src/invidious/views/user/preferences.ecr +++ b/src/invidious/views/user/preferences.ecr @@ -207,6 +207,11 @@ <legend><%= translate(locale, "preferences_category_subscription") %></legend> <div class="pure-control-group"> + <label for="watch_history"><%= translate(locale, "preferences_watch_history_label") %></label> + <input name="watch_history" id="watch_history" type="checkbox" <% if preferences.watch_history %>checked<% end %>> + </div> + + <div class="pure-control-group"> <label for="annotations_subscribed"><%= translate(locale, "preferences_annotations_subscribed_label") %></label> <input name="annotations_subscribed" id="annotations_subscribed" type="checkbox" <% if preferences.annotations_subscribed %>checked<% end %>> </div> |
