diff options
Diffstat (limited to 'src')
31 files changed, 252 insertions, 213 deletions
diff --git a/src/invidious.cr b/src/invidious.cr index 10c23dac..ec6df302 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -30,11 +30,8 @@ require "./invidious/*" require "./invidious/routes/**" require "./invidious/jobs/**" -ENV_CONFIG_NAME = "INVIDIOUS_CONFIG" - -CONFIG_STR = ENV.has_key?(ENV_CONFIG_NAME) ? ENV.fetch(ENV_CONFIG_NAME) : File.read("config/config.yml") -CONFIG = Config.from_yaml(CONFIG_STR) -HMAC_KEY = CONFIG.hmac_key || Random::Secure.hex(32) +CONFIG = Config.load +HMAC_KEY = CONFIG.hmac_key || Random::Secure.hex(32) PG_URL = URI.new( scheme: "postgres", @@ -52,7 +49,7 @@ PUBSUB_URL = URI.parse("https://pubsubhubbub.appspot.com") REDDIT_URL = URI.parse("https://www.reddit.com") TEXTCAPTCHA_URL = URI.parse("https://textcaptcha.com") YT_URL = URI.parse("https://www.youtube.com") -HOST_URL = make_host_url(CONFIG, Kemal.config) +HOST_URL = make_host_url(Kemal.config) CHARS_SAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" TEST_IDS = {"AgbeGFYluEA", "BaW_jenozKc", "a9LDPn-MO4I", "ddFvjfvPnqk", "iqKdEhx-dD4"} @@ -85,6 +82,7 @@ LOCALES = { "eo" => load_locale("eo"), "es" => load_locale("es"), "fa" => load_locale("fa"), + "fi" => load_locale("fi"), "fr" => load_locale("fr"), "hr" => load_locale("hr"), "is" => load_locale("is"), @@ -145,8 +143,6 @@ end OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mode: "a") LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level) -config = CONFIG - # Check table integrity if CONFIG.check_tables check_enum(PG_DB, "privacy", PlaylistPrivacy) @@ -167,28 +163,33 @@ end # Start jobs -Invidious::Jobs.register Invidious::Jobs::RefreshChannelsJob.new(PG_DB, config) -Invidious::Jobs.register Invidious::Jobs::RefreshFeedsJob.new(PG_DB, config) +if CONFIG.channel_threads > 0 + Invidious::Jobs.register Invidious::Jobs::RefreshChannelsJob.new(PG_DB) +end + +if CONFIG.feed_threads > 0 + Invidious::Jobs.register Invidious::Jobs::RefreshFeedsJob.new(PG_DB) +end DECRYPT_FUNCTION = DecryptFunction.new(CONFIG.decrypt_polling) -if config.decrypt_polling +if CONFIG.decrypt_polling Invidious::Jobs.register Invidious::Jobs::UpdateDecryptFunctionJob.new end -if config.statistics_enabled - Invidious::Jobs.register Invidious::Jobs::StatisticsRefreshJob.new(PG_DB, config, SOFTWARE) +if CONFIG.statistics_enabled + Invidious::Jobs.register Invidious::Jobs::StatisticsRefreshJob.new(PG_DB, SOFTWARE) end -if (config.use_pubsub_feeds.is_a?(Bool) && config.use_pubsub_feeds.as(Bool)) || (config.use_pubsub_feeds.is_a?(Int32) && config.use_pubsub_feeds.as(Int32) > 0) - Invidious::Jobs.register Invidious::Jobs::SubscribeToFeedsJob.new(PG_DB, config, HMAC_KEY) +if (CONFIG.use_pubsub_feeds.is_a?(Bool) && CONFIG.use_pubsub_feeds.as(Bool)) || (CONFIG.use_pubsub_feeds.is_a?(Int32) && CONFIG.use_pubsub_feeds.as(Int32) > 0) + Invidious::Jobs.register Invidious::Jobs::SubscribeToFeedsJob.new(PG_DB, HMAC_KEY) end -if config.popular_enabled +if CONFIG.popular_enabled Invidious::Jobs.register Invidious::Jobs::PullPopularVideosJob.new(PG_DB) end -if config.captcha_key - Invidious::Jobs.register Invidious::Jobs::BypassCaptchaJob.new(config) +if CONFIG.captcha_key + Invidious::Jobs.register Invidious::Jobs::BypassCaptchaJob.new end connection_channel = Channel({Bool, Channel(PQ::Notification)}).new(32) @@ -216,10 +217,10 @@ 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 + if (Kemal.config.ssl || CONFIG.https_only) && CONFIG.hsts env.response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload" end @@ -310,12 +311,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 @@ -334,9 +335,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 @@ -1164,7 +1165,7 @@ end get "/feed/popular" do |env| locale = LOCALES[env.get("preferences").as(Preferences).locale]? - if config.popular_enabled + if CONFIG.popular_enabled templated "popular" else message = translate(locale, "The Popular feed has been disabled by the administrator.") @@ -1427,9 +1428,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 @@ -1438,7 +1439,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 @@ -1633,7 +1634,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 @@ -1822,7 +1823,7 @@ get "/api/v1/stats" do |env| locale = LOCALES[env.get("preferences").as(Preferences).locale]? env.response.content_type = "application/json" - if !config.statistics_enabled + if !CONFIG.statistics_enabled next error_json(400, "Statistics are not enabled.") end @@ -1977,7 +1978,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 @@ -2232,7 +2233,7 @@ get "/api/v1/popular" do |env| env.response.content_type = "application/json" - if !config.popular_enabled + if !CONFIG.popular_enabled error_message = {"error" => "Administrator has disabled this endpoint."}.to_json env.response.status_code = 400 next error_message @@ -3183,7 +3184,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>") @@ -3191,7 +3192,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>" @@ -3204,7 +3205,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 @@ -3402,7 +3403,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 @@ -3514,7 +3515,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 @@ -3554,7 +3555,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}" @@ -3618,7 +3619,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 @@ -3858,7 +3859,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 @@ -3873,7 +3874,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..a8bbf74b 100644 --- a/src/invidious/comments.cr +++ b/src/invidious/comments.cr @@ -294,7 +294,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 +322,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 +375,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 +473,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 +544,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/errors.cr b/src/invidious/helpers/errors.cr index 2c62d44b..68ced430 100644 --- a/src/invidious/helpers/errors.cr +++ b/src/invidious/helpers/errors.cr @@ -7,7 +7,7 @@ class InfoException < Exception end macro error_template(*args) - error_template_helper(env, config, locale, {{*args}}) + error_template_helper(env, locale, {{*args}}) end def github_details(summary : String, content : String) @@ -22,9 +22,9 @@ def github_details(summary : String, content : String) return HTML.escape(details) end -def error_template_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) +def error_template_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) if exception.is_a?(InfoException) - return error_template_helper(env, config, locale, status_code, exception.message || "") + return error_template_helper(env, locale, status_code, exception.message || "") end env.response.content_type = "text/html" env.response.status_code = status_code @@ -43,7 +43,7 @@ def error_template_helper(env : HTTP::Server::Context, config : Config, locale : return templated "error" end -def error_template_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) +def error_template_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) env.response.content_type = "text/html" env.response.status_code = status_code error_message = translate(locale, message) @@ -51,31 +51,31 @@ def error_template_helper(env : HTTP::Server::Context, config : Config, locale : end macro error_atom(*args) - error_atom_helper(env, config, locale, {{*args}}) + error_atom_helper(env, locale, {{*args}}) end -def error_atom_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) +def error_atom_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) if exception.is_a?(InfoException) - return error_atom_helper(env, config, locale, status_code, exception.message || "") + return error_atom_helper(env, locale, status_code, exception.message || "") end env.response.content_type = "application/atom+xml" env.response.status_code = status_code return "<error>#{exception.inspect_with_backtrace}</error>" end -def error_atom_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) +def error_atom_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) env.response.content_type = "application/atom+xml" env.response.status_code = status_code return "<error>#{message}</error>" end macro error_json(*args) - error_json_helper(env, config, locale, {{*args}}) + error_json_helper(env, locale, {{*args}}) end -def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception, additional_fields : Hash(String, Object) | Nil) +def error_json_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception, additional_fields : Hash(String, Object) | Nil) if exception.is_a?(InfoException) - return error_json_helper(env, config, locale, status_code, exception.message || "", additional_fields) + return error_json_helper(env, locale, status_code, exception.message || "", additional_fields) end env.response.content_type = "application/json" env.response.status_code = status_code @@ -86,11 +86,11 @@ def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Has return error_message.to_json end -def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) - return error_json_helper(env, config, locale, status_code, exception, nil) +def error_json_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, exception : Exception) + return error_json_helper(env, locale, status_code, exception, nil) end -def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String, additional_fields : Hash(String, Object) | Nil) +def error_json_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String, additional_fields : Hash(String, Object) | Nil) env.response.content_type = "application/json" env.response.status_code = status_code error_message = {"error" => message} @@ -100,6 +100,6 @@ def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Has return error_message.to_json end -def error_json_helper(env : HTTP::Server::Context, config : Config, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) - error_json_helper(env, config, locale, status_code, message, nil) +def error_json_helper(env : HTTP::Server::Context, locale : Hash(String, JSON::Any) | Nil, status_code : Int32, message : String) + error_json_helper(env, locale, status_code, message, nil) end diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 6bbb18cb..00087143 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -115,6 +115,63 @@ class Config return false end end + + def self.load + # Load config from file or YAML string env var + env_config_file = "INVIDIOUS_CONFIG_FILE" + env_config_yaml = "INVIDIOUS_CONFIG" + + config_file = ENV.has_key?(env_config_file) ? ENV.fetch(env_config_file) : "config/config.yml" + config_yaml = ENV.has_key?(env_config_yaml) ? ENV.fetch(env_config_yaml) : File.read(config_file) + + config = Config.from_yaml(config_yaml) + + # Update config from env vars (upcased and prefixed with "INVIDIOUS_") + {% for ivar in Config.instance_vars %} + {% env_id = "INVIDIOUS_#{ivar.id.upcase}" %} + + if ENV.has_key?({{env_id}}) + # puts %(Config.{{ivar.id}} : Loading from env var {{env_id}}) + env_value = ENV.fetch({{env_id}}) + success = false + + # Use YAML converter if specified + {% ann = ivar.annotation(::YAML::Field) %} + {% if ann && ann[:converter] %} + puts %(Config.{{ivar.id}} : Parsing "#{env_value}" as {{ivar.type}} with {{ann[:converter]}} converter) + config.{{ivar.id}} = {{ann[:converter]}}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{env_id}})).nodes[0]) + puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}}) + success = true + + # Use regular YAML parser otherwise + {% else %} + {% ivar_types = ivar.type.union? ? ivar.type.union_types : [ivar.type] %} + # Sort types to avoid parsing nulls and numbers as strings + {% ivar_types = ivar_types.sort_by { |ivar_type| ivar_type == Nil ? 0 : ivar_type == Int32 ? 1 : 2 } %} + {{ivar_types}}.each do |ivar_type| + if !success + begin + # puts %(Config.{{ivar.id}} : Trying to parse "#{env_value}" as #{ivar_type}) + config.{{ivar.id}} = ivar_type.from_yaml(env_value) + puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}} (#{ivar_type})) + success = true + rescue + # nop + end + end + end + {% end %} + + # Exit on fail + if !success + puts %(Config.{{ivar.id}} failed to parse #{env_value} as {{ivar.type}}) + exit(1) + end + end + {% end %} + + return config + end end struct DBConfig 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 f068b5f2..2c95a373 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -280,9 +280,9 @@ def arg_array(array, start = 1) return args end -def make_host_url(config, kemal_config) - ssl = config.https_only || kemal_config.ssl - port = config.external_port || kemal_config.port +def make_host_url(kemal_config) + ssl = CONFIG.https_only || kemal_config.ssl + port = CONFIG.external_port || kemal_config.port if ssl scheme = "https://" @@ -297,11 +297,11 @@ def make_host_url(config, kemal_config) port = "" end - if !config.domain + if !CONFIG.domain return "" end - host = config.domain.not_nil!.lchop(".") + host = CONFIG.domain.not_nil!.lchop(".") return "#{scheme}#{host}#{port}" end @@ -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 @@ -345,7 +345,7 @@ def sha256(text) return digest.final.hexstring end -def subscribe_pubsub(topic, key, config) +def subscribe_pubsub(topic, key) case topic when .match(/^UC[A-Za-z0-9_-]{22}$/) topic = "channel_id=#{topic}" diff --git a/src/invidious/jobs/bypass_captcha_job.cr b/src/invidious/jobs/bypass_captcha_job.cr index 22c54036..4269e123 100644 --- a/src/invidious/jobs/bypass_captcha_job.cr +++ b/src/invidious/jobs/bypass_captcha_job.cr @@ -1,9 +1,4 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob - private getter config : Config - - def initialize(@config) - end - def begin loop do begin @@ -22,9 +17,9 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob headers = response.cookies.add_request_headers(HTTP::Headers.new) - response = JSON.parse(HTTP::Client.post(config.captcha_api_url + "/createTask", + response = JSON.parse(HTTP::Client.post(CONFIG.captcha_api_url + "/createTask", headers: HTTP::Headers{"Content-Type" => "application/json"}, body: { - "clientKey" => config.captcha_key, + "clientKey" => CONFIG.captcha_key, "task" => { "type" => "NoCaptchaTaskProxyless", "websiteURL" => "https://www.youtube.com#{path}", @@ -39,9 +34,9 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob loop do sleep 10.seconds - response = JSON.parse(HTTP::Client.post(config.captcha_api_url + "/getTaskResult", + response = JSON.parse(HTTP::Client.post(CONFIG.captcha_api_url + "/getTaskResult", headers: HTTP::Headers{"Content-Type" => "application/json"}, body: { - "clientKey" => config.captcha_key, + "clientKey" => CONFIG.captcha_key, "taskId" => task_id, }.to_json).body) @@ -58,14 +53,14 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob response.cookies .select { |cookie| cookie.name != "PREF" } - .each { |cookie| config.cookies << cookie } + .each { |cookie| CONFIG.cookies << cookie } # Persist cookies between runs - File.write("config/config.yml", config.to_yaml) + File.write("config/config.yml", CONFIG.to_yaml) 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! @@ -77,11 +72,11 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob inputs[node["name"]] = node["value"] end - captcha_client = HTTPClient.new(URI.parse(config.captcha_api_url)) - captcha_client.family = config.force_resolve || Socket::Family::INET + captcha_client = HTTPClient.new(URI.parse(CONFIG.captcha_api_url)) + captcha_client.family = CONFIG.force_resolve || Socket::Family::INET response = JSON.parse(captcha_client.post("/createTask", headers: HTTP::Headers{"Content-Type" => "application/json"}, body: { - "clientKey" => config.captcha_key, + "clientKey" => CONFIG.captcha_key, "task" => { "type" => "NoCaptchaTaskProxyless", "websiteURL" => location.to_s, @@ -100,7 +95,7 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob response = JSON.parse(captcha_client.post("/getTaskResult", headers: HTTP::Headers{"Content-Type" => "application/json"}, body: { - "clientKey" => config.captcha_key, + "clientKey" => CONFIG.captcha_key, "taskId" => task_id, }.to_json).body) @@ -119,10 +114,10 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob } cookies = HTTP::Cookies.from_headers(headers) - cookies.each { |cookie| config.cookies << cookie } + cookies.each { |cookie| CONFIG.cookies << cookie } # Persist cookies between runs - File.write("config/config.yml", config.to_yaml) + File.write("config/config.yml", CONFIG.to_yaml) end end rescue ex diff --git a/src/invidious/jobs/refresh_channels_job.cr b/src/invidious/jobs/refresh_channels_job.cr index 3e94a56e..fbe6d381 100644 --- a/src/invidious/jobs/refresh_channels_job.cr +++ b/src/invidious/jobs/refresh_channels_job.cr @@ -1,12 +1,11 @@ class Invidious::Jobs::RefreshChannelsJob < Invidious::Jobs::BaseJob private getter db : DB::Database - private getter config : Config - def initialize(@db, @config) + def initialize(@db) end def begin - max_fibers = config.channel_threads + max_fibers = CONFIG.channel_threads lim_fibers = max_fibers active_fibers = 0 active_channel = Channel(Bool).new @@ -31,7 +30,7 @@ class Invidious::Jobs::RefreshChannelsJob < Invidious::Jobs::BaseJob spawn do begin LOGGER.trace("RefreshChannelsJob: #{id} fiber : Fetching channel") - channel = fetch_channel(id, db, config.full_refresh) + channel = fetch_channel(id, db, CONFIG.full_refresh) lim_fibers = max_fibers diff --git a/src/invidious/jobs/refresh_feeds_job.cr b/src/invidious/jobs/refresh_feeds_job.cr index 7b4ccdea..926c27fa 100644 --- a/src/invidious/jobs/refresh_feeds_job.cr +++ b/src/invidious/jobs/refresh_feeds_job.cr @@ -1,12 +1,11 @@ class Invidious::Jobs::RefreshFeedsJob < Invidious::Jobs::BaseJob private getter db : DB::Database - private getter config : Config - def initialize(@db, @config) + def initialize(@db) end def begin - max_fibers = config.feed_threads + max_fibers = CONFIG.feed_threads active_fibers = 0 active_channel = Channel(Bool).new diff --git a/src/invidious/jobs/statistics_refresh_job.cr b/src/invidious/jobs/statistics_refresh_job.cr index 021671be..aa46fb0e 100644 --- a/src/invidious/jobs/statistics_refresh_job.cr +++ b/src/invidious/jobs/statistics_refresh_job.cr @@ -21,9 +21,8 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob } private getter db : DB::Database - private getter config : Config - def initialize(@db, @config, @software_config : Hash(String, String)) + def initialize(@db, @software_config : Hash(String, String)) end def begin @@ -43,7 +42,7 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob "version" => @software_config["version"], "branch" => @software_config["branch"], } - STATISTICS["openRegistration"] = config.registration_enabled + STATISTICS["openRegistration"] = CONFIG.registration_enabled end private def refresh_stats diff --git a/src/invidious/jobs/subscribe_to_feeds_job.cr b/src/invidious/jobs/subscribe_to_feeds_job.cr index 750aceb8..a431a48a 100644 --- a/src/invidious/jobs/subscribe_to_feeds_job.cr +++ b/src/invidious/jobs/subscribe_to_feeds_job.cr @@ -1,15 +1,14 @@ class Invidious::Jobs::SubscribeToFeedsJob < Invidious::Jobs::BaseJob private getter db : DB::Database private getter hmac_key : String - private getter config : Config - def initialize(@db, @config, @hmac_key) + def initialize(@db, @hmac_key) end def begin max_fibers = 1 - if config.use_pubsub_feeds.is_a?(Int32) - max_fibers = config.use_pubsub_feeds.as(Int32) + if CONFIG.use_pubsub_feeds.is_a?(Int32) + max_fibers = CONFIG.use_pubsub_feeds.as(Int32) end active_fibers = 0 @@ -30,7 +29,7 @@ class Invidious::Jobs::SubscribeToFeedsJob < Invidious::Jobs::BaseJob spawn do begin - response = subscribe_pubsub(ucid, hmac_key, config) + response = subscribe_pubsub(ucid, hmac_key) if response.status_code >= 400 LOGGER.error("SubscribeToFeedsJob: #{ucid} : #{response.body}") diff --git a/src/invidious/routes/base_route.cr b/src/invidious/routes/base_route.cr index 37624267..07c6f15b 100644 --- a/src/invidious/routes/base_route.cr +++ b/src/invidious/routes/base_route.cr @@ -1,6 +1,2 @@ abstract class Invidious::Routes::BaseRoute - private getter config : Config - - def initialize(@config) - end end 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 45a6d4d8..ffe5f568 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -6,7 +6,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute return env.redirect "/feed/subscriptions" if user - if !config.login_enabled + if !CONFIG.login_enabled return error_template(400, "Login has been disabled by administrator.") end @@ -33,7 +33,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute referer = get_referer(env, "/feed/subscriptions") - if !config.login_enabled + if !CONFIG.login_enabled return error_template(403, "Login has been disabled by administrator.") end @@ -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) } @@ -274,14 +274,14 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute host = URI.parse(env.request.headers["Host"]).host - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only secure = true else secure = false end cookies.each do |cookie| - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only cookie.secure = secure else cookie.secure = secure @@ -330,14 +330,14 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute sid = Base64.urlsafe_encode(Random::Secure.random_bytes(32)) PG_DB.exec("INSERT INTO session_ids VALUES ($1, $2, $3)", sid, email, Time.utc) - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only secure = true else secure = false end - if config.domain - env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{config.domain}", value: sid, expires: Time.utc + 2.years, + if CONFIG.domain + env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{CONFIG.domain}", value: sid, expires: Time.utc + 2.years, secure: secure, http_only: true) else env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", value: sid, expires: Time.utc + 2.years, @@ -354,7 +354,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute env.response.cookies << cookie end else - if !config.registration_enabled + if !CONFIG.registration_enabled return error_template(400, "Registration has been disabled by administrator.") end @@ -369,7 +369,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute password = password.byte_slice(0, 55) - if config.captcha_enabled + if CONFIG.captcha_enabled captcha_type = env.params.body["captcha_type"]? answer = env.params.body["answer"]? change_type = env.params.body["change_type"]? @@ -445,14 +445,14 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute view_name = "subscriptions_#{sha256(user.email)}" PG_DB.exec("CREATE MATERIALIZED VIEW #{view_name} AS #{MATERIALIZED_VIEW_SQL.call(user.email)}") - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only secure = true else secure = false end - if config.domain - env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{config.domain}", value: sid, expires: Time.utc + 2.years, + if CONFIG.domain + env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", domain: "#{CONFIG.domain}", value: sid, expires: Time.utc + 2.years, secure: secure, http_only: true) else env.response.cookies["SID"] = HTTP::Cookie.new(name: "SID", value: sid, expires: Time.utc + 2.years, 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 7f334115..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]? @@ -146,8 +146,8 @@ class Invidious::Routes::UserPreferences < Invidious::Routes::BaseRoute user = user.as(User) PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences, user.email) - if config.admins.includes? user.email - config.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || config.default_user_preferences.default_home + if CONFIG.admins.includes? user.email + CONFIG.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home admin_feed_menu = [] of String 4.times do |index| @@ -156,40 +156,39 @@ class Invidious::Routes::UserPreferences < Invidious::Routes::BaseRoute admin_feed_menu << option end end - config.default_user_preferences.feed_menu = admin_feed_menu + CONFIG.default_user_preferences.feed_menu = admin_feed_menu popular_enabled = env.params.body["popular_enabled"]?.try &.as(String) popular_enabled ||= "off" - config.popular_enabled = popular_enabled == "on" + CONFIG.popular_enabled = popular_enabled == "on" captcha_enabled = env.params.body["captcha_enabled"]?.try &.as(String) captcha_enabled ||= "off" - config.captcha_enabled = captcha_enabled == "on" + CONFIG.captcha_enabled = captcha_enabled == "on" login_enabled = env.params.body["login_enabled"]?.try &.as(String) login_enabled ||= "off" - config.login_enabled = login_enabled == "on" + CONFIG.login_enabled = login_enabled == "on" registration_enabled = env.params.body["registration_enabled"]?.try &.as(String) registration_enabled ||= "off" - config.registration_enabled = registration_enabled == "on" + CONFIG.registration_enabled = registration_enabled == "on" statistics_enabled = env.params.body["statistics_enabled"]?.try &.as(String) statistics_enabled ||= "off" - config.statistics_enabled = statistics_enabled == "on" + CONFIG.statistics_enabled = statistics_enabled == "on" - CONFIG.default_user_preferences = config.default_user_preferences - File.write("config/config.yml", config.to_yaml) + File.write("config/config.yml", CONFIG.to_yaml) end else - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only secure = true else secure = false end - if config.domain - env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{config.domain}", value: preferences, expires: Time.utc + 2.years, + if CONFIG.domain + env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{CONFIG.domain}", value: preferences, expires: Time.utc + 2.years, secure: secure, http_only: true) else env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", value: preferences, expires: Time.utc + 2.years, @@ -234,14 +233,14 @@ class Invidious::Routes::UserPreferences < Invidious::Routes::BaseRoute preferences = preferences.to_json - if Kemal.config.ssl || config.https_only + if Kemal.config.ssl || CONFIG.https_only secure = true else secure = false end - if config.domain - env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{config.domain}", value: preferences, expires: Time.utc + 2.years, + if CONFIG.domain + env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{CONFIG.domain}", value: preferences, expires: Time.utc + 2.years, secure: secure, http_only: true) else env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", value: preferences, expires: Time.utc + 2.years, 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/routing.cr b/src/invidious/routing.cr index 593c7372..82d0028b 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -1,14 +1,14 @@ module Invidious::Routing macro get(path, controller, method = :handle) get {{ path }} do |env| - controller_instance = {{ controller }}.new(config) + controller_instance = {{ controller }}.new controller_instance.{{ method.id }}(env) end end macro post(path, controller, method = :handle) post {{ path }} do |env| - controller_instance = {{ controller }}.new(config) + controller_instance = {{ controller }}.new controller_instance.{{ method.id }}(env) end end 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..a898a41f 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| %> 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/preferences.ecr b/src/invidious/views/preferences.ecr index 1ef080be..14d63536 100644 --- a/src/invidious/views/preferences.ecr +++ b/src/invidious/views/preferences.ecr @@ -208,14 +208,14 @@ </div> <% # Web notifications are only supported over HTTPS %> - <% if Kemal.config.ssl || config.https_only %> + <% if Kemal.config.ssl || CONFIG.https_only %> <div class="pure-control-group"> <a href="#" data-onclick="notification_requestPermission"><%= translate(locale, "Enable web notifications") %></a> </div> <% end %> <% end %> - <% if env.get?("user") && config.admins.includes? env.get?("user").as(User).email %> + <% if env.get?("user") && CONFIG.admins.includes? env.get?("user").as(User).email %> <legend><%= translate(locale, "Administrator preferences") %></legend> <div class="pure-control-group"> @@ -240,28 +240,28 @@ <div class="pure-control-group"> <label for="popular_enabled"><%= translate(locale, "Popular enabled: ") %></label> - <input name="popular_enabled" id="popular_enabled" type="checkbox" <% if config.popular_enabled %>checked<% end %>> + <input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.popular_enabled %>checked<% end %>> </div> <div class="pure-control-group"> <label for="captcha_enabled"><%= translate(locale, "CAPTCHA enabled: ") %></label> - <input name="captcha_enabled" id="captcha_enabled" type="checkbox" <% if config.captcha_enabled %>checked<% end %>> + <input name="captcha_enabled" id="captcha_enabled" type="checkbox" <% if CONFIG.captcha_enabled %>checked<% end %>> </div> <div class="pure-control-group"> <label for="login_enabled"><%= translate(locale, "Login enabled: ") %></label> - <input name="login_enabled" id="login_enabled" type="checkbox" <% if config.login_enabled %>checked<% end %>> + <input name="login_enabled" id="login_enabled" type="checkbox" <% if CONFIG.login_enabled %>checked<% end %>> </div> <div class="pure-control-group"> <label for="registration_enabled"><%= translate(locale, "Registration enabled: ") %></label> - <input name="registration_enabled" id="registration_enabled" type="checkbox" <% if config.registration_enabled %>checked<% end %>> + <input name="registration_enabled" id="registration_enabled" type="checkbox" <% if CONFIG.registration_enabled %>checked<% end %>> </div> <div class="pure-control-group"> <label for="statistics_enabled"><%= translate(locale, "Report statistics: ") %></label> - <input name="statistics_enabled" id="statistics_enabled" type="checkbox" <% if config.statistics_enabled %>checked<% end %>> + <input name="statistics_enabled" id="statistics_enabled" type="checkbox" <% if CONFIG.statistics_enabled %>checked<% end %>> </div> <% end %> diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr index f6e5262d..61b900e3 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -87,7 +87,7 @@ <i class="icon ion-ios-cog"></i> </a> </div> - <% if config.login_enabled %> + <% if CONFIG.login_enabled %> <div class="pure-u-1-3"> <a href="/login?referer=<%= env.get?("current_page") %>" class="pure-menu-heading"> <%= translate(locale, "Log in") %> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 786a88b6..924914a5 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 %> @@ -203,7 +204,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> |
