mirror of
https://github.com/iv-org/invidious.git
synced 2024-10-01 01:25:56 -04:00
getcompilation route to routes that are registered
This commit is contained in:
parent
7cfa09984e
commit
1d209c422e
@ -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
|
||||
|
@ -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)
|
||||
|
@ -202,7 +202,7 @@ module Invidious::Database::CompilationVideos
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Salect
|
||||
# Select
|
||||
# -------------------
|
||||
|
||||
def select(compid : String, index : VideoIndex, offset, limit = 100) : Array(CompilationVideo)
|
||||
|
@ -212,7 +212,7 @@ module Invidious::Database::PlaylistVideos
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Salect
|
||||
# Select
|
||||
# -------------------
|
||||
|
||||
def select(plid : String, index : VideoIndex, offset, limit = 100) : Array(PlaylistVideo)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -85,6 +85,7 @@ module Invidious::Routes::BeforeAll
|
||||
csrf_token = generate_response(sid, {
|
||||
":authorize_token",
|
||||
":playlist_ajax",
|
||||
":compilation_ajax",
|
||||
":signout",
|
||||
":subscription_ajax",
|
||||
":token_ajax",
|
||||
|
@ -1,7 +1,11 @@
|
||||
{% skip_file if flag?(:api_only) %}
|
||||
|
||||
module Invidious::Routes::Compilations
|
||||
def self.handle(env)
|
||||
return "<htm><body><p>Hello</p></body></html>"
|
||||
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.<br>#{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
|
||||
|
@ -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"]
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 %}
|
||||
|
@ -3,49 +3,6 @@
|
||||
|
||||
<% content_for "header" do %>
|
||||
<title><%= title %> - Invidious</title>
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="/feed/playlist/<%= plid %>" />
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS" href="/feed/compilation/<%= compid %>" />
|
||||
<% end %>
|
||||
|
||||
<div class="pure-g h-box">
|
||||
<div class="pure-u-2-3">
|
||||
<h3><%= title %></h3>
|
||||
<% if compilation.is_a? InvidiousCompilation %>
|
||||
<b>
|
||||
<% if compilation.author == user.try &.email %>
|
||||
<a href="/feed/compilations"><%= author %></a> |
|
||||
<% 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 %>
|
||||
<i class="icon ion-ios-unlock"></i> <%= translate(locale, "Unlisted") %>
|
||||
<% when CompilationPrivacy::Private %>
|
||||
<i class="icon ion-ios-lock"></i> <%= translate(locale, "Private") %>
|
||||
<% end %>
|
||||
</b>
|
||||
<% else %>
|
||||
<b>
|
||||
<a href="/channel/<%= compilation.ucid %>"><%= author %></a> |
|
||||
<%= translate_count(locale, "generic_videos_count", compilation.video_count) %> |
|
||||
<%= translate(locale, "Updated `x` ago", recode_date(compilation.updated, locale)) %>
|
||||
</b>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="pure-u-1-3" style="text-align:right">
|
||||
<h3>
|
||||
<div class="pure-g user-field">
|
||||
<% if compilation.is_a?(InvidiousCompilation) && compilation.author == user.try &.email %>
|
||||
<div class="pure-u-1-3"><a href="/edit_compilation?list=<%= compid %>"><i class="icon ion-md-create"></i></a></div>
|
||||
<div class="pure-u-1-3"><a href="/delete_compilation?list=<%= compid %>"><i class="icon ion-md-trash"></i></a></div>
|
||||
<% else %>
|
||||
<% if !Invidious::Database::Compilations.exists?(compilation.id) %>
|
||||
<div class="pure-u-1-3"><a href="/delete_compilation?list=<%= compid %>"><i class="icon ion-md-trash"></i></a></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<div class="pure-u-1-3"><a href="/feed/playlist/<%= plid %>"><i class="icon ion-logo-rss"></i></a></div>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
@ -53,7 +53,7 @@
|
||||
<p><%= translate_count(locale, "generic_channels_count", item.channel_count, NumberFormatting::Separator) %></p>
|
||||
<%- end -%>
|
||||
</div>
|
||||
<% 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 @@
|
||||
</p>
|
||||
</a></div>
|
||||
</div>
|
||||
<% when InvidiousCompilation %>
|
||||
<% url = "/compilation?list=#{item.id}" %>
|
||||
<a style="width:100%" href="<%= url %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
<div class="thumbnail">
|
||||
<img loading="lazy" tabindex="-1" class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").request_target %>" alt="" />
|
||||
<p class="length"><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<p dir="auto"><%= HTML.escape(item.title) %></p>
|
||||
</a>
|
||||
<a href="/channel/<%= item.ucid %>">
|
||||
<p dir="auto"><b><%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousCompilation) && !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></b></p>
|
||||
</a>
|
||||
<% when CompilationVideo %>
|
||||
<a style="width:100%" href="/watch?v=<%= item.id %>&list=<%= item.compid %>&index=<%= item.index %>">
|
||||
<% if !env.get("preferences").as(Preferences).thin_mode %>
|
||||
|
@ -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? %>
|
||||
<form data-onsubmit="return_false" class="pure-form pure-form-stacked" action="/compilation_ajax" method="post" target="_blank">
|
||||
<div class="pure-control-group">
|
||||
<label for="compilation_id"><%= translate(locale, "Add to compilation: ") %></label>
|
||||
<select style="width:100%" name="compilation_id" id="compilation_id">
|
||||
<% compilations.each do |compid, compilation_title| %>
|
||||
<option data-compid="<%= compid %>" value="<%= compid %>"><%= HTML.escape(compilation_title) %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(env.get?("csrf_token").try &.as(String) || "") %>">
|
||||
<input type="hidden" name="action_add_video" value="1">
|
||||
<input type="hidden" name="video_id" value="<%= video.id %>">
|
||||
<button data-onclick="add_compilation_video" data-id="<%= video.id %>" type="submit" class="pure-button pure-button-primary">
|
||||
<b><%= translate(locale, "Add to compilation") %></b>
|
||||
</button>
|
||||
</form>
|
||||
<script id="compilation_data" type="application/json">
|
||||
<%=
|
||||
{
|
||||
"csrf_token" => URI.encode_www_form(env.get?("csrf_token").try &.as(String) || "")
|
||||
}.to_pretty_json
|
||||
%>
|
||||
</script>
|
||||
<script src="/js/compilation_widget.js?v=<%= Time.utc.to_unix_ms %>"></script>
|
||||
<% end %>
|
||||
<% if !playlists.empty? %>
|
||||
<form data-onsubmit="return_false" class="pure-form pure-form-stacked" action="/playlist_ajax" method="post" target="_blank">
|
||||
<div class="pure-control-group">
|
||||
|
Loading…
Reference in New Issue
Block a user