diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/invidious.cr | 45 | ||||
| -rw-r--r-- | src/invidious/helpers/helpers.cr | 4 | ||||
| -rw-r--r-- | src/invidious/helpers/i18n.cr | 30 | ||||
| -rw-r--r-- | src/invidious/helpers/macros.cr | 3 | ||||
| -rw-r--r-- | src/invidious/helpers/utils.cr | 18 | ||||
| -rw-r--r-- | src/invidious/jobs/statistics_refresh_job.cr | 2 | ||||
| -rw-r--r-- | src/invidious/playlists.cr | 3 | ||||
| -rw-r--r-- | src/invidious/routes/misc.cr | 2 | ||||
| -rw-r--r-- | src/invidious/routes/watch.cr | 9 | ||||
| -rw-r--r-- | src/invidious/users.cr | 1 | ||||
| -rw-r--r-- | src/invidious/videos.cr | 26 | ||||
| -rw-r--r-- | src/invidious/views/empty.ecr | 8 | ||||
| -rw-r--r-- | src/invidious/views/preferences.ecr | 10 | ||||
| -rw-r--r-- | src/invidious/views/search_homepage.ecr | 24 | ||||
| -rw-r--r-- | src/invidious/views/template.ecr | 29 | ||||
| -rw-r--r-- | src/invidious/views/watch.ecr | 27 |
16 files changed, 162 insertions, 79 deletions
diff --git a/src/invidious.cr b/src/invidious.cr index 88b9ad85..ae20e13e 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -65,37 +65,7 @@ SOFTWARE = { "branch" => "#{CURRENT_BRANCH}", } -LOCALES = { - "ar" => load_locale("ar"), - "de" => load_locale("de"), - "el" => load_locale("el"), - "en-US" => load_locale("en-US"), - "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"), - "nb-NO" => load_locale("nb-NO"), - "nl" => load_locale("nl"), - "pl" => load_locale("pl"), - "pt-BR" => load_locale("pt-BR"), - "pt-PT" => load_locale("pt-PT"), - "ro" => load_locale("ro"), - "ru" => load_locale("ru"), - "sv" => load_locale("sv-SE"), - "tr" => load_locale("tr"), - "uk" => load_locale("uk"), - "zh-CN" => load_locale("zh-CN"), - "zh-TW" => load_locale("zh-TW"), -} - -YT_POOL = QUICPool.new(YT_URL, capacity: CONFIG.pool_size, timeout: 2.0) +YT_POOL = YoutubeConnectionPool.new(YT_URL, capacity: CONFIG.pool_size, timeout: 2.0, use_quic: CONFIG.use_quic) # CLI Kemal.config.extra_options do |parser| @@ -308,9 +278,17 @@ end 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 "/watch", Invidious::Routes::Watch, :handle +Invidious::Routing.get "/watch/:id", Invidious::Routes::Watch, :redirect +Invidious::Routing.get "/shorts/:id", Invidious::Routes::Watch, :redirect +Invidious::Routing.get "/w/:id", Invidious::Routes::Watch, :redirect +Invidious::Routing.get "/v/:id", Invidious::Routes::Watch, :redirect +Invidious::Routing.get "/e/:id", Invidious::Routes::Watch, :redirect + 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 @@ -323,12 +301,15 @@ Invidious::Routing.get "/add_playlist_items", Invidious::Routes::Playlists, :add Invidious::Routing.post "/playlist_ajax", Invidious::Routes::Playlists, :playlist_ajax Invidious::Routing.get "/playlist", Invidious::Routes::Playlists, :show Invidious::Routing.get "/mix", Invidious::Routes::Playlists, :mix + Invidious::Routing.get "/opensearch.xml", Invidious::Routes::Search, :opensearch Invidious::Routing.get "/results", Invidious::Routes::Search, :results 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::PreferencesRoute, :show Invidious::Routing.post "/preferences", Invidious::Routes::PreferencesRoute, :update Invidious::Routing.get "/toggle_theme", Invidious::Routes::PreferencesRoute, :toggle_theme diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index f6b6acd1..e1d877b7 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -50,6 +50,7 @@ struct ConfigPreferences property thin_mode : Bool = false property unseen_only : Bool = false property video_loop : Bool = false + property extend_desc : Bool = false property volume : Int32 = 100 def to_tuple @@ -98,6 +99,7 @@ class Config property port : Int32 = 3000 # Port to listen for connections (overrided by command line argument) property host_binding : String = "0.0.0.0" # Host to bind (overrided by command line argument) property pool_size : Int32 = 100 # Pool size for HTTP requests to youtube.com and ytimg.com (each domain has a separate pool of `pool_size`) + property use_quic : Bool = true # Use quic transport for youtube api @[YAML::Field(converter: Preferences::StringToCookies)] property cookies : HTTP::Cookies = HTTP::Cookies.new # Saved cookies in "name1=value1; name2=value2..." format @@ -678,7 +680,7 @@ def create_notification_stream(env, topics, connection_channel) end def extract_initial_data(body) : Hash(String, JSON::Any) - return JSON.parse(body.match(/(window\["ytInitialData"\]|var\s*ytInitialData)\s*=\s*(?<info>\{.*?\});/mx).try &.["info"] || "{}").as_h + return JSON.parse(body.match(/(window\["ytInitialData"\]|var\s*ytInitialData)\s*=\s*(?<info>{.*?});<\/script>/mx).try &.["info"] || "{}").as_h end def proxy_file(response, env) diff --git a/src/invidious/helpers/i18n.cr b/src/invidious/helpers/i18n.cr index 0faa2e32..45a3f1ae 100644 --- a/src/invidious/helpers/i18n.cr +++ b/src/invidious/helpers/i18n.cr @@ -1,3 +1,33 @@ +LOCALES = { + "ar" => load_locale("ar"), + "de" => load_locale("de"), + "el" => load_locale("el"), + "en-US" => load_locale("en-US"), + "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"), + "nb-NO" => load_locale("nb-NO"), + "nl" => load_locale("nl"), + "pl" => load_locale("pl"), + "pt-BR" => load_locale("pt-BR"), + "pt-PT" => load_locale("pt-PT"), + "ro" => load_locale("ro"), + "ru" => load_locale("ru"), + "sv" => load_locale("sv-SE"), + "tr" => load_locale("tr"), + "uk" => load_locale("uk"), + "zh-CN" => load_locale("zh-CN"), + "zh-TW" => load_locale("zh-TW"), +} + def load_locale(name) return JSON.parse(File.read("locales/#{name}.json")).as_h end diff --git a/src/invidious/helpers/macros.cr b/src/invidious/helpers/macros.cr index 8b74bc86..5d426a8b 100644 --- a/src/invidious/helpers/macros.cr +++ b/src/invidious/helpers/macros.cr @@ -48,7 +48,8 @@ module JSON::Serializable end end -macro templated(filename, template = "template") +macro templated(filename, template = "template", navbar_search = true) + navbar_search = {{navbar_search}} render "src/invidious/views/#{{{filename}}}.ecr", "src/invidious/views/#{{{template}}}.ecr" end diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr index 67f496df..10d4e6b6 100644 --- a/src/invidious/helpers/utils.cr +++ b/src/invidious/helpers/utils.cr @@ -16,15 +16,15 @@ def add_yt_headers(request) end end -struct QUICPool +struct YoutubeConnectionPool property! url : URI property! capacity : Int32 property! timeout : Float64 - property pool : ConnectionPool(QUIC::Client) + property pool : ConnectionPool(QUIC::Client | HTTP::Client) - def initialize(url : URI, @capacity = 5, @timeout = 5.0) + def initialize(url : URI, @capacity = 5, @timeout = 5.0, use_quic = true) @url = url - @pool = build_pool + @pool = build_pool(use_quic) end def client(region = nil, &block) @@ -50,9 +50,13 @@ struct QUICPool response end - private def build_pool - ConnectionPool(QUIC::Client).new(capacity: capacity, timeout: timeout) do - conn = QUIC::Client.new(url) + private def build_pool(use_quic) + ConnectionPool(QUIC::Client | HTTP::Client).new(capacity: capacity, timeout: timeout) do + if use_quic + conn = QUIC::Client.new(url) + else + conn = HTTP::Client.new(url) + end conn.family = (url.host == "www.youtube.com") ? CONFIG.force_resolve : Socket::Family::INET conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com" diff --git a/src/invidious/jobs/statistics_refresh_job.cr b/src/invidious/jobs/statistics_refresh_job.cr index aa46fb0e..6569c0a1 100644 --- a/src/invidious/jobs/statistics_refresh_job.cr +++ b/src/invidious/jobs/statistics_refresh_job.cr @@ -42,7 +42,7 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob "version" => @software_config["version"], "branch" => @software_config["branch"], } - STATISTICS["openRegistration"] = CONFIG.registration_enabled + STATISTICS["openRegistrations"] = CONFIG.registration_enabled end private def refresh_stats diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr index 71f6a9b8..073a9986 100644 --- a/src/invidious/playlists.cr +++ b/src/invidious/playlists.cr @@ -437,7 +437,8 @@ end def get_playlist_videos(db, playlist, offset, locale = nil, continuation = nil) # Show empy playlist if requested page is out of range - if offset >= playlist.video_count + # (e.g, when a new playlist has been created, offset will be negative) + if offset >= playlist.video_count || offset < 0 return [] of PlaylistVideo end diff --git a/src/invidious/routes/misc.cr b/src/invidious/routes/misc.cr index bc009633..d32ba892 100644 --- a/src/invidious/routes/misc.cr +++ b/src/invidious/routes/misc.cr @@ -22,7 +22,7 @@ class Invidious::Routes::Misc < Invidious::Routes::BaseRoute env.redirect "/feed/popular" end else - templated "empty" + templated "search_homepage", navbar_search: false end end diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index 8169e1ed..d0338882 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -187,4 +187,13 @@ class Invidious::Routes::Watch < Invidious::Routes::BaseRoute templated "watch" end + + def redirect(env) + url = "/watch?v=#{env.params.url["id"]}" + if env.params.query.size > 0 + url += "&#{env.params.query}" + end + + return env.redirect url + end end diff --git a/src/invidious/users.cr b/src/invidious/users.cr index 8fef64a0..e4ebb4d1 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -78,6 +78,7 @@ struct Preferences property thin_mode : Bool = CONFIG.default_user_preferences.thin_mode property unseen_only : Bool = CONFIG.default_user_preferences.unseen_only property video_loop : Bool = CONFIG.default_user_preferences.video_loop + property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc property volume : Int32 = CONFIG.default_user_preferences.volume module BoolToString diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index e6d4c764..bf281507 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -242,6 +242,7 @@ struct VideoPreferences property speed : Float32 | Float64 property video_end : Float64 | Int32 property video_loop : Bool + property extend_desc : Bool property video_start : Float64 | Int32 property volume : Int32 end @@ -818,7 +819,7 @@ end def extract_polymer_config(body) params = {} of String => JSON::Any - player_response = body.match(/(window\["ytInitialPlayerResponse"\]|var\sytInitialPlayerResponse)\s*=\s*(?<info>{.*?});/m) + player_response = body.match(/(window\["ytInitialPlayerResponse"\]|var\sytInitialPlayerResponse)\s*=\s*(?<info>{.*?});\s*var\s*meta/m) .try { |r| JSON.parse(r["info"]).as_h } if body.includes?("To continue with your YouTube experience, please fill out the form below.") || @@ -1050,6 +1051,7 @@ def process_video_params(query, preferences) related_videos = query["related_videos"]?.try { |q| (q == "true" || q == "1").to_unsafe } speed = query["speed"]?.try &.rchop("x").to_f? video_loop = query["loop"]?.try { |q| (q == "true" || q == "1").to_unsafe } + extend_desc = query["extend_desc"]?.try { |q| (q == "true" || q == "1").to_unsafe } volume = query["volume"]?.try &.to_i? if preferences @@ -1068,6 +1070,7 @@ def process_video_params(query, preferences) related_videos ||= preferences.related_videos.to_unsafe speed ||= preferences.speed video_loop ||= preferences.video_loop.to_unsafe + extend_desc ||= preferences.extend_desc.to_unsafe volume ||= preferences.volume end @@ -1085,6 +1088,7 @@ def process_video_params(query, preferences) related_videos ||= CONFIG.default_user_preferences.related_videos.to_unsafe speed ||= CONFIG.default_user_preferences.speed video_loop ||= CONFIG.default_user_preferences.video_loop.to_unsafe + extend_desc ||= CONFIG.default_user_preferences.extend_desc.to_unsafe volume ||= CONFIG.default_user_preferences.volume annotations = annotations == 1 @@ -1095,6 +1099,7 @@ def process_video_params(query, preferences) local = local == 1 related_videos = related_videos == 1 video_loop = video_loop == 1 + extend_desc = extend_desc == 1 if CONFIG.disabled?("dash") && quality == "dash" quality = "high" @@ -1141,6 +1146,7 @@ def process_video_params(query, preferences) speed: speed, video_end: video_end, video_loop: video_loop, + extend_desc: extend_desc, video_start: video_start, volume: volume, }) @@ -1150,15 +1156,15 @@ end def build_thumbnails(id) return { - {name: "maxres", host: "#{HOST_URL}", url: "maxres", height: 720, width: 1280}, - {name: "maxresdefault", host: "https://i.ytimg.com", url: "maxresdefault", height: 720, width: 1280}, - {name: "sddefault", host: "https://i.ytimg.com", url: "sddefault", height: 480, width: 640}, - {name: "high", host: "https://i.ytimg.com", url: "hqdefault", height: 360, width: 480}, - {name: "medium", host: "https://i.ytimg.com", url: "mqdefault", height: 180, width: 320}, - {name: "default", host: "https://i.ytimg.com", url: "default", height: 90, width: 120}, - {name: "start", host: "https://i.ytimg.com", url: "1", height: 90, width: 120}, - {name: "middle", host: "https://i.ytimg.com", url: "2", height: 90, width: 120}, - {name: "end", host: "https://i.ytimg.com", url: "3", height: 90, width: 120}, + {host: HOST_URL, height: 720, width: 1280, name: "maxres", url: "maxres"}, + {host: HOST_URL, height: 720, width: 1280, name: "maxresdefault", url: "maxresdefault"}, + {host: HOST_URL, height: 480, width: 640, name: "sddefault", url: "sddefault"}, + {host: HOST_URL, height: 360, width: 480, name: "high", url: "hqdefault"}, + {host: HOST_URL, height: 180, width: 320, name: "medium", url: "mqdefault"}, + {host: HOST_URL, height: 90, width: 120, name: "default", url: "default"}, + {host: HOST_URL, height: 90, width: 120, name: "start", url: "1"}, + {host: HOST_URL, height: 90, width: 120, name: "middle", url: "2"}, + {host: HOST_URL, height: 90, width: 120, name: "end", url: "3"}, } end diff --git a/src/invidious/views/empty.ecr b/src/invidious/views/empty.ecr deleted file mode 100644 index c10c097e..00000000 --- a/src/invidious/views/empty.ecr +++ /dev/null @@ -1,8 +0,0 @@ -<% content_for "header" do %> -<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> -<title> - Invidious -</title> -<% end %> - -<%= rendered "components/feed_menu" %> diff --git a/src/invidious/views/preferences.ecr b/src/invidious/views/preferences.ecr index 14d63536..602340a4 100644 --- a/src/invidious/views/preferences.ecr +++ b/src/invidious/views/preferences.ecr @@ -106,6 +106,12 @@ <input name="annotations" id="annotations" type="checkbox" <% if preferences.annotations %>checked<% end %>> </div> + <div class="pure-control-group"> + <label for="extend_desc"><%= translate(locale, "Automatically extend video description: ") %></label> + <input name="extend_desc" id="extend_desc" type="checkbox" <% if preferences.extend_desc %>checked<% end %>> + </div> + + <legend><%= translate(locale, "Visual preferences") %></legend> <div class="pure-control-group"> @@ -150,7 +156,7 @@ <label for="default_home"><%= translate(locale, "Default homepage: ") %></label> <select name="default_home" id="default_home"> <% feed_options.each do |option| %> - <option value="<%= option %>" <% if preferences.default_home == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> + <option value="<%= option %>" <% if preferences.default_home == option %> selected <% end %>><%= translate(locale, option.blank? ? "Search" : option) %></option> <% end %> </select> </div> @@ -160,7 +166,7 @@ <% (feed_options.size - 1).times do |index| %> <select name="feed_menu[<%= index %>]" id="feed_menu[<%= index %>]"> <% feed_options.each do |option| %> - <option value="<%= option %>" <% if preferences.feed_menu[index]? == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> + <option value="<%= option %>" <% if preferences.feed_menu[index]? == option %> selected <% end %>><%= translate(locale, option.blank? ? "Search" : option) %></option> <% end %> </select> <% end %> diff --git a/src/invidious/views/search_homepage.ecr b/src/invidious/views/search_homepage.ecr new file mode 100644 index 00000000..b36500e9 --- /dev/null +++ b/src/invidious/views/search_homepage.ecr @@ -0,0 +1,24 @@ +<% content_for "header" do %> +<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> +<title> + Invidious +</title> +<link rel="stylesheet" href="/css/empty.css?v=<%= ASSET_COMMIT %>"> +<% end %> + +<%= rendered "components/feed_menu" %> + +<div class="pure-g h-box" id="search-widget"> + <div class="pure-u-1" id="logo"> + <h1 href="/" class="pure-menu-heading">Invidious</h1> + </div> + <div class="pure-u-1-4"></div> + <div class="pure-u-1 pure-u-md-12-24 searchbar"> + <form class="pure-form" action="/search" method="get"> + <fieldset> + <input type="search" style="width:100%" name="q" placeholder="<%= translate(locale, "search") %>" value="<%= env.get?("search").try {|x| HTML.escape(x.as(String)) } %>"> + </fieldset> + </form> + </div> + <div class="pure-u-1-4"></div> +</div> diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr index 61b900e3..5b63bf1f 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -26,18 +26,21 @@ <span style="display:none" id="dark_mode_pref"><%= env.get("preferences").as(Preferences).dark_mode %></span> <div class="pure-g"> <div class="pure-u-1 pure-u-md-2-24"></div> - <div class="pure-u-1 pure-u-md-20-24"> + <div class="pure-u-1 pure-u-md-20-24", id="contents"> <div class="pure-g navbar h-box"> - <div class="pure-u-1 pure-u-md-4-24"> - <a href="/" class="index-link pure-menu-heading">Invidious</a> - </div> - <div class="pure-u-1 pure-u-md-12-24 searchbar"> - <form class="pure-form" action="/search" method="get"> - <fieldset> - <input type="search" style="width:100%" name="q" placeholder="<%= translate(locale, "search") %>" value="<%= env.get?("search").try {|x| HTML.escape(x.as(String)) } %>"> - </fieldset> - </form> - </div> + <% if navbar_search %> + <div class="pure-u-1 pure-u-md-4-24"> + <a href="/" class="index-link pure-menu-heading">Invidious</a> + </div> + <div class="pure-u-1 pure-u-md-12-24 searchbar"> + <form class="pure-form" action="/search" method="get"> + <fieldset> + <input type="search" style="width:100%" name="q" placeholder="<%= translate(locale, "search") %>" value="<%= env.get?("search").try {|x| HTML.escape(x.as(String)) } %>"> + </fieldset> + </form> + </div> + <% end %> + <div class="pure-u-1 pure-u-md-8-24 user-field"> <% if env.get? "user" %> <div class="pure-u-1-4"> @@ -106,7 +109,7 @@ <%= content %> - <div class="footer"> + <footer> <div class="pure-g"> <div class="pure-u-1 pure-u-md-1-3"> <a href="https://github.com/iv-org/invidious"> @@ -140,7 +143,7 @@ <%= translate(locale, "Current version: ") %> <%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %> @ <%= CURRENT_BRANCH %> </div> </div> - </div> + </footer> </div> <div class="pure-u-1 pure-u-md-2-24"></div> </div> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index a86e23b2..8b587eb3 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -25,6 +25,19 @@ <link rel="alternate" href="https://www.youtube.com/watch?v=<%= video.id %>"> <%= rendered "components/player_sources" %> <title><%= HTML.escape(video.title) %> - Invidious</title> + +<!-- Description expansion also updates the 'Show more' button to 'Show less' so +we're going to need to do it here in order to allow for translations. + --> +<style> +#descexpansionbutton + label > a::after { + content: "<%= translate(locale, "Show more") %>" +} + +#descexpansionbutton:checked + label > a::after { + content: "<%= translate(locale, "Show less") %>" +} +</style> <% end %> <script id="video_data" type="application/json"> @@ -227,8 +240,18 @@ <% end %> </p> - <div> - <%= video.description_html %> + <div id="description-box"> <!-- Description --> + <% if video.description.size < 200 || params.extend_desc %> + <%= video.description_html %> + <% else %> + <input id="descexpansionbutton" type="checkbox"/> + <label for="descexpansionbutton" style="order: 1;"> + <a></a> + </label> + <div id="descriptionWrapper"> + <%= video.description_html %> + </div> + <% end %> </div> <hr> |
