summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile44
-rw-r--r--config/config.example.yml10
-rw-r--r--docker-compose.yml57
-rw-r--r--locales/en-US.json1
-rw-r--r--locales/es.json3
-rw-r--r--locales/is.json3
-rw-r--r--locales/pl.json35
-rw-r--r--locales/tr.json3
-rw-r--r--src/invidious.cr87
-rw-r--r--src/invidious/config.cr1
-rw-r--r--src/invidious/routes/api/v1/authenticated.cr10
-rw-r--r--src/invidious/routes/api/v1/videos.cr2
-rw-r--r--src/invidious/routes/channels.cr33
-rw-r--r--src/invidious/routes/login.cr7
-rw-r--r--src/invidious/routes/playlists.cr11
-rw-r--r--src/invidious/routes/preferences.cr5
-rw-r--r--src/invidious/routes/watch.cr2
-rw-r--r--src/invidious/routing.cr4
-rw-r--r--src/invidious/user/preferences.cr1
-rw-r--r--src/invidious/views/user/preferences.ecr5
20 files changed, 186 insertions, 138 deletions
diff --git a/Makefile b/Makefile
index 7f56d722..7d09f39c 100644
--- a/Makefile
+++ b/Makefile
@@ -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>