From 1d209c422e1422c831a826ca87b40b5777917821 Mon Sep 17 00:00:00 2001 From: broquemonsieur Date: Tue, 27 Jun 2023 00:25:01 -0700 Subject: [PATCH] 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? %>