From 8aff1d04094b5636714b580980fe30fb8139d7f9 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Mon, 5 Jun 2023 00:16:23 -0700 Subject: [PATCH 01/45] Create compilations file --- src/invidious/channels/compilations.cr | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/invidious/channels/compilations.cr diff --git a/src/invidious/channels/compilations.cr b/src/invidious/channels/compilations.cr new file mode 100644 index 00000000..e69de29b From 5fb47c5e9e76294312dd326a7861ae49eeb0e38d Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 6 Jun 2023 23:54:34 -0700 Subject: [PATCH 02/45] add Compilation symbols --- config/config.example.yml | 6 +++--- locales/en-US.json | 1 + spec/spec_helper.cr | 1 + src/invidious.cr | 2 +- src/invidious/routes/feeds.cr | 4 ++++ src/invidious/routes/misc.cr | 6 ++++++ src/invidious/routes/preferences.cr | 2 +- src/invidious/routing.cr | 1 + .../{channels/compilations.cr => views/compilation.ecr} | 0 src/invidious/views/components/feed_menu.ecr | 2 +- src/invidious/views/feeds/compilations.ecr | 4 ++++ src/invidious/views/user/preferences.ecr | 2 +- 12 files changed, 24 insertions(+), 7 deletions(-) rename src/invidious/{channels/compilations.cr => views/compilation.ecr} (100%) create mode 100644 src/invidious/views/feeds/compilations.ecr diff --git a/config/config.example.yml b/config/config.example.yml index e925a5e3..4c9f0cca 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -627,11 +627,11 @@ default_user_preferences: ## ## Accepted values: A list of strings ## Each entry can be one of: "Popular", "Trending", - ## "Subscriptions", "Playlists" + ## "Subscriptions", "Playlists", "Compilations" ## - ## Default: ["Popular", "Trending", "Subscriptions", "Playlists"] (show all feeds) + ## Default: ["Popular", "Trending", "Subscriptions", "Playlists","Compilations"] (show all feeds) ## - #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists"] + #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists","Compilations"] ## ## Default feed to display on the home page. diff --git a/locales/en-US.json b/locales/en-US.json index 06d095dc..a65e2119 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -413,6 +413,7 @@ "Audio mode": "Audio mode", "Video mode": "Video mode", "Playlists": "Playlists", + "Compilations": "Compilations", "search_filters_title": "Filters", "search_filters_date_label": "Upload date", "search_filters_date_option_none": "Any date", diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index b3060acf..2ce03e33 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -8,6 +8,7 @@ require "../src/invidious/channels/*" require "../src/invidious/videos/caption" require "../src/invidious/videos" require "../src/invidious/playlists" +require "../src/invidious/compilations" require "../src/invidious/search/ctoken" require "../src/invidious/trending" require "spectator" diff --git a/src/invidious.cr b/src/invidious.cr index e0bd0101..270e999a 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -121,7 +121,7 @@ Kemal.config.extra_options do |parser| puts SOFTWARE.to_pretty_json exit end - parser.on("--migrate", "Run any migrations (beta, use at your own risk!!") do + parser.on("--migrate", "Run any migrations (beta, use at your own risk!!)") do Invidious::Database::Migrator.new(PG_DB).migrate exit end diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index 40bca008..cc275dfe 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -5,6 +5,10 @@ module Invidious::Routes::Feeds env.redirect "/feed/playlists" end + def self.compilations(env) + templated "feeds/compilations" + end + def self.playlists(env) locale = env.get("preferences").as(Preferences).locale diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index d6bd9571..bd3245cc 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -23,6 +23,12 @@ module Invidious::Routes::Misc else env.redirect "/feed/popular" end + when "Compilations" + if user + env.redirect "/feed/compilations" + else + env.redirect "/feed/popular" + end else templated "search_homepage", navbar_search: false end diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index abe0f34e..6d410e87 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -99,7 +99,7 @@ module Invidious::Routes::PreferencesRoute default_home = env.params.body["default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home feed_menu = [] of String - 4.times do |index| + 5.times do |index| option = env.params.body["feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? feed_menu << option diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 9c43171c..a653c1a5 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -99,6 +99,7 @@ module Invidious::Routing get "/feed/popular", Routes::Feeds, :popular get "/feed/trending", Routes::Feeds, :trending get "/feed/subscriptions", Routes::Feeds, :subscriptions + get "/feed/compilations", Routes::Feeds, :compilations get "/feed/history", Routes::Feeds, :history # RSS Feeds diff --git a/src/invidious/channels/compilations.cr b/src/invidious/views/compilation.ecr similarity index 100% rename from src/invidious/channels/compilations.cr rename to src/invidious/views/compilation.ecr diff --git a/src/invidious/views/components/feed_menu.ecr b/src/invidious/views/components/feed_menu.ecr index 3dbeaf37..180a263f 100644 --- a/src/invidious/views/components/feed_menu.ecr +++ b/src/invidious/views/components/feed_menu.ecr @@ -1,7 +1,7 @@ <% if env.get?("user") %> - <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists"} %> + <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists","Compilations"} %> <% else %> <% feed_options = {"", "Popular", "Trending"} %> <% end %> From d0a3c994f4885a38a6273151b81dfa2aeb084b12 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Wed, 7 Jun 2023 01:11:15 -0700 Subject: [PATCH 03/45] Add Compilation symbols until "Compilations" appears in feeds menu --- .gitignore | 1 + config/config.example.yml | 4 ++-- src/invidious/routes/compilations.cr | 2 ++ src/invidious/routes/feeds.cr | 2 ++ src/invidious/routes/preferences.cr | 2 +- src/invidious/views/compilation.ecr | 6 ++++++ src/invidious/views/feeds/compilations.ecr | 2 ++ 7 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/invidious/routes/compilations.cr diff --git a/.gitignore b/.gitignore index 7a26e1a6..2a49e68d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /invidious /sentry /config/config.yml +.DS_Store \ No newline at end of file diff --git a/config/config.example.yml b/config/config.example.yml index 4c9f0cca..5f41a4f7 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -629,9 +629,9 @@ default_user_preferences: ## Each entry can be one of: "Popular", "Trending", ## "Subscriptions", "Playlists", "Compilations" ## - ## Default: ["Popular", "Trending", "Subscriptions", "Playlists","Compilations"] (show all feeds) + ## Default: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] (show all feeds) ## - #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists","Compilations"] + feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] ## ## Default feed to display on the home page. diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr new file mode 100644 index 00000000..600d34de --- /dev/null +++ b/src/invidious/routes/compilations.cr @@ -0,0 +1,2 @@ +module Invidious::Routes::Compilations +end \ No newline at end of file diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index cc275dfe..affd165d 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -6,6 +6,8 @@ module Invidious::Routes::Feeds end def self.compilations(env) + locale = env.get("preferences").as(Preferences).locale + templated "feeds/compilations" end diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index 6d410e87..eea93858 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -186,7 +186,7 @@ module Invidious::Routes::PreferencesRoute CONFIG.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home admin_feed_menu = [] of String - 4.times do |index| + 5.times do |index| option = env.params.body["admin_feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? admin_feed_menu << option diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index e69de29b..0dff7417 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -0,0 +1,6 @@ +<% title = HTML.escape(compilation.title) %> +<% author = HTML.escape(compilation.author) %> + +<% content_for "header" do %> +<%= title %> - Invidious +<% end %> \ No newline at end of file diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr index a55e1e5a..de605f27 100644 --- a/src/invidious/views/feeds/compilations.ecr +++ b/src/invidious/views/feeds/compilations.ecr @@ -2,3 +2,5 @@ <%= translate(locale, "Compilations") %> - Invidious <% end %> +<%= rendered "components/feed_menu" %> + From 24f55a787626259e27d49b114606235ba208ea0e Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Wed, 7 Jun 2023 02:01:59 -0700 Subject: [PATCH 04/45] Add backend Compilation symbols --- config/config.example.yml | 2 +- config/sql/compilations.sql | 29 +++ src/invidious/compilations.cr | 14 ++ src/invidious/database/compilations.cr | 261 +++++++++++++++++++++++++ 4 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 config/sql/compilations.sql create mode 100644 src/invidious/compilations.cr create mode 100644 src/invidious/database/compilations.cr diff --git a/config/config.example.yml b/config/config.example.yml index 5f41a4f7..de051bb0 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -631,7 +631,7 @@ default_user_preferences: ## ## Default: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] (show all feeds) ## - feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] + #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] ## ## Default feed to display on the home page. diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql new file mode 100644 index 00000000..ccf04c30 --- /dev/null +++ b/config/sql/compilations.sql @@ -0,0 +1,29 @@ +-- Type: public.privacy + +-- DROP TYPE public.privacy; + +CREATE TYPE public.privacy AS ENUM +( + 'Public', + 'Unlisted', + 'Private' +); + +-- Table: public.playlists + +-- DROP TABLE public.playlists; + +CREATE TABLE IF NOT EXISTS public.playlists +( + title text, + id text primary key, + author text, + description text, + video_count integer, + created timestamptz, + updated timestamptz, + privacy privacy, + index int8[] +); + +GRANT ALL ON public.playlists TO current_user; \ No newline at end of file diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr new file mode 100644 index 00000000..e2b037b8 --- /dev/null +++ b/src/invidious/compilations.cr @@ -0,0 +1,14 @@ +struct Compilation + include DB::Serializable + + property title : String + property id : String + property author : String + property ucid : String + property length_seconds : Int32 + property published : Time + property plid : String + property index : Int64 + property live_now : Bool + +end \ No newline at end of file diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr new file mode 100644 index 00000000..c6754a1e --- /dev/null +++ b/src/invidious/database/compilations.cr @@ -0,0 +1,261 @@ +require "./base.cr" + +# +# This module contains functions related to the "playlists" table. +# +module Invidious::Database::Playlists + extend self + + # ------------------- + # Insert / delete + # ------------------- + + def insert(playlist : InvidiousPlaylist) + playlist_array = playlist.to_a + + request = <<-SQL + INSERT INTO playlists + VALUES (#{arg_array(playlist_array)}) + SQL + + PG_DB.exec(request, args: playlist_array) + end + + # deletes the given playlist and connected playlist videos + def delete(id : String) + PlaylistVideos.delete_by_playlist(id) + request = <<-SQL + DELETE FROM playlists * + WHERE id = $1 + SQL + + PG_DB.exec(request, id) + end + + # ------------------- + # Update + # ------------------- + + def update(id : String, title : String, privacy, description, updated) + request = <<-SQL + UPDATE playlists + SET title = $1, privacy = $2, description = $3, updated = $4 + WHERE id = $5 + SQL + + PG_DB.exec(request, title, privacy, description, updated, id) + end + + def update_description(id : String, description) + request = <<-SQL + UPDATE playlists + SET description = $1 + WHERE id = $2 + SQL + + PG_DB.exec(request, description, id) + end + + def update_subscription_time(id : String) + request = <<-SQL + UPDATE playlists + SET subscribed = now() + WHERE id = $1 + SQL + + PG_DB.exec(request, id) + end + + def update_video_added(id : String, index : String | Int64) + request = <<-SQL + UPDATE playlists + SET index = array_append(index, $1), + video_count = cardinality(index) + 1, + updated = now() + WHERE id = $2 + SQL + + PG_DB.exec(request, index, id) + end + + def update_video_removed(id : String, index : String | Int64) + request = <<-SQL + UPDATE playlists + SET index = array_remove(index, $1), + video_count = cardinality(index) - 1, + updated = now() + WHERE id = $2 + SQL + + PG_DB.exec(request, index, id) + end + + # ------------------- + # Salect + # ------------------- + + def select(*, id : String) : InvidiousPlaylist? + request = <<-SQL + SELECT * FROM playlists + WHERE id = $1 + SQL + + return PG_DB.query_one?(request, id, as: InvidiousPlaylist) + end + + def select_all(*, author : String) : Array(InvidiousPlaylist) + request = <<-SQL + SELECT * FROM playlists + WHERE author = $1 + SQL + + return PG_DB.query_all(request, author, as: InvidiousPlaylist) + end + + # ------------------- + # Salect (filtered) + # ------------------- + + def select_like_iv(email : String) : Array(InvidiousPlaylist) + request = <<-SQL + SELECT * FROM playlists + WHERE author = $1 AND id LIKE 'IV%' + ORDER BY created + SQL + + PG_DB.query_all(request, email, as: InvidiousPlaylist) + end + + def select_not_like_iv(email : String) : Array(InvidiousPlaylist) + request = <<-SQL + SELECT * FROM playlists + WHERE author = $1 AND id NOT LIKE 'IV%' + ORDER BY created + SQL + + PG_DB.query_all(request, email, as: InvidiousPlaylist) + end + + def select_user_created_playlists(email : String) : Array({String, String}) + request = <<-SQL + SELECT id,title FROM playlists + WHERE author = $1 AND id LIKE 'IV%' + SQL + + PG_DB.query_all(request, email, as: {String, String}) + end + + # ------------------- + # Misc checks + # ------------------- + + # Check if given playlist ID exists + def exists?(id : String) : Bool + request = <<-SQL + SELECT id FROM playlists + WHERE id = $1 + SQL + + return PG_DB.query_one?(request, id, as: String).nil? + end + + # Count how many playlist a user has created. + def count_owned_by(author : String) : Int64 + request = <<-SQL + SELECT count(*) FROM playlists + WHERE author = $1 + SQL + + return PG_DB.query_one?(request, author, as: Int64) || 0_i64 + end +end + +# +# This module contains functions related to the "playlist_videos" table. +# +module Invidious::Database::PlaylistVideos + extend self + + private alias VideoIndex = Int64 | Array(Int64) + + # ------------------- + # Insert / Delete + # ------------------- + + def insert(video : PlaylistVideo) + video_array = video.to_a + + request = <<-SQL + INSERT INTO playlist_videos + VALUES (#{arg_array(video_array)}) + SQL + + PG_DB.exec(request, args: video_array) + end + + def delete(index) + request = <<-SQL + DELETE FROM playlist_videos * + WHERE index = $1 + SQL + + PG_DB.exec(request, index) + end + + def delete_by_playlist(plid : String) + request = <<-SQL + DELETE FROM playlist_videos * + WHERE plid = $1 + SQL + + PG_DB.exec(request, plid) + end + + # ------------------- + # Salect + # ------------------- + + def select(plid : String, index : VideoIndex, offset, limit = 100) : Array(PlaylistVideo) + request = <<-SQL + SELECT * FROM playlist_videos + WHERE plid = $1 + ORDER BY array_position($2, index) + LIMIT $3 + OFFSET $4 + SQL + + return PG_DB.query_all(request, plid, index, limit, offset, as: PlaylistVideo) + end + + def select_index(plid : String, vid : String) : Int64? + request = <<-SQL + SELECT index FROM playlist_videos + WHERE plid = $1 AND id = $2 + LIMIT 1 + SQL + + return PG_DB.query_one?(request, plid, vid, as: Int64) + end + + def select_one_id(plid : String, index : VideoIndex) : String? + request = <<-SQL + SELECT id FROM playlist_videos + WHERE plid = $1 + ORDER BY array_position($2, index) + LIMIT 1 + SQL + + return PG_DB.query_one?(request, plid, index, as: String) + end + + def select_ids(plid : String, index : VideoIndex, limit = 500) : Array(String) + request = <<-SQL + SELECT id FROM playlist_videos + WHERE plid = $1 + ORDER BY array_position($2, index) + LIMIT $3 + SQL + + return PG_DB.query_all(request, plid, index, limit, as: String) + end +end From bef234fd747899fa13cc33fc25e0d7458f36b97f Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Wed, 14 Jun 2023 22:53:02 -0700 Subject: [PATCH 05/45] Add compilations to DB --- config/sql/compilations.sql | 17 +++-------------- docker/init-invidious-db.sh | 2 ++ src/invidious/database/compilations.cr | 8 +++----- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql index ccf04c30..4076e1b8 100644 --- a/config/sql/compilations.sql +++ b/config/sql/compilations.sql @@ -1,19 +1,8 @@ --- Type: public.privacy +-- Table: public.compilations --- DROP TYPE public.privacy; +-- DROP TABLE public.compilations; -CREATE TYPE public.privacy AS ENUM -( - 'Public', - 'Unlisted', - 'Private' -); - --- Table: public.playlists - --- DROP TABLE public.playlists; - -CREATE TABLE IF NOT EXISTS public.playlists +CREATE TABLE IF NOT EXISTS public.compilations ( title text, id text primary key, diff --git a/docker/init-invidious-db.sh b/docker/init-invidious-db.sh index 22b4cc5f..f7fe3e7f 100755 --- a/docker/init-invidious-db.sh +++ b/docker/init-invidious-db.sh @@ -10,3 +10,5 @@ psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/nonces.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/annotations.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlists.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlist_videos.sql +psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilations.sql +psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilation_videos.sql diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index c6754a1e..80672abf 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -3,7 +3,7 @@ require "./base.cr" # # This module contains functions related to the "playlists" table. # -module Invidious::Database::Playlists +module Invidious::Database::Compilations extend self # ------------------- @@ -173,16 +173,14 @@ end # # This module contains functions related to the "playlist_videos" table. # -module Invidious::Database::PlaylistVideos +module Invidious::Database::CompilationVideos extend self - private alias VideoIndex = Int64 | Array(Int64) - # ------------------- # Insert / Delete # ------------------- - def insert(video : PlaylistVideo) + def insert(video : CompilationVideo) video_array = video.to_a request = <<-SQL From 6b984c6677da0782dd0e4e52bd004a563c6c0326 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 15 Jun 2023 03:25:36 -0700 Subject: [PATCH 06/45] Remove files that were prematurely added and add backend Compilation files --- config/config.example.yml | 6 +- config/sql/compilation_videos.sql | 20 ++++ config/sql/compilations.sql | 12 +- docker/init-invidious-db.sh | 2 +- locales/en-US.json | 1 - spec/spec_helper.cr | 1 - src/invidious/compilations.cr | 14 --- src/invidious/database/compilations.cr | 118 +++++++++---------- src/invidious/database/playlists.cr | 2 +- src/invidious/routes/compilations.cr | 2 - src/invidious/routes/feeds.cr | 20 ++++ src/invidious/routes/misc.cr | 6 - src/invidious/routes/preferences.cr | 4 +- src/invidious/views/compilation.ecr | 6 - src/invidious/views/components/feed_menu.ecr | 4 +- src/invidious/views/feeds/compilations.ecr | 6 - src/invidious/views/user/preferences.ecr | 2 +- 17 files changed, 115 insertions(+), 111 deletions(-) create mode 100644 config/sql/compilation_videos.sql delete mode 100644 src/invidious/compilations.cr delete mode 100644 src/invidious/routes/compilations.cr delete mode 100644 src/invidious/views/compilation.ecr delete mode 100644 src/invidious/views/feeds/compilations.ecr diff --git a/config/config.example.yml b/config/config.example.yml index de051bb0..e925a5e3 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -627,11 +627,11 @@ default_user_preferences: ## ## Accepted values: A list of strings ## Each entry can be one of: "Popular", "Trending", - ## "Subscriptions", "Playlists", "Compilations" + ## "Subscriptions", "Playlists" ## - ## Default: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] (show all feeds) + ## Default: ["Popular", "Trending", "Subscriptions", "Playlists"] (show all feeds) ## - #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] + #feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists"] ## ## Default feed to display on the home page. diff --git a/config/sql/compilation_videos.sql b/config/sql/compilation_videos.sql new file mode 100644 index 00000000..91eb886c --- /dev/null +++ b/config/sql/compilation_videos.sql @@ -0,0 +1,20 @@ +-- Table: public.compilation_videos + +-- DROP TABLE public.compilation_videos; + +CREATE TABLE IF NOT EXISTS public.compilation_videos +( + title text, + id text, + author text, + ucid text, + length_seconds integer, + starting_timestamp_seconds integer, + ending_timestamp_seconds integer, + published timestamptz, + compid text references compilations(id), + index int8, + PRIMARY KEY (index,compid) +); + +GRANT ALL ON TABLE public.compilation_videos TO current_user; diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql index 4076e1b8..d1ee949b 100644 --- a/config/sql/compilations.sql +++ b/config/sql/compilations.sql @@ -1,3 +1,13 @@ +-- Type: public.privacy + +-- DROP TYPE public.privacy; + +CREATE TYPE public.privacy AS ENUM +( + 'Unlisted', + 'Private' +); + -- Table: public.compilations -- DROP TABLE public.compilations; @@ -15,4 +25,4 @@ CREATE TABLE IF NOT EXISTS public.compilations index int8[] ); -GRANT ALL ON public.playlists TO current_user; \ No newline at end of file +GRANT ALL ON public.compilations TO current_user; diff --git a/docker/init-invidious-db.sh b/docker/init-invidious-db.sh index f7fe3e7f..62df4229 100755 --- a/docker/init-invidious-db.sh +++ b/docker/init-invidious-db.sh @@ -11,4 +11,4 @@ psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/annotation psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlists.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlist_videos.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilations.sql -psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilation_videos.sql +psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilation_videos.sql \ No newline at end of file diff --git a/locales/en-US.json b/locales/en-US.json index a65e2119..06d095dc 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -413,7 +413,6 @@ "Audio mode": "Audio mode", "Video mode": "Video mode", "Playlists": "Playlists", - "Compilations": "Compilations", "search_filters_title": "Filters", "search_filters_date_label": "Upload date", "search_filters_date_option_none": "Any date", diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 2ce03e33..b3060acf 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -8,7 +8,6 @@ require "../src/invidious/channels/*" require "../src/invidious/videos/caption" require "../src/invidious/videos" require "../src/invidious/playlists" -require "../src/invidious/compilations" require "../src/invidious/search/ctoken" require "../src/invidious/trending" require "spectator" diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr deleted file mode 100644 index e2b037b8..00000000 --- a/src/invidious/compilations.cr +++ /dev/null @@ -1,14 +0,0 @@ -struct Compilation - include DB::Serializable - - property title : String - property id : String - property author : String - property ucid : String - property length_seconds : Int32 - property published : Time - property plid : String - property index : Int64 - property live_now : Bool - -end \ No newline at end of file diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 80672abf..69281a55 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -1,7 +1,7 @@ require "./base.cr" # -# This module contains functions related to the "playlists" table. +# This module contains functions related to the "compilations" table. # module Invidious::Database::Compilations extend self @@ -10,22 +10,22 @@ module Invidious::Database::Compilations # Insert / delete # ------------------- - def insert(playlist : InvidiousPlaylist) - playlist_array = playlist.to_a + def insert(compilation : InvidiousCompilation) + compilation_array = compilation.to_a request = <<-SQL - INSERT INTO playlists - VALUES (#{arg_array(playlist_array)}) + INSERT INTO compilations + VALUES (#{arg_array(compilation_array)}) SQL - PG_DB.exec(request, args: playlist_array) + PG_DB.exec(request, args: compilation_array) end - # deletes the given playlist and connected playlist videos + # deletes the given compilation and connected compilation videos def delete(id : String) - PlaylistVideos.delete_by_playlist(id) + CompilationVideos.delete_by_compilation(id) request = <<-SQL - DELETE FROM playlists * + DELETE FROM compilations * WHERE id = $1 SQL @@ -38,7 +38,7 @@ module Invidious::Database::Compilations def update(id : String, title : String, privacy, description, updated) request = <<-SQL - UPDATE playlists + UPDATE compilations SET title = $1, privacy = $2, description = $3, updated = $4 WHERE id = $5 SQL @@ -48,7 +48,7 @@ module Invidious::Database::Compilations def update_description(id : String, description) request = <<-SQL - UPDATE playlists + UPDATE compilations SET description = $1 WHERE id = $2 SQL @@ -56,19 +56,9 @@ module Invidious::Database::Compilations PG_DB.exec(request, description, id) end - def update_subscription_time(id : String) - request = <<-SQL - UPDATE playlists - SET subscribed = now() - WHERE id = $1 - SQL - - PG_DB.exec(request, id) - end - def update_video_added(id : String, index : String | Int64) request = <<-SQL - UPDATE playlists + UPDATE compilations SET index = array_append(index, $1), video_count = cardinality(index) + 1, updated = now() @@ -80,7 +70,7 @@ module Invidious::Database::Compilations def update_video_removed(id : String, index : String | Int64) request = <<-SQL - UPDATE playlists + UPDATE compilations SET index = array_remove(index, $1), video_count = cardinality(index) - 1, updated = now() @@ -94,51 +84,51 @@ module Invidious::Database::Compilations # Salect # ------------------- - def select(*, id : String) : InvidiousPlaylist? + def select(*, id : String) : InvidiousCompilation? request = <<-SQL - SELECT * FROM playlists + SELECT * FROM compilations WHERE id = $1 SQL - return PG_DB.query_one?(request, id, as: InvidiousPlaylist) + return PG_DB.query_one?(request, id, as: InvidiousCompilation) end - def select_all(*, author : String) : Array(InvidiousPlaylist) + def select_all(*, author : String) : Array(InvidiousCompilation) request = <<-SQL - SELECT * FROM playlists + SELECT * FROM compilations WHERE author = $1 SQL - return PG_DB.query_all(request, author, as: InvidiousPlaylist) + return PG_DB.query_all(request, author, as: InvidiousCompilation) end # ------------------- # Salect (filtered) # ------------------- - def select_like_iv(email : String) : Array(InvidiousPlaylist) + def select_like_iv(email : String) : Array(InvidiousCompilation) request = <<-SQL - SELECT * FROM playlists + SELECT * FROM compilation WHERE author = $1 AND id LIKE 'IV%' ORDER BY created SQL - PG_DB.query_all(request, email, as: InvidiousPlaylist) + PG_DB.query_all(request, email, as: InvidiousCompilation) end - def select_not_like_iv(email : String) : Array(InvidiousPlaylist) + def select_not_like_iv(email : String) : Array(InvidiousCompilation) request = <<-SQL - SELECT * FROM playlists + SELECT * FROM compilations WHERE author = $1 AND id NOT LIKE 'IV%' ORDER BY created SQL - PG_DB.query_all(request, email, as: InvidiousPlaylist) + PG_DB.query_all(request, email, as: InvidiousCompilation) end - def select_user_created_playlists(email : String) : Array({String, String}) + def select_user_created_compilations(email : String) : Array({String, String}) request = <<-SQL - SELECT id,title FROM playlists + SELECT id,title FROM compilations WHERE author = $1 AND id LIKE 'IV%' SQL @@ -149,20 +139,20 @@ module Invidious::Database::Compilations # Misc checks # ------------------- - # Check if given playlist ID exists + # Check if given compilation ID exists def exists?(id : String) : Bool request = <<-SQL - SELECT id FROM playlists + SELECT id FROM compilations WHERE id = $1 SQL return PG_DB.query_one?(request, id, as: String).nil? end - # Count how many playlist a user has created. + # Count how many compilations a user has created. def count_owned_by(author : String) : Int64 request = <<-SQL - SELECT count(*) FROM playlists + SELECT count(*) FROM compilations WHERE author = $1 SQL @@ -171,7 +161,7 @@ module Invidious::Database::Compilations end # -# This module contains functions related to the "playlist_videos" table. +# This module contains functions related to the "compilation_videos" table. # module Invidious::Database::CompilationVideos extend self @@ -184,7 +174,7 @@ module Invidious::Database::CompilationVideos video_array = video.to_a request = <<-SQL - INSERT INTO playlist_videos + INSERT INTO compilation_videos VALUES (#{arg_array(video_array)}) SQL @@ -193,67 +183,67 @@ module Invidious::Database::CompilationVideos def delete(index) request = <<-SQL - DELETE FROM playlist_videos * + DELETE FROM compilation_videos * WHERE index = $1 SQL PG_DB.exec(request, index) end - def delete_by_playlist(plid : String) + def delete_by_compilation(compid : String) request = <<-SQL - DELETE FROM playlist_videos * - WHERE plid = $1 + DELETE FROM compilation_videos * + WHERE compid = $1 SQL - PG_DB.exec(request, plid) + PG_DB.exec(request, compid) end # ------------------- # Salect # ------------------- - def select(plid : String, index : VideoIndex, offset, limit = 100) : Array(PlaylistVideo) + def select(compid : String, index : VideoIndex, offset, limit = 100) : Array(CompilationVideo) request = <<-SQL - SELECT * FROM playlist_videos - WHERE plid = $1 + SELECT * FROM compilation_videos + WHERE compid = $1 ORDER BY array_position($2, index) LIMIT $3 OFFSET $4 SQL - return PG_DB.query_all(request, plid, index, limit, offset, as: PlaylistVideo) + return PG_DB.query_all(request, compid, index, limit, offset, as: CompilationVideo) end - def select_index(plid : String, vid : String) : Int64? + def select_index(compid : String, vid : String) : Int64? request = <<-SQL - SELECT index FROM playlist_videos - WHERE plid = $1 AND id = $2 + SELECT index FROM compilation_videos + WHERE compid = $1 AND id = $2 LIMIT 1 SQL - return PG_DB.query_one?(request, plid, vid, as: Int64) + return PG_DB.query_one?(request, compid, vid, as: Int64) end - def select_one_id(plid : String, index : VideoIndex) : String? + def select_one_id(compid : String, index : VideoIndex) : String? request = <<-SQL - SELECT id FROM playlist_videos - WHERE plid = $1 + SELECT id FROM compilation_videos + WHERE compid = $1 ORDER BY array_position($2, index) LIMIT 1 SQL - return PG_DB.query_one?(request, plid, index, as: String) + return PG_DB.query_one?(request, compid, index, as: String) end - def select_ids(plid : String, index : VideoIndex, limit = 500) : Array(String) + def select_ids(compid : String, index : VideoIndex, limit = 500) : Array(String) request = <<-SQL - SELECT id FROM playlist_videos - WHERE plid = $1 + SELECT id FROM compilation_videos + WHERE compid = $1 ORDER BY array_position($2, index) LIMIT $3 SQL - return PG_DB.query_all(request, plid, index, limit, as: String) + return PG_DB.query_all(request, compid, index, limit, as: String) end end diff --git a/src/invidious/database/playlists.cr b/src/invidious/database/playlists.cr index c6754a1e..c961c16e 100644 --- a/src/invidious/database/playlists.cr +++ b/src/invidious/database/playlists.cr @@ -159,7 +159,7 @@ module Invidious::Database::Playlists return PG_DB.query_one?(request, id, as: String).nil? end - # Count how many playlist a user has created. + # Count how many playlists a user has created. def count_owned_by(author : String) : Int64 request = <<-SQL SELECT count(*) FROM playlists diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr deleted file mode 100644 index 600d34de..00000000 --- a/src/invidious/routes/compilations.cr +++ /dev/null @@ -1,2 +0,0 @@ -module Invidious::Routes::Compilations -end \ No newline at end of file diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index affd165d..fec94682 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -8,6 +8,26 @@ module Invidious::Routes::Feeds def self.compilations(env) locale = env.get("preferences").as(Preferences).locale + user = env.get? "user" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + + # TODO: make a single DB call and separate the items here? + items_created = Invidious::Database::Compilations.select_like_iv(user.email) + items_created.map! do |item| + item.author = "" + item + end + + items_saved = Invidious::Database::Compilations.select_not_like_iv(user.email) + items_saved.map! do |item| + item.author = "" + item + end + templated "feeds/compilations" end diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index bd3245cc..d6bd9571 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -23,12 +23,6 @@ module Invidious::Routes::Misc else env.redirect "/feed/popular" end - when "Compilations" - if user - env.redirect "/feed/compilations" - else - env.redirect "/feed/popular" - end else templated "search_homepage", navbar_search: false end diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index eea93858..abe0f34e 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -99,7 +99,7 @@ module Invidious::Routes::PreferencesRoute default_home = env.params.body["default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home feed_menu = [] of String - 5.times do |index| + 4.times do |index| option = env.params.body["feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? feed_menu << option @@ -186,7 +186,7 @@ module Invidious::Routes::PreferencesRoute CONFIG.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home admin_feed_menu = [] of String - 5.times do |index| + 4.times do |index| option = env.params.body["admin_feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? admin_feed_menu << option diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr deleted file mode 100644 index 0dff7417..00000000 --- a/src/invidious/views/compilation.ecr +++ /dev/null @@ -1,6 +0,0 @@ -<% title = HTML.escape(compilation.title) %> -<% author = HTML.escape(compilation.author) %> - -<% content_for "header" do %> -<%= title %> - Invidious -<% end %> \ No newline at end of file diff --git a/src/invidious/views/components/feed_menu.ecr b/src/invidious/views/components/feed_menu.ecr index 180a263f..3fb20086 100644 --- a/src/invidious/views/components/feed_menu.ecr +++ b/src/invidious/views/components/feed_menu.ecr @@ -1,11 +1,11 @@ + \ No newline at end of file diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr deleted file mode 100644 index de605f27..00000000 --- a/src/invidious/views/feeds/compilations.ecr +++ /dev/null @@ -1,6 +0,0 @@ -<% content_for "header" do %> -<%= translate(locale, "Compilations") %> - Invidious -<% end %> - -<%= rendered "components/feed_menu" %> - diff --git a/src/invidious/views/user/preferences.ecr b/src/invidious/views/user/preferences.ecr index 1f24bd4e..dfda1434 100644 --- a/src/invidious/views/user/preferences.ecr +++ b/src/invidious/views/user/preferences.ecr @@ -165,7 +165,7 @@ <% if env.get?("user") %> - <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists","Compilations"} %> + <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists"} %> <% else %> <% feed_options = {"", "Popular", "Trending"} %> <% end %> From 696ca4227414b3d3336d91b79f5ceae2f5cf9ceb Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 15 Jun 2023 04:19:06 -0700 Subject: [PATCH 07/45] Add structs and DB methods for Compilations --- src/invidious/compilations.cr | 454 +++++++++++++++++++++ src/invidious/database/compilations.cr | 2 +- src/invidious/views/feeds/compilations.ecr | 5 + 3 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 src/invidious/compilations.cr create mode 100644 src/invidious/views/feeds/compilations.ecr diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr new file mode 100644 index 00000000..b048fb84 --- /dev/null +++ b/src/invidious/compilations.cr @@ -0,0 +1,454 @@ +struct CompilationVideo + include DB::Serializable + + property title : String + property id : String + property author : String + property ucid : String + property length_seconds : Int32 + property starting_timestamp_seconds : Int32 + property ending_timestamp_seconds : Int32 + property published : Time + property compid : String + property index : Int64 + + def to_xml(xml : XML::Builder) + xml.element("entry") do + xml.element("id") { xml.text "yt:video:#{self.id}" } + xml.element("yt:videoId") { xml.text self.id } + xml.element("yt:channelId") { xml.text self.ucid } + xml.element("title") { xml.text self.title } + xml.element("link", rel: "alternate", href: "#{HOST_URL}/watch?v=#{self.id}") + + xml.element("author") do + xml.element("name") { xml.text self.author } + xml.element("uri") { xml.text "#{HOST_URL}/channel/#{self.ucid}" } + end + + xml.element("content", type: "xhtml") do + xml.element("div", xmlns: "http://www.w3.org/1999/xhtml") do + xml.element("a", href: "#{HOST_URL}/watch?v=#{self.id}") do + xml.element("img", src: "#{HOST_URL}/vi/#{self.id}/mqdefault.jpg") + end + end + end + + xml.element("published") { xml.text self.published.to_s("%Y-%m-%dT%H:%M:%S%:z") } + + xml.element("media:group") do + xml.element("media:title") { xml.text self.title } + xml.element("media:thumbnail", url: "#{HOST_URL}/vi/#{self.id}/mqdefault.jpg", + width: "320", height: "180") + end + end + end + + def to_xml(_xml : Nil = nil) + XML.build { |xml| to_xml(xml) } + end + + def to_json(json : JSON::Builder, index : Int32? = nil) + json.object do + json.field "title", self.title + json.field "videoId", self.id + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "videoThumbnails" do + Invidious::JSONify::APIv1.thumbnails(json, self.id) + end + + if index + json.field "index", index + json.field "indexId", self.index.to_u64.to_s(16).upcase + else + json.field "index", self.index + end + + json.field "lengthSeconds", self.length_seconds + json.field "startingTimestampSeconds", self.starting_timestamp_seconds + json.field "endingTimestampSeconds", self.ending_timestamp_seconds + end + end + + def to_json(_json : Nil, index : Int32? = nil) + JSON.build { |json| to_json(json, index: index) } + end +end + +struct Compilation + include DB::Serializable + + property title : String + property id : String + property author : String + property author_thumbnail : String + property ucid : String + property description : String + property description_html : String + property video_count : Int32 + property views : Int64 + property updated : Time + property thumbnail : String? + + def to_json(offset, json : JSON::Builder, video_id : String? = nil) + json.object do + json.field "type", "compilation" + json.field "title", self.title + json.field "compilationId", self.id + json.field "compilationThumbnail", self.thumbnail + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", "/channel/#{self.ucid}" + + json.field "authorThumbnails" do + json.array do + qualities = {32, 48, 76, 100, 176, 512} + + qualities.each do |quality| + json.object do + json.field "url", self.author_thumbnail.not_nil!.gsub(/=\d+/, "=s#{quality}") + json.field "width", quality + json.field "height", quality + end + end + end + end + + json.field "description", self.description + json.field "descriptionHtml", self.description_html + json.field "videoCount", self.video_count + + json.field "viewCount", self.views + json.field "updated", self.updated.to_unix + + json.field "videos" do + json.array do + videos = get_compilation_videos(self, offset: offset, video_id: video_id) + videos.each do |video| + video.to_json(json) + end + end + end + end + end + + def to_json(offset, _json : Nil = nil, video_id : String? = nil) + JSON.build do |json| + to_json(offset, json, video_id: video_id) + end + end + + def privacy + CompilationPrivacy::Unlisted + end +end + +enum CompilationPrivacy + Unlisted = 0 + Private = 1 +end + +struct InvidiousCompilation + include DB::Serializable + + property title : String + property id : String + property author : String + property description : String = "" + property video_count : Int32 + property created : Time + property updated : Time + + @[DB::Field(converter: InvidiousCompilation::CompilationPrivacyConverter)] + property privacy : CompilationPrivacy = CompilationPrivacy::Private + property index : Array(Int64) + + @[DB::Field(ignore: true)] + property thumbnail_id : String? + + module CompilationPrivacyConverter + def self.from_rs(rs) + return CompilationPrivacy.parse(String.new(rs.read(Slice(UInt8)))) + end + end + + def to_json(offset, json : JSON::Builder, video_id : String? = nil) + json.object do + json.field "type", "invidiousCompilation" + json.field "title", self.title + json.field "compilationId", self.id + + json.field "author", self.author + json.field "authorId", self.ucid + json.field "authorUrl", nil + json.field "authorThumbnails", [] of String + + json.field "description", html_to_content(self.description_html) + json.field "descriptionHtml", self.description_html + json.field "videoCount", self.video_count + + json.field "viewCount", self.views + json.field "updated", self.updated.to_unix + + json.field "videos" do + json.array do + if (!offset || offset == 0) && !video_id.nil? + index = Invidious::Database::CompilationVideos.select_index(self.id, video_id) + offset = self.index.index(index) || 0 + end + + videos = get_compilation_videos(self, offset: offset, video_id: video_id) + videos.each_with_index do |video, idx| + video.to_json(json, offset + idx) + end + end + end + end + end + + def to_json(offset, _json : Nil = nil, video_id : String? = nil) + JSON.build do |json| + to_json(offset, json, video_id: video_id) + end + end + + def thumbnail + # TODO: Get compilation thumbnail from compilation data rather than first video + @thumbnail_id ||= Invidious::Database::CompilationVideos.select_one_id(self.id, self.index) || "-----------" + "/vi/#{@thumbnail_id}/mqdefault.jpg" + end + + def author_thumbnail + nil + end + + def ucid + nil + end + + def views + 0_i64 + end + + def description_html + HTML.escape(self.description) + end +end + +def create_compilation(title, privacy, user) + plid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" + + playlist = InvidiousCompilation.new({ + title: title.byte_slice(0, 150), + id: compid, + author: user.email, + description: "", # Max 5000 characters + video_count: 0, + created: Time.utc, + updated: Time.utc, + privacy: privacy, + index: [] of Int64, + }) + + Invidious::Database::Compilations.insert(compilation) + + return compilation +end + +def subscribe_compilation(user, compilation) + compilation = InvidiousCompilation.new({ + title: compilation.title.byte_slice(0, 150), + id: compilation.id, + author: user.email, + description: "", # Max 5000 characters + video_count: compilation.video_count, + created: Time.utc, + updated: compilation.updated, + privacy: CompilationPrivacy::Private, + index: [] of Int64, + }) + + Invidious::Database::Compilations.insert(compilation) + + return compilation +end + +def produce_compilation_continuation(id, index) + if id.starts_with? "UC" + id = "UU" + id.lchop("UC") + end + compid = "VL" + id + + # Emulate a "request counter" increment, to make perfectly valid + # ctokens, even if at the time of writing, it's ignored by youtube. + request_count = (index / 100).to_i64 || 1_i64 + + data = {"1:varint" => index.to_i64} + .try { |i| Protodec::Any.cast_json(i) } + .try { |i| Protodec::Any.from_json(i) } + .try { |i| Base64.urlsafe_encode(i, padding: false) } + + object = { + "80226972:embedded" => { + "2:string" => plid, + "3:base64" => { + "1:varint" => request_count, + "15:string" => "PT:#{data}", + "104:embedded" => {"1:0:varint" => 0_i64}, + }, + "35:string" => id, + }, + } + + continuation = object.try { |i| Protodec::Any.cast_json(i) } + .try { |i| Protodec::Any.from_json(i) } + .try { |i| Base64.urlsafe_encode(i) } + .try { |i| URI.encode_www_form(i) } + + return continuation +end + +def get_compilation(compid : String) + if compid.starts_with? "IV" + if compilation = Invidious::Database::Compilations.select(id: compid) + return compilation + else + raise NotFoundException.new("Compilation does not exist.") + end + else + return fetch_compilation(compid) + end +end + +def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) + # Show empty compilation if requested page is out of range + # (e.g, when a new compilation has been created, offset will be negative) + if offset >= compilation.video_count || offset < 0 + return [] of CompilationVideo + end + + if compilation.is_a? InvidiousCompilation + Invidious::Database::CompilationVideos.select(compilation.id, compilation.index, offset, limit: 100) + else + if video_id + initial_data = YoutubeAPI.next({ + "videoId" => video_id, + "compilationId" => compilation.id, + }) + offset = initial_data.dig?("contents", "twoColumnWatchNextResults", "compilation", "compilation", "currentIndex").try &.as_i || offset + end + + videos = [] of CompilationVideo + + until videos.size >= 200 || videos.size == compilation.video_count || offset >= compilation.video_count + # 100 videos per request + ctoken = produce_compilation_continuation(compilation.id, offset) + initial_data = YoutubeAPI.browse(ctoken) + videos += extract_compilation_videos(initial_data) + + offset += 100 + end + + return videos + end +end + +def extract_compilation_videos(initial_data : Hash(String, JSON::Any)) + videos = [] of CompilationVideo + + if initial_data["contents"]? + tabs = initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"] + tabs_renderer = tabs.as_a.select(&.["tabRenderer"]["selected"]?.try &.as_bool)[0]["tabRenderer"] + + # Watch out the two versions, with and without "s" + if tabs_renderer["contents"]? || tabs_renderer["content"]? + # Initial compilation data + tabs_contents = tabs_renderer.["contents"]? || tabs_renderer.["content"] + + list_renderer = tabs_contents.["sectionListRenderer"]["contents"][0] + item_renderer = list_renderer.["itemSectionRenderer"]["contents"][0] + contents = item_renderer.["compilationVideoListRenderer"]["contents"].as_a + else + # Continuation data + contents = initial_data["onResponseReceivedActions"][0]? + .try &.["appendContinuationItemsAction"]["continuationItems"].as_a + end + else + contents = initial_data["response"]?.try &.["continuationContents"]["compilationVideoListContinuation"]["contents"].as_a + end + + contents.try &.each do |item| + if i = item["compilationVideoRenderer"]? + video_id = i["navigationEndpoint"]["watchEndpoint"]["videoId"].as_s + compid = i["navigationEndpoint"]["watchEndpoint"]["compilationId"].as_s + index = i["navigationEndpoint"]["watchEndpoint"]["index"].as_i64 + + title = i["title"].try { |t| t["simpleText"]? || t["runs"]?.try &.[0]["text"]? }.try &.as_s || "" + author = i["shortBylineText"]?.try &.["runs"][0]["text"].as_s || "" + ucid = i["shortBylineText"]?.try &.["runs"][0]["navigationEndpoint"]["browseEndpoint"]["browseId"].as_s || "" + length_seconds = i["lengthSeconds"]?.try &.as_s.to_i + live = false + + if !length_seconds + live = true + length_seconds = 0 + end + + videos << CompilationVideo.new({ + title: title, + id: video_id, + author: author, + ucid: ucid, + length_seconds: length_seconds, + starting_timestamp_seconds: starting_timestamp_seconds, + ending_timestamp_seconds: ending_timestamp_seconds, + published: Time.utc, + compid: plid, + index: index, + }) + end + end + + return videos +end + +def template_compilation(compilation) + html = <<-END_HTML +

+ + #{compilation["title"]} + +

+
+
    + END_HTML + + compilation["videos"].as_a.each do |video| + html += <<-END_HTML +
  1. + +
    + +

    #{recode_length_seconds(video["lengthSeconds"].as_i)}

    +
    +

    #{video["title"]}

    +

    + #{video["author"]} +

    +
    +
  2. + END_HTML + end + + html += <<-END_HTML +
+
+
+ END_HTML + + html +end diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 69281a55..ff727e99 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -108,7 +108,7 @@ module Invidious::Database::Compilations def select_like_iv(email : String) : Array(InvidiousCompilation) request = <<-SQL - SELECT * FROM compilation + SELECT * FROM compilations WHERE author = $1 AND id LIKE 'IV%' ORDER BY created SQL diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr new file mode 100644 index 00000000..096a5090 --- /dev/null +++ b/src/invidious/views/feeds/compilations.ecr @@ -0,0 +1,5 @@ +<% content_for "header" do %> +<%= translate(locale, "Compilations") %> - Invidious +<% end %> + +<%= rendered "components/feed_menu" %> \ No newline at end of file From 7c92b051b3a966b5d8d37af14d3b911262223229 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 15 Jun 2023 20:38:46 -0700 Subject: [PATCH 08/45] Add custom item for CompilationVideo --- locales/en-US.json | 3 +++ src/invidious/compilations.cr | 4 ++-- src/invidious/database/compilations.cr | 2 ++ src/invidious/views/components/item.ecr | 9 ++++++-- src/invidious/views/feeds/compilations.ecr | 26 +++++++++++++++++++++- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/locales/en-US.json b/locales/en-US.json index 06d095dc..e206bc0e 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -174,6 +174,7 @@ "Delete playlist `x`?": "Delete playlist `x`?", "Delete playlist": "Delete playlist", "Create playlist": "Create playlist", + "Create compilation": "Create compilation", "Title": "Title", "Playlist privacy": "Playlist privacy", "Editing playlist `x`": "Editing playlist `x`", @@ -413,6 +414,7 @@ "Audio mode": "Audio mode", "Video mode": "Video mode", "Playlists": "Playlists", + "Compilations": "Compilations", "search_filters_title": "Filters", "search_filters_date_label": "Upload date", "search_filters_date_option_none": "Any date", @@ -469,6 +471,7 @@ "download_subtitles": "Subtitles - `x` (.vtt)", "user_created_playlists": "`x` created playlists", "user_saved_playlists": "`x` saved playlists", + "user_created_compilations": "`x` created compilations", "Video unavailable": "Video unavailable", "preferences_save_player_pos_label": "Save playback position: ", "crash_page_you_found_a_bug": "It looks like you found a bug in Invidious!", diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index b048fb84..42e9aaf5 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -240,9 +240,9 @@ struct InvidiousCompilation end def create_compilation(title, privacy, user) - plid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" + compid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" - playlist = InvidiousCompilation.new({ + compilation = InvidiousCompilation.new({ title: title.byte_slice(0, 150), id: compid, author: user.email, diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index ff727e99..76e45641 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -166,6 +166,8 @@ end module Invidious::Database::CompilationVideos extend self + private alias VideoIndex = Int64 | Array(Int64) + # ------------------- # Insert / Delete # ------------------- diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index c29ec47b..867e2e8f 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -1,6 +1,6 @@ <%- thin_mode = env.get("preferences").as(Preferences).thin_mode - item_watched = !item.is_a?(SearchChannel | SearchHashtag | SearchPlaylist | InvidiousPlaylist | Category) && env.get?("user").try &.as(User).watched.index(item.id) != nil + item_watched = !item.is_a?(SearchChannel | SearchHashtag | SearchPlaylist | InvidiousPlaylist | InvidiousCompilation | Category) && env.get?("user").try &.as(User).watched.index(item.id) != nil author_verified = item.responds_to?(:author_verified) && item.author_verified -%> @@ -53,7 +53,7 @@

<%= translate_count(locale, "generic_channels_count", item.channel_count, NumberFormatting::Separator) %>

<%- end -%> - <% when SearchPlaylist, InvidiousPlaylist %> + <% when SearchPlaylist, InvidiousPlaylist, InvidiousCompilation %> <%- if item.id.starts_with? "RD" link_url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" @@ -87,6 +87,11 @@

+ <% when CompilationVideo %> + + <% if !env.get("preferences").as(Preferences).thin_mode %> + <% end %> + <% when Category %> <% else %> <%- diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr index 096a5090..a7280e30 100644 --- a/src/invidious/views/feeds/compilations.ecr +++ b/src/invidious/views/feeds/compilations.ecr @@ -2,4 +2,28 @@ <%= translate(locale, "Compilations") %> - Invidious <% end %> -<%= rendered "components/feed_menu" %> \ No newline at end of file +<%= rendered "components/feed_menu" %> + +
+
+

<%= translate(locale, "user_created_compilations", %(#{items_created.size})) %>

+
+ + +
+ +
+<% items_created.each do |item| %> + <%= rendered "components/item" %> +<% end %> +
\ No newline at end of file From b6181b9d97d270356d5dae3dabe1f03d8dd34803 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 15 Jun 2023 21:29:37 -0700 Subject: [PATCH 09/45] Add authenticated API for compilation creation --- assets/css/default.css | 7 ++++++ src/invidious/routes/api/v1/authenticated.cr | 26 ++++++++++++++++++++ src/invidious/routing.cr | 2 ++ src/invidious/views/components/item.ecr | 3 +++ src/invidious/views/feeds/compilations.ecr | 2 +- 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/assets/css/default.css b/assets/css/default.css index c31b24e5..9828513a 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -759,3 +759,10 @@ h1, h2, h3, h4, h5, p, .channel-emoji { margin: 0 2px; } + +div.compilation-video-panel { + display: block; + margin-left: auto; + margin-right: auto; + color: #d9d9d9; +} diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index a35d2f2b..0f96965c 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -207,6 +207,32 @@ module Invidious::Routes::API::V1::Authenticated end end + def self.create_compilation(env) + env.response.content_type = "application/json" + user = env.get("user").as(User) + + title = env.params.json["title"]?.try &.as(String).delete("<>").byte_slice(0, 150) + if !title + return error_json(400, "Invalid title.") + end + + privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } + if !privacy + return error_json(400, "Invalid privacy setting.") + end + + if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 + return error_json(400, "User cannot have more than 100 compilations.") + end + + compilation = create_compilation(title, privacy, user) + env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{playlist.id}" + env.response.status_code = 201 + { + "title" => title, + "compilationId" => compilation.id, + }.to_json + def self.create_playlist(env) env.response.content_type = "application/json" user = env.get("user").as(User) diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index a653c1a5..a40bef73 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -274,6 +274,8 @@ module Invidious::Routing post "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :subscribe_channel delete "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :unsubscribe_channel + get "/api/v1/auth/compilations", {{namespace}}::Authenticated, :create_compilation + get "/api/v1/auth/playlists", {{namespace}}::Authenticated, :list_playlists post "/api/v1/auth/playlists", {{namespace}}::Authenticated, :create_playlist patch "/api/v1/auth/playlists/:plid",{{namespace}}:: Authenticated, :update_playlist_attribute diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 867e2e8f..8f8ba40f 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -90,6 +90,9 @@ <% when CompilationVideo %> <% if !env.get("preferences").as(Preferences).thin_mode %> +
+ +
<% end %>
<% when Category %> diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr index a7280e30..31d073c4 100644 --- a/src/invidious/views/feeds/compilations.ecr +++ b/src/invidious/views/feeds/compilations.ecr @@ -10,7 +10,7 @@
From bac4fd90979432873663c6e67faac4f1f1de3c7f Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 15 Jun 2023 23:17:44 -0700 Subject: [PATCH 10/45] Add create_compilation route and ecr --- src/invidious/routes/api/v1/authenticated.cr | 3 ++- src/invidious/routing.cr | 5 +++++ src/invidious/views/create_compilation.ecr | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/invidious/views/create_compilation.ecr diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 0f96965c..11ffe7ff 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -226,12 +226,13 @@ module Invidious::Routes::API::V1::Authenticated end compilation = create_compilation(title, privacy, user) - env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{playlist.id}" + env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{compilation.id}" env.response.status_code = 201 { "title" => title, "compilationId" => compilation.id, }.to_json + end def self.create_playlist(env) env.response.content_type = "application/json" diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index a40bef73..434392e9 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -80,6 +80,11 @@ module Invidious::Routing get "/subscription_manager", Routes::Subscriptions, :subscription_manager end + def register_iv_compilation_routes + get "/create_compilation", Routes::Compilations, :new + post "/create_compilation", Routes::Compilations, :create + end + def register_iv_playlist_routes get "/create_playlist", Routes::Playlists, :new post "/create_playlist", Routes::Playlists, :create diff --git a/src/invidious/views/create_compilation.ecr b/src/invidious/views/create_compilation.ecr new file mode 100644 index 00000000..296d873e --- /dev/null +++ b/src/invidious/views/create_compilation.ecr @@ -0,0 +1,3 @@ +<% content_for "header" do %> +<%= translate(locale, "Create compilation") %> - Invidious +<% end %> \ No newline at end of file From 74d42c18dda03a999f8f59142ba673b59cf8572c Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 16 Jun 2023 01:49:38 -0700 Subject: [PATCH 11/45] Add ecr for individual compilation items (videos) --- assets/js/compilation_widget.js | 48 ++ config/config.example.yml | 8 + locales/en-US.json | 1 + src/invidious/routes/compilations.cr | 410 ++++++++++++++++++ src/invidious/views/add_compilation_items.ecr | 40 ++ src/invidious/views/components/feed_menu.ecr | 2 +- src/invidious/views/create_compilation.ecr | 38 +- 7 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 assets/js/compilation_widget.js create mode 100644 src/invidious/routes/compilations.cr create mode 100644 src/invidious/views/add_compilation_items.ecr diff --git a/assets/js/compilation_widget.js b/assets/js/compilation_widget.js new file mode 100644 index 00000000..7e8e6356 --- /dev/null +++ b/assets/js/compilation_widget.js @@ -0,0 +1,48 @@ +'use strict'; +var compilation_data = JSON.parse(document.getElementById('compilation_data').textContent); +var payload = 'csrf_token=' + compilation_data.csrf_token; + +function add_compilation_video(target) { + var select = target.parentNode.children[0].children[1]; + var option = select.children[select.selectedIndex]; + + var url = '/compilation_ajax?action_add_video=1&redirect=false' + + '&video_id=' + target.getAttribute('data-id') + + '&compilation_id=' + option.getAttribute('data-compid'); + + helpers.xhr('POST', url, {payload: payload}, { + on200: function (response) { + option.textContent = '✓' + option.textContent; + } + }); +} + +function add_compilation_item(target) { + var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode; + tile.style.display = 'none'; + + var url = '/compilation_ajax?action_add_video=1&redirect=false' + + '&video_id=' + target.getAttribute('data-id') + + '&compilation_id=' + target.getAttribute('data-compid'); + + helpers.xhr('POST', url, {payload: payload}, { + onNon200: function (xhr) { + tile.style.display = ''; + } + }); +} + +function remove_compilation_item(target) { + var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode; + tile.style.display = 'none'; + + var url = '/compilation_ajax?action_remove_video=1&redirect=false' + + '&set_video_id=' + target.getAttribute('data-index') + + '&compilation_id=' + target.getAttribute('data-compid'); + + helpers.xhr('POST', url, {payload: payload}, { + onNon200: function (xhr) { + tile.style.display = ''; + } + }); +} diff --git a/config/config.example.yml b/config/config.example.yml index e925a5e3..ff568a5b 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -483,6 +483,14 @@ hmac_key: "CHANGE_ME!!" ## #playlist_length_limit: 500 +## +## Maximum custom compilation length limit. +## +## Accepted values: Integer +## Default: 500 +## +#compilation_length_limit: 500 + ######################################### # # Default user preferences diff --git a/locales/en-US.json b/locales/en-US.json index e206bc0e..3905de6e 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -177,6 +177,7 @@ "Create compilation": "Create compilation", "Title": "Title", "Playlist privacy": "Playlist privacy", + "Compilation privacy": "Compilation privacy", "Editing playlist `x`": "Editing playlist `x`", "playlist_button_add_items": "Add videos", "Show more": "Show more", diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr new file mode 100644 index 00000000..0189b60b --- /dev/null +++ b/src/invidious/routes/compilations.cr @@ -0,0 +1,410 @@ +{% skip_file if flag?(:api_only) %} + +module Invidious::Routes::Compilations + def self.new(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + sid = sid.as(String) + csrf_token = generate_response(sid, {":create_compilation"}, HMAC_KEY) + + templated "create_compilation" + end + + def self.create(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + sid = sid.as(String) + token = env.params.body["csrf_token"]? + + begin + validate_request(token, sid, env.request, HMAC_KEY, locale) + rescue ex + return error_template(400, ex) + end + + title = env.params.body["title"]?.try &.as(String) + if !title || title.empty? + return error_template(400, "Title cannot be empty.") + end + + privacy = CompilationPrivacy.parse?(env.params.body["privacy"]?.try &.as(String) || "") + if !privacy + return error_template(400, "Invalid privacy setting.") + end + + if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 + return error_template(400, "User cannot have more than 100 compilations.") + end + + compilation = create_compilation(title, privacy, user) + + env.redirect "/compilation?list=#{compilation.id}" + end + + def self.delete_page(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + sid = sid.as(String) + + compid = env.params.query["list"]? + if !compid || compid.empty? + return error_template(400, "A compilation ID is required") + end + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email + return env.redirect referer + end + + csrf_token = generate_response(sid, {":delete_compilation"}, HMAC_KEY) + + templated "delete_compilation" + end + + def self.delete(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + compid = env.params.query["list"]? + return env.redirect referer if compid.nil? + + user = user.as(User) + sid = sid.as(String) + token = env.params.body["csrf_token"]? + + begin + validate_request(token, sid, env.request, HMAC_KEY, locale) + rescue ex + return error_template(400, ex) + end + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email + return env.redirect referer + end + + Invidious::Database::Compilations.delete(compid) + + env.redirect "/feed/compilations" + end + + def self.edit(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + sid = sid.as(String) + + compid = env.params.query["list"]? + if !compid || !compid.starts_with?("IV") + return env.redirect referer + end + + page = env.params.query["page"]?.try &.to_i? + page ||= 1 + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email + return env.redirect referer + end + + begin + videos = get_compilation_videos(compilation, offset: (page - 1) * 100) + rescue ex + videos = [] of CompilationVideo + end + + csrf_token = generate_response(sid, {":edit_compilation"}, HMAC_KEY) + + templated "edit_compilation" + end + + def self.update(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + compid = env.params.query["list"]? + return env.redirect referer if compid.nil? + + user = user.as(User) + sid = sid.as(String) + token = env.params.body["csrf_token"]? + + begin + validate_request(token, sid, env.request, HMAC_KEY, locale) + rescue ex + return error_template(400, ex) + end + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email + return env.redirect referer + end + + title = env.params.body["title"]?.try &.delete("<>") || "" + privacy = CompilationPrivacy.parse(env.params.body["privacy"]? || "Unlisted") + description = env.params.body["description"]?.try &.delete("\r") || "" + + if title != compilation.title || + compilation != compilation.privacy || + description != compilation.description + updated = Time.utc + else + updated = compilation.updated + end + + Invidious::Database::Compilations.update(compid, title, privacy, description, updated) + + env.redirect "/compilation?list=#{compid}" + end + + def self.add_compilation_items_page(env) + prefs = env.get("preferences").as(Preferences) + locale = prefs.locale + + region = env.params.query["region"]? || prefs.region + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env) + + return env.redirect "/" if user.nil? + + user = user.as(User) + sid = sid.as(String) + + compid = env.params.query["list"]? + if !compid || !compid.starts_with?("IV") + return env.redirect referer + end + + page = env.params.query["page"]?.try &.to_i? + page ||= 1 + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email + return env.redirect referer + end + + begin + query = Invidious::Search::Query.new(env.params.query, :compilation, region) + videos = query.process.select(SearchVideo).map(&.as(SearchVideo)) + rescue ex + videos = [] of SearchVideo + end + + env.set "add_compilation_items", compid + templated "add_compilation_items" + end + + def self.compilation_ajax(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get? "user" + sid = env.get? "sid" + referer = get_referer(env, "/") + + redirect = env.params.query["redirect"]? + redirect ||= "true" + redirect = redirect == "true" + if !user + if redirect + return env.redirect referer + else + return error_json(403, "No such user") + end + end + + user = user.as(User) + sid = sid.as(String) + token = env.params.body["csrf_token"]? + + begin + validate_request(token, sid, env.request, HMAC_KEY, locale) + rescue ex + if redirect + return error_template(400, ex) + else + return error_json(400, ex) + end + end + + if env.params.query["action_create_compilation"]? + action = "action_create_compilation" + elsif env.params.query["action_delete_compilation"]? + action = "action_delete_compilation" + elsif env.params.query["action_edit_compilation"]? + action = "action_edit_compilation" + elsif env.params.query["action_add_video"]? + action = "action_add_video" + video_id = env.params.query["video_id"] + elsif env.params.query["action_remove_video"]? + action = "action_remove_video" + elsif env.params.query["action_move_video_before"]? + action = "action_move_video_before" + else + return env.redirect referer + end + + begin + compilation_id = env.params.query["compilation_id"] + compilation = get_compilation(compilation_id).as(InvidiousCompilation) + raise "Invalid user" if compilation.author != user.email + rescue ex : NotFoundException + return error_json(404, ex) + rescue ex + if redirect + return error_template(400, ex) + else + return error_json(400, ex) + end + end + + email = user.email + + case action + when "action_edit_compilation" + # TODO: Compilation stub + when "action_add_video" + if compilation.index.size >= CONFIG.compilation_length_limit + if redirect + return error_template(400, "Compilation cannot have more than #{CONFIG.compilation_length_limit} videos") + else + return error_json(400, "Compilation cannot have more than #{CONFIG.compilation_length_limit} videos") + end + end + + video_id = env.params.query["video_id"] + + begin + video = get_video(video_id) + rescue ex : NotFoundException + return error_json(404, ex) + rescue ex + if redirect + return error_template(500, ex) + else + return error_json(500, ex) + end + end + + compilation_video = CompilationVideo.new({ + title: video.title, + id: video.id, + author: video.author, + ucid: video.ucid, + length_seconds: video.length_seconds, + starting_timestamp_seconds: video.length_seconds, + ending_timestamp_seconds: video.length_seconds, + published: video.published, + compid: compilation_id, + live_now: video.live_now, + index: Random::Secure.rand(0_i64..Int64::MAX), + }) + + Invidious::Database::CompilationVideos.insert(compilation_video) + Invidious::Database::Compilations.update_video_added(compilation_id, compilation_video.index) + when "action_remove_video" + index = env.params.query["set_video_id"] + Invidious::Database::CompilationVideos.delete(index) + Invidious::Database::Compilations.update_video_removed(compilation_id, index) + when "action_move_video_before" + # TODO: Compilation stub + else + return error_json(400, "Unsupported action #{action}") + end + + if redirect + env.redirect referer + else + env.response.content_type = "application/json" + "{}" + end + end + + def self.show(env) + locale = env.get("preferences").as(Preferences).locale + + user = env.get?("user").try &.as(User) + referer = get_referer(env) + + compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + if !compid + return env.redirect "/" + end + + page = env.params.query["page"]?.try &.to_i? + page ||= 1 + + if compid.starts_with? "RD" + return env.redirect "/mix?list=#{compid}" + end + + begin + compilation = get_compilation(compid) + rescue ex : NotFoundException + return error_template(404, ex) + rescue ex + return error_template(500, ex) + end + + page_count = (compilation.video_count / 200).to_i + page_count += 1 if (compilation.video_count % 200) > 0 + + if page > page_count + return env.redirect "/compilation?list=#{compid}&page=#{page_count}" + end + + if compilation.privacy == CompilationPrivacy::Private && compilation.author != user.try &.email + return error_template(403, "This compilation is private.") + end + + begin + videos = get_compilation_videos(compilation, offset: (page - 1) * 200) + rescue ex + return error_template(500, "Error encountered while retrieving compilation videos.
#{ex.message}") + end + + if compilation.author == user.try &.email + env.set "remove_compilation_items", compid + end + + templated "compilation" + end +end \ No newline at end of file diff --git a/src/invidious/views/add_compilation_items.ecr b/src/invidious/views/add_compilation_items.ecr new file mode 100644 index 00000000..28494d98 --- /dev/null +++ b/src/invidious/views/add_compilation_items.ecr @@ -0,0 +1,40 @@ +<% content_for "header" do %> +<%= compilation.title %> - Invidious + +<% end %> + +
+
+
+
+
+ <%= translate(locale, "Editing compilation `x`", %|"#{HTML.escape(compilation.title)}"|) %> + +
+ value="<%= HTML.escape(query.text) %>"<% end %> + placeholder="<%= translate(locale, "Search for videos") %>"> + +
+
+
+
+
+
+ + + + +
+ <% videos.each_slice(4) do |slice| %> + <% slice.each do |item| %> + <%= rendered "components/item" %> + <% end %> + <% end %> +
\ No newline at end of file diff --git a/src/invidious/views/components/feed_menu.ecr b/src/invidious/views/components/feed_menu.ecr index 3fb20086..ff3b2474 100644 --- a/src/invidious/views/components/feed_menu.ecr +++ b/src/invidious/views/components/feed_menu.ecr @@ -1,7 +1,7 @@
<% feed_menu = env.get("preferences").as(Preferences).feed_menu.dup %> <% if !env.get?("user") %> - <% feed_menu.reject! {|item| {"Subscriptions", "Playlists"}.includes? item} %> + <% feed_menu.reject! {|item| {"Subscriptions", "Playlists", "Compilations"}.includes? item} %> <% end %> <% feed_menu.each do |feed| %> diff --git a/src/invidious/views/create_compilation.ecr b/src/invidious/views/create_compilation.ecr index 296d873e..4d8fc03c 100644 --- a/src/invidious/views/create_compilation.ecr +++ b/src/invidious/views/create_compilation.ecr @@ -1,3 +1,39 @@ <% content_for "header" do %> <%= translate(locale, "Create compilation") %> - Invidious -<% end %> \ No newline at end of file +<% end %> + +
+
+
+
+
+
+ <%= translate(locale, "Create compilation") %> + +
+ + "> +
+ +
+ + +
+ +
+ +
+ + +
+
+
+
+
+
From ea482395434254f0083cd09a297350b28b51f043 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 16 Jun 2023 02:49:43 -0700 Subject: [PATCH 12/45] Add erc for viewing one compliation --- src/invidious/routes/misc.cr | 6 +++ src/invidious/routes/preferences.cr | 2 +- src/invidious/views/compilation.ecr | 51 ++++++++++++++++++++++++ src/invidious/views/user/preferences.ecr | 2 +- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/invidious/views/compilation.ecr diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index d6bd9571..4f7f65a8 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -23,6 +23,12 @@ module Invidious::Routes::Misc else env.redirect "/feed/popular" end + when "Compilations" + if user + env.redirect "/feed/compilations" + else + env.redirect "/feed/popyular" + end else templated "search_homepage", navbar_search: false end diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index abe0f34e..6d410e87 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -99,7 +99,7 @@ module Invidious::Routes::PreferencesRoute default_home = env.params.body["default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home feed_menu = [] of String - 4.times do |index| + 5.times do |index| option = env.params.body["feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? feed_menu << option diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr new file mode 100644 index 00000000..de3ac1fa --- /dev/null +++ b/src/invidious/views/compilation.ecr @@ -0,0 +1,51 @@ +<% title = HTML.escape(compilation.title) %> +<% author = HTML.escape(compilation.author) %> + +<% content_for "header" do %> +<%= title %> - Invidious + +<% end %> + +
+
+

<%= title %>

+ <% if compilation.is_a? InvidiousCompilation %> + + <% if compilation.author == user.try &.email %> +
<%= author %> | + <% else %> + <%= author %> | + <% end %> + <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | + <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> | + <% case compilation.as(InvidiousCompilation).privacy when %> + <% when CompilationPrivacy::Unlisted %> + <%= translate(locale, "Unlisted") %> + <% when CompilationPrivacy::Private %> + <%= translate(locale, "Private") %> + <% end %> + + <% else %> + + <%= author %> | + <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | + <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> + + <% end %> +
+
+

+
+ <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> +
+
+ <% else %> + <% if !Invidious::Database::Compilations.exists?(compilation.id) %> +
+ <% end %> + <% end %> +
+
+

+
+
\ No newline at end of file diff --git a/src/invidious/views/user/preferences.ecr b/src/invidious/views/user/preferences.ecr index dfda1434..1ef99cd2 100644 --- a/src/invidious/views/user/preferences.ecr +++ b/src/invidious/views/user/preferences.ecr @@ -165,7 +165,7 @@
<% if env.get?("user") %> - <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists"} %> + <% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists", "Compilations"} %> <% else %> <% feed_options = {"", "Popular", "Trending"} %> <% end %> From 7cfa09984ea7b1b149a23d852d82377611f9753b Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 18 Jun 2023 00:12:33 -0700 Subject: [PATCH 13/45] Add compilations to feeds menu --- assets/js/handlers.js | 9 +++++++++ config/sql/compilations.sql | 8 ++++---- src/invidious/compilations.cr | 2 -- src/invidious/config.cr | 5 ++++- src/invidious/routes/feeds.cr | 4 ++++ src/invidious/routes/misc.cr | 2 +- src/invidious/routes/preferences.cr | 2 +- src/invidious/routing.cr | 4 +++- src/invidious/views/user/preferences.ecr | 4 ++-- 9 files changed, 28 insertions(+), 12 deletions(-) diff --git a/assets/js/handlers.js b/assets/js/handlers.js index 539974fb..f36da244 100644 --- a/assets/js/handlers.js +++ b/assets/js/handlers.js @@ -60,12 +60,21 @@ document.querySelectorAll('[data-onclick="add_playlist_video"]').forEach(function (el) { el.onclick = function () { add_playlist_video(el); }; }); + document.querySelectorAll('[data-onclick="add_compilation_video"]').forEach(function (el) { + el.onclick = function () { add_compilation_video(el); }; + }); document.querySelectorAll('[data-onclick="add_playlist_item"]').forEach(function (el) { el.onclick = function () { add_playlist_item(el); }; }); + document.querySelectorAll('[data-onclick="add_compilation_item"]').forEach(function (el) { + el.onclick = function () { add_compilation_item(el); }; + }); document.querySelectorAll('[data-onclick="remove_playlist_item"]').forEach(function (el) { el.onclick = function () { remove_playlist_item(el); }; }); + document.querySelectorAll('[data-onclick="remove_compilation_item"]').forEach(function (el) { + el.onclick = function () { remove_compilation_item(el); }; + }); document.querySelectorAll('[data-onclick="revoke_token"]').forEach(function (el) { el.onclick = function () { revoke_token(el); }; }); diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql index d1ee949b..95d2d0af 100644 --- a/config/sql/compilations.sql +++ b/config/sql/compilations.sql @@ -1,8 +1,8 @@ --- Type: public.privacy +-- Type: public.compilation_privacy --- DROP TYPE public.privacy; +-- DROP TYPE public.compilation_privacy; -CREATE TYPE public.privacy AS ENUM +CREATE TYPE public.compilation_privacy AS ENUM ( 'Unlisted', 'Private' @@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS public.compilations video_count integer, created timestamptz, updated timestamptz, - privacy privacy, + privacy compilation_privacy, index int8[] ); diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 42e9aaf5..695a37ea 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -319,8 +319,6 @@ def get_compilation(compid : String) else raise NotFoundException.new("Compilation does not exist.") end - else - return fetch_compilation(compid) end end diff --git a/src/invidious/config.cr b/src/invidious/config.cr index cee33ce1..df64c9b8 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -30,7 +30,7 @@ struct ConfigPreferences property quality : String = "hd720" property quality_dash : String = "auto" property default_home : String? = "Popular" - property feed_menu : Array(String) = ["Popular", "Trending", "Subscriptions", "Playlists"] + property feed_menu : Array(String) = ["Popular", "Trending", "Subscriptions", "Playlists", "Compilations"] property automatic_instance_redirect : Bool = false property region : String = "US" property related_videos : Bool = true @@ -138,6 +138,9 @@ class Config # Playlist length limit property playlist_length_limit : Int32 = 500 + # Compilation length limit + property compilation_length_limit : Int32 = 500 + def disabled?(option) case disabled = CONFIG.disable_proxy when Bool diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index fec94682..3e68bcfb 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -5,6 +5,10 @@ module Invidious::Routes::Feeds env.redirect "/feed/playlists" end + def self.view_all_compilations_redirect(env) + env.redirect "/feed/compilations" + end + def self.compilations(env) locale = env.get("preferences").as(Preferences).locale diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index 4f7f65a8..bd3245cc 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -27,7 +27,7 @@ module Invidious::Routes::Misc if user env.redirect "/feed/compilations" else - env.redirect "/feed/popyular" + env.redirect "/feed/popular" end else templated "search_homepage", navbar_search: false diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index 6d410e87..eea93858 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -186,7 +186,7 @@ module Invidious::Routes::PreferencesRoute CONFIG.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home admin_feed_menu = [] of String - 4.times do |index| + 5.times do |index| option = env.params.body["admin_feed_menu[#{index}]"]?.try &.as(String) || "" if !option.empty? admin_feed_menu << option diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 434392e9..5f743ab5 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -26,6 +26,7 @@ module Invidious::Routing self.register_watch_routes self.register_iv_playlist_routes + self.register_iv_compilation_routes self.register_yt_playlist_routes self.register_search_routes @@ -83,6 +84,7 @@ module Invidious::Routing def register_iv_compilation_routes get "/create_compilation", Routes::Compilations, :new post "/create_compilation", Routes::Compilations, :create + post "/compilation_ajax", Routes::Compilations, :compilation_ajax end def register_iv_playlist_routes @@ -279,7 +281,7 @@ module Invidious::Routing post "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :subscribe_channel delete "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :unsubscribe_channel - get "/api/v1/auth/compilations", {{namespace}}::Authenticated, :create_compilation + post "/api/v1/auth/compilations", {{namespace}}::Authenticated, :create_compilation get "/api/v1/auth/playlists", {{namespace}}::Authenticated, :list_playlists post "/api/v1/auth/playlists", {{namespace}}::Authenticated, :create_playlist diff --git a/src/invidious/views/user/preferences.ecr b/src/invidious/views/user/preferences.ecr index 1ef99cd2..93f03a05 100644 --- a/src/invidious/views/user/preferences.ecr +++ b/src/invidious/views/user/preferences.ecr @@ -174,7 +174,7 @@
@@ -184,7 +184,7 @@ <% (feed_options.size - 1).times do |index| %> <% end %> From 1d209c422e1422c831a826ca87b40b5777917821 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 27 Jun 2023 00:25:01 -0700 Subject: [PATCH 14/45] getcompilation route to routes that are registered --- src/invidious/compilations.cr | 9 ++- src/invidious/database/base.cr | 3 + src/invidious/database/compilations.cr | 2 +- src/invidious/database/playlists.cr | 2 +- src/invidious/playlists.cr | 5 ++ src/invidious/routes/api/v1/authenticated.cr | 24 ++++++- src/invidious/routes/api/v1/misc.cr | 69 ++++++++++++++++++++ src/invidious/routes/before_all.cr | 1 + src/invidious/routes/compilations.cr | 23 ++++++- src/invidious/routes/embed.cr | 1 + src/invidious/routes/feeds.cr | 3 + src/invidious/routes/playlists.cr | 4 ++ src/invidious/routes/watch.cr | 3 + src/invidious/routing.cr | 8 +++ src/invidious/views/compilation.ecr | 45 +------------ src/invidious/views/components/item.ecr | 16 ++++- src/invidious/views/watch.ecr | 28 ++++++++ 17 files changed, 196 insertions(+), 50 deletions(-) diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 695a37ea..8e9ee21b 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -240,7 +240,9 @@ struct InvidiousCompilation end def create_compilation(title, privacy, user) + LOGGER.info("2. create_compilation") compid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" + LOGGER.info("generated compilation id") compilation = InvidiousCompilation.new({ title: title.byte_slice(0, 150), @@ -253,8 +255,10 @@ def create_compilation(title, privacy, user) privacy: privacy, index: [] of Int64, }) + LOGGER.info("Creating compilation db") Invidious::Database::Compilations.insert(compilation) + LOGGER.info("inserted compilation db entry") return compilation end @@ -313,6 +317,7 @@ def produce_compilation_continuation(id, index) end def get_compilation(compid : String) + LOGGER.info("8. get_compilation") if compid.starts_with? "IV" if compilation = Invidious::Database::Compilations.select(id: compid) return compilation @@ -323,6 +328,8 @@ def get_compilation(compid : String) end def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) + LOGGER.info("1. get_compilation") + LOGGER.info("Getting compilation") # Show empty compilation if requested page is out of range # (e.g, when a new compilation has been created, offset will be negative) if offset >= compilation.video_count || offset < 0 @@ -405,7 +412,7 @@ def extract_compilation_videos(initial_data : Hash(String, JSON::Any)) starting_timestamp_seconds: starting_timestamp_seconds, ending_timestamp_seconds: ending_timestamp_seconds, published: Time.utc, - compid: plid, + compid: compid, index: index, }) end diff --git a/src/invidious/database/base.cr b/src/invidious/database/base.cr index 0fb1b6af..9cd8d705 100644 --- a/src/invidious/database/base.cr +++ b/src/invidious/database/base.cr @@ -10,11 +10,14 @@ module Invidious::Database def check_integrity(cfg) return if !cfg.check_tables Invidious::Database.check_enum("privacy", PlaylistPrivacy) + Invidious::Database.check_enum("compilation_privacy", CompilationPrivacy) Invidious::Database.check_table("channels", InvidiousChannel) Invidious::Database.check_table("channel_videos", ChannelVideo) Invidious::Database.check_table("playlists", InvidiousPlaylist) Invidious::Database.check_table("playlist_videos", PlaylistVideo) + Invidious::Database.check_table("compilations", InvidiousCompilation) + Invidious::Database.check_table("compilation_videos", CompilationVideo) Invidious::Database.check_table("nonces", Nonce) Invidious::Database.check_table("session_ids", SessionId) Invidious::Database.check_table("users", User) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 76e45641..f0306364 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -202,7 +202,7 @@ module Invidious::Database::CompilationVideos end # ------------------- - # Salect + # Select # ------------------- def select(compid : String, index : VideoIndex, offset, limit = 100) : Array(CompilationVideo) diff --git a/src/invidious/database/playlists.cr b/src/invidious/database/playlists.cr index c961c16e..a51deab6 100644 --- a/src/invidious/database/playlists.cr +++ b/src/invidious/database/playlists.cr @@ -212,7 +212,7 @@ module Invidious::Database::PlaylistVideos end # ------------------- - # Salect + # Select # ------------------- def select(plid : String, index : VideoIndex, offset, limit = 100) : Array(PlaylistVideo) diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr index 013be268..dc05d209 100644 --- a/src/invidious/playlists.cr +++ b/src/invidious/playlists.cr @@ -240,6 +240,8 @@ struct InvidiousPlaylist end def create_playlist(title, privacy, user) + LOGGER.info("2. create_playlist") + LOGGER.info("create playlist inv/pl.cr") plid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" playlist = InvidiousPlaylist.new({ @@ -313,6 +315,7 @@ def produce_playlist_continuation(id, index) end def get_playlist(plid : String) + LOGGER.info("8. get_playlist") if plid.starts_with? "IV" if playlist = Invidious::Database::Playlists.select(id: plid) return playlist @@ -401,6 +404,8 @@ def fetch_playlist(plid : String) end def get_playlist_videos(playlist : InvidiousPlaylist | Playlist, offset : Int32, video_id = nil) + LOGGER.info("1. get_playlist_videos") + LOGGER.info("get_playlist_videos") # Show empty playlist if requested page is out of range # (e.g, when a new playlist has been created, offset will be negative) if offset >= playlist.video_count || offset < 0 diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 11ffe7ff..2cbcd7cb 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -192,6 +192,21 @@ module Invidious::Routes::API::V1::Authenticated env.response.status_code = 204 end + def self.list_compilations(env) + env.response.content_type = "application/json" + user = env.get("user").as(User) + + compilations = Invidious::Database::Compilations.select_all(author: user.email) + + JSON.build do |json| + json.array do + compilations.each do |compilation| + compilation.to_json(0, json) + end + end + end + end + def self.list_playlists(env) env.response.content_type = "application/json" user = env.get("user").as(User) @@ -208,33 +223,40 @@ module Invidious::Routes::API::V1::Authenticated end def self.create_compilation(env) + LOGGER.info("creating comp in auth fashion") env.response.content_type = "application/json" user = env.get("user").as(User) + LOGGER.info("app json compilation") title = env.params.json["title"]?.try &.as(String).delete("<>").byte_slice(0, 150) if !title return error_json(400, "Invalid title.") end - + LOGGER.info("set title") privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } if !privacy return error_json(400, "Invalid privacy setting.") end + LOGGER.info("set privacy") if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 return error_json(400, "User cannot have more than 100 compilations.") end + LOGGER.info("400 forgone") compilation = create_compilation(title, privacy, user) env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{compilation.id}" env.response.status_code = 201 + LOGGER.info("location set") { "title" => title, "compilationId" => compilation.id, }.to_json + LOGGER.info("Creating json") end def self.create_playlist(env) + LOGGER.info("7. create_playlist") env.response.content_type = "application/json" user = env.get("user").as(User) diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr index e499f4d6..b99a15f1 100644 --- a/src/invidious/routes/api/v1/misc.cr +++ b/src/invidious/routes/api/v1/misc.cr @@ -10,6 +10,75 @@ module Invidious::Routes::API::V1::Misc end end + def self.get_compilation(env : HTTP::Server::Context) + LOGGER.info("15. get_compilation") + env.response.content_type = "application/json" + compid = env.params.url["compid"] + LOGGER.info("the compid is #{compid}") + offset = env.params.query["index"]?.try &.to_i? + offset ||= env.params.query["page"]?.try &.to_i?.try { |page| (page - 1) * 100 } + offset ||= 0 + + video_id = env.params.query["continuation"]? + + format = env.params.query["format"]? + format ||= "json" + + if compid.starts_with? "RD" + return env.redirect "/api/v1/mixes/#{compid}" + end + + begin + compilation = get_compilation(compid) + rescue ex : InfoException + return error_json(404, ex) + rescue ex + return error_json(404, "Compilation does not exist.") + end + + user = env.get?("user").try &.as(User) + if !compilation || compilation.privacy.private? && compilation.author != user.try &.email + return error_json(404, "Compilation does not exist.") + end + + # includes into the compilation a maximum of 50 videos, before the offset + if offset > 0 + lookback = offset < 50 ? offset : 50 + response = compilation.to_json(offset - lookback) + json_response = JSON.parse(response) + else + # Unless the continuation is really the offset 0, it becomes expensive. + # It happens when the offset is not set. + # First we find the actual offset, and then we lookback + # it shouldn't happen often though + + lookback = 0 + response = compilation.to_json(offset, video_id: video_id) + json_response = JSON.parse(response) + + if json_response["videos"].as_a[0]["index"] != offset + offset = json_response["videos"].as_a[0]["index"].as_i + lookback = offset < 50 ? offset : 50 + response = compilation.to_json(offset - lookback) + json_response = JSON.parse(response) + end + end + + if format == "html" + compilation_html = template_compilation(json_response) + index, next_video = json_response["videos"].as_a.skip(1 + lookback).select { |video| !video["author"].as_s.empty? }[0]?.try { |v| {v["index"], v["videoId"]} } || {nil, nil} + + response = { + "compilationHtml" => compilation_html, + "index" => index, + "nextVideo" => next_video, + }.to_json + end + + response + end + + # APIv1 currently uses the same logic for both # user playlists and Invidious playlists. This means that we can't # reasonably split them yet. This should be addressed in APIv2 diff --git a/src/invidious/routes/before_all.cr b/src/invidious/routes/before_all.cr index 396840a4..3c027027 100644 --- a/src/invidious/routes/before_all.cr +++ b/src/invidious/routes/before_all.cr @@ -85,6 +85,7 @@ module Invidious::Routes::BeforeAll csrf_token = generate_response(sid, { ":authorize_token", ":playlist_ajax", + ":compilation_ajax", ":signout", ":subscription_ajax", ":token_ajax", diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 0189b60b..5a0dd726 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -1,7 +1,11 @@ {% skip_file if flag?(:api_only) %} module Invidious::Routes::Compilations + def self.handle(env) + return "

Hello

" + end def self.new(env) + LOGGER.info("15. new") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -18,6 +22,7 @@ module Invidious::Routes::Compilations end def self.create(env) + LOGGER.info("3. create") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -49,7 +54,8 @@ module Invidious::Routes::Compilations if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 return error_template(400, "User cannot have more than 100 compilations.") end - + LOGGER.info("creating a compilation") + # POST /create_compilation?referer=%2Ffeed%2Fcompilations 12.11ms compilation = create_compilation(title, privacy, user) env.redirect "/compilation?list=#{compilation.id}" @@ -195,6 +201,7 @@ module Invidious::Routes::Compilations end def self.add_compilation_items_page(env) + LOGGER.info("13. add_compilation_items") prefs = env.get("preferences").as(Preferences) locale = prefs.locale @@ -234,6 +241,7 @@ module Invidious::Routes::Compilations end def self.compilation_ajax(env) + LOGGER.info("14. compilation_ajax") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -359,22 +367,29 @@ module Invidious::Routes::Compilations end def self.show(env) + LOGGER.info("4. show | comp") locale = env.get("preferences").as(Preferences).locale + LOGGER.info("set locale") user = env.get?("user").try &.as(User) + LOGGER.info("got user") referer = get_referer(env) + LOGGER.info("got referer") compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + LOGGER.info("got compid comp") if !compid return env.redirect "/" end page = env.params.query["page"]?.try &.to_i? page ||= 1 + LOGGER.info("set page") if compid.starts_with? "RD" return env.redirect "/mix?list=#{compid}" end + LOGGER.info("RD comp") begin compilation = get_compilation(compid) @@ -383,27 +398,33 @@ module Invidious::Routes::Compilations rescue ex return error_template(500, ex) end + LOGGER.info("got 200 comp") page_count = (compilation.video_count / 200).to_i page_count += 1 if (compilation.video_count % 200) > 0 + LOGGER.info("set page count") if page > page_count return env.redirect "/compilation?list=#{compid}&page=#{page_count}" end + if compilation.privacy == CompilationPrivacy::Private && compilation.author != user.try &.email return error_template(403, "This compilation is private.") end + LOGGER.info("set privacy") begin videos = get_compilation_videos(compilation, offset: (page - 1) * 200) rescue ex return error_template(500, "Error encountered while retrieving compilation videos.
#{ex.message}") end + LOGGER.info("set offset") if compilation.author == user.try &.email env.set "remove_compilation_items", compid end + LOGGER.info("showing author") templated "compilation" end diff --git a/src/invidious/routes/embed.cr b/src/invidious/routes/embed.cr index 266f7ba4..8756bb49 100644 --- a/src/invidious/routes/embed.cr +++ b/src/invidious/routes/embed.cr @@ -31,6 +31,7 @@ module Invidious::Routes::Embed end def self.show(env) + LOGGER.info("9? show") locale = env.get("preferences").as(Preferences).locale id = env.params.url["id"] diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index 3e68bcfb..39f681dc 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -10,6 +10,7 @@ module Invidious::Routes::Feeds end def self.compilations(env) + LOGGER.info("5. compilations") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -36,6 +37,8 @@ module Invidious::Routes::Feeds end def self.playlists(env) + LOGGER.info("5. playlists") + LOGGER.info("Generating the playlist items") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr index 9c6843e9..dc06d364 100644 --- a/src/invidious/routes/playlists.cr +++ b/src/invidious/routes/playlists.cr @@ -18,6 +18,8 @@ module Invidious::Routes::Playlists end def self.create(env) + LOGGER.info("3. create") + LOGGER.info("creating a play") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -396,6 +398,8 @@ module Invidious::Routes::Playlists end def self.show(env) + LOGGER.info("4. show") + LOGGER.info("showing a play") locale = env.get("preferences").as(Preferences).locale user = env.get?("user").try &.as(User) diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index e5cf3716..e63bfc8c 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -2,6 +2,7 @@ module Invidious::Routes::Watch def self.handle(env) + LOGGER.info("6. handle") locale = env.get("preferences").as(Preferences).locale region = env.params.query["region"]? @@ -202,6 +203,7 @@ module Invidious::Routes::Watch end def self.redirect(env) + LOGGER.info("10? redirect") url = "/watch?v=#{env.params.url["id"]}" if env.params.query.size > 0 url += "&#{env.params.query}" @@ -275,6 +277,7 @@ module Invidious::Routes::Watch end def self.clip(env) + LOGGER.info("11? clip") clip_id = env.params.url["clip"]? return error_template(400, "A clip ID is required") if !clip_id diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index 5f743ab5..d64ccceb 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -28,6 +28,7 @@ module Invidious::Routing self.register_iv_playlist_routes self.register_iv_compilation_routes self.register_yt_playlist_routes + self.register_compilation_routes self.register_search_routes @@ -172,6 +173,10 @@ module Invidious::Routing get "/watch_videos", Routes::Playlists, :watch_videos end + def register_compilation_routes + get "/compilation", Routes::Compilations, :show + end + def register_search_routes get "/opensearch.xml", Routes::Search, :opensearch get "/results", Routes::Search, :results @@ -282,6 +287,7 @@ module Invidious::Routing delete "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :unsubscribe_channel post "/api/v1/auth/compilations", {{namespace}}::Authenticated, :create_compilation + get "/api/v1/auth/compilations", {{namespace}}::Authenticated, :list_compilations get "/api/v1/auth/playlists", {{namespace}}::Authenticated, :list_playlists post "/api/v1/auth/playlists", {{namespace}}::Authenticated, :create_playlist @@ -303,6 +309,8 @@ module Invidious::Routing get "/api/v1/stats", {{namespace}}::Misc, :stats get "/api/v1/playlists/:plid", {{namespace}}::Misc, :get_playlist get "/api/v1/auth/playlists/:plid", {{namespace}}::Misc, :get_playlist + get "/api/v1/compilations/:compid", {{namespace}}::Misc, :get_compilation + get "/api/v1/auth/compilations/:compid", {{namespace}}::Misc, :get_compilation get "/api/v1/mixes/:rdid", {{namespace}}::Misc, :mixes get "/api/v1/resolveurl", {{namespace}}::Misc, :resolve_url {% end %} diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index de3ac1fa..741f6770 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -3,49 +3,6 @@ <% content_for "header" do %> <%= title %> - Invidious - + <% end %> -
-
-

<%= title %>

- <% if compilation.is_a? InvidiousCompilation %> - - <% if compilation.author == user.try &.email %> - <%= author %> | - <% else %> - <%= author %> | - <% end %> - <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | - <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> | - <% case compilation.as(InvidiousCompilation).privacy when %> - <% when CompilationPrivacy::Unlisted %> - <%= translate(locale, "Unlisted") %> - <% when CompilationPrivacy::Private %> - <%= translate(locale, "Private") %> - <% end %> - - <% else %> - - <%= author %> | - <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | - <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> - - <% end %> -
-
-

-
- <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> -
-
- <% else %> - <% if !Invidious::Database::Compilations.exists?(compilation.id) %> -
- <% end %> - <% end %> -
-
-

-
-
\ No newline at end of file diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 8f8ba40f..e01a119e 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -53,7 +53,7 @@

<%= translate_count(locale, "generic_channels_count", item.channel_count, NumberFormatting::Separator) %>

<%- end -%> - <% when SearchPlaylist, InvidiousPlaylist, InvidiousCompilation %> + <% when SearchPlaylist, InvidiousPlaylist %> <%- if item.id.starts_with? "RD" link_url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" @@ -87,6 +87,20 @@

+ <% when InvidiousCompilation %> + <% url = "/compilation?list=#{item.id}" %> + + <% if !env.get("preferences").as(Preferences).thin_mode %> +
+ " alt="" /> +

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

+
+ <% end %> +

<%= HTML.escape(item.title) %>

+
+ +

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

+
<% when CompilationVideo %> <% if !env.get("preferences").as(Preferences).thin_mode %> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 498d57a1..b861422e 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -139,6 +139,34 @@ we're going to need to do it here in order to allow for translations. <% if user %> <% playlists = Invidious::Database::Playlists.select_user_created_playlists(user.email) %> + <% compilations = Invidious::Database::Compilations.select_user_created_compilations(user.email) %> + <% if !compilations.empty? %> +
+
+ + +
+ + "> + + + +
+ + + <% end %> <% if !playlists.empty? %>
From 8c15c1e8cc7e9ae49d4f9d8bd8fbd0383f498950 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Wed, 28 Jun 2023 23:48:43 -0700 Subject: [PATCH 15/45] Add migration table for compilations --- assets/js/embed.js | 35 ++++++++++++ assets/js/watch.js | 54 ++++++++++++++++++- .../0011_create_compilations_table.cr | 49 +++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/invidious/database/migrations/0011_create_compilations_table.cr diff --git a/assets/js/embed.js b/assets/js/embed.js index b11b5e5a..b5fa1b3f 100644 --- a/assets/js/embed.js +++ b/assets/js/embed.js @@ -1,6 +1,39 @@ 'use strict'; var video_data = JSON.parse(document.getElementById('video_data').textContent); +function get_compilation(compid) { + var compid_url; + compid_url = '/api/v1/compilations/' + compid + + '?index=' + video_data.index + + '&continuation' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; + + helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { + on200: function (response) { + if (!response.nextVideo) + return; + + player.on('ended', function () { + var url = new URL('https://example.com/embed/' + response.nextVideo); + + url.searchParams.set('list', compid); + if (!compid.startsWith('RD')) + url.searchParams.set('index', response.index); + if (video_data.params.autoplay || video_data.params.continue_autoplay) + url.searchParams.set('autoplay', '1'); + if (video_data.params.listen !== video_data.preferences.listen) + url.searchParams.set('listen', video_data.params.listen); + if (video_data.params.speed !== video_data.preferences.speed) + url.searchParams.set('speed', video_data.params.speed); + if (video_data.params.local !== video_data.preferences.local) + url.searchParams.set('local', video_data.params.local); + + location.assign(url.pathname + url.search); + }); + } + }); +} + function get_playlist(plid) { var plid_url; if (plid.startsWith('RD')) { @@ -43,6 +76,8 @@ function get_playlist(plid) { addEventListener('load', function (e) { if (video_data.plid) { get_playlist(video_data.plid); + } else if (video_data.compid) { + get_compilation(video_data.compid) } else if (video_data.video_series) { player.on('ended', function () { var url = new URL('https://example.com/embed/' + video_data.video_series.shift()); diff --git a/assets/js/watch.js b/assets/js/watch.js index 36506abd..809a9f19 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -102,6 +102,57 @@ function continue_autoplay(event) { } } +function get_compilation(compid) { + var compilation = document.getElementById('compilations'); + + compilation.innerHTML = spinnerHTMLwithHR; + + var compid_url; + compid_url = '/api/v1/compilations/' + compid + + '?index=' + video_data.index + + '&continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; + + helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { + on200: function (response) { + compilation.innerHTML = response.compilationHtml; + + if (!response.nextVideo) return; + + var nextVideo = document.getElementById(response.nextVideo); + nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop; + + player.on('ended', function () { + var url = new URL('https://example.com/watch?v=' + response.nextVideo); + + url.searchParams.set('list', compid); + if (!plid.startsWith('RD')) + url.searchParams.set('index', response.index); + if (video_data.params.autoplay || video_data.params.continue_autoplay) + url.searchParams.set('autoplay', '1'); + if (video_data.params.listen !== video_data.preferences.listen) + url.searchParams.set('listen', video_data.params.listen); + if (video_data.params.speed !== video_data.preferences.speed) + url.searchParams.set('speed', video_data.params.speed); + if (video_data.params.local !== video_data.preferences.local) + url.searchParams.set('local', video_data.params.local); + + location.assign(url.pathname + url.search); + }); + }, + onNon200: function (xhr) { + compilation.innerHTML = ''; + document.getElementById('continue').style.display = ''; + }, + onError: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + }, + onTimeout: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + } + }); + } + function get_playlist(plid) { var playlist = document.getElementById('playlist'); @@ -334,7 +385,8 @@ if (video_data.play_next) { addEventListener('load', function (e) { if (video_data.plid) get_playlist(video_data.plid); - + if (video_data.compid) + get_compilation(video_data.compid); if (video_data.params.comments[0] === 'youtube') { get_youtube_comments(); } else if (video_data.params.comments[0] === 'reddit') { diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr new file mode 100644 index 00000000..30404183 --- /dev/null +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -0,0 +1,49 @@ +module Invidious::Database::Migrations + class CreateCompilationsTable < Migration + version 8 + + def up(conn : DB::Connection) + if !privacy_type_exists?(conn) + conn.exec <<-SQL + CREATE TYPE public.compilation_privacy AS ENUM + ( + 'Unlisted', + 'Private' + ); + SQL + end + + conn.exec <<-SQL + CREATE TABLE IF NOT EXISTS public.compilations + ( + title text, + id text primary key, + author text, + description text, + video_count integer, + created timestamptz, + updated timestamptz, + privacy compilation_privacy, + index int8[] + ); + SQL + + conn.exec <<-SQL + GRANT ALL ON public.compilations TO current_user; + SQL + end + + private def privacy_type_exists?(conn : DB::Connection) : Bool + request = <<-SQL + SELECT 1 AS one + FROM pg_type + INNER JOIN pg_namespace ON pg_namespace.oid = pg_type.typnamespace + WHERE pg_namespace.nspname = 'public' + AND pg_type.typname = 'privacy' + LIMIT 1; + SQL + + !conn.query_one?(request, as: Int32).nil? + end + end +end From 128d54132352dff5bbf0401cb5b30aca81100c93 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 29 Jun 2023 20:36:11 -0700 Subject: [PATCH 16/45] Remove compid check for Nil error debugging --- src/invidious/compilations.cr | 5 ++--- src/invidious/database/compilations.cr | 4 ++-- src/invidious/database/playlists.cr | 4 ++-- src/invidious/routes/compilations.cr | 18 +----------------- src/invidious/routes/playlists.cr | 1 - 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 8e9ee21b..b75622f3 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -317,14 +317,13 @@ def produce_compilation_continuation(id, index) end def get_compilation(compid : String) - LOGGER.info("8. get_compilation") - if compid.starts_with? "IV" + #if compid.starts_with? "IV" if compilation = Invidious::Database::Compilations.select(id: compid) return compilation else raise NotFoundException.new("Compilation does not exist.") end - end + #end end def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index f0306364..a3372ac7 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -81,7 +81,7 @@ module Invidious::Database::Compilations end # ------------------- - # Salect + # Select # ------------------- def select(*, id : String) : InvidiousCompilation? @@ -103,7 +103,7 @@ module Invidious::Database::Compilations end # ------------------- - # Salect (filtered) + # Select (filtered) # ------------------- def select_like_iv(email : String) : Array(InvidiousCompilation) diff --git a/src/invidious/database/playlists.cr b/src/invidious/database/playlists.cr index a51deab6..2fed2d95 100644 --- a/src/invidious/database/playlists.cr +++ b/src/invidious/database/playlists.cr @@ -91,7 +91,7 @@ module Invidious::Database::Playlists end # ------------------- - # Salect + # Select # ------------------- def select(*, id : String) : InvidiousPlaylist? @@ -113,7 +113,7 @@ module Invidious::Database::Playlists end # ------------------- - # Salect (filtered) + # Select (filtered) # ------------------- def select_like_iv(email : String) : Array(InvidiousPlaylist) diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 5a0dd726..eb459e98 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -1,9 +1,6 @@ {% skip_file if flag?(:api_only) %} module Invidious::Routes::Compilations - def self.handle(env) - return "

Hello

" - end def self.new(env) LOGGER.info("15. new") locale = env.get("preferences").as(Preferences).locale @@ -54,8 +51,7 @@ module Invidious::Routes::Compilations if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 return error_template(400, "User cannot have more than 100 compilations.") end - LOGGER.info("creating a compilation") - # POST /create_compilation?referer=%2Ffeed%2Fcompilations 12.11ms + compilation = create_compilation(title, privacy, user) env.redirect "/compilation?list=#{compilation.id}" @@ -370,26 +366,20 @@ module Invidious::Routes::Compilations LOGGER.info("4. show | comp") locale = env.get("preferences").as(Preferences).locale - LOGGER.info("set locale") user = env.get?("user").try &.as(User) - LOGGER.info("got user") referer = get_referer(env) - LOGGER.info("got referer") compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") - LOGGER.info("got compid comp") if !compid return env.redirect "/" end page = env.params.query["page"]?.try &.to_i? page ||= 1 - LOGGER.info("set page") if compid.starts_with? "RD" return env.redirect "/mix?list=#{compid}" end - LOGGER.info("RD comp") begin compilation = get_compilation(compid) @@ -398,33 +388,27 @@ module Invidious::Routes::Compilations rescue ex return error_template(500, ex) end - LOGGER.info("got 200 comp") page_count = (compilation.video_count / 200).to_i page_count += 1 if (compilation.video_count % 200) > 0 - LOGGER.info("set page count") if page > page_count return env.redirect "/compilation?list=#{compid}&page=#{page_count}" end - if compilation.privacy == CompilationPrivacy::Private && compilation.author != user.try &.email return error_template(403, "This compilation is private.") end - LOGGER.info("set privacy") begin videos = get_compilation_videos(compilation, offset: (page - 1) * 200) rescue ex return error_template(500, "Error encountered while retrieving compilation videos.
#{ex.message}") end - LOGGER.info("set offset") if compilation.author == user.try &.email env.set "remove_compilation_items", compid end - LOGGER.info("showing author") templated "compilation" end diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr index dc06d364..240c7583 100644 --- a/src/invidious/routes/playlists.cr +++ b/src/invidious/routes/playlists.cr @@ -399,7 +399,6 @@ module Invidious::Routes::Playlists def self.show(env) LOGGER.info("4. show") - LOGGER.info("showing a play") locale = env.get("preferences").as(Preferences).locale user = env.get?("user").try &.as(User) From 2a9789cc1ec27addea9af716e5d1247a793a1cfa Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Mon, 3 Jul 2023 19:46:29 -0700 Subject: [PATCH 17/45] Add CSS element for compilation video --- assets/css/default.css | 16 +++- src/invidious/routing.cr | 1 + src/invidious/search/query.cr | 9 +- src/invidious/views/compilation.ecr | 96 +++++++++++++++++++ .../views/components/compilation_video.ecr | 15 +++ src/invidious/views/components/item.ecr | 80 +++++++++++++++- 6 files changed, 208 insertions(+), 9 deletions(-) create mode 100644 src/invidious/views/components/compilation_video.ecr diff --git a/assets/css/default.css b/assets/css/default.css index 9828513a..504329cd 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -761,8 +761,16 @@ h1, h2, h3, h4, h5, p, } div.compilation-video-panel { - display: block; - margin-left: auto; - margin-right: auto; - color: #d9d9d9; + padding: 28.125%; + position: relative; + box-sizing: border-box; } + +img.compilation-video-panel { + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + object-fit: cover; +} \ No newline at end of file diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index d64ccceb..ac01694d 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -86,6 +86,7 @@ module Invidious::Routing get "/create_compilation", Routes::Compilations, :new post "/create_compilation", Routes::Compilations, :create post "/compilation_ajax", Routes::Compilations, :compilation_ajax + get "/add_compilation_items", Routes::Compilations, :add_compilation_items_page end def register_iv_playlist_routes diff --git a/src/invidious/search/query.cr b/src/invidious/search/query.cr index e38845d9..de64388e 100644 --- a/src/invidious/search/query.cr +++ b/src/invidious/search/query.cr @@ -8,6 +8,7 @@ module Invidious::Search # Types specific to Invidious Subscriptions # Search user subscriptions Playlist # "Add playlist item" search + Compilation # "Add compilation item" search end getter type : Type = Type::Regular @@ -75,6 +76,12 @@ module Invidious::Search # @filters, _, @query, _ = Filters.from_legacy_filters(@raw_query) # + when .compilation? + # In "add compilation item" mode, filters are parsed from the query + # string itself (legacy), and the channel is ignored. + # + @filters, _, @query, _ = Filters.from_legacy_filters(@raw_query) + # when .subscriptions?, .regular? if params["sp"]? # Parse the `sp` URL parameter (youtube compatibility) @@ -112,7 +119,7 @@ module Invidious::Search return items if self.empty_raw_query? case @type - when .regular?, .playlist? + when .regular?, .playlist?, .compilation? items = Processors.regular(self) # when .channel? diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index 741f6770..6bcd7d0f 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -6,3 +6,99 @@ <% end %> +
+
+

<%= title %>

+ <% if compilation.is_a? InvidiousCompilation %> + + <% if compilation.author == user.try &.email %> +
<%= author %> | + <% else %> + <%= author %> | + <% end %> + <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | + <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> | + <% case compilation.as(InvidiousCompilation).privacy when %> + <% when CompilationPrivacy::Unlisted %> + <%= translate(locale, "Unlisted") %> + <% when CompilationPrivacy::Private %> + <%= translate(locale, "Private") %> + <% end %> + + <% else %> + + <%= author %> | + <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | + <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> + + <% end %> +
+
+

+
+ <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> +
+
+ <% else %> + <% if !Invidious::Database::Compilations.exists?(compilation.id) %> +
+ <% end %> + <% end %> +
+
+

+
+
+ +
+
<%= compilation.description_html %>
+
+ +<% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> +
+

+ +

+
+<% end %> + +
+
+
+ +<% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> + + +<% end %> + +
+<% videos.each do |compilation_video| %> + <%= rendered "components/compilation_video" %> +<% end %> +
+ + + +
+
+ <% if page > 1 %> + + <%= translate(locale, "Previous page") %> + + <% end %> +
+
+
+ <% if page_count != 1 && page < page_count %> + + <%= translate(locale, "Next page") %> + + <% end %> +
+
\ No newline at end of file diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr new file mode 100644 index 00000000..0feb34ea --- /dev/null +++ b/src/invidious/views/components/compilation_video.ecr @@ -0,0 +1,15 @@ +
+
+
+
+ + + + + + +
+ +
+
+
\ No newline at end of file diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index e01a119e..57115b8f 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -102,13 +102,78 @@

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

<% when CompilationVideo %> - +
+ +
+ <% when PlaylistVideo %> +
+ <% if !env.get("preferences").as(Preferences).thin_mode %> +
+ + + <% if plid_form = env.get?("remove_playlist_items") %> + " method="post"> + "> +

+ +

+ + <% end %> + + <% if item.responds_to?(:live_now) && item.live_now %> +

<%= translate(locale, "LIVE") %>

+ <% elsif item.length_seconds != 0 %> +

<%= recode_length_seconds(item.length_seconds) %>

+ <% end %> + + <% if item_watched %> +
+
+ <% end %> +
+ <% end %> +

<%= HTML.escape(item.title) %>

+
+ +
+ + <% endpoint_params = "?v=#{item.id}&list=#{item.plid}" %> + <%= rendered "components/video-context-buttons" %> +
+ +
+
+ <% if item.responds_to?(:premiere_timestamp) && item.premiere_timestamp.try &.> Time.utc %> +

<%= translate(locale, "Premieres in `x`", recode_date((item.premiere_timestamp.as(Time) - Time.utc).ago, locale)) %>

+ <% elsif Time.utc - item.published > 1.minute %> +

<%= translate(locale, "Shared `x` ago", recode_date(item.published, locale)) %>

+ <% end %> +
+ + <% if item.responds_to?(:views) && item.views %> +
+

<%= translate_count(locale, "generic_views_count", item.views || 0, NumberFormatting::Short) %>

+
+ <% end %> +
<% when Category %> <% else %> <%- @@ -157,6 +222,13 @@ + <% elsif compid_form = env.get? "add_compilation_items" %> +
" method="post"> + "> +

+ +

+
<%- elsif item.is_a?(PlaylistVideo) && (plid_form = env.get?("remove_playlist_items")) -%> <%- form_parameters = "action_remove_video=1&set_video_id=#{item.index}&playlist_id=#{plid_form}&referer=#{env.get("current_page")}" -%>
From 0e2fefe1e9d56ac1093647ed4a0cf87b4bdc1295 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 4 Jul 2023 00:04:59 -0700 Subject: [PATCH 18/45] Add arrows to change video order --- .../views/components/compilation_video.ecr | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index 0feb34ea..7a9d36e4 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -2,14 +2,25 @@
- + - +
+
+
+

<%= HTML.escape(compilation_video.title) %>

+
+
+

from

+ +

to

+ +
+
\ No newline at end of file From bfa9f77441d2c181743cf85241a06bdbf72cb97b Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Wed, 5 Jul 2023 00:26:01 -0700 Subject: [PATCH 19/45] Add margins to video panel elements --- assets/css/default.css | 58 +++++++++++++++---- .../views/components/compilation_video.ecr | 28 ++++++--- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/assets/css/default.css b/assets/css/default.css index 504329cd..b5d8cfad 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -761,16 +761,54 @@ h1, h2, h3, h4, h5, p, } div.compilation-video-panel { - padding: 28.125%; + display:flex; + justify-content:flex-start; + width:calc(100% - 20px); + height:100px; + border:1px solid #f0f0f0; + margin: 10px; + /*background: #d9d9d9;*/ +} + +div.compilation-order-swap-arrows { + display:flex; + flex-direction:column; + justify-content:space-between; +} + +svg.compilation-video-swap-arrow { + border: solid black; + width:20px; + height:50%; + background-color: beige; + margin: 10px; +} + +div.compilation-video-input-panel { + display:flex; + flex-direction:column; + min-width: 0; + margin: 10px; +} + +div.compilation-video-title { + display:flex; + justify-content:flex-start; +} + +span.compilation-video-title { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +div.compilation-video-timestamps { + display:flex; + justify-content: flex-start; +} + + +div.compilation-video-thumbnail { position: relative; box-sizing: border-box; } - -img.compilation-video-panel { - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - object-fit: cover; -} \ No newline at end of file diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index 7a9d36e4..6d6561a2 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -1,20 +1,32 @@
-
-
- +
+
+ - +
-
-
-

<%= HTML.escape(compilation_video.title) %>

+ +
+
+ <%= HTML.escape(compilation_video.title) %>
-
+

from

to

From b95a4e8432bd3897a07d2aebd4c86ab12bbb534a Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 7 Jul 2023 16:49:17 -0700 Subject: [PATCH 20/45] Use text input for timestamp --- .gitignore | 4 +++- assets/css/default.css | 11 ++++++++--- src/invidious/views/components/compilation_video.ecr | 8 ++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 2a49e68d..a2703134 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,6 @@ /invidious /sentry /config/config.yml -.DS_Store \ No newline at end of file +.DS_Store +docker-compose.yml +Dockerfile \ No newline at end of file diff --git a/assets/css/default.css b/assets/css/default.css index b5d8cfad..c238835f 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -760,12 +760,17 @@ h1, h2, h3, h4, h5, p, margin: 0 2px; } +input.compilation-video-timestamp { + width: 50px; + height: 20px; +} + div.compilation-video-panel { display:flex; justify-content:flex-start; width:calc(100% - 20px); height:100px; - border:1px solid #f0f0f0; + border:2px solid #ccc; margin: 10px; /*background: #d9d9d9;*/ } @@ -802,12 +807,12 @@ span.compilation-video-title { overflow: hidden; } -div.compilation-video-timestamps { +div.compilation-video-timestamp-set { display:flex; justify-content: flex-start; + align-items: center; } - div.compilation-video-thumbnail { position: relative; box-sizing: border-box; diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index 6d6561a2..d3722b8c 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -26,10 +26,10 @@
<%= HTML.escape(compilation_video.title) %>
-
-

from

- -

to

+
+

from

+ +

to

From 7b757aaf9c746a64857b629a2a09a2a843eb55c3 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 7 Jul 2023 17:16:35 -0700 Subject: [PATCH 21/45] Address gitignore persistence --- .gitignore | 2 +- docker-compose.yml | 16 ++++++++++++++++ .../views/components/compilation_video.ecr | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a2703134..303e1f4e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ /config/config.yml .DS_Store docker-compose.yml -Dockerfile \ No newline at end of file +docker/Dockerfile \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 6a854475..7b501566 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,7 @@ services: host: invidious-db port: 5432 check_tables: true + log_level: Info # external_port: # domain: # https_only: false @@ -53,5 +54,20 @@ services: healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + invidious-pgadmin: + image: docker.io/dpage/pgadmin4:latest + restart: unless-stopped + environment: + - PGADMIN_DEFAULT_EMAIL=******* + - PGADMIN_DEFAULT_PASSWORD=******* + - PGADMIN_DISABLE_POSTFIX=1 + - GUNICORN_ACCESS_LOGFILE=/dev/null + - GUNICORN_THREADS=1 + ports: + - "127.0.0.1:5050:80" + depends_on: + invidious-db: + condition: service_healthy + volumes: postgresdata: diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index d3722b8c..ea03603b 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -29,7 +29,7 @@

from

-

to

+

to

From ff6a9b965df399c0547ebb6e020228c3b724c1c2 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sat, 8 Jul 2023 09:23:24 -0700 Subject: [PATCH 22/45] Make the layout nice for video panels --- src/invidious/views/components/compilation_video.ecr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index ea03603b..ee586aa0 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -30,7 +30,7 @@

from

to

- +
From da290e5d6f0b8b06dcbda25c1ab0d9734a9b6f27 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 16 Jul 2023 23:22:22 -0400 Subject: [PATCH 23/45] Add timestamps to update compilation POST request --- config/sql/compilation_videos.sql | 1 + src/invidious/compilations.cr | 4 ++ src/invidious/routes/compilations.cr | 1 + src/invidious/routing.cr | 2 + .../views/components/compilation_video.ecr | 21 ++++-- src/invidious/views/edit_compilation.ecr | 67 +++++++++++++++++++ 6 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/invidious/views/edit_compilation.ecr diff --git a/config/sql/compilation_videos.sql b/config/sql/compilation_videos.sql index 91eb886c..aae5e8a1 100644 --- a/config/sql/compilation_videos.sql +++ b/config/sql/compilation_videos.sql @@ -14,6 +14,7 @@ CREATE TABLE IF NOT EXISTS public.compilation_videos published timestamptz, compid text references compilations(id), index int8, + order_index integer, PRIMARY KEY (index,compid) ); diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index b75622f3..e87a1a7a 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -11,6 +11,7 @@ struct CompilationVideo property published : Time property compid : String property index : Int64 + property order_index : Int32 def to_xml(xml : XML::Builder) xml.element("entry") do @@ -18,6 +19,7 @@ struct CompilationVideo xml.element("yt:videoId") { xml.text self.id } xml.element("yt:channelId") { xml.text self.ucid } xml.element("title") { xml.text self.title } + xml.element("orderIndex") {xml.text self.order_index } xml.element("link", rel: "alternate", href: "#{HOST_URL}/watch?v=#{self.id}") xml.element("author") do @@ -67,6 +69,7 @@ struct CompilationVideo json.field "index", self.index end + json.field "orderIndex", self.order_index json.field "lengthSeconds", self.length_seconds json.field "startingTimestampSeconds", self.starting_timestamp_seconds json.field "endingTimestampSeconds", self.ending_timestamp_seconds @@ -413,6 +416,7 @@ def extract_compilation_videos(initial_data : Hash(String, JSON::Any)) published: Time.utc, compid: compid, index: index, + order_index: order_index }) end end diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index eb459e98..253ac22e 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -340,6 +340,7 @@ module Invidious::Routes::Compilations compid: compilation_id, live_now: video.live_now, index: Random::Secure.rand(0_i64..Int64::MAX), + order_index: compilation.index.size }) Invidious::Database::CompilationVideos.insert(compilation_video) diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index ac01694d..dc7aadd8 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -87,6 +87,8 @@ module Invidious::Routing post "/create_compilation", Routes::Compilations, :create post "/compilation_ajax", Routes::Compilations, :compilation_ajax get "/add_compilation_items", Routes::Compilations, :add_compilation_items_page + get "/edit_compilation", Routes::Compilations, :edit + post "/edit_compilation", Routes::Compilations, :update end def register_iv_playlist_routes diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index ee586aa0..84dafc2a 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -26,12 +26,21 @@
<%= HTML.escape(compilation_video.title) %>
-
-

from

- -

to

- -
+ <% if compid_form = env.get?("remove_compilation_items") %> +
+

from

+ +

to

+ +
+ <% else %> +
+

from

+ +

to

+ +
+ <% end %>
diff --git a/src/invidious/views/edit_compilation.ecr b/src/invidious/views/edit_compilation.ecr new file mode 100644 index 00000000..d3b85ea0 --- /dev/null +++ b/src/invidious/views/edit_compilation.ecr @@ -0,0 +1,67 @@ +<% title = HTML.escape(compilation.title) %> + +<% content_for "header" do %> +<%= title %> - Invidious +<% end %> + + +
+
+

+ + <%= HTML.escape(compilation.author) %> | + <%= translate_count(locale, "generic_videos_count", compilation.video_count) %> | + <%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %> | + "> + + +
+
+

+
+ +
+
+

+
+
+ + + + + <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> +
+

+ +

+
+ <% end %> + +
+
+
+ +
+ <% videos.each do |compilation_video| %> + <%= rendered "components/compilation_video" %> + <% end %> +
+ + + + + + + From be42dd0a4b0a5ffd5c2e94e7a6ad8d854da65f27 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Mon, 17 Jul 2023 00:24:27 -0400 Subject: [PATCH 24/45] Redo conflict resolution --- assets/css/default.css | 4 + src/invidious/views/components/item.ecr | 135 ++++++++---------------- 2 files changed, 46 insertions(+), 93 deletions(-) diff --git a/assets/css/default.css b/assets/css/default.css index c238835f..910a8fed 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -760,6 +760,10 @@ h1, h2, h3, h4, h5, p, margin: 0 2px; } +/* + * Compilations + */ + input.compilation-video-timestamp { width: 50px; height: 20px; diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 57115b8f..b0f50fe2 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -87,93 +87,6 @@

- <% when InvidiousCompilation %> - <% url = "/compilation?list=#{item.id}" %> - - <% if !env.get("preferences").as(Preferences).thin_mode %> -
- " alt="" /> -

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

-
- <% end %> -

<%= HTML.escape(item.title) %>

-
- -

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

-
- <% when CompilationVideo %> -
- -
- <% when PlaylistVideo %> - - <% if !env.get("preferences").as(Preferences).thin_mode %> -
- - - <% if plid_form = env.get?("remove_playlist_items") %> -
" method="post"> - "> -

- -

-
- <% end %> - - <% if item.responds_to?(:live_now) && item.live_now %> -

<%= translate(locale, "LIVE") %>

- <% elsif item.length_seconds != 0 %> -

<%= recode_length_seconds(item.length_seconds) %>

- <% end %> - - <% if item_watched %> -
-
- <% end %> -
- <% end %> -

<%= HTML.escape(item.title) %>

-
- -
- - <% endpoint_params = "?v=#{item.id}&list=#{item.plid}" %> - <%= rendered "components/video-context-buttons" %> -
- -
-
- <% if item.responds_to?(:premiere_timestamp) && item.premiere_timestamp.try &.> Time.utc %> -

<%= translate(locale, "Premieres in `x`", recode_date((item.premiere_timestamp.as(Time) - Time.utc).ago, locale)) %>

- <% elsif Time.utc - item.published > 1.minute %> -

<%= translate(locale, "Shared `x` ago", recode_date(item.published, locale)) %>

- <% end %> -
- - <% if item.responds_to?(:views) && item.views %> -
-

<%= translate_count(locale, "generic_views_count", item.views || 0, NumberFormatting::Short) %>

-
- <% end %> -
<% when Category %> <% else %> <%- @@ -184,6 +97,42 @@ elsif item.is_a?(MixVideo) link_url = "/watch?v=#{item.id}&list=#{item.rdid}" endpoint_params = "?v=#{item.id}&list=#{item.rdid}" + elsif item.is_a?(InvidiousCompilation) + <% when InvidiousCompilation %> + <% url = "/compilation?list=#{item.id}" %> + + <% if !env.get("preferences").as(Preferences).thin_mode %> +
+ " alt="" /> +

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

+
+ <% end %> +

<%= HTML.escape(item.title) %>

+ elsif item.is_a?(CompilationVideo) + <% when CompilationVideo %> +
+ +
+
+ +

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

+
else link_url = "/watch?v=#{item.id}" endpoint_params = "?v=#{item.id}" @@ -223,12 +172,12 @@ data-onclick="add_playlist_item" data-id="<%= item.id %>" data-plid="<%= plid_form %>"> <% elsif compid_form = env.get? "add_compilation_items" %> -
" method="post"> - "> -

- -

-
+
" method="post"> + "> +

+ +

+
<%- elsif item.is_a?(PlaylistVideo) && (plid_form = env.get?("remove_playlist_items")) -%> <%- form_parameters = "action_remove_video=1&set_video_id=#{item.index}&playlist_id=#{plid_form}&referer=#{env.get("current_page")}" -%>
From 60a184eda35330942c5512d3b08aac82013ad451 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 18 Jul 2023 20:16:40 -0700 Subject: [PATCH 25/45] Add timestamp DB handling --- src/invidious/database/compilations.cr | 11 +++++ src/invidious/routes/compilations.cr | 58 +++++++++++++++++++++++++ src/invidious/routing.cr | 2 +- src/invidious/views/components/item.ecr | 51 +++++++--------------- 4 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index a3372ac7..b5bf8bf3 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -248,4 +248,15 @@ module Invidious::Database::CompilationVideos return PG_DB.query_all(request, compid, index, limit, as: String) end + + # ------------------- + # Update + # ------------------- + + def update_start_timestamp(compid : String, index : VideoIndex, starting_timestamp_seconds : Int64) + request = <<-SQL + UPDATE compilation_videos + SET starting_timestamp_seconds = starting_timestamp_seconds + WHERE id = $2 + end end diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 253ac22e..a76e72b5 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -196,6 +196,63 @@ module Invidious::Routes::Compilations env.redirect "/compilation?list=#{compid}" end + def self.adjust_timestamps(env) + LOGGER.info("Handle POST request for edit compilation") + env.response.content_type = "application/json" + user = env.get("user").as(User) + + compid = env.params.url["compid"]? + if !compid || compid.empty? + return error_json(400, "A compilation ID is required") + end + + compilation = Invidious::Database::Compilations.select(id: compid) + if !compilation || compilation.author != user.email && compilation.privacy.private? + return error_json(404, "Compilation does not exist.") + end + + if compilation.author != user.email + return error_json(403, "Invalid user") + end + + title = env.params.json["title"].try &.as(String).delete("<>").byte_slice(0, 150) || compilation.title + privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } || compilation.privacy + + if title != compilation.title || + privacy != compilation.privacy + updated = Time.utc + else + updated = compilation.updated + end + + {1...Invidious::Database::Compilations.count_owned_by(user.email)} each do |index| + start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title + + (1..Invidious::Database::Compilations.count_owned_by(user.email)).each do |index| { + compilation_video = Invidious::Database::CompilationVideos.select(order_index: index) + start_timestamp = env.params.json[index+"_start_timestamp"]?.try &.as(String).byte_slice(0, 8) + if !start_timestamp.empty? + start_timestamp_seconds = decode_length_seconds(start_timestamp) + if !start_timestamp_seconds.empty + if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video + Invidious::Database::CompilationVideos.update_start_timestamp(compid, compilation_video.index, start_timestamp_seconds) + end + end + end + + end_timestamp = env.params.json[index+"_end_timestamp"]?.try &.as(String).byte_slice(0, 8) + if !end_timestamp.empty? + end_timestamp_seconds = decode_length_seconds(end_timestamp) + if !end_timestamp_seconds.empty + if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video + Invidious::Database::CompilationVideos.update_end_timestamp(compid, compilation_video.index, end_timestamp_seconds) + end + end + end + } + + + def self.add_compilation_items_page(env) LOGGER.info("13. add_compilation_items") prefs = env.get("preferences").as(Preferences) @@ -305,6 +362,7 @@ module Invidious::Routes::Compilations case action when "action_edit_compilation" # TODO: Compilation stub + LOGGER.info("Begin handling of Compilation edit") when "action_add_video" if compilation.index.size >= CONFIG.compilation_length_limit if redirect diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index dc7aadd8..b5cb0527 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -88,7 +88,7 @@ module Invidious::Routing post "/compilation_ajax", Routes::Compilations, :compilation_ajax get "/add_compilation_items", Routes::Compilations, :add_compilation_items_page get "/edit_compilation", Routes::Compilations, :edit - post "/edit_compilation", Routes::Compilations, :update + post "/edit_compilation", Routes::Compilations, :adjust_timestamps end def register_iv_playlist_routes diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index b0f50fe2..63f44e8c 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -87,6 +87,20 @@

+ <% when InvidiousCompilation %> + <% link_url = "/compilation?list=#{item.id}" %> + + <% if !env.get("preferences").as(Preferences).thin_mode %> +
+ " alt="" /> +

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

+
+ <% end %> +

<%= HTML.escape(item.title) %>

+
+ +

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

+
<% when Category %> <% else %> <%- @@ -97,42 +111,7 @@ elsif item.is_a?(MixVideo) link_url = "/watch?v=#{item.id}&list=#{item.rdid}" endpoint_params = "?v=#{item.id}&list=#{item.rdid}" - elsif item.is_a?(InvidiousCompilation) - <% when InvidiousCompilation %> - <% url = "/compilation?list=#{item.id}" %> - - <% if !env.get("preferences").as(Preferences).thin_mode %> -
- " alt="" /> -

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

-
- <% end %> -

<%= HTML.escape(item.title) %>

- elsif item.is_a?(CompilationVideo) - <% when CompilationVideo %> -
- -
-
- -

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

-
+ # elsif item.is_a?(CompilationVideo) else link_url = "/watch?v=#{item.id}" endpoint_params = "?v=#{item.id}" From ea878e22a162afd800042b5fd138157e5fa1ffd1 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 23 Jul 2023 12:39:47 -0700 Subject: [PATCH 26/45] Debug the DB methods for compilations --- src/invidious/database/compilations.cr | 37 ++++++++++++++++++++++-- src/invidious/routes/compilations.cr | 38 ++++++++++++++----------- src/invidious/views/components/item.ecr | 16 +---------- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index b5bf8bf3..babe59bc 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -217,6 +217,26 @@ module Invidious::Database::CompilationVideos return PG_DB.query_all(request, compid, index, limit, offset, as: CompilationVideo) end + def select_id_from_order_index(order_index : Int32) + request = <<-SQL + SELECT id FROM compilation_videos + WHERE order_index = $1 + LIMIT 1 + SQL + + return PG_DB.query_one?(request, order_index, as: String) + end + + def select_index_from_order_index(order_index : Int32) + request = <<-SQL + SELECT index FROM compilation_videos + WHERE order_index = $1 + LIMIT 1 + SQL + + return PG_DB.query_one?(request, order_index, as: VideoIndex) + end + def select_index(compid : String, vid : String) : Int64? request = <<-SQL SELECT index FROM compilation_videos @@ -253,10 +273,23 @@ module Invidious::Database::CompilationVideos # Update # ------------------- - def update_start_timestamp(compid : String, index : VideoIndex, starting_timestamp_seconds : Int64) + def update_start_timestamp(id : String, starting_timestamp_seconds : Int32) request = <<-SQL UPDATE compilation_videos SET starting_timestamp_seconds = starting_timestamp_seconds - WHERE id = $2 + WHERE id = $1 + SQL + + PG_DB.exec(request, id) + end + + def update_end_timestamp(id : String, ending_timestamp_seconds : Int64) + request = <<-SQL + UPDATE compilation_videos + SET ending_timestamp_seconds = ending_timestamp_seconds + WHERE id = $1 + SQL + + PG_DB.exec(request, id) end end diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index a76e72b5..3171bebc 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -225,33 +225,39 @@ module Invidious::Routes::Compilations updated = compilation.updated end - {1...Invidious::Database::Compilations.count_owned_by(user.email)} each do |index| - start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title + #{1...Invidious::Database::Compilations.count_owned_by(user.email)}.each do |index| + # start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title - (1..Invidious::Database::Compilations.count_owned_by(user.email)).each do |index| { - compilation_video = Invidious::Database::CompilationVideos.select(order_index: index) - start_timestamp = env.params.json[index+"_start_timestamp"]?.try &.as(String).byte_slice(0, 8) - if !start_timestamp.empty? + (0..Invidious::Database::Compilations.count_owned_by(user.email)).each do |index| + compilation_video_id = Invidious::Database::CompilationVideos.select_id_from_order_index(order_index: index) + #compilation_video_index = Invidious::Database::CompilationVideos.select_index_from_order_index(order_index: index) + compilation_video = Invidious::Database::CompilationVideos.select(compid, compilation.index, 0, 1) + #numerical_string = index.to + json_timestamp_query = index.to_s + "_start_timestamp" + start_timestamp = env.params.json[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) + if !start_timestamp.nil? && !compilation_video_id.nil? start_timestamp_seconds = decode_length_seconds(start_timestamp) - if !start_timestamp_seconds.empty - if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video - Invidious::Database::CompilationVideos.update_start_timestamp(compid, compilation_video.index, start_timestamp_seconds) + if !start_timestamp_seconds.nil? + if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].starting_timestamp_seconds + Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video_id, start_timestamp_seconds) end end end - end_timestamp = env.params.json[index+"_end_timestamp"]?.try &.as(String).byte_slice(0, 8) - if !end_timestamp.empty? + json_timestamp_query = index.to_s + "_end_timestamp" + end_timestamp = env.params.json[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) + if !end_timestamp.nil? && !compilation_video_id.nil? end_timestamp_seconds = decode_length_seconds(end_timestamp) - if !end_timestamp_seconds.empty - if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video - Invidious::Database::CompilationVideos.update_end_timestamp(compid, compilation_video.index, end_timestamp_seconds) + if !end_timestamp_seconds.nil? + if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video[0].ending_timestamp_seconds + Invidious::Database::CompilationVideos.update_end_timestamp(compilation_video_id, end_timestamp_seconds) end end end - } - + end + end + def self.add_compilation_items_page(env) LOGGER.info("13. add_compilation_items") diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 63f44e8c..4a9bacb3 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -53,7 +53,7 @@

<%= translate_count(locale, "generic_channels_count", item.channel_count, NumberFormatting::Separator) %>

<%- end -%> - <% when SearchPlaylist, InvidiousPlaylist %> + <% when SearchPlaylist, InvidiousPlaylist, InvidiousCompilation %> <%- if item.id.starts_with? "RD" link_url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" @@ -87,20 +87,6 @@

- <% when InvidiousCompilation %> - <% link_url = "/compilation?list=#{item.id}" %> - - <% if !env.get("preferences").as(Preferences).thin_mode %> -
- " alt="" /> -

<%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %>

-
- <% end %> -

<%= HTML.escape(item.title) %>

-
- -

<%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <% end %>

-
<% when Category %> <% else %> <%- From a8c0023eb08676ab01141231fc04135a9052aa3a Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 23 Jul 2023 21:45:00 -0700 Subject: [PATCH 27/45] Debug SQL query for timestamp adjustment --- src/invidious/database/compilations.cr | 4 +-- src/invidious/routes/compilations.cr | 35 ++++++++++++++++--------- src/invidious/views/components/item.ecr | 2 +- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index babe59bc..c8da9cfa 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -276,11 +276,11 @@ module Invidious::Database::CompilationVideos def update_start_timestamp(id : String, starting_timestamp_seconds : Int32) request = <<-SQL UPDATE compilation_videos - SET starting_timestamp_seconds = starting_timestamp_seconds + SET starting_timestamp_seconds = $2 WHERE id = $1 SQL - PG_DB.exec(request, id) + PG_DB.exec(request, id, starting_timestamp_seconds) end def update_end_timestamp(id : String, ending_timestamp_seconds : Int64) diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 3171bebc..4e9e72bb 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -201,7 +201,7 @@ module Invidious::Routes::Compilations env.response.content_type = "application/json" user = env.get("user").as(User) - compid = env.params.url["compid"]? + compid = env.params.query["list"]? if !compid || compid.empty? return error_json(400, "A compilation ID is required") end @@ -215,31 +215,37 @@ module Invidious::Routes::Compilations return error_json(403, "Invalid user") end - title = env.params.json["title"].try &.as(String).delete("<>").byte_slice(0, 150) || compilation.title - privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } || compilation.privacy + #title = env.params.json["title"].try &.as(String).delete("<>").byte_slice(0, 150) || compilation.title + #privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } || compilation.privacy - if title != compilation.title || - privacy != compilation.privacy - updated = Time.utc - else - updated = compilation.updated - end + #if title != compilation.title || + # privacy != compilation.privacy + # updated = Time.utc + #else + # updated = compilation.updated + #end #{1...Invidious::Database::Compilations.count_owned_by(user.email)}.each do |index| # start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title + compilation_video_cardinality = Invidious::Database::CompilationVideos.select_ids(compid, compilation.index).size - (0..Invidious::Database::Compilations.count_owned_by(user.email)).each do |index| + (0..compilation_video_cardinality-1).each do |index| + LOGGER.info("for loop cycle #{index} of #{Invidious::Database::Compilations.count_owned_by(user.email)}") compilation_video_id = Invidious::Database::CompilationVideos.select_id_from_order_index(order_index: index) #compilation_video_index = Invidious::Database::CompilationVideos.select_index_from_order_index(order_index: index) compilation_video = Invidious::Database::CompilationVideos.select(compid, compilation.index, 0, 1) #numerical_string = index.to json_timestamp_query = index.to_s + "_start_timestamp" - start_timestamp = env.params.json[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) + LOGGER.info("adjust #{json_timestamp_query} ") + start_timestamp = env.params.body[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) + LOGGER.info("render #{env.params.body[json_timestamp_query]} ") if !start_timestamp.nil? && !compilation_video_id.nil? + LOGGER.info("adjust #{json_timestamp_query} which renders as #{start_timestamp}") start_timestamp_seconds = decode_length_seconds(start_timestamp) if !start_timestamp_seconds.nil? - if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].starting_timestamp_seconds - Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video_id, start_timestamp_seconds) + if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].length_seconds + LOGGER.info("adjusting timestamps to #{start_timestamp_seconds} which is #{start_timestamp_seconds.to_i}") + Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video_id, start_timestamp_seconds.to_i) end end end @@ -256,6 +262,8 @@ module Invidious::Routes::Compilations end end + + env.redirect "/compilation?list=#{compid}" end @@ -369,6 +377,7 @@ module Invidious::Routes::Compilations when "action_edit_compilation" # TODO: Compilation stub LOGGER.info("Begin handling of Compilation edit") + when "action_add_video" if compilation.index.size >= CONFIG.compilation_length_limit if redirect diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 4a9bacb3..163ebc11 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -58,7 +58,7 @@ if item.id.starts_with? "RD" link_url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" else - link_url = "/playlist?list=#{item.id}" + link_url = "/compilation?list=#{item.id}" end -%> From 890802481b6241dbd367adfb70922ecc358c1efb Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Mon, 24 Jul 2023 01:22:34 -0700 Subject: [PATCH 28/45] Use ion for arrow swap icons --- assets/js/compilation_widget.js | 15 ++++ locales/en-US.json | 3 + src/invidious/compilations.cr | 4 +- src/invidious/routes/compilations.cr | 31 ++++++- src/invidious/views/compilation.ecr | 81 +++++++++---------- .../views/components/compilation_video.ecr | 25 ++++-- src/invidious/views/components/item.ecr | 4 +- src/invidious/views/edit_compilation.ecr | 69 ++++++++-------- 8 files changed, 142 insertions(+), 90 deletions(-) diff --git a/assets/js/compilation_widget.js b/assets/js/compilation_widget.js index 7e8e6356..16ace89e 100644 --- a/assets/js/compilation_widget.js +++ b/assets/js/compilation_widget.js @@ -46,3 +46,18 @@ function remove_compilation_item(target) { } }); } + +function move_compilation_video_before(target) { + var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode; + tile.style.display = 'none'; + + var url = '/compilation_ajax?action_move_video_before=1&redirect=false' + + '&set_video_id=' + target.getAttribute('data-index') + + '&compilation_id=' + target.getAttribute('data-compid'); + + helpers.xhr('POST', url, {payload: payload}, { + onNon200: function (xhr) { + tile.style.display = ''; + } + }); +} diff --git a/locales/en-US.json b/locales/en-US.json index 3905de6e..73fbd177 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -179,7 +179,10 @@ "Playlist privacy": "Playlist privacy", "Compilation privacy": "Compilation privacy", "Editing playlist `x`": "Editing playlist `x`", + "Editing compilation `x`": "Editing compilation `x`", "playlist_button_add_items": "Add videos", + "compilation_button_add_items": "Add videos", + "compilation_button_play": "Play", "Show more": "Show more", "Show less": "Show less", "Watch on YouTube": "Watch on YouTube", diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index e87a1a7a..bf532ac9 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -244,7 +244,7 @@ end def create_compilation(title, privacy, user) LOGGER.info("2. create_compilation") - compid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" + compid = "IVCMP#{Random::Secure.urlsafe_base64(24)[0, 31]}" LOGGER.info("generated compilation id") compilation = InvidiousCompilation.new({ @@ -320,7 +320,7 @@ def produce_compilation_continuation(id, index) end def get_compilation(compid : String) - #if compid.starts_with? "IV" + #if compid.starts_with? "IVCMP" if compilation = Invidious::Database::Compilations.select(id: compid) return compilation else diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 4e9e72bb..90ccb2e1 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -197,11 +197,31 @@ module Invidious::Routes::Compilations end def self.adjust_timestamps(env) + locale = env.get("preferences").as(Preferences).locale LOGGER.info("Handle POST request for edit compilation") env.response.content_type = "application/json" - user = env.get("user").as(User) + user = env.get("user") + sid = env.get? "sid" + + referer = get_referer(env) + + return env.redirect "/" if user.nil? compid = env.params.query["list"]? + return env.redirect referer if compid.nil? + + user = user.as(User) + + sid = sid.as(String) + token = env.params.body["csrf_token"]? + + begin + validate_request(token, sid, env.request, HMAC_KEY, locale) + rescue ex + return error_template(400, ex) + end + + if !compid || compid.empty? return error_json(400, "A compilation ID is required") end @@ -215,6 +235,9 @@ module Invidious::Routes::Compilations return error_json(403, "Invalid user") end + title = env.params.body["title"]?.try &.delete("<>") || "" + privacy = CompilationPrivacy.parse(env.params.body["privacy"]? || "Private") + #title = env.params.json["title"].try &.as(String).delete("<>").byte_slice(0, 150) || compilation.title #privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } || compilation.privacy @@ -225,6 +248,8 @@ module Invidious::Routes::Compilations # updated = compilation.updated #end + Invidious::Database::Compilations.update(compid, title, privacy, "", compilation.updated) + #{1...Invidious::Database::Compilations.count_owned_by(user.email)}.each do |index| # start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title compilation_video_cardinality = Invidious::Database::CompilationVideos.select_ids(compid, compilation.index).size @@ -238,7 +263,7 @@ module Invidious::Routes::Compilations json_timestamp_query = index.to_s + "_start_timestamp" LOGGER.info("adjust #{json_timestamp_query} ") start_timestamp = env.params.body[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) - LOGGER.info("render #{env.params.body[json_timestamp_query]} ") + LOGGER.info("render #{env.params.body[json_timestamp_query]?} ") if !start_timestamp.nil? && !compilation_video_id.nil? LOGGER.info("adjust #{json_timestamp_query} which renders as #{start_timestamp}") start_timestamp_seconds = decode_length_seconds(start_timestamp) @@ -353,6 +378,8 @@ module Invidious::Routes::Compilations action = "action_remove_video" elsif env.params.query["action_move_video_before"]? action = "action_move_video_before" + elsif env.params.query["action_move_video_after"]? + action = "action_move_video_after" else return env.redirect referer end diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index 6bcd7d0f..2520dc0c 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -6,9 +6,43 @@ <% end %> + +
-
-

<%= title %>

+
<% if compilation.is_a? InvidiousCompilation %> <% if compilation.author == user.try &.email %> @@ -33,35 +67,12 @@ <% end %>
-
-

-
- <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> -
-
- <% else %> - <% if !Invidious::Database::Compilations.exists?(compilation.id) %> -
- <% end %> - <% end %> -
-
-

-
<%= compilation.description_html %>
-<% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> -
-

- -

-
-<% end %> -

@@ -82,23 +93,3 @@ <%= rendered "components/compilation_video" %> <% end %>
- - - -
-
- <% if page > 1 %> - - <%= translate(locale, "Previous page") %> - - <% end %> -
-
-
- <% if page_count != 1 && page < page_count %> - - <%= translate(locale, "Next page") %> - - <% end %> -
-
\ No newline at end of file diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index 84dafc2a..b30d6a2e 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -2,12 +2,25 @@
- - - - - - + <%- form_parameters = "action_move_video_before=1&set_video_id=#{compilation_video.index}&compilation_id=#{compilation_video.compid}&referer=#{env.get("current_page")}" -%> + + "> + + + <%- form_parameters = "action_move_video_after=1&set_video_id=#{compilation_video.index}&compilation_id=#{compilation_video.compid}&referer=#{env.get("current_page")}" -%> +
+ "> + +
- <% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %> -
-

- -

-
- <% end %> -

@@ -65,3 +64,5 @@ + + From 0211d69f117cd2c97343005832aa451143525a1d Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Mon, 24 Jul 2023 23:23:29 -0700 Subject: [PATCH 29/45] Enable swap arrows to rearrange order of videos --- src/invidious/database/compilations.cr | 22 +++++++++++++++++++ src/invidious/routes/compilations.cr | 22 +++++++++++++++++++ .../views/components/compilation_video.ecr | 10 +++------ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index c8da9cfa..29c6987f 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -80,6 +80,16 @@ module Invidious::Database::Compilations PG_DB.exec(request, index, id) end + def move_video_before(id : String, index : Array(Int64)) + request = <<-SQL + UPDATE compilations + SET index = $2 + WHERE id = $1 + SQL + + PG_DB.exec(request, id, index) + end + # ------------------- # Select # ------------------- @@ -217,6 +227,18 @@ module Invidious::Database::CompilationVideos return PG_DB.query_all(request, compid, index, limit, offset, as: CompilationVideo) end + def select_video(compid : String, index : VideoIndex, video_index, offset, limit = 100) : Array(CompilationVideo) + request = <<-SQL + SELECT * FROM compilation_videos + WHERE compid = $1 AND index = $3 + ORDER BY array_position($2, index) + LIMIT $5 + OFFSET $4 + SQL + + return PG_DB.query_all(request, compid, index, video_index, offset, limit, as: CompilationVideo) + end + def select_id_from_order_index(order_index : Int32) request = <<-SQL SELECT id FROM compilation_videos diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 90ccb2e1..7add2bf6 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -451,6 +451,28 @@ module Invidious::Routes::Compilations Invidious::Database::Compilations.update_video_removed(compilation_id, index) when "action_move_video_before" # TODO: Compilation stub + #video_index = compilation.index + video_index = env.params.query["video_index"] + begin + #video_index = get_video(video_index) + compilation_video = Invidious::Database::CompilationVideos.select_video(compilation_id, compilation.index, video_index, 0, 1) + compilation_index_array = compilation.index + rescue ex : NotFoundException + return error_json(404, ex) + rescue ex + if redirect + return error_template(500, ex) + else + return error_json(500, ex) + end + end + compilation_index_array_position = compilation_index_array.index(compilation_video[0].index) + LOGGER.info("for #{compilation_index_array}, the item #{compilation_video[0].index} is a position #{compilation_index_array.index(compilation_video[0].index)}") + if !compilation_index_array_position.nil? + compilation_index_array.delete_at(compilation_index_array_position) + compilation_index_array.insert(compilation_index_array_position-1,compilation_video[0].index) + Invidious::Database::Compilations.move_video_before(compilation_id, compilation_index_array) + end else return error_json(400, "Unsupported action #{action}") end diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index b30d6a2e..c291e0c9 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -2,14 +2,10 @@
- <%- form_parameters = "action_move_video_before=1&set_video_id=#{compilation_video.index}&compilation_id=#{compilation_video.compid}&referer=#{env.get("current_page")}" -%> -
+ <%- form_parameters = "action_move_video_before=1&video_index=#{compilation_video.index}&compilation_id=#{compilation_video.compid}" -%> + "> -
From f05d38aa8e147a53852806fc95a7f75ad8dc6fd5 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 3 Aug 2023 00:37:21 -0700 Subject: [PATCH 30/45] Prevent autoplay breakage by vetting each change from top to compilation_video.ecr --- config/sql/compilations.sql | 3 +- locales/en-US.json | 1 + src/invidious/compilations.cr | 53 ++++++++++++------- src/invidious/database/compilations.cr | 29 ++++++++++ .../0011_create_compilations_table.cr | 3 +- src/invidious/routes/compilations.cr | 51 ++++++------------ src/invidious/routes/watch.cr | 9 +++- src/invidious/videos.cr | 4 +- src/invidious/views/compilation.ecr | 12 +++-- .../views/components/compilation_video.ecr | 8 +-- 10 files changed, 106 insertions(+), 67 deletions(-) diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql index 95d2d0af..5802c9a8 100644 --- a/config/sql/compilations.sql +++ b/config/sql/compilations.sql @@ -22,7 +22,8 @@ CREATE TABLE IF NOT EXISTS public.compilations created timestamptz, updated timestamptz, privacy compilation_privacy, - index int8[] + index int8[], + first_video_id text ); GRANT ALL ON public.compilations TO current_user; diff --git a/locales/en-US.json b/locales/en-US.json index 73fbd177..f34089aa 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -244,6 +244,7 @@ "Not a playlist.": "Not a playlist.", "Playlist does not exist.": "Playlist does not exist.", "Could not pull trending pages.": "Could not pull trending pages.", + "Compilation does not exist.": "Compilation does not exist.", "Hidden field \"challenge\" is a required field": "Hidden field \"challenge\" is a required field", "Hidden field \"token\" is a required field": "Hidden field \"token\" is a required field", "Erroneous challenge": "Erroneous challenge", diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index bf532ac9..5710e6b2 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -95,6 +95,7 @@ struct Compilation property views : Int64 property updated : Time property thumbnail : String? + property first_video_id : String def to_json(offset, json : JSON::Builder, video_id : String? = nil) json.object do @@ -169,6 +170,7 @@ struct InvidiousCompilation @[DB::Field(converter: InvidiousCompilation::CompilationPrivacyConverter)] property privacy : CompilationPrivacy = CompilationPrivacy::Private property index : Array(Int64) + property first_video_id : String @[DB::Field(ignore: true)] property thumbnail_id : String? @@ -248,15 +250,16 @@ def create_compilation(title, privacy, user) LOGGER.info("generated compilation id") compilation = InvidiousCompilation.new({ - title: title.byte_slice(0, 150), - id: compid, - author: user.email, - description: "", # Max 5000 characters - video_count: 0, - created: Time.utc, - updated: Time.utc, - privacy: privacy, - index: [] of Int64, + title: title.byte_slice(0, 150), + id: compid, + author: user.email, + description: "", # Max 5000 characters + video_count: 0, + created: Time.utc, + updated: Time.utc, + privacy: privacy, + index: [] of Int64, + first_video_id: "" }) LOGGER.info("Creating compilation db") @@ -268,15 +271,16 @@ end def subscribe_compilation(user, compilation) compilation = InvidiousCompilation.new({ - title: compilation.title.byte_slice(0, 150), - id: compilation.id, - author: user.email, - description: "", # Max 5000 characters - video_count: compilation.video_count, - created: Time.utc, - updated: compilation.updated, - privacy: CompilationPrivacy::Private, - index: [] of Int64, + title: compilation.title.byte_slice(0, 150), + id: compilation.id, + author: user.email, + description: "", # Max 5000 characters + video_count: compilation.video_count, + created: Time.utc, + updated: compilation.updated, + privacy: CompilationPrivacy::Private, + index: [] of Int64, + first_video_id: "" }) Invidious::Database::Compilations.insert(compilation) @@ -329,6 +333,19 @@ def get_compilation(compid : String) #end end +def update_first_video_id(compid : String) + if compilation = Invidious::Database::Compilations.select(id: compid) + compilation_index_array = compilation.index + first_index = compilation_index_array[0] + first_id = Invidious::Database::CompilationVideos.select_id_from_index(first_index) + if !first_id.nil? + Invidious::Database::Compilations.update_first_video_id(compid, first_id) + end + else + raise NotFoundException.new("Compilation does not exist.") + end +end + def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) LOGGER.info("1. get_compilation") LOGGER.info("Getting compilation") diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 29c6987f..daf597b0 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -90,6 +90,15 @@ module Invidious::Database::Compilations PG_DB.exec(request, id, index) end + def update_first_video_id(id : String, first_video_id : String) + request = <<-SQL + UPDATE compilations + SET first_video_id = $2 + WHERE id = $1 + SQL + + PG_DB.exec(request, id, first_video_id) + end # ------------------- # Select # ------------------- @@ -112,6 +121,16 @@ module Invidious::Database::Compilations return PG_DB.query_all(request, author, as: InvidiousCompilation) end + def select_index_array(id : String) + request = <<-SQL + SELECT index FROM compilations + WHERE id = $1 + LIMIT 1 + SQL + + PG_DB.query_one?(request, id, as: String) + end + # ------------------- # Select (filtered) # ------------------- @@ -249,6 +268,16 @@ module Invidious::Database::CompilationVideos return PG_DB.query_one?(request, order_index, as: String) end + def select_id_from_index(index : Int64) + request = <<-SQL + SELECT id FROM compilation_videos + WHERE index = $1 + LIMIT 1 + SQL + + return PG_DB.query_one?(request, index, as: String) + end + def select_index_from_order_index(order_index : Int32) request = <<-SQL SELECT index FROM compilation_videos diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr index 30404183..4bf5a814 100644 --- a/src/invidious/database/migrations/0011_create_compilations_table.cr +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -24,7 +24,8 @@ module Invidious::Database::Migrations created timestamptz, updated timestamptz, privacy compilation_privacy, - index int8[] + index int8[], + first_video_id text ); SQL diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 7add2bf6..c592eb70 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -129,7 +129,7 @@ module Invidious::Routes::Compilations sid = sid.as(String) compid = env.params.query["list"]? - if !compid || !compid.starts_with?("IV") + if !compid || !compid.starts_with?("IVCMP") return env.redirect referer end @@ -238,50 +238,30 @@ module Invidious::Routes::Compilations title = env.params.body["title"]?.try &.delete("<>") || "" privacy = CompilationPrivacy.parse(env.params.body["privacy"]? || "Private") - #title = env.params.json["title"].try &.as(String).delete("<>").byte_slice(0, 150) || compilation.title - #privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } || compilation.privacy - - #if title != compilation.title || - # privacy != compilation.privacy - # updated = Time.utc - #else - # updated = compilation.updated - #end - Invidious::Database::Compilations.update(compid, title, privacy, "", compilation.updated) - #{1...Invidious::Database::Compilations.count_owned_by(user.email)}.each do |index| - # start_timestamp = env.params.json["_start_timestamp"]?.try &.as(String).byte_slice(0, 150) || compilation.title - compilation_video_cardinality = Invidious::Database::CompilationVideos.select_ids(compid, compilation.index).size + (0..compilation.index.size - 1).each do |index| + compilation_video_index = compilation.index[index] + compilation_video = Invidious::Database::CompilationVideos.select_video(compid, compilation.index, compilation_video_index, 0, 1) + json_timestamp_query_start = compilation_video_index.to_s + "_start_timestamp" - (0..compilation_video_cardinality-1).each do |index| - LOGGER.info("for loop cycle #{index} of #{Invidious::Database::Compilations.count_owned_by(user.email)}") - compilation_video_id = Invidious::Database::CompilationVideos.select_id_from_order_index(order_index: index) - #compilation_video_index = Invidious::Database::CompilationVideos.select_index_from_order_index(order_index: index) - compilation_video = Invidious::Database::CompilationVideos.select(compid, compilation.index, 0, 1) - #numerical_string = index.to - json_timestamp_query = index.to_s + "_start_timestamp" - LOGGER.info("adjust #{json_timestamp_query} ") - start_timestamp = env.params.body[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) - LOGGER.info("render #{env.params.body[json_timestamp_query]?} ") - if !start_timestamp.nil? && !compilation_video_id.nil? - LOGGER.info("adjust #{json_timestamp_query} which renders as #{start_timestamp}") + start_timestamp = env.params.body[json_timestamp_query_start]?.try &.as(String).byte_slice(0, 8) + if !start_timestamp.nil? && !compilation_video[0].id.nil? start_timestamp_seconds = decode_length_seconds(start_timestamp) if !start_timestamp_seconds.nil? if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].length_seconds - LOGGER.info("adjusting timestamps to #{start_timestamp_seconds} which is #{start_timestamp_seconds.to_i}") - Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video_id, start_timestamp_seconds.to_i) + Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video[0].id, start_timestamp_seconds.to_i) end end end - json_timestamp_query = index.to_s + "_end_timestamp" - end_timestamp = env.params.json[json_timestamp_query]?.try &.as(String).byte_slice(0, 8) - if !end_timestamp.nil? && !compilation_video_id.nil? + json_timestamp_query_end = compilation_video_index.to_s + "_end_timestamp" + end_timestamp = env.params.json[json_timestamp_query_end]?.try &.as(String).byte_slice(0, 8) + if !end_timestamp.nil? && !compilation_video[0].id.nil? end_timestamp_seconds = decode_length_seconds(end_timestamp) if !end_timestamp_seconds.nil? - if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video[0].ending_timestamp_seconds - Invidious::Database::CompilationVideos.update_end_timestamp(compilation_video_id, end_timestamp_seconds) + if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video[0].ending_timestamp_seconds && end_timestamp_seconds > compilation_video[0].starting_timestamp_seconds + Invidious::Database::CompilationVideos.update_end_timestamp(compilation_video[0].id, end_timestamp_seconds) end end end @@ -309,7 +289,7 @@ module Invidious::Routes::Compilations sid = sid.as(String) compid = env.params.query["list"]? - if !compid || !compid.starts_with?("IV") + if !compid || !compid.starts_with?("IVCMP") return env.redirect referer end @@ -445,10 +425,12 @@ module Invidious::Routes::Compilations Invidious::Database::CompilationVideos.insert(compilation_video) Invidious::Database::Compilations.update_video_added(compilation_id, compilation_video.index) + update_first_video_id(compilation_id) when "action_remove_video" index = env.params.query["set_video_id"] Invidious::Database::CompilationVideos.delete(index) Invidious::Database::Compilations.update_video_removed(compilation_id, index) + update_first_video_id(compilation_id) when "action_move_video_before" # TODO: Compilation stub #video_index = compilation.index @@ -473,6 +455,7 @@ module Invidious::Routes::Compilations compilation_index_array.insert(compilation_index_array_position-1,compilation_video[0].index) Invidious::Database::Compilations.move_video_before(compilation_id, compilation_index_array) end + update_first_video_id(compilation_id) else return error_json(400, "Unsupported action #{action}") end diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index e63bfc8c..bd0f46e1 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -39,8 +39,13 @@ module Invidious::Routes::Watch embed_link += embed_params.to_s end - plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") - continuation = process_continuation(env.params.query, plid, id) + if env.params.query["list"]?.try &.starts_with? "IVPL" + plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + continuation = process_continuation(env.params.query, plid, id) + elsif env.params.query["list"]?.try &.starts_with? "IVCMP" + compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + continuation = process_continuation(env.params.query, compid, id) + end nojs = env.params.query["nojs"]? diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index f38b33e5..d13e90dc 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -410,9 +410,9 @@ def fetch_video(id, region) return video end -def process_continuation(query, plid, id) +def process_continuation(query, list_id, id) continuation = nil - if plid + if list_id if index = query["index"]?.try &.to_i? continuation = index else diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index 2520dc0c..b86fac39 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -11,11 +11,13 @@
<%- if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email -%> - + <%- if compilation.index.size > 0 -%> + + <%- end -%> From d7a53d0159c6d1c58c2008f61737311badbf5782 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Thu, 3 Aug 2023 02:33:07 -0700 Subject: [PATCH 31/45] Finish vetting changes for autoplay stability --- src/invidious/compilations.cr | 20 +++++++++---------- src/invidious/database/compilations.cr | 6 +++--- src/invidious/helpers/utils.cr | 4 +++- src/invidious/routes/compilations.cr | 20 ++++++++++++------- src/invidious/views/add_compilation_items.ecr | 8 +------- src/invidious/views/components/item.ecr | 11 +++++----- src/invidious/views/user/preferences.ecr | 4 ++-- src/invidious/views/watch.ecr | 1 + 8 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 5710e6b2..2dda46e2 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -423,17 +423,17 @@ def extract_compilation_videos(initial_data : Hash(String, JSON::Any)) end videos << CompilationVideo.new({ - title: title, - id: video_id, - author: author, - ucid: ucid, - length_seconds: length_seconds, + title: title, + id: video_id, + author: author, + ucid: ucid, + length_seconds: length_seconds, starting_timestamp_seconds: starting_timestamp_seconds, - ending_timestamp_seconds: ending_timestamp_seconds, - published: Time.utc, - compid: compid, - index: index, - order_index: order_index + ending_timestamp_seconds: ending_timestamp_seconds, + published: Time.utc, + compid: compid, + index: index, + order_index: order_index }) end end diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index daf597b0..8ccc532f 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -334,13 +334,13 @@ module Invidious::Database::CompilationVideos PG_DB.exec(request, id, starting_timestamp_seconds) end - def update_end_timestamp(id : String, ending_timestamp_seconds : Int64) + def update_end_timestamp(id : String, ending_timestamp_seconds : Int32) request = <<-SQL UPDATE compilation_videos - SET ending_timestamp_seconds = ending_timestamp_seconds + SET ending_timestamp_seconds = $2 WHERE id = $1 SQL - PG_DB.exec(request, id) + PG_DB.exec(request, id, ending_timestamp_seconds) end end diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index a006d602..8441ea8f 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -35,8 +35,10 @@ def decode_length_seconds(string) end def recode_length_seconds(time) - if time <= 0 + if time < 0 return "" + elsif time == 0 + return "0:00" else time = time.seconds text = "#{time.minutes.to_s.rjust(2, '0')}:#{time.seconds.to_s.rjust(2, '0')}" diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index c592eb70..4e0b210d 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -244,7 +244,6 @@ module Invidious::Routes::Compilations compilation_video_index = compilation.index[index] compilation_video = Invidious::Database::CompilationVideos.select_video(compid, compilation.index, compilation_video_index, 0, 1) json_timestamp_query_start = compilation_video_index.to_s + "_start_timestamp" - start_timestamp = env.params.body[json_timestamp_query_start]?.try &.as(String).byte_slice(0, 8) if !start_timestamp.nil? && !compilation_video[0].id.nil? start_timestamp_seconds = decode_length_seconds(start_timestamp) @@ -254,14 +253,14 @@ module Invidious::Routes::Compilations end end end - + compilation_video = Invidious::Database::CompilationVideos.select_video(compid, compilation.index, compilation_video_index, 0, 1) json_timestamp_query_end = compilation_video_index.to_s + "_end_timestamp" end_timestamp = env.params.json[json_timestamp_query_end]?.try &.as(String).byte_slice(0, 8) if !end_timestamp.nil? && !compilation_video[0].id.nil? end_timestamp_seconds = decode_length_seconds(end_timestamp) if !end_timestamp_seconds.nil? - if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video[0].ending_timestamp_seconds && end_timestamp_seconds > compilation_video[0].starting_timestamp_seconds - Invidious::Database::CompilationVideos.update_end_timestamp(compilation_video[0].id, end_timestamp_seconds) + if end_timestamp_seconds >= 0 && end_timestamp_seconds <= compilation_video[0].length_seconds && end_timestamp_seconds > compilation_video[0].starting_timestamp_seconds + Invidious::Database::CompilationVideos.update_end_timestamp(compilation_video[0].id, end_timestamp_seconds.to_i) end end end @@ -303,11 +302,18 @@ module Invidious::Routes::Compilations begin query = Invidious::Search::Query.new(env.params.query, :compilation, region) - videos = query.process.select(SearchVideo).map(&.as(SearchVideo)) + items = query.process.select(SearchVideo).map(&.as(SearchVideo)) rescue ex - videos = [] of SearchVideo + items = [] of SearchVideo end + query_encoded = URI.encode_www_form(query.try &.text || "", space_to_plus: true) + page_nav_html = Frontend::Pagination.nav_numeric(locale, + base_url: "/add_compilation_items?list=#{compilation.id}&q=#{query_encoded}", + current_page: page, + show_next: (items.size >= 20) + ) + env.set "add_compilation_items", compid templated "add_compilation_items" end @@ -414,7 +420,7 @@ module Invidious::Routes::Compilations author: video.author, ucid: video.ucid, length_seconds: video.length_seconds, - starting_timestamp_seconds: video.length_seconds, + starting_timestamp_seconds: 0, ending_timestamp_seconds: video.length_seconds, published: video.published, compid: compilation_id, diff --git a/src/invidious/views/add_compilation_items.ecr b/src/invidious/views/add_compilation_items.ecr index 28494d98..3fbb5d96 100644 --- a/src/invidious/views/add_compilation_items.ecr +++ b/src/invidious/views/add_compilation_items.ecr @@ -31,10 +31,4 @@ -
- <% videos.each_slice(4) do |slice| %> - <% slice.each do |item| %> - <%= rendered "components/item" %> - <% end %> - <% end %> -
\ No newline at end of file +<%= rendered "components/items_paginated" %> \ No newline at end of file diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index e7da1764..4e960d8d 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -138,12 +138,13 @@ - <% elsif compid_form = env.get? "add_compilation_items" %> -
" method="post"> + <%- elsif compid_form = env.get?("add_compilation_items") -%> + <%- form_parameters = "action_add_video=1&video_id=#{item.id}&compilation_id=#{compid_form}&referer=#{env.get("current_page")}" -%> + "> -

- -

+
<%- elsif item.is_a?(PlaylistVideo) && (plid_form = env.get?("remove_playlist_items")) -%> <%- form_parameters = "action_remove_video=1&set_video_id=#{item.index}&playlist_id=#{plid_form}&referer=#{env.get("current_page")}" -%> diff --git a/src/invidious/views/user/preferences.ecr b/src/invidious/views/user/preferences.ecr index 93f03a05..1ef99cd2 100644 --- a/src/invidious/views/user/preferences.ecr +++ b/src/invidious/views/user/preferences.ecr @@ -174,7 +174,7 @@
@@ -184,7 +184,7 @@ <% (feed_options.size - 1).times do |index| %> <% end %> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index b861422e..890732e4 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -50,6 +50,7 @@ we're going to need to do it here in order to allow for translations. "id" => video.id, "index" => continuation, "plid" => plid, + "compid" => compid, "length_seconds" => video.length_seconds.to_f, "play_next" => !video.related_videos.empty? && !plid && params.continue, "next_video" => video.related_videos.select { |rv| rv["id"]? }[0]?.try &.["id"], From 472a2d7e76330371a712c37d473a3772d4edc1a3 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sat, 5 Aug 2023 02:53:36 -0700 Subject: [PATCH 32/45] Use markers to implement timestamps --- assets/js/player.js | 17 +++++-- assets/js/watch.js | 68 +++++++++++++------------- src/invidious/database/compilations.cr | 12 +++++ src/invidious/routes/watch.cr | 7 +++ src/invidious/views/watch.ecr | 8 ++- 5 files changed, 72 insertions(+), 40 deletions(-) diff --git a/assets/js/player.js b/assets/js/player.js index bb53ac24..36dd3eea 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -200,13 +200,20 @@ if (!video_data.params.listen && video_data.vr && video_data.params.vr_mode) { // Add markers if (video_data.params.video_start > 0 || video_data.params.video_end > 0) { var markers = [{ time: video_data.params.video_start, text: 'Start' }]; - - if (video_data.params.video_end < 0) { - markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); - } else { - markers.push({ time: video_data.params.video_end, text: 'End' }); + if (video_data.starting_timestamp_seconds) { + markers = [{ time: video_data.starting_timestamp_seconds, text: 'Start' }]; } + if (!video_data.ending_timestamp_seconds) { + if (video_data.params.video_end < 0) { + markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); + } else { + markers.push({ time: video_data.params.video_end, text: 'End' }); + } + } else { + markers.push({ time: video_data.ending_timestamp_seconds, text: 'End' }); + } + player.markers({ onMarkerReached: function (marker) { if (marker.text === 'End') diff --git a/assets/js/watch.js b/assets/js/watch.js index 809a9f19..4930d6a7 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -103,7 +103,7 @@ function continue_autoplay(event) { } function get_compilation(compid) { - var compilation = document.getElementById('compilations'); + var compilation = document.getElementById('compilation'); compilation.innerHTML = spinnerHTMLwithHR; @@ -111,47 +111,49 @@ function get_compilation(compid) { compid_url = '/api/v1/compilations/' + compid + '?index=' + video_data.index + '&continuation=' + video_data.id + - '&format=html&hl=' + video_data.preferences.locale; + '&format=html&hl=' + video_data.preferences.locale; + + console.log("Send "+compid_url); helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { on200: function (response) { compilation.innerHTML = response.compilationHtml; - if (!response.nextVideo) return; + if (!response.nextVideo) return; - var nextVideo = document.getElementById(response.nextVideo); - nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop; + var nextVideo = document.getElementById(response.nextVideo); + nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop; - player.on('ended', function () { - var url = new URL('https://example.com/watch?v=' + response.nextVideo); + player.on('ended', function () { + var url = new URL('https://example.com/watch?v=' + response.nextVideo); - url.searchParams.set('list', compid); - if (!plid.startsWith('RD')) - url.searchParams.set('index', response.index); - if (video_data.params.autoplay || video_data.params.continue_autoplay) - url.searchParams.set('autoplay', '1'); - if (video_data.params.listen !== video_data.preferences.listen) - url.searchParams.set('listen', video_data.params.listen); - if (video_data.params.speed !== video_data.preferences.speed) - url.searchParams.set('speed', video_data.params.speed); - if (video_data.params.local !== video_data.preferences.local) - url.searchParams.set('local', video_data.params.local); + url.searchParams.set('list', compid); + if (!compid.startsWith('RD')) + url.searchParams.set('index', response.index); + if (video_data.params.autoplay || video_data.params.continue_autoplay) + url.searchParams.set('autoplay', '1'); + if (video_data.params.listen !== video_data.preferences.listen) + url.searchParams.set('listen', video_data.params.listen); + if (video_data.params.speed !== video_data.preferences.speed) + url.searchParams.set('speed', video_data.params.speed); + if (video_data.params.local !== video_data.preferences.local) + url.searchParams.set('local', video_data.params.local); - location.assign(url.pathname + url.search); - }); - }, - onNon200: function (xhr) { - compilation.innerHTML = ''; - document.getElementById('continue').style.display = ''; - }, - onError: function (xhr) { - compilation.innerHTML = spinnerHTMLwithHR; - }, - onTimeout: function (xhr) { - compilation.innerHTML = spinnerHTMLwithHR; - } - }); - } + location.assign(url.pathname + url.search); + }); + }, + onNon200: function (xhr) { + compilation.innerHTML = ''; + document.getElementById('continue').style.display = ''; + }, + onError: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + }, + onTimeout: function (xhr) { + compilation.innerHTML = spinnerHTMLwithHR; + } + }); +} function get_playlist(plid) { var playlist = document.getElementById('playlist'); diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 8ccc532f..aa7a7341 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -258,6 +258,18 @@ module Invidious::Database::CompilationVideos return PG_DB.query_all(request, compid, index, video_index, offset, limit, as: CompilationVideo) end + def select_timestamps(compid : String, vid : String) + + request = <<-SQL + SELECT starting_timestamp_seconds,ending_timestamp_seconds FROM compilation_videos + WHERE compid = $1 AND id = $2 + LIMIT 1 + SQL + + return PG_DB.query_one?(request, compid, vid, as: {Int32,Int32}) + + end + def select_id_from_order_index(order_index : Int32) request = <<-SQL SELECT id FROM compilation_videos diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index bd0f46e1..e5bf1668 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -44,6 +44,13 @@ module Invidious::Routes::Watch continuation = process_continuation(env.params.query, plid, id) elsif env.params.query["list"]?.try &.starts_with? "IVCMP" compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + if (!compid.nil?) + timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, id) + if (!timestamps.nil?) + starting_timestamp_seconds=timestamps[0] + ending_timestamp_seconds=timestamps[1] + end + end continuation = process_continuation(env.params.query, compid, id) end diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 890732e4..4c844534 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -51,6 +51,8 @@ we're going to need to do it here in order to allow for translations. "index" => continuation, "plid" => plid, "compid" => compid, + "starting_timestamp_seconds" => starting_timestamp_seconds, + "ending_timestamp_seconds" => ending_timestamp_seconds, "length_seconds" => video.length_seconds.to_f, "play_next" => !video.related_videos.empty? && !plid && params.continue, "next_video" => video.related_videos.select { |rv| rv["id"]? }[0]?.try &.["id"], @@ -313,16 +315,18 @@ we're going to need to do it here in order to allow for translations.
- <% if params.related_videos || plid %> + <% if params.related_videos || plid || compid%>
<% if plid %>
+ <% elsif compid %> +
<% end %> <% if params.related_videos %>
<% if !video.related_videos.empty? %> -
style="display:none"<% end %>> +
style="display:none"<% end %>>
checked<% end %>> From 510d85c0452a4a468062f53d84cfbe2f64e7ef41 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sat, 5 Aug 2023 17:42:10 -0700 Subject: [PATCH 33/45] Query DB for timestamps after current id --- assets/js/player.js | 15 ++++----------- assets/js/watch.js | 2 ++ src/invidious/database/compilations.cr | 2 +- src/invidious/routes/watch.cr | 25 ++++++++++++++++++++----- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/assets/js/player.js b/assets/js/player.js index 36dd3eea..44640402 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -200,19 +200,12 @@ if (!video_data.params.listen && video_data.vr && video_data.params.vr_mode) { // Add markers if (video_data.params.video_start > 0 || video_data.params.video_end > 0) { var markers = [{ time: video_data.params.video_start, text: 'Start' }]; - if (video_data.starting_timestamp_seconds) { - markers = [{ time: video_data.starting_timestamp_seconds, text: 'Start' }]; - } - if (!video_data.ending_timestamp_seconds) { - if (video_data.params.video_end < 0) { - markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); - } else { - markers.push({ time: video_data.params.video_end, text: 'End' }); - } + if (video_data.params.video_end < 0) { + markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); } else { - markers.push({ time: video_data.ending_timestamp_seconds, text: 'End' }); - } + markers.push({ time: video_data.params.video_end, text: 'End' }); + } player.markers({ onMarkerReached: function (marker) { diff --git a/assets/js/watch.js b/assets/js/watch.js index 4930d6a7..debf610b 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -111,6 +111,7 @@ function get_compilation(compid) { compid_url = '/api/v1/compilations/' + compid + '?index=' + video_data.index + '&continuation=' + video_data.id + + //'&t=' + video_data.video_data.starting_timestamp_seconds + '&format=html&hl=' + video_data.preferences.locale; console.log("Send "+compid_url); @@ -138,6 +139,7 @@ function get_compilation(compid) { url.searchParams.set('speed', video_data.params.speed); if (video_data.params.local !== video_data.preferences.local) url.searchParams.set('local', video_data.params.local); + url.searchParams.set('t',video_data.starting_timestamp_seconds); location.assign(url.pathname + url.search); }); diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index aa7a7341..1cdd1479 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -128,7 +128,7 @@ module Invidious::Database::Compilations LIMIT 1 SQL - PG_DB.query_one?(request, id, as: String) + PG_DB.query_one?(request, id, as: Array(Int64)) end # ------------------- diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index e5bf1668..d9582ec1 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -45,11 +45,26 @@ module Invidious::Routes::Watch elsif env.params.query["list"]?.try &.starts_with? "IVCMP" compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") if (!compid.nil?) - timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, id) - if (!timestamps.nil?) - starting_timestamp_seconds=timestamps[0] - ending_timestamp_seconds=timestamps[1] - end + index=Invidious::Database::CompilationVideos.select_index(compid,id) + indices_array=Invidious::Database::Compilations.select_index_array(compid) + if (!indices_array.nil?) + position_of_index=indices_array.index(index) + if (!position_of_index.nil? && position_of_index != indices_array.size - 1) + next_index=indices_array[position_of_index+1] + else + next_index=indices_array[0] + end + if (!next_index.nil?) + next_id=Invidious::Database::CompilationVideos.select_id_from_index(next_index) + if (!next_id.nil?) + timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, next_id) + if (!timestamps.nil?) + starting_timestamp_seconds=timestamps[0] + ending_timestamp_seconds=timestamps[1] + end + end + end + end end continuation = process_continuation(env.params.query, compid, id) end From f48083da3375234696c6cd66fda671a2731716a8 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 00:59:53 -0700 Subject: [PATCH 34/45] Add end marker continuation utility --- assets/js/player.js | 9 ++++- assets/js/watch.js | 1 + config/sql/compilations.sql | 4 +- src/invidious/compilations.cr | 40 +++++++++++++------ src/invidious/database/compilations.cr | 8 ++-- .../0011_create_compilations_table.cr | 4 +- src/invidious/routes/compilations.cr | 10 +++-- src/invidious/views/compilation.ecr | 2 +- 8 files changed, 53 insertions(+), 25 deletions(-) diff --git a/assets/js/player.js b/assets/js/player.js index 44640402..bd250119 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -209,8 +209,13 @@ if (video_data.params.video_start > 0 || video_data.params.video_end > 0) { player.markers({ onMarkerReached: function (marker) { - if (marker.text === 'End') - player.loop() ? player.markers.prev('Start') : player.pause(); + if (marker.text === 'End') { + if (video_data.ending_timestamp_seconds) { + player.currentTime(player.duration()); + } else { + player.loop() ? player.markers.prev('Start') : player.pause(); + } + } }, markers: markers }); diff --git a/assets/js/watch.js b/assets/js/watch.js index debf610b..dbfdf5be 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -140,6 +140,7 @@ function get_compilation(compid) { if (video_data.params.local !== video_data.preferences.local) url.searchParams.set('local', video_data.params.local); url.searchParams.set('t',video_data.starting_timestamp_seconds); + url.searchParams.set('end',video_data.ending_timestamp_seconds); location.assign(url.pathname + url.search); }); diff --git a/config/sql/compilations.sql b/config/sql/compilations.sql index 5802c9a8..60587e44 100644 --- a/config/sql/compilations.sql +++ b/config/sql/compilations.sql @@ -23,7 +23,9 @@ CREATE TABLE IF NOT EXISTS public.compilations updated timestamptz, privacy compilation_privacy, index int8[], - first_video_id text + first_video_id text, + first_video_starting_timestamp_seconds integer, + first_video_ending_timestamp_seconds integer ); GRANT ALL ON public.compilations TO current_user; diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 2dda46e2..35d7066e 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -96,6 +96,8 @@ struct Compilation property updated : Time property thumbnail : String? property first_video_id : String + property first_video_starting_timestamp_seconds : Int32 + property first_video_ending_timestamp_seconds : Int32 def to_json(offset, json : JSON::Builder, video_id : String? = nil) json.object do @@ -171,6 +173,8 @@ struct InvidiousCompilation property privacy : CompilationPrivacy = CompilationPrivacy::Private property index : Array(Int64) property first_video_id : String + property first_video_starting_timestamp_seconds : Int32 + property first_video_ending_timestamp_seconds : Int32 @[DB::Field(ignore: true)] property thumbnail_id : String? @@ -250,16 +254,18 @@ def create_compilation(title, privacy, user) LOGGER.info("generated compilation id") compilation = InvidiousCompilation.new({ - title: title.byte_slice(0, 150), - id: compid, - author: user.email, - description: "", # Max 5000 characters - video_count: 0, - created: Time.utc, - updated: Time.utc, - privacy: privacy, - index: [] of Int64, - first_video_id: "" + title: title.byte_slice(0, 150), + id: compid, + author: user.email, + description: "", # Max 5000 characters + video_count: 0, + created: Time.utc, + updated: Time.utc, + privacy: privacy, + index: [] of Int64, + first_video_id: "", + first_video_starting_timestamp_seconds: 0, + first_video_ending_timestamp_seconds: 0 }) LOGGER.info("Creating compilation db") @@ -280,7 +286,9 @@ def subscribe_compilation(user, compilation) updated: compilation.updated, privacy: CompilationPrivacy::Private, index: [] of Int64, - first_video_id: "" + first_video_id: "", + first_video_starting_timestamp_seconds: 0, + first_video_ending_timestamp_seconds: 0 }) Invidious::Database::Compilations.insert(compilation) @@ -326,6 +334,7 @@ end def get_compilation(compid : String) #if compid.starts_with? "IVCMP" if compilation = Invidious::Database::Compilations.select(id: compid) + update_first_video_params(compid) return compilation else raise NotFoundException.new("Compilation does not exist.") @@ -333,13 +342,18 @@ def get_compilation(compid : String) #end end -def update_first_video_id(compid : String) +def update_first_video_params(compid : String) if compilation = Invidious::Database::Compilations.select(id: compid) compilation_index_array = compilation.index first_index = compilation_index_array[0] first_id = Invidious::Database::CompilationVideos.select_id_from_index(first_index) if !first_id.nil? - Invidious::Database::Compilations.update_first_video_id(compid, first_id) + timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, first_id) + if (!timestamps.nil?) + starting_timestamp_seconds=timestamps[0] + ending_timestamp_seconds=timestamps[1] + Invidious::Database::Compilations.update_first_video_params(compid, first_id, starting_timestamp_seconds, ending_timestamp_seconds) + end end else raise NotFoundException.new("Compilation does not exist.") diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 1cdd1479..2f3d7072 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -90,14 +90,16 @@ module Invidious::Database::Compilations PG_DB.exec(request, id, index) end - def update_first_video_id(id : String, first_video_id : String) + def update_first_video_params(id : String, first_video_id : String, starting_timestamp_seconds : Int32, ending_timestamp_seconds : Int32) request = <<-SQL UPDATE compilations - SET first_video_id = $2 + SET first_video_id = $2, + first_video_starting_timestamp_seconds = $3, + first_video_ending_timestamp_seconds = $4 WHERE id = $1 SQL - PG_DB.exec(request, id, first_video_id) + PG_DB.exec(request, id, first_video_id, starting_timestamp_seconds, ending_timestamp_seconds) end # ------------------- # Select diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr index 4bf5a814..643cd506 100644 --- a/src/invidious/database/migrations/0011_create_compilations_table.cr +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -25,7 +25,9 @@ module Invidious::Database::Migrations updated timestamptz, privacy compilation_privacy, index int8[], - first_video_id text + first_video_id text, + first_video_starting_timestamp_seconds integer, + first_video_ending_timestamp_seconds integer ); SQL diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 4e0b210d..bd1db90d 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -255,7 +255,7 @@ module Invidious::Routes::Compilations end compilation_video = Invidious::Database::CompilationVideos.select_video(compid, compilation.index, compilation_video_index, 0, 1) json_timestamp_query_end = compilation_video_index.to_s + "_end_timestamp" - end_timestamp = env.params.json[json_timestamp_query_end]?.try &.as(String).byte_slice(0, 8) + end_timestamp = env.params.body[json_timestamp_query_end]?.try &.as(String).byte_slice(0, 8) if !end_timestamp.nil? && !compilation_video[0].id.nil? end_timestamp_seconds = decode_length_seconds(end_timestamp) if !end_timestamp_seconds.nil? @@ -267,6 +267,8 @@ module Invidious::Routes::Compilations end + update_first_video_params(compid) + env.redirect "/compilation?list=#{compid}" end @@ -431,12 +433,12 @@ module Invidious::Routes::Compilations Invidious::Database::CompilationVideos.insert(compilation_video) Invidious::Database::Compilations.update_video_added(compilation_id, compilation_video.index) - update_first_video_id(compilation_id) + update_first_video_params(compilation_id) when "action_remove_video" index = env.params.query["set_video_id"] Invidious::Database::CompilationVideos.delete(index) Invidious::Database::Compilations.update_video_removed(compilation_id, index) - update_first_video_id(compilation_id) + update_first_video_params(compilation_id) when "action_move_video_before" # TODO: Compilation stub #video_index = compilation.index @@ -461,7 +463,7 @@ module Invidious::Routes::Compilations compilation_index_array.insert(compilation_index_array_position-1,compilation_video[0].index) Invidious::Database::Compilations.move_video_before(compilation_id, compilation_index_array) end - update_first_video_id(compilation_id) + update_first_video_params(compilation_id) else return error_json(400, "Unsupported action #{action}") end diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index b86fac39..7fa900a1 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -13,7 +13,7 @@ <%- if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email -%> <%- if compilation.index.size > 0 -%> From f7fc05eb676efd6aaecb585240f9362031c847d6 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 01:04:35 -0700 Subject: [PATCH 35/45] Remove development-purpose file ignores --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 303e1f4e..2a49e68d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,4 @@ /invidious /sentry /config/config.yml -.DS_Store -docker-compose.yml -docker/Dockerfile \ No newline at end of file +.DS_Store \ No newline at end of file From 0d968a320f838f422f3ca22528b17ff7456c4117 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 01:39:29 -0700 Subject: [PATCH 36/45] Remove LOGGER statements --- assets/js/player.js | 2 +- assets/js/watch.js | 5 +-- src/invidious/compilations.cr | 20 ++++------- src/invidious/database/compilations.cr | 2 +- src/invidious/playlists.cr | 5 --- src/invidious/routes/api/v1/authenticated.cr | 8 ----- src/invidious/routes/api/v1/misc.cr | 2 -- src/invidious/routes/compilations.cr | 34 +++++++++++++------ src/invidious/routes/embed.cr | 1 - src/invidious/routes/feeds.cr | 3 -- src/invidious/routes/playlists.cr | 3 -- src/invidious/routes/watch.cr | 3 -- .../views/components/compilation_video.ecr | 19 ++--------- 13 files changed, 35 insertions(+), 72 deletions(-) diff --git a/assets/js/player.js b/assets/js/player.js index bd250119..cc0b5755 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -205,7 +205,7 @@ if (video_data.params.video_start > 0 || video_data.params.video_end > 0) { markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); } else { markers.push({ time: video_data.params.video_end, text: 'End' }); - } + } player.markers({ onMarkerReached: function (marker) { diff --git a/assets/js/watch.js b/assets/js/watch.js index dbfdf5be..92f27bf8 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -111,10 +111,7 @@ function get_compilation(compid) { compid_url = '/api/v1/compilations/' + compid + '?index=' + video_data.index + '&continuation=' + video_data.id + - //'&t=' + video_data.video_data.starting_timestamp_seconds + - '&format=html&hl=' + video_data.preferences.locale; - - console.log("Send "+compid_url); + '&format=html&hl=' + video_data.preferences.locale; helpers.xhr('GET', compid_url, {retries: 5, entity_name: 'compilation'}, { on200: function (response) { diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 35d7066e..d2dc4e16 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -249,9 +249,7 @@ struct InvidiousCompilation end def create_compilation(title, privacy, user) - LOGGER.info("2. create_compilation") compid = "IVCMP#{Random::Secure.urlsafe_base64(24)[0, 31]}" - LOGGER.info("generated compilation id") compilation = InvidiousCompilation.new({ title: title.byte_slice(0, 150), @@ -267,10 +265,8 @@ def create_compilation(title, privacy, user) first_video_starting_timestamp_seconds: 0, first_video_ending_timestamp_seconds: 0 }) - LOGGER.info("Creating compilation db") Invidious::Database::Compilations.insert(compilation) - LOGGER.info("inserted compilation db entry") return compilation end @@ -332,14 +328,12 @@ def produce_compilation_continuation(id, index) end def get_compilation(compid : String) - #if compid.starts_with? "IVCMP" - if compilation = Invidious::Database::Compilations.select(id: compid) - update_first_video_params(compid) - return compilation - else - raise NotFoundException.new("Compilation does not exist.") - end - #end + if compilation = Invidious::Database::Compilations.select(id: compid) + update_first_video_params(compid) + return compilation + else + raise NotFoundException.new("Compilation does not exist.") + end end def update_first_video_params(compid : String) @@ -361,8 +355,6 @@ def update_first_video_params(compid : String) end def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) - LOGGER.info("1. get_compilation") - LOGGER.info("Getting compilation") # Show empty compilation if requested page is out of range # (e.g, when a new compilation has been created, offset will be negative) if offset >= compilation.video_count || offset < 0 diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 2f3d7072..8c2e00a6 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -80,7 +80,7 @@ module Invidious::Database::Compilations PG_DB.exec(request, index, id) end - def move_video_before(id : String, index : Array(Int64)) + def move_video_position(id : String, index : Array(Int64)) request = <<-SQL UPDATE compilations SET index = $2 diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr index dc05d209..013be268 100644 --- a/src/invidious/playlists.cr +++ b/src/invidious/playlists.cr @@ -240,8 +240,6 @@ struct InvidiousPlaylist end def create_playlist(title, privacy, user) - LOGGER.info("2. create_playlist") - LOGGER.info("create playlist inv/pl.cr") plid = "IVPL#{Random::Secure.urlsafe_base64(24)[0, 31]}" playlist = InvidiousPlaylist.new({ @@ -315,7 +313,6 @@ def produce_playlist_continuation(id, index) end def get_playlist(plid : String) - LOGGER.info("8. get_playlist") if plid.starts_with? "IV" if playlist = Invidious::Database::Playlists.select(id: plid) return playlist @@ -404,8 +401,6 @@ def fetch_playlist(plid : String) end def get_playlist_videos(playlist : InvidiousPlaylist | Playlist, offset : Int32, video_id = nil) - LOGGER.info("1. get_playlist_videos") - LOGGER.info("get_playlist_videos") # Show empty playlist if requested page is out of range # (e.g, when a new playlist has been created, offset will be negative) if offset >= playlist.video_count || offset < 0 diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 2cbcd7cb..2846f709 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -223,40 +223,32 @@ module Invidious::Routes::API::V1::Authenticated end def self.create_compilation(env) - LOGGER.info("creating comp in auth fashion") env.response.content_type = "application/json" user = env.get("user").as(User) - LOGGER.info("app json compilation") title = env.params.json["title"]?.try &.as(String).delete("<>").byte_slice(0, 150) if !title return error_json(400, "Invalid title.") end - LOGGER.info("set title") privacy = env.params.json["privacy"]?.try { |p| CompilationPrivacy.parse(p.as(String).downcase) } if !privacy return error_json(400, "Invalid privacy setting.") end - LOGGER.info("set privacy") if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 return error_json(400, "User cannot have more than 100 compilations.") end - LOGGER.info("400 forgone") compilation = create_compilation(title, privacy, user) env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{compilation.id}" env.response.status_code = 201 - LOGGER.info("location set") { "title" => title, "compilationId" => compilation.id, }.to_json - LOGGER.info("Creating json") end def self.create_playlist(env) - LOGGER.info("7. create_playlist") env.response.content_type = "application/json" user = env.get("user").as(User) diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr index b99a15f1..cf769512 100644 --- a/src/invidious/routes/api/v1/misc.cr +++ b/src/invidious/routes/api/v1/misc.cr @@ -11,10 +11,8 @@ module Invidious::Routes::API::V1::Misc end def self.get_compilation(env : HTTP::Server::Context) - LOGGER.info("15. get_compilation") env.response.content_type = "application/json" compid = env.params.url["compid"] - LOGGER.info("the compid is #{compid}") offset = env.params.query["index"]?.try &.to_i? offset ||= env.params.query["page"]?.try &.to_i?.try { |page| (page - 1) * 100 } offset ||= 0 diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index bd1db90d..997e2475 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -2,7 +2,6 @@ module Invidious::Routes::Compilations def self.new(env) - LOGGER.info("15. new") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -19,7 +18,6 @@ module Invidious::Routes::Compilations end def self.create(env) - LOGGER.info("3. create") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -198,7 +196,6 @@ module Invidious::Routes::Compilations def self.adjust_timestamps(env) locale = env.get("preferences").as(Preferences).locale - LOGGER.info("Handle POST request for edit compilation") env.response.content_type = "application/json" user = env.get("user") sid = env.get? "sid" @@ -274,7 +271,6 @@ module Invidious::Routes::Compilations def self.add_compilation_items_page(env) - LOGGER.info("13. add_compilation_items") prefs = env.get("preferences").as(Preferences) locale = prefs.locale @@ -321,7 +317,6 @@ module Invidious::Routes::Compilations end def self.compilation_ajax(env) - LOGGER.info("14. compilation_ajax") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -391,7 +386,6 @@ module Invidious::Routes::Compilations case action when "action_edit_compilation" # TODO: Compilation stub - LOGGER.info("Begin handling of Compilation edit") when "action_add_video" if compilation.index.size >= CONFIG.compilation_length_limit @@ -441,10 +435,8 @@ module Invidious::Routes::Compilations update_first_video_params(compilation_id) when "action_move_video_before" # TODO: Compilation stub - #video_index = compilation.index video_index = env.params.query["video_index"] begin - #video_index = get_video(video_index) compilation_video = Invidious::Database::CompilationVideos.select_video(compilation_id, compilation.index, video_index, 0, 1) compilation_index_array = compilation.index rescue ex : NotFoundException @@ -457,13 +449,34 @@ module Invidious::Routes::Compilations end end compilation_index_array_position = compilation_index_array.index(compilation_video[0].index) - LOGGER.info("for #{compilation_index_array}, the item #{compilation_video[0].index} is a position #{compilation_index_array.index(compilation_video[0].index)}") if !compilation_index_array_position.nil? compilation_index_array.delete_at(compilation_index_array_position) compilation_index_array.insert(compilation_index_array_position-1,compilation_video[0].index) - Invidious::Database::Compilations.move_video_before(compilation_id, compilation_index_array) + Invidious::Database::Compilations.move_video_position(compilation_id, compilation_index_array) end update_first_video_params(compilation_id) + when "action_move_video_after" + # TODO: Compilation stub + video_index = env.params.query["video_index"] + begin + compilation_video = Invidious::Database::CompilationVideos.select_video(compilation_id, compilation.index, video_index, 0, 1) + compilation_index_array = compilation.index + rescue ex : NotFoundException + return error_json(404, ex) + rescue ex + if redirect + return error_template(500, ex) + else + return error_json(500, ex) + end + end + compilation_index_array_position = compilation_index_array.index(compilation_video[0].index) + if !compilation_index_array_position.nil? + compilation_index_array.delete_at(compilation_index_array_position) + compilation_index_array.insert(compilation_index_array_position+1,compilation_video[0].index) + Invidious::Database::Compilations.move_video_position(compilation_id, compilation_index_array) + end + update_first_video_params(compilation_id) else return error_json(400, "Unsupported action #{action}") end @@ -477,7 +490,6 @@ module Invidious::Routes::Compilations end def self.show(env) - LOGGER.info("4. show | comp") locale = env.get("preferences").as(Preferences).locale user = env.get?("user").try &.as(User) diff --git a/src/invidious/routes/embed.cr b/src/invidious/routes/embed.cr index 8756bb49..266f7ba4 100644 --- a/src/invidious/routes/embed.cr +++ b/src/invidious/routes/embed.cr @@ -31,7 +31,6 @@ module Invidious::Routes::Embed end def self.show(env) - LOGGER.info("9? show") locale = env.get("preferences").as(Preferences).locale id = env.params.url["id"] diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index 39f681dc..3e68bcfb 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -10,7 +10,6 @@ module Invidious::Routes::Feeds end def self.compilations(env) - LOGGER.info("5. compilations") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -37,8 +36,6 @@ module Invidious::Routes::Feeds end def self.playlists(env) - LOGGER.info("5. playlists") - LOGGER.info("Generating the playlist items") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr index 240c7583..9c6843e9 100644 --- a/src/invidious/routes/playlists.cr +++ b/src/invidious/routes/playlists.cr @@ -18,8 +18,6 @@ module Invidious::Routes::Playlists end def self.create(env) - LOGGER.info("3. create") - LOGGER.info("creating a play") locale = env.get("preferences").as(Preferences).locale user = env.get? "user" @@ -398,7 +396,6 @@ module Invidious::Routes::Playlists end def self.show(env) - LOGGER.info("4. show") locale = env.get("preferences").as(Preferences).locale user = env.get?("user").try &.as(User) diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index d9582ec1..1ba84543 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -2,7 +2,6 @@ module Invidious::Routes::Watch def self.handle(env) - LOGGER.info("6. handle") locale = env.get("preferences").as(Preferences).locale region = env.params.query["region"]? @@ -230,7 +229,6 @@ module Invidious::Routes::Watch end def self.redirect(env) - LOGGER.info("10? redirect") url = "/watch?v=#{env.params.url["id"]}" if env.params.query.size > 0 url += "&#{env.params.query}" @@ -304,7 +302,6 @@ module Invidious::Routes::Watch end def self.clip(env) - LOGGER.info("11? clip") clip_id = env.params.url["clip"]? return error_template(400, "A clip ID is required") if !clip_id diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index 9de334fb..eab9d48a 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -9,28 +9,15 @@ - <%- form_parameters = "action_move_video_after=1&set_video_id=#{compilation_video.index}&compilation_id=#{compilation_video.compid}&referer=#{env.get("current_page")}" -%> -
+ <%- form_parameters = "action_move_video_after=1&video_index=#{compilation_video.index}&compilation_id=#{compilation_video.compid}" -%> + "> -
-
<%= HTML.escape(compilation_video.title) %> From 212509ec6021fb96367ab964231bd3efa0368571 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 02:24:11 -0700 Subject: [PATCH 37/45] Revert docker-compose --- docker-compose.yml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b501566..854d2051 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,7 +26,6 @@ services: host: invidious-db port: 5432 check_tables: true - log_level: Info # external_port: # domain: # https_only: false @@ -54,20 +53,5 @@ services: healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] - invidious-pgadmin: - image: docker.io/dpage/pgadmin4:latest - restart: unless-stopped - environment: - - PGADMIN_DEFAULT_EMAIL=******* - - PGADMIN_DEFAULT_PASSWORD=******* - - PGADMIN_DISABLE_POSTFIX=1 - - GUNICORN_ACCESS_LOGFILE=/dev/null - - GUNICORN_THREADS=1 - ports: - - "127.0.0.1:5050:80" - depends_on: - invidious-db: - condition: service_healthy - volumes: - postgresdata: + postgresdata: \ No newline at end of file From 205c5493db1fc7ef067aaa4571670ac1e451b767 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 10:35:53 -0700 Subject: [PATCH 38/45] Replace EOF carriage returns --- .gitignore | 2 +- docker-compose.yml | 2 +- docker/init-invidious-db.sh | 2 +- src/invidious/compilations.cr | 20 ++++++++++--------- src/invidious/views/add_compilation_items.ecr | 2 +- .../views/components/compilation_video.ecr | 2 +- src/invidious/views/components/feed_menu.ecr | 2 +- src/invidious/views/feeds/compilations.ecr | 2 +- 8 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 2a49e68d..f36ac1ee 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ /invidious /sentry /config/config.yml -.DS_Store \ No newline at end of file +.DS_Store diff --git a/docker-compose.yml b/docker-compose.yml index 854d2051..6a854475 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -54,4 +54,4 @@ services: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] volumes: - postgresdata: \ No newline at end of file + postgresdata: diff --git a/docker/init-invidious-db.sh b/docker/init-invidious-db.sh index 62df4229..f7fe3e7f 100755 --- a/docker/init-invidious-db.sh +++ b/docker/init-invidious-db.sh @@ -11,4 +11,4 @@ psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/annotation psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlists.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlist_videos.sql psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilations.sql -psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilation_videos.sql \ No newline at end of file +psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/compilation_videos.sql diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index d2dc4e16..929a5fbd 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -339,16 +339,18 @@ end def update_first_video_params(compid : String) if compilation = Invidious::Database::Compilations.select(id: compid) compilation_index_array = compilation.index - first_index = compilation_index_array[0] - first_id = Invidious::Database::CompilationVideos.select_id_from_index(first_index) - if !first_id.nil? - timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, first_id) - if (!timestamps.nil?) - starting_timestamp_seconds=timestamps[0] - ending_timestamp_seconds=timestamps[1] - Invidious::Database::Compilations.update_first_video_params(compid, first_id, starting_timestamp_seconds, ending_timestamp_seconds) + if (compilation_index_array.size > 0) + first_index = compilation_index_array[0] + first_id = Invidious::Database::CompilationVideos.select_id_from_index(first_index) + if !first_id.nil? + timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, first_id) + if (!timestamps.nil?) + starting_timestamp_seconds=timestamps[0] + ending_timestamp_seconds=timestamps[1] + Invidious::Database::Compilations.update_first_video_params(compid, first_id, starting_timestamp_seconds, ending_timestamp_seconds) + end end - end + end else raise NotFoundException.new("Compilation does not exist.") end diff --git a/src/invidious/views/add_compilation_items.ecr b/src/invidious/views/add_compilation_items.ecr index 3fbb5d96..e62e860c 100644 --- a/src/invidious/views/add_compilation_items.ecr +++ b/src/invidious/views/add_compilation_items.ecr @@ -31,4 +31,4 @@ -<%= rendered "components/items_paginated" %> \ No newline at end of file +<%= rendered "components/items_paginated" %> diff --git a/src/invidious/views/components/compilation_video.ecr b/src/invidious/views/components/compilation_video.ecr index eab9d48a..cca1f5cb 100644 --- a/src/invidious/views/components/compilation_video.ecr +++ b/src/invidious/views/components/compilation_video.ecr @@ -40,4 +40,4 @@
-
\ No newline at end of file +
diff --git a/src/invidious/views/components/feed_menu.ecr b/src/invidious/views/components/feed_menu.ecr index ff3b2474..180a263f 100644 --- a/src/invidious/views/components/feed_menu.ecr +++ b/src/invidious/views/components/feed_menu.ecr @@ -8,4 +8,4 @@ <%= translate(locale, feed) %> <% end %> -
\ No newline at end of file +
diff --git a/src/invidious/views/feeds/compilations.ecr b/src/invidious/views/feeds/compilations.ecr index 31d073c4..7e56dd93 100644 --- a/src/invidious/views/feeds/compilations.ecr +++ b/src/invidious/views/feeds/compilations.ecr @@ -26,4 +26,4 @@ <% items_created.each do |item| %> <%= rendered "components/item" %> <% end %> -
\ No newline at end of file +
From 93ac7cdeb419ef3e54d976a1ef612270f77d4775 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 6 Aug 2023 16:53:56 -0700 Subject: [PATCH 39/45] Run Crystal formatting tool --- src/invidious/compilations.cr | 40 ++++++++++---------- src/invidious/database/compilations.cr | 11 +++--- src/invidious/helpers/utils.cr | 2 +- src/invidious/routes/api/v1/authenticated.cr | 4 +- src/invidious/routes/api/v1/misc.cr | 5 +-- src/invidious/routes/compilations.cr | 31 +++++++-------- src/invidious/routes/misc.cr | 2 +- src/invidious/routes/watch.cr | 30 +++++++-------- src/invidious/routing.cr | 2 +- src/invidious/search/query.cr | 2 +- 10 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 929a5fbd..0315f6ec 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -19,7 +19,7 @@ struct CompilationVideo xml.element("yt:videoId") { xml.text self.id } xml.element("yt:channelId") { xml.text self.ucid } xml.element("title") { xml.text self.title } - xml.element("orderIndex") {xml.text self.order_index } + xml.element("orderIndex") { xml.text self.order_index } xml.element("link", rel: "alternate", href: "#{HOST_URL}/watch?v=#{self.id}") xml.element("author") do @@ -263,7 +263,7 @@ def create_compilation(title, privacy, user) index: [] of Int64, first_video_id: "", first_video_starting_timestamp_seconds: 0, - first_video_ending_timestamp_seconds: 0 + first_video_ending_timestamp_seconds: 0, }) Invidious::Database::Compilations.insert(compilation) @@ -273,18 +273,18 @@ end def subscribe_compilation(user, compilation) compilation = InvidiousCompilation.new({ - title: compilation.title.byte_slice(0, 150), - id: compilation.id, - author: user.email, - description: "", # Max 5000 characters - video_count: compilation.video_count, - created: Time.utc, - updated: compilation.updated, - privacy: CompilationPrivacy::Private, - index: [] of Int64, - first_video_id: "", + title: compilation.title.byte_slice(0, 150), + id: compilation.id, + author: user.email, + description: "", # Max 5000 characters + video_count: compilation.video_count, + created: Time.utc, + updated: compilation.updated, + privacy: CompilationPrivacy::Private, + index: [] of Int64, + first_video_id: "", first_video_starting_timestamp_seconds: 0, - first_video_ending_timestamp_seconds: 0 + first_video_ending_timestamp_seconds: 0, }) Invidious::Database::Compilations.insert(compilation) @@ -339,21 +339,21 @@ end def update_first_video_params(compid : String) if compilation = Invidious::Database::Compilations.select(id: compid) compilation_index_array = compilation.index - if (compilation_index_array.size > 0) + if (compilation_index_array.size > 0) first_index = compilation_index_array[0] first_id = Invidious::Database::CompilationVideos.select_id_from_index(first_index) if !first_id.nil? timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, first_id) if (!timestamps.nil?) - starting_timestamp_seconds=timestamps[0] - ending_timestamp_seconds=timestamps[1] + starting_timestamp_seconds = timestamps[0] + ending_timestamp_seconds = timestamps[1] Invidious::Database::Compilations.update_first_video_params(compid, first_id, starting_timestamp_seconds, ending_timestamp_seconds) end end - end + end else raise NotFoundException.new("Compilation does not exist.") - end + end end def get_compilation_videos(compilation : InvidiousCompilation | Compilation, offset : Int32, video_id = nil) @@ -368,7 +368,7 @@ def get_compilation_videos(compilation : InvidiousCompilation | Compilation, off else if video_id initial_data = YoutubeAPI.next({ - "videoId" => video_id, + "videoId" => video_id, "compilationId" => compilation.id, }) offset = initial_data.dig?("contents", "twoColumnWatchNextResults", "compilation", "compilation", "currentIndex").try &.as_i || offset @@ -441,7 +441,7 @@ def extract_compilation_videos(initial_data : Hash(String, JSON::Any)) published: Time.utc, compid: compid, index: index, - order_index: order_index + order_index: order_index, }) end end diff --git a/src/invidious/database/compilations.cr b/src/invidious/database/compilations.cr index 8c2e00a6..9d82a3eb 100644 --- a/src/invidious/database/compilations.cr +++ b/src/invidious/database/compilations.cr @@ -88,7 +88,7 @@ module Invidious::Database::Compilations SQL PG_DB.exec(request, id, index) - end + end def update_first_video_params(id : String, first_video_id : String, starting_timestamp_seconds : Int32, ending_timestamp_seconds : Int32) request = <<-SQL @@ -100,7 +100,8 @@ module Invidious::Database::Compilations SQL PG_DB.exec(request, id, first_video_id, starting_timestamp_seconds, ending_timestamp_seconds) - end + end + # ------------------- # Select # ------------------- @@ -131,7 +132,7 @@ module Invidious::Database::Compilations SQL PG_DB.query_one?(request, id, as: Array(Int64)) - end + end # ------------------- # Select (filtered) @@ -261,15 +262,13 @@ module Invidious::Database::CompilationVideos end def select_timestamps(compid : String, vid : String) - request = <<-SQL SELECT starting_timestamp_seconds,ending_timestamp_seconds FROM compilation_videos WHERE compid = $1 AND id = $2 LIMIT 1 SQL - return PG_DB.query_one?(request, compid, vid, as: {Int32,Int32}) - + return PG_DB.query_one?(request, compid, vid, as: {Int32, Int32}) end def select_id_from_order_index(order_index : Int32) diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index 8441ea8f..f4701f74 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -38,7 +38,7 @@ def recode_length_seconds(time) if time < 0 return "" elsif time == 0 - return "0:00" + return "0:00" else time = time.seconds text = "#{time.minutes.to_s.rjust(2, '0')}:#{time.seconds.to_s.rjust(2, '0')}" diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 2846f709..59a380ae 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -243,10 +243,10 @@ module Invidious::Routes::API::V1::Authenticated env.response.headers["Location"] = "#{HOST_URL}/api/v1/auth/compilations/#{compilation.id}" env.response.status_code = 201 { - "title" => title, + "title" => title, "compilationId" => compilation.id, }.to_json - end + end def self.create_playlist(env) env.response.content_type = "application/json" diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr index cf769512..4fdb7074 100644 --- a/src/invidious/routes/api/v1/misc.cr +++ b/src/invidious/routes/api/v1/misc.cr @@ -68,15 +68,14 @@ module Invidious::Routes::API::V1::Misc response = { "compilationHtml" => compilation_html, - "index" => index, - "nextVideo" => next_video, + "index" => index, + "nextVideo" => next_video, }.to_json end response end - # APIv1 currently uses the same logic for both # user playlists and Invidious playlists. This means that we can't # reasonably split them yet. This should be addressed in APIv2 diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 997e2475..4a8a17ca 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -22,7 +22,7 @@ module Invidious::Routes::Compilations user = env.get? "user" sid = env.get? "sid" - referer = get_referer(env) + referer = get_referer(env) return env.redirect "/" if user.nil? @@ -49,7 +49,7 @@ module Invidious::Routes::Compilations if Invidious::Database::Compilations.count_owned_by(user.email) >= 100 return error_template(400, "User cannot have more than 100 compilations.") end - + compilation = create_compilation(title, privacy, user) env.redirect "/compilation?list=#{compilation.id}" @@ -218,7 +218,6 @@ module Invidious::Routes::Compilations return error_template(400, ex) end - if !compid || compid.empty? return error_json(400, "A compilation ID is required") end @@ -245,7 +244,7 @@ module Invidious::Routes::Compilations if !start_timestamp.nil? && !compilation_video[0].id.nil? start_timestamp_seconds = decode_length_seconds(start_timestamp) if !start_timestamp_seconds.nil? - if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].length_seconds + if start_timestamp_seconds >= 0 && start_timestamp_seconds <= compilation_video[0].length_seconds Invidious::Database::CompilationVideos.update_start_timestamp(compilation_video[0].id, start_timestamp_seconds.to_i) end end @@ -261,14 +260,12 @@ module Invidious::Routes::Compilations end end end - end update_first_video_params(compid) env.redirect "/compilation?list=#{compid}" end - def self.add_compilation_items_page(env) prefs = env.get("preferences").as(Preferences) @@ -314,7 +311,7 @@ module Invidious::Routes::Compilations env.set "add_compilation_items", compid templated "add_compilation_items" - end + end def self.compilation_ajax(env) locale = env.get("preferences").as(Preferences).locale @@ -326,7 +323,7 @@ module Invidious::Routes::Compilations redirect = env.params.query["redirect"]? redirect ||= "true" redirect = redirect == "true" - if !user + if !user if redirect return env.redirect referer else @@ -362,7 +359,7 @@ module Invidious::Routes::Compilations elsif env.params.query["action_move_video_before"]? action = "action_move_video_before" elsif env.params.query["action_move_video_after"]? - action = "action_move_video_after" + action = "action_move_video_after" else return env.redirect referer end @@ -422,7 +419,7 @@ module Invidious::Routes::Compilations compid: compilation_id, live_now: video.live_now, index: Random::Secure.rand(0_i64..Int64::MAX), - order_index: compilation.index.size + order_index: compilation.index.size, }) Invidious::Database::CompilationVideos.insert(compilation_video) @@ -451,7 +448,7 @@ module Invidious::Routes::Compilations compilation_index_array_position = compilation_index_array.index(compilation_video[0].index) if !compilation_index_array_position.nil? compilation_index_array.delete_at(compilation_index_array_position) - compilation_index_array.insert(compilation_index_array_position-1,compilation_video[0].index) + compilation_index_array.insert(compilation_index_array_position - 1, compilation_video[0].index) Invidious::Database::Compilations.move_video_position(compilation_id, compilation_index_array) end update_first_video_params(compilation_id) @@ -473,10 +470,14 @@ module Invidious::Routes::Compilations compilation_index_array_position = compilation_index_array.index(compilation_video[0].index) if !compilation_index_array_position.nil? compilation_index_array.delete_at(compilation_index_array_position) - compilation_index_array.insert(compilation_index_array_position+1,compilation_video[0].index) + if (compilation_index_array_position == compilation_index_array.size) + compilation_index_array.insert(compilation_index_array_position, compilation_video[0].index) + else + compilation_index_array.insert(compilation_index_array_position + 1, compilation_video[0].index) + end Invidious::Database::Compilations.move_video_position(compilation_id, compilation_index_array) end - update_first_video_params(compilation_id) + update_first_video_params(compilation_id) else return error_json(400, "Unsupported action #{action}") end @@ -537,5 +538,5 @@ module Invidious::Routes::Compilations end templated "compilation" - end -end \ No newline at end of file + end +end diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index bd3245cc..ea71186b 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -28,7 +28,7 @@ module Invidious::Routes::Misc env.redirect "/feed/compilations" else env.redirect "/feed/popular" - end + end else templated "search_homepage", navbar_search: false end diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index 1ba84543..f7529c84 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -41,32 +41,32 @@ module Invidious::Routes::Watch if env.params.query["list"]?.try &.starts_with? "IVPL" plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") continuation = process_continuation(env.params.query, plid, id) - elsif env.params.query["list"]?.try &.starts_with? "IVCMP" + elsif env.params.query["list"]?.try &.starts_with? "IVCMP" compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") if (!compid.nil?) - index=Invidious::Database::CompilationVideos.select_index(compid,id) - indices_array=Invidious::Database::Compilations.select_index_array(compid) + index = Invidious::Database::CompilationVideos.select_index(compid, id) + indices_array = Invidious::Database::Compilations.select_index_array(compid) if (!indices_array.nil?) - position_of_index=indices_array.index(index) + position_of_index = indices_array.index(index) if (!position_of_index.nil? && position_of_index != indices_array.size - 1) - next_index=indices_array[position_of_index+1] + next_index = indices_array[position_of_index + 1] else - next_index=indices_array[0] - end + next_index = indices_array[0] + end if (!next_index.nil?) - next_id=Invidious::Database::CompilationVideos.select_id_from_index(next_index) + next_id = Invidious::Database::CompilationVideos.select_id_from_index(next_index) if (!next_id.nil?) timestamps = Invidious::Database::CompilationVideos.select_timestamps(compid, next_id) if (!timestamps.nil?) - starting_timestamp_seconds=timestamps[0] - ending_timestamp_seconds=timestamps[1] + starting_timestamp_seconds = timestamps[0] + ending_timestamp_seconds = timestamps[1] end - end - end - end - end + end + end + end + end continuation = process_continuation(env.params.query, compid, id) - end + end nojs = env.params.query["nojs"]? diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index b5cb0527..a5ee47b9 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -89,7 +89,7 @@ module Invidious::Routing get "/add_compilation_items", Routes::Compilations, :add_compilation_items_page get "/edit_compilation", Routes::Compilations, :edit post "/edit_compilation", Routes::Compilations, :adjust_timestamps - end + end def register_iv_playlist_routes get "/create_playlist", Routes::Playlists, :new diff --git a/src/invidious/search/query.cr b/src/invidious/search/query.cr index de64388e..83e9f597 100644 --- a/src/invidious/search/query.cr +++ b/src/invidious/search/query.cr @@ -81,7 +81,7 @@ module Invidious::Search # string itself (legacy), and the channel is ignored. # @filters, _, @query, _ = Filters.from_legacy_filters(@raw_query) - # + # when .subscriptions?, .regular? if params["sp"]? # Parse the `sp` URL parameter (youtube compatibility) From 379761ab7b37038bdb7e95c48c16fce1ca1eab84 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 3 Dec 2023 17:20:36 -0800 Subject: [PATCH 40/45] Change "list" to "comp" --- src/invidious/compilations.cr | 4 ++-- src/invidious/routes/compilations.cr | 10 +++------- src/invidious/views/add_compilation_items.ecr | 4 ++-- src/invidious/views/compilation.ecr | 8 ++++---- src/invidious/views/components/item.ecr | 3 +-- src/invidious/views/edit_compilation.ecr | 6 +++--- 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/invidious/compilations.cr b/src/invidious/compilations.cr index 0315f6ec..e3a4147f 100644 --- a/src/invidious/compilations.cr +++ b/src/invidious/compilations.cr @@ -452,7 +452,7 @@ end def template_compilation(compilation) html = <<-END_HTML

- + #{compilation["title"]}

@@ -463,7 +463,7 @@ def template_compilation(compilation) compilation["videos"].as_a.each do |video| html += <<-END_HTML
  • - +

    #{recode_length_seconds(video["lengthSeconds"].as_i)}

    diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 4a8a17ca..0ccc67c1 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -52,7 +52,7 @@ module Invidious::Routes::Compilations compilation = create_compilation(title, privacy, user) - env.redirect "/compilation?list=#{compilation.id}" + env.redirect "/compilation?comp=#{compilation.id}" end def self.delete_page(env) @@ -264,7 +264,7 @@ module Invidious::Routes::Compilations update_first_video_params(compid) - env.redirect "/compilation?list=#{compid}" + env.redirect "/compilation?comp=#{compid}" end def self.add_compilation_items_page(env) @@ -496,7 +496,7 @@ module Invidious::Routes::Compilations user = env.get?("user").try &.as(User) referer = get_referer(env) - compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + compid = env.params.query["comp"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") if !compid return env.redirect "/" end @@ -504,10 +504,6 @@ module Invidious::Routes::Compilations page = env.params.query["page"]?.try &.to_i? page ||= 1 - if compid.starts_with? "RD" - return env.redirect "/mix?list=#{compid}" - end - begin compilation = get_compilation(compid) rescue ex : NotFoundException diff --git a/src/invidious/views/add_compilation_items.ecr b/src/invidious/views/add_compilation_items.ecr index e62e860c..d8874930 100644 --- a/src/invidious/views/add_compilation_items.ecr +++ b/src/invidious/views/add_compilation_items.ecr @@ -8,13 +8,13 @@
    diff --git a/src/invidious/views/compilation.ecr b/src/invidious/views/compilation.ecr index 7fa900a1..c1d994f9 100644 --- a/src/invidious/views/compilation.ecr +++ b/src/invidious/views/compilation.ecr @@ -13,23 +13,23 @@ <%- if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email -%> <%- if compilation.index.size > 0 -%> <%- end -%> diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr index 2155d74c..c08bc7f5 100644 --- a/src/invidious/views/components/item.ecr +++ b/src/invidious/views/components/item.ecr @@ -59,7 +59,7 @@ if item.id.starts_with? "RD" link_url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" elsif item.id.starts_with? "IVCMP" - link_url = "/compilation?list=#{item.id}" + link_url = "/compilation?comp=#{item.id}" else link_url = "/playlist?list=#{item.id}" end @@ -100,7 +100,6 @@ elsif item.is_a?(MixVideo) link_url = "/watch?v=#{item.id}&list=#{item.rdid}" endpoint_params = "?v=#{item.id}&list=#{item.rdid}" - # elsif item.is_a?(CompilationVideo) else link_url = "/watch?v=#{item.id}" endpoint_params = "?v=#{item.id}" diff --git a/src/invidious/views/edit_compilation.ecr b/src/invidious/views/edit_compilation.ecr index 94c3e180..b6ec7ce1 100644 --- a/src/invidious/views/edit_compilation.ecr +++ b/src/invidious/views/edit_compilation.ecr @@ -5,11 +5,11 @@ <% end %> -
    +
    From df188c032ca8f52d4960fb8dd35d5bda0f6f650f Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Sun, 3 Dec 2023 18:44:07 -0800 Subject: [PATCH 41/45] Complete the bifurcation of "list" and "comp" --- assets/js/embed.js | 2 +- assets/js/watch.js | 2 +- config/config.example.yml | 2 +- docker-compose.yml | 2 +- src/invidious/routes/compilations.cr | 18 +++++++++--------- src/invidious/routes/watch.cr | 4 ++-- src/invidious/views/edit_compilation.ecr | 8 -------- 7 files changed, 15 insertions(+), 23 deletions(-) diff --git a/assets/js/embed.js b/assets/js/embed.js index b5fa1b3f..f7940345 100644 --- a/assets/js/embed.js +++ b/assets/js/embed.js @@ -16,7 +16,7 @@ function get_compilation(compid) { player.on('ended', function () { var url = new URL('https://example.com/embed/' + response.nextVideo); - url.searchParams.set('list', compid); + url.searchParams.set('comp', compid); if (!compid.startsWith('RD')) url.searchParams.set('index', response.index); if (video_data.params.autoplay || video_data.params.continue_autoplay) diff --git a/assets/js/watch.js b/assets/js/watch.js index 50e1f82e..08ab490c 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -73,7 +73,7 @@ function get_compilation(compid) { player.on('ended', function () { var url = new URL('https://example.com/watch?v=' + response.nextVideo); - url.searchParams.set('list', compid); + url.searchParams.set('comp', compid); if (!compid.startsWith('RD')) url.searchParams.set('index', response.index); if (video_data.params.autoplay || video_data.params.continue_autoplay) diff --git a/config/config.example.yml b/config/config.example.yml index 4e4d6a8b..cfdef561 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -457,7 +457,7 @@ jobs: ## Accepted values: a string ## Default: ## -hmac_key: "CHANGE_ME!!" +hmac_key: "83646b9f96e6823d2c6e275911ade98f5e9436fa" ## ## List of video IDs where the "download" widget must be diff --git a/docker-compose.yml b/docker-compose.yml index d879919a..8a267b25 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,7 +30,7 @@ services: # domain: # https_only: false # statistics_enabled: false - hmac_key: "CHANGE_ME!!" + hmac_key: "83646b9f96e6823d2c6e275911ade98f5e9436fa" healthcheck: test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1 interval: 30s diff --git a/src/invidious/routes/compilations.cr b/src/invidious/routes/compilations.cr index 0ccc67c1..ccc6819d 100644 --- a/src/invidious/routes/compilations.cr +++ b/src/invidious/routes/compilations.cr @@ -67,7 +67,7 @@ module Invidious::Routes::Compilations user = user.as(User) sid = sid.as(String) - compid = env.params.query["list"]? + compid = env.params.query["comp"]? if !compid || compid.empty? return error_template(400, "A compilation ID is required") end @@ -91,7 +91,7 @@ module Invidious::Routes::Compilations return env.redirect "/" if user.nil? - compid = env.params.query["list"]? + compid = env.params.query["comp"]? return env.redirect referer if compid.nil? user = user.as(User) @@ -126,7 +126,7 @@ module Invidious::Routes::Compilations user = user.as(User) sid = sid.as(String) - compid = env.params.query["list"]? + compid = env.params.query["comp"]? if !compid || !compid.starts_with?("IVCMP") return env.redirect referer end @@ -159,7 +159,7 @@ module Invidious::Routes::Compilations return env.redirect "/" if user.nil? - compid = env.params.query["list"]? + compid = env.params.query["comp"]? return env.redirect referer if compid.nil? user = user.as(User) @@ -191,7 +191,7 @@ module Invidious::Routes::Compilations Invidious::Database::Compilations.update(compid, title, privacy, description, updated) - env.redirect "/compilation?list=#{compid}" + env.redirect "/compilation?comp=#{compid}" end def self.adjust_timestamps(env) @@ -204,7 +204,7 @@ module Invidious::Routes::Compilations return env.redirect "/" if user.nil? - compid = env.params.query["list"]? + compid = env.params.query["comp"]? return env.redirect referer if compid.nil? user = user.as(User) @@ -282,7 +282,7 @@ module Invidious::Routes::Compilations user = user.as(User) sid = sid.as(String) - compid = env.params.query["list"]? + compid = env.params.query["comp"]? if !compid || !compid.starts_with?("IVCMP") return env.redirect referer end @@ -304,7 +304,7 @@ module Invidious::Routes::Compilations query_encoded = URI.encode_www_form(query.try &.text || "", space_to_plus: true) page_nav_html = Frontend::Pagination.nav_numeric(locale, - base_url: "/add_compilation_items?list=#{compilation.id}&q=#{query_encoded}", + base_url: "/add_compilation_items?comp=#{compilation.id}&q=#{query_encoded}", current_page: page, show_next: (items.size >= 20) ) @@ -516,7 +516,7 @@ module Invidious::Routes::Compilations page_count += 1 if (compilation.video_count % 200) > 0 if page > page_count - return env.redirect "/compilation?list=#{compid}&page=#{page_count}" + return env.redirect "/compilation?comp=#{compid}&page=#{page_count}" end if compilation.privacy == CompilationPrivacy::Private && compilation.author != user.try &.email diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index f7529c84..8f4b602f 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -41,8 +41,8 @@ module Invidious::Routes::Watch if env.params.query["list"]?.try &.starts_with? "IVPL" plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") continuation = process_continuation(env.params.query, plid, id) - elsif env.params.query["list"]?.try &.starts_with? "IVCMP" - compid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") + elsif env.params.query["comp"]?.try &.starts_with? "IVCMP" + compid = env.params.query["comp"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "") if (!compid.nil?) index = Invidious::Database::CompilationVideos.select_index(compid, id) indices_array = Invidious::Database::Compilations.select_index_array(compid) diff --git a/src/invidious/views/edit_compilation.ecr b/src/invidious/views/edit_compilation.ecr index b6ec7ce1..a70a0db5 100644 --- a/src/invidious/views/edit_compilation.ecr +++ b/src/invidious/views/edit_compilation.ecr @@ -58,11 +58,3 @@ <% end %>
    - - - - - - - - From 7a31ca733d8e25512dc596844c165aa4471d27fe Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 5 Dec 2023 00:27:18 -0800 Subject: [PATCH 42/45] Revert mistake --- config/config.example.yml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.example.yml b/config/config.example.yml index cfdef561..4e4d6a8b 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -457,7 +457,7 @@ jobs: ## Accepted values: a string ## Default: ## -hmac_key: "83646b9f96e6823d2c6e275911ade98f5e9436fa" +hmac_key: "CHANGE_ME!!" ## ## List of video IDs where the "download" widget must be diff --git a/docker-compose.yml b/docker-compose.yml index 8a267b25..d879919a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,7 +30,7 @@ services: # domain: # https_only: false # statistics_enabled: false - hmac_key: "83646b9f96e6823d2c6e275911ade98f5e9436fa" + hmac_key: "CHANGE_ME!!" healthcheck: test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1 interval: 30s From a33c01bd5346d07d94fe5a718a9fdc325e8e0676 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 29 Dec 2023 04:09:08 -0800 Subject: [PATCH 43/45] Fix version number --- .../database/migrations/0011_create_compilations_table.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr index 643cd506..c637d6e4 100644 --- a/src/invidious/database/migrations/0011_create_compilations_table.cr +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -1,6 +1,6 @@ module Invidious::Database::Migrations class CreateCompilationsTable < Migration - version 8 + version 11 def up(conn : DB::Connection) if !privacy_type_exists?(conn) From 22455bbf9e7ed4db23b862885a90fa50be05f87c Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 29 Dec 2023 04:30:31 -0800 Subject: [PATCH 44/45] Add new enum --- .../database/migrations/0011_create_compilations_table.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/invidious/database/migrations/0011_create_compilations_table.cr b/src/invidious/database/migrations/0011_create_compilations_table.cr index c637d6e4..363f2107 100644 --- a/src/invidious/database/migrations/0011_create_compilations_table.cr +++ b/src/invidious/database/migrations/0011_create_compilations_table.cr @@ -3,7 +3,7 @@ module Invidious::Database::Migrations version 11 def up(conn : DB::Connection) - if !privacy_type_exists?(conn) + if !compilation_privacy_type_exists?(conn) conn.exec <<-SQL CREATE TYPE public.compilation_privacy AS ENUM ( @@ -36,13 +36,13 @@ module Invidious::Database::Migrations SQL end - private def privacy_type_exists?(conn : DB::Connection) : Bool + private def compilation_privacy_type_exists?(conn : DB::Connection) : Bool request = <<-SQL SELECT 1 AS one FROM pg_type INNER JOIN pg_namespace ON pg_namespace.oid = pg_type.typnamespace WHERE pg_namespace.nspname = 'public' - AND pg_type.typname = 'privacy' + AND pg_type.typname = 'compilation_privacy' LIMIT 1; SQL From 10d8a4b3ca96398e5d2586ef6bed16b605ccb09a Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Fri, 29 Dec 2023 04:53:28 -0800 Subject: [PATCH 45/45] Add new migration --- .../0012_create_compilation_videos_table.cr | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/invidious/database/migrations/0012_create_compilation_videos_table.cr diff --git a/src/invidious/database/migrations/0012_create_compilation_videos_table.cr b/src/invidious/database/migrations/0012_create_compilation_videos_table.cr new file mode 100644 index 00000000..6d891066 --- /dev/null +++ b/src/invidious/database/migrations/0012_create_compilation_videos_table.cr @@ -0,0 +1,30 @@ +module Invidious::Database::Migrations + class CreateCompilationVideosTable < Migration + version 12 + + def up(conn : DB::Connection) + conn.exec <<-SQL + CREATE TABLE IF NOT EXISTS public.compilation_videos + ( + title text, + id text, + author text, + ucid text, + length_seconds integer, + starting_timestamp_seconds integer, + ending_timestamp_seconds integer, + published timestamptz, + compid text references compilations(id), + index int8, + order_index integer, + PRIMARY KEY (index,compid) + ); + SQL + + conn.exec <<-SQL + GRANT ALL ON TABLE public.playlist_videos TO current_user; + SQL + end + end + end + \ No newline at end of file