diff options
| -rw-r--r-- | assets/css/default.css | 25 | ||||
| -rw-r--r-- | locales/da.json | 212 | ||||
| -rw-r--r-- | src/invidious.cr | 13 | ||||
| -rw-r--r-- | src/invidious/channels.cr | 110 | ||||
| -rw-r--r-- | src/invidious/helpers/helpers.cr | 2 | ||||
| -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/watch.cr | 9 | ||||
| -rw-r--r-- | src/invidious/users.cr | 2 | ||||
| -rw-r--r-- | src/invidious/videos.cr | 18 | ||||
| -rw-r--r-- | src/invidious/views/template.ecr | 6 |
11 files changed, 231 insertions, 171 deletions
diff --git a/assets/css/default.css b/assets/css/default.css index a5148f5b..a725b456 100644 --- a/assets/css/default.css +++ b/assets/css/default.css @@ -5,6 +5,12 @@ body { Arial, sans-serif; } +#contents { + display: flex; + flex-direction: column; + min-height: 100vh; +} + .deleted { background-color: rgb(255, 0, 0, 0.5); } @@ -280,14 +286,16 @@ input[type="search"]::-webkit-search-cancel-button { * Footer */ -.footer { - color: #666666; - margin: 2em 0; +footer { + color: #919191; + margin-top: auto; + padding: 1.5em 0; text-align: center; + max-height: 30vh; } -body .footer a { - color: inherit; +footer a { + color: #919191 !important; text-decoration: underline; } @@ -654,3 +662,10 @@ body.dark-theme { content: "[ - ]"; font-size: 1.5em; } + +/*With commit d9528f5 all contents of the page is now within a flexbox. However, +the hr element is rendered improperly within one. +See https://stackoverflow.com/a/34372979 for more info */ +hr { + margin: auto 0 auto 0; +} diff --git a/locales/da.json b/locales/da.json index 4d265062..b52905c3 100644 --- a/locales/da.json +++ b/locales/da.json @@ -13,7 +13,7 @@ }, "LIVE": "DIREKTE", "Shared `x` ago": "Delt for `x` siden", - "Unsubscribe": "", + "Unsubscribe": "Opsig abonnement", "Subscribe": "Abonner", "View channel on YouTube": "Vis kanal på YouTube", "View playlist on YouTube": "Vis afspilningsliste på YouTube", @@ -28,13 +28,13 @@ "New passwords must match": "Nye kodeord skal matche", "Cannot change password for Google accounts": "Kan ikke skifte kodeord til Google-konti", "Authorize token?": "Godkend token?", - "Authorize token for `x`?": "Godkende token til `x`?", + "Authorize token for `x`?": "Godkend token til `x`?", "Yes": "Ja", "No": "Nej", "Import and Export Data": "Importer og Eksporter Data", "Import": "Importer", "Import Invidious data": "Importer Invidious data", - "Import YouTube subscriptions": "Importer Youtube abonnementer", + "Import YouTube subscriptions": "Importer YouTube abonnementer", "Import FreeTube subscriptions (.db)": "Importer FreeTube abonnementer (.db)", "Import NewPipe subscriptions (.json)": "Importer NewPipe abonnementer (.json)", "Import NewPipe data (.zip)": "Importer NewPipe data (.zip)", @@ -58,9 +58,9 @@ "Sign In": "Log ind", "Register": "Registrer", "E-mail": "E-mail", - "Google verification code": "Google verifications kode", + "Google verification code": "Google-verifikationskode", "Preferences": "Præferencer", - "Player preferences": "", + "Player preferences": "Afspillerindstillinger", "Always loop: ": "Altid gentag: ", "Autoplay: ": "Auto afspil: ", "Play next by default: ": "Afspil næste som standard: ", @@ -74,118 +74,118 @@ "youtube": "youtube", "reddit": "reddit", "Default captions: ": "Standard undertekster: ", - "Fallback captions: ": "", - "Show related videos: ": "", - "Show annotations by default: ": "", - "Visual preferences": "", - "Player style: ": "", - "Dark mode: ": "", - "Theme: ": "", - "dark": "", - "light": "", - "Thin mode: ": "", - "Subscription preferences": "", - "Show annotations by default for subscribed channels: ": "", - "Redirect homepage to feed: ": "", - "Number of videos shown in feed: ": "", - "Sort videos by: ": "", - "published": "", - "published - reverse": "", - "alphabetically": "", - "alphabetically - reverse": "", - "channel name": "", - "channel name - reverse": "", - "Only show latest video from channel: ": "", - "Only show latest unwatched video from channel: ": "", - "Only show unwatched: ": "", - "Only show notifications (if there are any): ": "", - "Enable web notifications": "", - "`x` uploaded a video": "", - "`x` is live": "", - "Data preferences": "", - "Clear watch history": "", - "Import/export data": "", - "Change password": "", - "Manage subscriptions": "", - "Manage tokens": "", - "Watch history": "", - "Delete account": "", - "Administrator preferences": "", - "Default homepage: ": "", - "Feed menu: ": "", - "Top enabled: ": "", - "CAPTCHA enabled: ": "", - "Login enabled: ": "", - "Registration enabled: ": "", - "Report statistics: ": "", - "Save preferences": "", - "Subscription manager": "", - "Token manager": "", - "Token": "", + "Fallback captions: ": "Alternative undertekster: ", + "Show related videos: ": "Vis relaterede videoer: ", + "Show annotations by default: ": "Vis annotationer som standard: ", + "Visual preferences": "Visuelle præferencer", + "Player style: ": "Afspiller stil: ", + "Dark mode: ": "Mørk tilstand: ", + "Theme: ": "Tema: ", + "dark": "mørk", + "light": "lys", + "Thin mode: ": "Tynd tilstand: ", + "Subscription preferences": "Abonnements præferencer", + "Show annotations by default for subscribed channels: ": "Vis annotationer som standard for abonnerede kanaler: ", + "Redirect homepage to feed: ": "Omdiriger startside til feed: ", + "Number of videos shown in feed: ": "Antal videoer vist i feed: ", + "Sort videos by: ": "Sorter videoer efter: ", + "published": "offentliggjort", + "published - reverse": "offentliggjort - omvendt", + "alphabetically": "alfabetisk", + "alphabetically - reverse": "alfabetisk - omvendt", + "channel name": "kanalnavn", + "channel name - reverse": "kanalnavn - omvendt", + "Only show latest video from channel: ": "Vis kun seneste video fra kanal: ", + "Only show latest unwatched video from channel: ": "Vis kun seneste usete video fra kanal: ", + "Only show unwatched: ": "Vis kun usete: ", + "Only show notifications (if there are any): ": "Vis kun notifikationer (hvis der er nogle): ", + "Enable web notifications": "Aktiver webnotifikationer", + "`x` uploaded a video": "`x` uploadede en video", + "`x` is live": "`x` er live", + "Data preferences": "Data præferencer", + "Clear watch history": "Ryd afspilningshistorik", + "Import/export data": "Importer/exporter data", + "Change password": "Skift adgangskode", + "Manage subscriptions": "Administrer abonnementer", + "Manage tokens": "Administrer tokens", + "Watch history": "Afspilningshistorik", + "Delete account": "Slet konto", + "Administrator preferences": "Administrator præferencer", + "Default homepage: ": "Standard startside: ", + "Feed menu: ": "Feed menu: ", + "Top enabled: ": "Top aktiveret: ", + "CAPTCHA enabled: ": "CAPTCHA aktiveret: ", + "Login enabled: ": "Login aktiveret: ", + "Registration enabled: ": "Registrering aktiveret: ", + "Report statistics: ": "Indsend statistik: ", + "Save preferences": "Gem præferencer", + "Subscription manager": "Abonnementsmanager", + "Token manager": "Tokenmanager", + "Token": "Token", "`x` subscriptions": { - "([^.,0-9]|^)1([^.,0-9]|$)": "", - "": "" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x` abonnementer.([^.,0-9]|^)1([^.,0-9]|$)", + "": "`x`" }, "`x` tokens": { - "([^.,0-9]|^)1([^.,0-9]|$)": "", - "": "" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x` tokens.([^.,0-9]|^)1([^.,0-9]|$)", + "": "`x` tokens." }, - "Import/export": "", - "unsubscribe": "", - "revoke": "", - "Subscriptions": "", + "Import/export": "Importer/eksporter", + "unsubscribe": "opsig abonnement", + "revoke": "tilbagekald", + "Subscriptions": "Abonnementer", "`x` unseen notifications": { - "([^.,0-9]|^)1([^.,0-9]|$)": "", - "": "" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x` usete notifikationer.([^.,0-9]|^)1([^.,0-9]|$)", + "": "`x` usete notifikationer." }, - "search": "", - "Log out": "", - "Released under the AGPLv3 by Omar Roth.": "", - "Source available here.": "", - "View JavaScript license information.": "", - "View privacy policy.": "", - "Trending": "", - "Public": "", - "Unlisted": "", - "Private": "", - "View all playlists": "", + "search": "søg", + "Log out": "Log ud", + "Released under the AGPLv3 by Omar Roth.": "Offentliggjort under AGPLv3 af Omar Roth.", + "Source available here.": "Kilde tilgængelig her.", + "View JavaScript license information.": "Vis JavaScriptlicensinformation.", + "View privacy policy.": "Vis privatpolitik.", + "Trending": "Trending", + "Public": "Offentlig", + "Unlisted": "Skjult", + "Private": "Privat", + "View all playlists": "Vis alle afspilningslister", "Updated `x` ago": "", - "Delete playlist `x`?": "", - "Delete playlist": "", - "Create playlist": "", - "Title": "", - "Playlist privacy": "", - "Editing playlist `x`": "", - "Watch on YouTube": "", - "Hide annotations": "", - "Show annotations": "", - "Genre: ": "", - "License: ": "", - "Family friendly? ": "", - "Wilson score: ": "", - "Engagement: ": "", - "Whitelisted regions: ": "", - "Blacklisted regions: ": "", - "Shared `x`": "", + "Delete playlist `x`?": "Opdateret `x` siden", + "Delete playlist": "Slet afspilningsliste", + "Create playlist": "Opret afspilningsliste", + "Title": "Titel", + "Playlist privacy": "Privatlivsindstillinger for afspilningsliste", + "Editing playlist `x`": "Redigerer afspilningsliste `x`", + "Watch on YouTube": "Se på YouTube", + "Hide annotations": "Skjul annotationer", + "Show annotations": "Vis annotationer", + "Genre: ": "Genre: ", + "License: ": "Licens: ", + "Family friendly? ": "Familievenlig? ", + "Wilson score: ": "Wilson score: ", + "Engagement: ": "Engagement: ", + "Whitelisted regions: ": "Whitelistede regioner: ", + "Blacklisted regions: ": "Blacklistede regioner: ", + "Shared `x`": "Delt `x`", "`x` views": { - "([^.,0-9]|^)1([^.,0-9]|$)": "", - "": "" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x` visninger.([^.,0-9]|^)1([^.,0-9]|$)", + "": "`x` visninger" }, - "Premieres in `x`": "", - "Premieres `x`": "", - "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "", - "View YouTube comments": "", - "View more comments on Reddit": "", + "Premieres in `x`": "Har premiere om `x`", + "Premieres `x`": "Har premiere om `x`", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Hej! Det ser ud til at du har JavaScript slået fra. Klik her for at se kommentarer, vær opmærksom på at de kan tage længere om at loade.", + "View YouTube comments": "Vis YouTube kommentarer", + "View more comments on Reddit": "Se flere kommentarer på Reddit", "View `x` comments": { - "([^.,0-9]|^)1([^.,0-9]|$)": "", - "": "" + "([^.,0-9]|^)1([^.,0-9]|$)": "Vis `x` kommentarer.([^.,0-9]|^)1([^.,0-9]|$)", + "": "Vis `x` kommentarer." }, - "View Reddit comments": "", - "Hide replies": "", - "Show replies": "", - "Incorrect password": "", - "Quota exceeded, try again in a few hours": "", - "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "", + "View Reddit comments": "Vis Reddit kommentarer", + "Hide replies": "Skjul svar", + "Show replies": "Vis svar", + "Incorrect password": "Forkert adgangskode", + "Quota exceeded, try again in a few hours": "Kvota overskredet, prøv igen om et par timer", + "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Login fejlet, tjek at totrinsbekræftelse (Authenticator eller SMS) er slået til.", "Invalid TFA code": "", "Login failed. This may be because two-factor authentication is not turned on for your account.": "", "Wrong answer": "", diff --git a/src/invidious.cr b/src/invidious.cr index 88b9ad85..463a286a 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -308,9 +308,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 +331,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/channels.cr b/src/invidious/channels.cr index 47dfcbd6..3109b508 100644 --- a/src/invidious/channels.cr +++ b/src/invidious/channels.cr @@ -821,63 +821,87 @@ def get_about_info(ucid, locale) raise ChannelRedirect.new(channel_id: browse_endpoint["browseId"].to_s) end - author = initdata["metadata"]["channelMetadataRenderer"]["title"].as_s - author_url = initdata["metadata"]["channelMetadataRenderer"]["channelUrl"].as_s - author_thumbnail = initdata["metadata"]["channelMetadataRenderer"]["avatar"]["thumbnails"][0]["url"].as_s + auto_generated = false + # Check for special auto generated gaming channels + if !initdata.has_key?("metadata") + auto_generated = true + end + + if auto_generated + author = initdata["header"]["interactiveTabbedHeaderRenderer"]["title"]["simpleText"].as_s + author_url = initdata["microformat"]["microformatDataRenderer"]["urlCanonical"].as_s + author_thumbnail = initdata["header"]["interactiveTabbedHeaderRenderer"]["boxArt"]["thumbnails"][0]["url"].as_s - ucid = initdata["metadata"]["channelMetadataRenderer"]["externalId"].as_s + # Raises a KeyError on failure. + banners = initdata["header"]["interactiveTabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]? + banner = banners.try &.[-1]?.try &.["url"].as_s? - # Raises a KeyError on failure. - banners = initdata["header"]["c4TabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]? - banner = banners.try &.[-1]?.try &.["url"].as_s? + description = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"]["simpleText"].as_s + description_html = HTML.escape(description).gsub("\n", "<br>") - # if banner.includes? "channels/c4/default_banner" - # banner = nil - # end + paid = false + is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool + allowed_regions = initdata["microformat"]["microformatDataRenderer"]["availableCountries"].as_a.map { |a| a.as_s } - description = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?.try &.as_s? || "" - description_html = HTML.escape(description).gsub("\n", "<br>") + related_channels = [] of AboutRelatedChannel + else + author = initdata["metadata"]["channelMetadataRenderer"]["title"].as_s + author_url = initdata["metadata"]["channelMetadataRenderer"]["channelUrl"].as_s + author_thumbnail = initdata["metadata"]["channelMetadataRenderer"]["avatar"]["thumbnails"][0]["url"].as_s - paid = about.xpath_node(%q(//meta[@itemprop="paid"])).not_nil!["content"] == "True" - is_family_friendly = about.xpath_node(%q(//meta[@itemprop="isFamilyFriendly"])).not_nil!["content"] == "True" - allowed_regions = about.xpath_node(%q(//meta[@itemprop="regionsAllowed"])).not_nil!["content"].split(",") + ucid = initdata["metadata"]["channelMetadataRenderer"]["externalId"].as_s - related_channels = initdata["contents"]["twoColumnBrowseResultsRenderer"] - .["secondaryContents"]?.try &.["browseSecondaryContentsRenderer"]["contents"][0]? - .try &.["verticalChannelSectionRenderer"]?.try &.["items"]?.try &.as_a.map do |node| - renderer = node["miniChannelRenderer"]? - related_id = renderer.try &.["channelId"]?.try &.as_s? - related_id ||= "" + # Raises a KeyError on failure. + banners = initdata["header"]["c4TabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]? + banner = banners.try &.[-1]?.try &.["url"].as_s? - related_title = renderer.try &.["title"]?.try &.["simpleText"]?.try &.as_s? - related_title ||= "" + # if banner.includes? "channels/c4/default_banner" + # banner = nil + # end - related_author_url = renderer.try &.["navigationEndpoint"]?.try &.["commandMetadata"]?.try &.["webCommandMetadata"]? - .try &.["url"]?.try &.as_s? - related_author_url ||= "" + description = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?.try &.as_s? || "" + description_html = HTML.escape(description).gsub("\n", "<br>") - related_author_thumbnails = renderer.try &.["thumbnail"]?.try &.["thumbnails"]?.try &.as_a? - related_author_thumbnails ||= [] of JSON::Any + paid = about.xpath_node(%q(//meta[@itemprop="paid"])).not_nil!["content"] == "True" + is_family_friendly = about.xpath_node(%q(//meta[@itemprop="isFamilyFriendly"])).not_nil!["content"] == "True" + allowed_regions = about.xpath_node(%q(//meta[@itemprop="regionsAllowed"])).not_nil!["content"].split(",") - related_author_thumbnail = "" - if related_author_thumbnails.size > 0 - related_author_thumbnail = related_author_thumbnails[-1]["url"]?.try &.as_s? - related_author_thumbnail ||= "" - end + related_channels = initdata["contents"]["twoColumnBrowseResultsRenderer"] + .["secondaryContents"]?.try &.["browseSecondaryContentsRenderer"]["contents"][0]? + .try &.["verticalChannelSectionRenderer"]?.try &.["items"]?.try &.as_a.map do |node| + renderer = node["miniChannelRenderer"]? + related_id = renderer.try &.["channelId"]?.try &.as_s? + related_id ||= "" - AboutRelatedChannel.new({ - ucid: related_id, - author: related_title, - author_url: related_author_url, - author_thumbnail: related_author_thumbnail, - }) - end - related_channels ||= [] of AboutRelatedChannel + related_title = renderer.try &.["title"]?.try &.["simpleText"]?.try &.as_s? + related_title ||= "" + + related_author_url = renderer.try &.["navigationEndpoint"]?.try &.["commandMetadata"]?.try &.["webCommandMetadata"]? + .try &.["url"]?.try &.as_s? + related_author_url ||= "" + + related_author_thumbnails = renderer.try &.["thumbnail"]?.try &.["thumbnails"]?.try &.as_a? + related_author_thumbnails ||= [] of JSON::Any + + related_author_thumbnail = "" + if related_author_thumbnails.size > 0 + related_author_thumbnail = related_author_thumbnails[-1]["url"]?.try &.as_s? + related_author_thumbnail ||= "" + end + + AboutRelatedChannel.new({ + ucid: related_id, + author: related_title, + author_url: related_author_url, + author_thumbnail: related_author_thumbnail, + }) + end + related_channels ||= [] of AboutRelatedChannel + end total_views = 0_i64 joined = Time.unix(0) tabs = [] of String - auto_generated = false tabs_json = initdata["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]?.try &.as_a? if !tabs_json.nil? @@ -895,7 +919,7 @@ def get_about_info(ucid, locale) joined = channel_about_meta["joinedDateText"]?.try &.["runs"]?.try &.as_a.reduce("") { |acc, node| acc + node["text"].as_s } .try { |text| Time.parse(text, "Joined %b %-d, %Y", Time::Location.local) } || Time.unix(0) - # Auto-generated channels + # Normal Auto-generated channels # https://support.google.com/youtube/answer/2579942 # For auto-generated channels, channel_about_meta only has ["description"]["simpleText"] and ["primaryLinks"][0]["title"]["simpleText"] if (channel_about_meta["primaryLinks"]?.try &.size || 0) == 1 && (channel_about_meta["primaryLinks"][0]?) && diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr index 5d127e1a..f6b6acd1 100644 --- a/src/invidious/helpers/helpers.cr +++ b/src/invidious/helpers/helpers.cr @@ -42,7 +42,7 @@ struct ConfigPreferences property player_style : String = "invidious" property quality : String = "hd720" property quality_dash : String = "auto" - property default_home : String = "Popular" + property default_home : String? = "Popular" property feed_menu : Array(String) = ["Popular", "Trending", "Subscriptions", "Playlists"] property related_videos : Bool = true property sort : String = "published" 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/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 7a948b76..8fef64a0 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -68,7 +68,7 @@ struct Preferences property quality : String = CONFIG.default_user_preferences.quality @[JSON::Field(converter: Preferences::ProcessString)] property quality_dash : String = CONFIG.default_user_preferences.quality_dash - property default_home : String = CONFIG.default_user_preferences.default_home + property default_home : String? = CONFIG.default_user_preferences.default_home property feed_menu : Array(String) = CONFIG.default_user_preferences.feed_menu property related_videos : Bool = CONFIG.default_user_preferences.related_videos diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index e6d4c764..38646311 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -1150,15 +1150,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/template.ecr b/src/invidious/views/template.ecr index 33638055..5b63bf1f 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -26,7 +26,7 @@ <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"> <% if navbar_search %> <div class="pure-u-1 pure-u-md-4-24"> @@ -109,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"> @@ -143,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> |
