summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/invidious.cr55
-rw-r--r--src/invidious/comments.cr20
-rw-r--r--src/invidious/helpers/helpers.cr4
-rw-r--r--src/invidious/helpers/logger.cr2
-rw-r--r--src/invidious/helpers/proxy.cr6
-rw-r--r--src/invidious/helpers/utils.cr2
-rw-r--r--src/invidious/jobs/bypass_captcha_job.cr2
-rw-r--r--src/invidious/routes/embed.cr (renamed from src/invidious/routes/embed/show.cr)32
-rw-r--r--src/invidious/routes/embed/index.cr25
-rw-r--r--src/invidious/routes/licenses.cr6
-rw-r--r--src/invidious/routes/login.cr2
-rw-r--r--src/invidious/routes/misc.cr (renamed from src/invidious/routes/home.cr)14
-rw-r--r--src/invidious/routes/preferences.cr (renamed from src/invidious/routes/user_preferences.cr)2
-rw-r--r--src/invidious/routes/privacy.cr6
-rw-r--r--src/invidious/routes/watch.cr4
-rw-r--r--src/invidious/search.cr11
-rw-r--r--src/invidious/videos.cr5
-rw-r--r--src/invidious/views/channel.ecr4
-rw-r--r--src/invidious/views/community.ecr4
-rw-r--r--src/invidious/views/components/item.ecr6
-rw-r--r--src/invidious/views/components/player.ecr9
-rw-r--r--src/invidious/views/components/player_sources.ecr1
-rw-r--r--src/invidious/views/playlists.ecr4
-rw-r--r--src/invidious/views/watch.ecr7
24 files changed, 122 insertions, 111 deletions
diff --git a/src/invidious.cr b/src/invidious.cr
index a0702820..cb2bb5fe 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -73,8 +73,11 @@ LOCALES = {
"eo" => load_locale("eo"),
"es" => load_locale("es"),
"fa" => load_locale("fa"),
+ "fi" => load_locale("fi"),
"fr" => load_locale("fr"),
+ "he" => load_locale("he"),
"hr" => load_locale("hr"),
+ "id" => load_locale("id"),
"is" => load_locale("is"),
"it" => load_locale("it"),
"ja" => load_locale("ja"),
@@ -207,7 +210,7 @@ before_all do |env|
extra_media_csp += " https://*.youtube.com:443"
end
# TODO: Remove style-src's 'unsafe-inline', requires to remove all inline styles (<style> [..] </style>, style=" [..] ")
- env.response.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob:#{extra_media_csp}"
+ env.response.headers["Content-Security-Policy"] = "default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; manifest-src 'self'; media-src 'self' blob:#{extra_media_csp}; child-src blob:"
env.response.headers["Referrer-Policy"] = "same-origin"
if (Kemal.config.ssl || CONFIG.https_only) && CONFIG.hsts
@@ -301,12 +304,12 @@ before_all do |env|
env.set "current_page", URI.encode_www_form(current_page)
end
-Invidious::Routing.get "/", Invidious::Routes::Home
-Invidious::Routing.get "/privacy", Invidious::Routes::Privacy
-Invidious::Routing.get "/licenses", Invidious::Routes::Licenses
+Invidious::Routing.get "/", Invidious::Routes::Misc, :home
+Invidious::Routing.get "/privacy", Invidious::Routes::Misc, :privacy
+Invidious::Routing.get "/licenses", Invidious::Routes::Misc, :licenses
Invidious::Routing.get "/watch", Invidious::Routes::Watch
-Invidious::Routing.get "/embed/", Invidious::Routes::Embed::Index
-Invidious::Routing.get "/embed/:id", Invidious::Routes::Embed::Show
+Invidious::Routing.get "/embed/", Invidious::Routes::Embed, :redirect
+Invidious::Routing.get "/embed/:id", Invidious::Routes::Embed, :show
Invidious::Routing.get "/view_all_playlists", Invidious::Routes::Playlists, :index
Invidious::Routing.get "/create_playlist", Invidious::Routes::Playlists, :new
Invidious::Routing.post "/create_playlist", Invidious::Routes::Playlists, :create
@@ -325,9 +328,9 @@ Invidious::Routing.get "/search", Invidious::Routes::Search, :search
Invidious::Routing.get "/login", Invidious::Routes::Login, :login_page
Invidious::Routing.post "/login", Invidious::Routes::Login, :login
Invidious::Routing.post "/signout", Invidious::Routes::Login, :signout
-Invidious::Routing.get "/preferences", Invidious::Routes::UserPreferences, :show
-Invidious::Routing.post "/preferences", Invidious::Routes::UserPreferences, :update
-Invidious::Routing.get "/toggle_theme", Invidious::Routes::UserPreferences, :toggle_theme
+Invidious::Routing.get "/preferences", Invidious::Routes::PreferencesRoute, :show
+Invidious::Routing.post "/preferences", Invidious::Routes::PreferencesRoute, :update
+Invidious::Routing.get "/toggle_theme", Invidious::Routes::PreferencesRoute, :toggle_theme
# Users
@@ -1418,9 +1421,9 @@ get "/feed/playlist/:plid" do |env|
node.attributes.each do |attribute|
case attribute.name
when "url", "href"
- full_path = URI.parse(node[attribute.name]).full_path
- query_string_opt = full_path.starts_with?("/watch?v=") ? "&#{params}" : ""
- node[attribute.name] = "#{HOST_URL}#{full_path}#{query_string_opt}"
+ request_target = URI.parse(node[attribute.name]).request_target
+ query_string_opt = request_target.starts_with?("/watch?v=") ? "&#{params}" : ""
+ node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
else nil # Skip
end
end
@@ -1429,7 +1432,7 @@ get "/feed/playlist/:plid" do |env|
document = document.to_xml(options: XML::SaveOptions::NO_DECL)
document.scan(/<uri>(?<url>[^<]+)<\/uri>/).each do |match|
- content = "#{HOST_URL}#{URI.parse(match["url"]).full_path}"
+ content = "#{HOST_URL}#{URI.parse(match["url"]).request_target}"
document = document.gsub(match[0], "<uri>#{content}</uri>")
end
@@ -1624,7 +1627,7 @@ end
get "/attribution_link" do |env|
if query = env.params.query["u"]?
- url = URI.parse(query).full_path
+ url = URI.parse(query).request_target
else
url = "/"
end
@@ -1968,7 +1971,7 @@ get "/api/v1/captions/:id" do |env|
caption = caption[0]
end
- url = URI.parse("#{caption.baseUrl}&tlang=#{tlang}").full_path
+ url = URI.parse("#{caption.baseUrl}&tlang=#{tlang}").request_target
# Auto-generated captions often have cues that aren't aligned properly with the video,
# as well as some other markup that makes it cumbersome, so we try to fix that here
@@ -2548,12 +2551,12 @@ get "/api/v1/search" do |env|
content_type ||= "video"
begin
- search_params = produce_search_params(sort_by, date, content_type, duration, features)
+ search_params = produce_search_params(page, sort_by, date, content_type, duration, features)
rescue ex
next error_json(400, ex)
end
- count, search_results = search(query, page, search_params, region).as(Tuple)
+ count, search_results = search(query, search_params, region).as(Tuple)
JSON.build do |json|
json.array do
search_results.each do |item|
@@ -3174,7 +3177,7 @@ get "/api/manifest/dash/id/:id" do |env|
end
if dashmpd = video.dash_manifest_url
- manifest = YT_POOL.client &.get(URI.parse(dashmpd).full_path).body
+ manifest = YT_POOL.client &.get(URI.parse(dashmpd).request_target).body
manifest = manifest.gsub(/<BaseURL>[^<]+<\/BaseURL>/) do |baseurl|
url = baseurl.lchop("<BaseURL>")
@@ -3182,7 +3185,7 @@ get "/api/manifest/dash/id/:id" do |env|
if local
uri = URI.parse(url)
- url = "#{uri.full_path}host/#{uri.host}/"
+ url = "#{uri.request_target}host/#{uri.host}/"
end
"<BaseURL>#{url}</BaseURL>"
@@ -3195,7 +3198,7 @@ get "/api/manifest/dash/id/:id" do |env|
if local
adaptive_fmts.each do |fmt|
- fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path)
+ fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target)
end
end
@@ -3393,7 +3396,7 @@ get "/latest_version" do |env|
next
end
- url = URI.parse(url).full_path.not_nil! if local
+ url = URI.parse(url).request_target.not_nil! if local
url = "#{url}&title=#{title}" if title
env.redirect url
@@ -3505,7 +3508,7 @@ get "/videoplayback" do |env|
client = make_client(URI.parse(new_host), region)
end
- url = "#{location.full_path}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
+ url = "#{location.request_target}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
else
break
end
@@ -3545,7 +3548,7 @@ get "/videoplayback" do |env|
if location = response.headers["Location"]?
location = URI.parse(location)
- location = "#{location.full_path}&host=#{location.host}"
+ location = "#{location.request_target}&host=#{location.host}"
if region
location += "&region=#{region}"
@@ -3609,7 +3612,7 @@ get "/videoplayback" do |env|
if location = response.headers["Location"]?
location = URI.parse(location)
- location = "#{location.full_path}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
+ location = "#{location.request_target}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
env.redirect location
break
@@ -3849,7 +3852,7 @@ end
get "/watch_videos" do |env|
response = YT_POOL.client &.get(env.request.resource)
if url = response.headers["Location"]?
- url = URI.parse(url).full_path
+ url = URI.parse(url).request_target
next env.redirect url
end
@@ -3864,7 +3867,7 @@ error 404 do |env|
response = YT_POOL.client &.get("/#{item}")
if response.status_code == 301
- response = YT_POOL.client &.get(URI.parse(response.headers["Location"]).full_path)
+ response = YT_POOL.client &.get(URI.parse(response.headers["Location"]).request_target)
end
if response.body.empty?
diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr
index 0ac99ba5..13ebbd73 100644
--- a/src/invidious/comments.cr
+++ b/src/invidious/comments.cr
@@ -195,8 +195,14 @@ def fetch_youtube_comments(id, db, cursor, format, locale, thin_mode, region, so
end
if node_replies && !response["commentRepliesContinuation"]?
- reply_count = (node_replies["moreText"]["simpleText"]? || node_replies["moreText"]["runs"]?.try &.[0]?.try &.["text"]?)
- .try &.as_s.gsub(/\D/, "").to_i? || 1
+ if node_replies["moreText"]?
+ reply_count = (node_replies["moreText"]["simpleText"]? || node_replies["moreText"]["runs"]?.try &.[0]?.try &.["text"]?)
+ .try &.as_s.gsub(/\D/, "").to_i? || 1
+ elsif node_replies["viewReplies"]?
+ reply_count = node_replies["viewReplies"]["buttonRenderer"]["text"]?.try &.["runs"][1]?.try &.["text"]?.try &.as_s.to_i? || 1
+ else
+ reply_count = 1
+ end
continuation = node_replies["continuations"]?.try &.as_a[0]["nextContinuationData"]["continuation"].as_s
continuation ||= ""
@@ -294,7 +300,7 @@ def template_youtube_comments(comments, locale, thin_mode)
end
if !thin_mode
- author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).full_path}"
+ author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).request_target}"
else
author_thumbnail = ""
end
@@ -322,7 +328,7 @@ def template_youtube_comments(comments, locale, thin_mode)
html << <<-END_HTML
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
- <img style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).full_path}">
+ <img style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).request_target}">
</div>
</div>
END_HTML
@@ -375,7 +381,7 @@ def template_youtube_comments(comments, locale, thin_mode)
if child["creatorHeart"]?
if !thin_mode
- creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).full_path}"
+ creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).request_target}"
else
creator_thumbnail = ""
end
@@ -473,7 +479,7 @@ def replace_links(html)
params = HTTP::Params.parse(url.query.not_nil!)
anchor["href"] = params["q"]?
else
- anchor["href"] = url.full_path
+ anchor["href"] = url.request_target
end
elsif url.to_s == "#"
begin
@@ -544,7 +550,7 @@ def content_to_comment_html(content)
if url.path == "/redirect"
url = HTTP::Params.parse(url.query.not_nil!)["q"]
else
- url = url.full_path
+ url = url.request_target
end
end
diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr
index a591b5eb..6452b68c 100644
--- a/src/invidious/helpers/helpers.cr
+++ b/src/invidious/helpers/helpers.cr
@@ -251,7 +251,7 @@ def extract_item(item : JSON::Any, author_fallback : String? = nil, author_id_fa
video_id = i["videoId"].as_s
title = i["title"].try { |t| t["simpleText"]?.try &.as_s || t["runs"]?.try &.as_a.map(&.["text"].as_s).join("") } || ""
- author_info = i["ownerText"]?.try &.["runs"].as_a[0]?
+ author_info = i["ownerText"]?.try &.["runs"]?.try &.as_a?.try &.[0]?
author = author_info.try &.["text"].as_s || author_fallback || ""
author_id = author_info.try &.["navigationEndpoint"]?.try &.["browseEndpoint"]["browseId"].as_s || author_id_fallback || ""
@@ -342,7 +342,7 @@ def extract_item(item : JSON::Any, author_fallback : String? = nil, author_id_fa
video_count = i["videoCount"]?.try &.as_s.to_i || 0
playlist_thumbnail = i["thumbnails"].as_a[0]?.try &.["thumbnails"]?.try &.as_a[0]?.try &.["url"].as_s || ""
- author_info = i["shortBylineText"]?.try &.["runs"].as_a[0]?
+ author_info = i["shortBylineText"]?.try &.["runs"]?.try &.as_a?.try &.[0]?
author = author_info.try &.["text"].as_s || author_fallback || ""
author_id = author_info.try &.["navigationEndpoint"]?.try &.["browseEndpoint"]["browseId"].as_s || author_id_fallback || ""
diff --git a/src/invidious/helpers/logger.cr b/src/invidious/helpers/logger.cr
index 7c5b0247..5d91a258 100644
--- a/src/invidious/helpers/logger.cr
+++ b/src/invidious/helpers/logger.cr
@@ -1,5 +1,3 @@
-require "logger"
-
enum LogLevel
All = 0
Trace = 1
diff --git a/src/invidious/helpers/proxy.cr b/src/invidious/helpers/proxy.cr
index 7a42ef41..3418d887 100644
--- a/src/invidious/helpers/proxy.cr
+++ b/src/invidious/helpers/proxy.cr
@@ -71,14 +71,14 @@ end
class HTTPClient < HTTP::Client
def set_proxy(proxy : HTTPProxy)
begin
- @socket = proxy.open(host: @host, port: @port, tls: @tls, connection_options: proxy_connection_options)
+ @io = proxy.open(host: @host, port: @port, tls: @tls, connection_options: proxy_connection_options)
rescue IO::Error
- @socket = nil
+ @io = nil
end
end
def unset_proxy
- @socket = nil
+ @io = nil
end
def proxy_connection_options
diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr
index 7d94a6e5..2c95a373 100644
--- a/src/invidious/helpers/utils.cr
+++ b/src/invidious/helpers/utils.cr
@@ -329,7 +329,7 @@ def get_referer(env, fallback = "/", unroll = true)
end
end
- referer = referer.full_path
+ referer = referer.request_target
referer = "/" + referer.gsub(/[^\/?@&%=\-_.0-9a-zA-Z]/, "").lstrip("/\\")
if referer == env.request.path
diff --git a/src/invidious/jobs/bypass_captcha_job.cr b/src/invidious/jobs/bypass_captcha_job.cr
index 8b1aed5f..4269e123 100644
--- a/src/invidious/jobs/bypass_captcha_job.cr
+++ b/src/invidious/jobs/bypass_captcha_job.cr
@@ -60,7 +60,7 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob
elsif response.headers["Location"]?.try &.includes?("/sorry/index")
location = response.headers["Location"].try { |u| URI.parse(u) }
headers = HTTP::Headers{":authority" => location.host.not_nil!}
- response = YT_POOL.client &.get(location.full_path, headers)
+ response = YT_POOL.client &.get(location.request_target, headers)
html = XML.parse_html(response.body)
form = html.xpath_node(%(//form[@action="index"])).not_nil!
diff --git a/src/invidious/routes/embed/show.cr b/src/invidious/routes/embed.cr
index 8a655556..5db32788 100644
--- a/src/invidious/routes/embed/show.cr
+++ b/src/invidious/routes/embed.cr
@@ -1,5 +1,29 @@
-class Invidious::Routes::Embed::Show < Invidious::Routes::BaseRoute
- def handle(env)
+class Invidious::Routes::Embed < Invidious::Routes::BaseRoute
+ def redirect(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+
+ if plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
+ begin
+ playlist = get_playlist(PG_DB, plid, locale: locale)
+ offset = env.params.query["index"]?.try &.to_i? || 0
+ videos = get_playlist_videos(PG_DB, playlist, offset: offset, locale: locale)
+ rescue ex
+ return error_template(500, ex)
+ end
+
+ url = "/embed/#{videos[0].id}?#{env.params.query}"
+
+ if env.params.query.size > 0
+ url += "?#{env.params.query}"
+ end
+ else
+ url = "/"
+ end
+
+ env.redirect url
+ end
+
+ def show(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
id = env.params.url["id"]
@@ -120,8 +144,8 @@ class Invidious::Routes::Embed::Show < Invidious::Routes::BaseRoute
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
+ fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
end
video_streams = video.video_streams
diff --git a/src/invidious/routes/embed/index.cr b/src/invidious/routes/embed/index.cr
deleted file mode 100644
index 32a4966b..00000000
--- a/src/invidious/routes/embed/index.cr
+++ /dev/null
@@ -1,25 +0,0 @@
-class Invidious::Routes::Embed::Index < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
-
- if plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
- begin
- playlist = get_playlist(PG_DB, plid, locale: locale)
- offset = env.params.query["index"]?.try &.to_i? || 0
- videos = get_playlist_videos(PG_DB, playlist, offset: offset, locale: locale)
- rescue ex
- return error_template(500, ex)
- end
-
- url = "/embed/#{videos[0].id}?#{env.params.query}"
-
- if env.params.query.size > 0
- url += "?#{env.params.query}"
- end
- else
- url = "/"
- end
-
- env.redirect url
- end
-end
diff --git a/src/invidious/routes/licenses.cr b/src/invidious/routes/licenses.cr
deleted file mode 100644
index 38fde7bb..00000000
--- a/src/invidious/routes/licenses.cr
+++ /dev/null
@@ -1,6 +0,0 @@
-class Invidious::Routes::Licenses < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
- rendered "licenses"
- end
-end
diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr
index 662fdf13..ffe5f568 100644
--- a/src/invidious/routes/login.cr
+++ b/src/invidious/routes/login.cr
@@ -255,7 +255,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute
traceback << "Unhandled dialog /b/0/SmsAuthInterstitial."
end
- login = client.get(location.full_path, headers)
+ login = client.get(location.request_target, headers)
headers = login.cookies.add_request_headers(headers)
location = login.headers["Location"]?.try { |u| URI.parse(u) }
diff --git a/src/invidious/routes/home.cr b/src/invidious/routes/misc.cr
index 486a7344..bc009633 100644
--- a/src/invidious/routes/home.cr
+++ b/src/invidious/routes/misc.cr
@@ -1,5 +1,5 @@
-class Invidious::Routes::Home < Invidious::Routes::BaseRoute
- def handle(env)
+class Invidious::Routes::Misc < Invidious::Routes::BaseRoute
+ def home(env)
preferences = env.get("preferences").as(Preferences)
locale = LOCALES[preferences.locale]?
user = env.get? "user"
@@ -25,4 +25,14 @@ class Invidious::Routes::Home < Invidious::Routes::BaseRoute
templated "empty"
end
end
+
+ def privacy(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+ templated "privacy"
+ end
+
+ def licenses(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+ rendered "licenses"
+ end
end
diff --git a/src/invidious/routes/user_preferences.cr b/src/invidious/routes/preferences.cr
index a689a2a2..4901d22b 100644
--- a/src/invidious/routes/user_preferences.cr
+++ b/src/invidious/routes/preferences.cr
@@ -1,4 +1,4 @@
-class Invidious::Routes::UserPreferences < Invidious::Routes::BaseRoute
+class Invidious::Routes::PreferencesRoute < Invidious::Routes::BaseRoute
def show(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
diff --git a/src/invidious/routes/privacy.cr b/src/invidious/routes/privacy.cr
deleted file mode 100644
index 4565c94c..00000000
--- a/src/invidious/routes/privacy.cr
+++ /dev/null
@@ -1,6 +0,0 @@
-class Invidious::Routes::Privacy < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
- templated "privacy"
- end
-end
diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr
index 65604a88..8169e1ed 100644
--- a/src/invidious/routes/watch.cr
+++ b/src/invidious/routes/watch.cr
@@ -126,8 +126,8 @@ class Invidious::Routes::Watch < Invidious::Routes::BaseRoute
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
+ fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
end
video_streams = video.video_streams
diff --git a/src/invidious/search.cr b/src/invidious/search.cr
index 1c4bc74e..cf8fd790 100644
--- a/src/invidious/search.cr
+++ b/src/invidious/search.cr
@@ -249,10 +249,10 @@ def channel_search(query, page, channel)
return items.size, items
end
-def search(query, page = 1, search_params = produce_search_params(content_type: "all"), region = nil)
+def search(query, search_params = produce_search_params(content_type: "all"), region = nil)
return 0, [] of SearchItem if query.empty?
- body = YT_POOL.client(region, &.get("/results?q=#{URI.encode_www_form(query)}&page=#{page}&sp=#{search_params}&hl=en").body)
+ body = YT_POOL.client(region, &.get("/results?search_query=#{URI.encode_www_form(query)}&sp=#{search_params}&hl=en").body)
return 0, [] of SearchItem if body.empty?
initial_data = extract_initial_data(body)
@@ -263,11 +263,12 @@ def search(query, page = 1, search_params = produce_search_params(content_type:
return items.size, items
end
-def produce_search_params(sort : String = "relevance", date : String = "", content_type : String = "",
+def produce_search_params(page = 1, sort : String = "relevance", date : String = "", content_type : String = "",
duration : String = "", features : Array(String) = [] of String)
object = {
"1:varint" => 0_i64,
"2:embedded" => {} of String => Int64,
+ "9:varint" => ((page - 1) * 20).to_i64,
}
case sort
@@ -439,10 +440,10 @@ def process_search_query(query, page, user, region)
count = 0
end
else
- search_params = produce_search_params(sort: sort, date: date, content_type: content_type,
+ search_params = produce_search_params(page: page, sort: sort, date: date, content_type: content_type,
duration: duration, features: features)
- count, items = search(search_query, page, search_params, region).as(Tuple)
+ count, items = search(search_query, search_params, region).as(Tuple)
end
{search_query, count, items, operators}
diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr
index 74edc156..95d9a80c 100644
--- a/src/invidious/videos.cr
+++ b/src/invidious/videos.cr
@@ -517,7 +517,7 @@ struct Video
end
def published : Time
- info["microformat"]?.try &.["playerMicroformatRenderer"]?.try &.["publishDate"]?.try { |t| Time.parse(t.as_s, "%Y-%m-%d", Time::Location.local) } || Time.local
+ info["microformat"]?.try &.["playerMicroformatRenderer"]?.try &.["publishDate"]?.try { |t| Time.parse(t.as_s, "%Y-%m-%d", Time::Location::UTC) } || Time.utc
end
def published=(other : Time)
@@ -534,7 +534,8 @@ struct Video
end
def live_now
- info["videoDetails"]["isLiveContent"]?.try &.as_bool || false
+ info["microformat"]?.try &.["playerMicroformatRenderer"]?
+ .try &.["liveBroadcastDetails"]?.try &.["isLiveNow"]?.try &.as_bool || false
end
def is_listed
diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr
index caa0ad0e..061d7eec 100644
--- a/src/invidious/views/channel.ecr
+++ b/src/invidious/views/channel.ecr
@@ -5,7 +5,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -16,7 +16,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/community.ecr b/src/invidious/views/community.ecr
index 69724390..3c4eaabb 100644
--- a/src/invidious/views/community.ecr
+++ b/src/invidious/views/community.ecr
@@ -4,7 +4,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -15,7 +15,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr
index e4a60697..ea7d356c 100644
--- a/src/invidious/views/components/item.ecr
+++ b/src/invidious/views/components/item.ecr
@@ -5,7 +5,7 @@
<a style="width:100%" href="/channel/<%= item.ucid %>">
<% if !env.get("preferences").as(Preferences).thin_mode %>
<center>
- <img style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).full_path %>"/>
+ <img style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>"/>
</center>
<% end %>
<p><%= item.author %></p>
@@ -15,7 +15,7 @@
<h5><%= item.description_html %></h5>
<% when SearchPlaylist, InvidiousPlaylist %>
<% if item.id.starts_with? "RD" %>
- <% url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").full_path.split("/")[2]}" %>
+ <% url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" %>
<% else %>
<% url = "/playlist?list=#{item.id}" %>
<% end %>
@@ -23,7 +23,7 @@
<a style="width:100%" href="<%= url %>">
<% if !env.get("preferences").as(Preferences).thin_mode %>
<div class="thumbnail">
- <img class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").full_path %>"/>
+ <img class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").request_target %>"/>
<p class="length"><%= number_with_separator(item.video_count) %> videos</p>
</div>
<% end %>
diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr
index 625c6fee..cff3e60a 100644
--- a/src/invidious/views/components/player.ecr
+++ b/src/invidious/views/components/player.ecr
@@ -4,7 +4,7 @@
<% if params.video_loop %>loop<% end %>
<% if params.controls %>controls<% end %>>
<% if (hlsvp = video.hls_manifest_url) && !CONFIG.disabled?("livestreams") %>
- <source src="<%= URI.parse(hlsvp).full_path %><% if params.local %>?local=true<% end %>" type="application/x-mpegURL" label="livestream">
+ <source src="<%= URI.parse(hlsvp).request_target %><% if params.local %>?local=true<% end %>" type="application/x-mpegURL" label="livestream">
<% else %>
<% if params.listen %>
<% audio_streams.each_with_index do |fmt, i| %>
@@ -24,9 +24,9 @@
<% end %>
<% end %>
- <% preferred_captions.each_with_index do |caption, i| %>
+ <% preferred_captions.each do |caption| %>
<track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name.simpleText %>&hl=<%= env.get("preferences").as(Preferences).locale %>"
- label="<%= caption.name.simpleText %>" <% if i == 0 %>default<% end %>>
+ label="<%= caption.name.simpleText %>">
<% end %>
<% captions.each do |caption| %>
@@ -42,7 +42,8 @@
"aspect_ratio" => aspect_ratio,
"title" => video.title,
"description" => HTML.escape(video.short_description),
- "thumbnail" => thumbnail
+ "thumbnail" => thumbnail,
+ "preferred_caption_found" => !preferred_captions.empty?
}.to_pretty_json
%>
</script>
diff --git a/src/invidious/views/components/player_sources.ecr b/src/invidious/views/components/player_sources.ecr
index 8162546e..d950e0da 100644
--- a/src/invidious/views/components/player_sources.ecr
+++ b/src/invidious/views/components/player_sources.ecr
@@ -3,7 +3,6 @@
<link rel="stylesheet" href="/css/videojs.markers.min.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/css/videojs-share.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/css/videojs-vtt-thumbnails.css?v=<%= ASSET_COMMIT %>">
-<script src="/js/global.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/js/video.min.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/js/videojs-contrib-quality-levels.min.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/js/videojs-http-source-selector.min.js?v=<%= ASSET_COMMIT %>"></script>
diff --git a/src/invidious/views/playlists.ecr b/src/invidious/views/playlists.ecr
index a77d106d..44bdb94d 100644
--- a/src/invidious/views/playlists.ecr
+++ b/src/invidious/views/playlists.ecr
@@ -4,7 +4,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -15,7 +15,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr
index 786a88b6..a86e23b2 100644
--- a/src/invidious/views/watch.ecr
+++ b/src/invidious/views/watch.ecr
@@ -22,6 +22,7 @@
<meta name="twitter:player" content="<%= HOST_URL %>/embed/<%= video.id %>">
<meta name="twitter:player:width" content="1280">
<meta name="twitter:player:height" content="720">
+<link rel="alternate" href="https://www.youtube.com/watch?v=<%= video.id %>">
<%= rendered "components/player_sources" %>
<title><%= HTML.escape(video.title) %> - Invidious</title>
<% end %>
@@ -80,6 +81,10 @@
<h3>
<%= video.premiere_timestamp.try { |t| translate(locale, "Premieres in `x`", recode_date((t - Time.utc).ago, locale)) } %>
</h3>
+ <% elsif video.live_now %>
+ <h3>
+ <%= video.premiere_timestamp.try { |t| translate(locale, "Started streaming `x` ago", recode_date((Time.utc - t).ago, locale)) } %>
+ </h3>
<% end %>
</div>
@@ -203,7 +208,7 @@
<a href="/channel/<%= video.ucid %>" style="display:block;width:fit-content;width:-moz-fit-content">
<div class="channel-profile">
<% if !video.author_thumbnail.empty? %>
- <img src="/ggpht<%= URI.parse(video.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(video.author_thumbnail).request_target %>">
<% end %>
<span id="channel-name"><%= video.author %></span>
</div>