diff options
Diffstat (limited to 'src')
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 ? "®ion=#{region}" : ""}" + url = "#{location.request_target}&host=#{location.host}#{region ? "®ion=#{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 += "®ion=#{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 ? "®ion=#{region}" : ""}" + location = "#{location.request_target}&host=#{location.host}#{region ? "®ion=#{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> |
