From 6c9754e66316d903ed4f89d2cd59cd82940509f5 Mon Sep 17 00:00:00 2001 From: Samantaz Fox <coding@samantaz.fr> Date: Wed, 30 Nov 2022 00:29:48 +0100 Subject: [PATCH] frontend: Add support for shorts and livestreams --- locales/en-US.json | 9 +++-- src/invidious/channels/about.cr | 10 ++++- src/invidious/frontend/channel_page.cr | 43 ++++++++++++++++++++ src/invidious/routes/channels.cr | 54 ++++++++++++++++++++++++-- src/invidious/routing.cr | 4 +- src/invidious/views/channel.ecr | 30 +++++--------- src/invidious/views/community.ecr | 15 +------ src/invidious/views/playlists.ecr | 14 +------ 8 files changed, 124 insertions(+), 55 deletions(-) create mode 100644 src/invidious/frontend/channel_page.cr diff --git a/locales/en-US.json b/locales/en-US.json index 5554b928..44b40c24 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -404,9 +404,7 @@ "`x` marked it with a ❤": "`x` marked it with a ❤", "Audio mode": "Audio mode", "Video mode": "Video mode", - "Videos": "Videos", "Playlists": "Playlists", - "Community": "Community", "search_filters_title": "Filters", "search_filters_date_label": "Upload date", "search_filters_date_option_none": "Any date", @@ -472,5 +470,10 @@ "crash_page_read_the_faq": "read the <a href=\"`x`\">Frequently Asked Questions (FAQ)</a>", "crash_page_search_issue": "searched for <a href=\"`x`\">existing issues on GitHub</a>", "crash_page_report_issue": "If none of the above helped, please <a href=\"`x`\">open a new issue on GitHub</a> (preferably in English) and include the following text in your message (do NOT translate that text):", - "error_video_not_in_playlist": "The requested video doesn't exist in this playlist. <a href=\"`x`\">Click here for the playlist home page.</a>" + "error_video_not_in_playlist": "The requested video doesn't exist in this playlist. <a href=\"`x`\">Click here for the playlist home page.</a>", + "channel_tab_videos_label": "Videos", + "channel_tab_shorts_label": "Shorts", + "channel_tab_streams_label": "Livestreams", + "channel_tab_playlists_label": "Playlists", + "channel_tab_community_label": "Community" } diff --git a/src/invidious/channels/about.cr b/src/invidious/channels/about.cr index bb9bd8c7..09c3427a 100644 --- a/src/invidious/channels/about.cr +++ b/src/invidious/channels/about.cr @@ -104,8 +104,14 @@ def get_about_info(ucid, locale) : AboutChannel if tabs_json = initdata["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]? # Get the name of the tabs available on this channel - tab_names = tabs_json.as_a - .compact_map(&.dig?("tabRenderer", "title").try &.as_s.downcase) + tab_names = tabs_json.as_a.compact_map do |entry| + name = entry.dig?("tabRenderer", "title").try &.as_s.downcase + + # This is a small fix to not add extra code on the HTML side + # I.e, the URL for the "live" tab is .../streams, so use "streams" + # everywhere for the sake of simplicity + (name == "live") ? "streams" : name + end # Get the currently active tab ("About") about_tab = extract_selected_tab(tabs_json) diff --git a/src/invidious/frontend/channel_page.cr b/src/invidious/frontend/channel_page.cr new file mode 100644 index 00000000..7ac0e071 --- /dev/null +++ b/src/invidious/frontend/channel_page.cr @@ -0,0 +1,43 @@ +module Invidious::Frontend::ChannelPage + extend self + + enum TabsAvailable + Videos + Shorts + Streams + Playlists + Community + end + + def generate_tabs_links(locale : String, channel : AboutChannel, selected_tab : TabsAvailable) + return String.build(1500) do |str| + base_url = "/channel/#{channel.ucid}" + + TabsAvailable.each do |tab| + # Ignore playlists, as it is not supported for auto-generated channels yet + next if (tab.playlists? && channel.auto_generated) + + tab_name = tab.to_s.downcase + + if channel.tabs.includes? tab_name + str << %(<div class="pure-u-1 pure-md-1-3">\n) + + if tab == selected_tab + str << "\t<b>" + str << translate(locale, "channel_tab_#{tab_name}_label") + str << "</b>\n" + else + # Video tab doesn't have the last path component + url = tab.videos? ? base_url : "#{base_url}/#{tab_name}" + + str << %(\t<a href=") << url << %(">) + str << translate(locale, "channel_tab_#{tab_name}_label") + str << "</a>\n" + end + + str << "</div>" + end + end + end + end +end diff --git a/src/invidious/routes/channels.cr b/src/invidious/routes/channels.cr index 2773deb7..78b38341 100644 --- a/src/invidious/routes/channels.cr +++ b/src/invidious/routes/channels.cr @@ -18,7 +18,7 @@ module Invidious::Routes::Channels sort_options = {"last", "oldest", "newest"} sort_by ||= "last" - items, continuation = fetch_channel_playlists(channel.ucid, channel.author, continuation, sort_by) + items, next_continuation = fetch_channel_playlists(channel.ucid, channel.author, continuation, sort_by) items.uniq! do |item| if item.responds_to?(:title) item.title @@ -32,11 +32,59 @@ module Invidious::Routes::Channels sort_options = {"newest", "oldest", "popular"} sort_by ||= "newest" - items, continuation = Channel::Tabs.get_60_videos( + # Fetch items and continuation token + items, next_continuation = Channel::Tabs.get_videos( channel, continuation: continuation, sort_by: sort_by ) end + selected_tab = Frontend::ChannelPage::TabsAvailable::Videos + templated "channel" + end + + def self.shorts(env) + data = self.fetch_basic_information(env) + return data if !data.is_a?(Tuple) + + locale, user, subscriptions, continuation, ucid, channel = data + + if !channel.tabs.includes? "shorts" + return env.redirect "/channel/#{channel.ucid}" + end + + # TODO: support sort option for shorts + sort_by = "" + sort_options = [] of String + + # Fetch items and continuation token + items, next_continuation = Channel::Tabs.get_shorts( + channel, continuation: continuation + ) + + selected_tab = Frontend::ChannelPage::TabsAvailable::Shorts + templated "channel" + end + + def self.streams(env) + data = self.fetch_basic_information(env) + return data if !data.is_a?(Tuple) + + locale, user, subscriptions, continuation, ucid, channel = data + + if !channel.tabs.includes? "streams" + return env.redirect "/channel/#{channel.ucid}" + end + + # TODO: support sort option for livestreams + sort_by = "" + sort_options = [] of String + + # Fetch items and continuation token + items, next_continuation = Channel::Tabs.get_60_livestreams( + channel, continuation: continuation + ) + + selected_tab = Frontend::ChannelPage::TabsAvailable::Streams templated "channel" end @@ -124,7 +172,7 @@ module Invidious::Routes::Channels end selected_tab = env.request.path.split("/")[-1] - if ["home", "videos", "playlists", "community", "channels", "about"].includes? selected_tab + if {"home", "videos", "shorts", "streams", "playlists", "community", "channels", "about"}.includes? selected_tab url = "/channel/#{ucid}/#{selected_tab}" else url = "/channel/#{ucid}" diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr index f409f13c..08739c3d 100644 --- a/src/invidious/routing.cr +++ b/src/invidious/routing.cr @@ -115,6 +115,8 @@ module Invidious::Routing get "/channel/:ucid", Routes::Channels, :home get "/channel/:ucid/home", Routes::Channels, :home get "/channel/:ucid/videos", Routes::Channels, :videos + get "/channel/:ucid/shorts", Routes::Channels, :shorts + get "/channel/:ucid/streams", Routes::Channels, :streams get "/channel/:ucid/playlists", Routes::Channels, :playlists get "/channel/:ucid/community", Routes::Channels, :community get "/channel/:ucid/about", Routes::Channels, :about @@ -122,7 +124,7 @@ module Invidious::Routing get "/user/:user/live", Routes::Channels, :live get "/c/:user/live", Routes::Channels, :live - ["", "/videos", "/playlists", "/community", "/about"].each do |path| + {"", "/videos", "/shorts", "/streams", "/playlists", "/community", "/about"}.each do |path| # /c/LinusTechTips get "/c/:user#{path}", Routes::Channels, :brand_redirect # /user/linustechtips | Not always the same as /c/ diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr index 878587d4..f6cc3340 100644 --- a/src/invidious/views/channel.ecr +++ b/src/invidious/views/channel.ecr @@ -64,23 +64,8 @@ <a href="https://redirect.invidious.io<%= env.request.path %>"><%= translate(locale, "Switch Invidious Instance") %></a> <% end %> </div> - <% if !channel.auto_generated %> - <div class="pure-u-1 pure-md-1-3"> - <b><%= translate(locale, "Videos") %></b> - </div> - <% end %> - <div class="pure-u-1 pure-md-1-3"> - <% if channel.auto_generated %> - <b><%= translate(locale, "Playlists") %></b> - <% else %> - <a href="/channel/<%= ucid %>/playlists"><%= translate(locale, "Playlists") %></a> - <% end %> - </div> - <div class="pure-u-1 pure-md-1-3"> - <% if channel.tabs.includes? "community" %> - <a href="/channel/<%= ucid %>/community"><%= translate(locale, "Community") %></a> - <% end %> - </div> + + <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, selected_tab) %> </div> <div class="pure-u-1-3"></div> <div class="pure-u-1-3"> @@ -111,7 +96,12 @@ </div> <div class="pure-g h-box"> - <div class="pure-u-1 pure-u-lg-1-5"></div> - <div class="pure-u-1 pure-u-lg-3-5"></div> - <div class="pure-u-1 pure-u-lg-1-5"></div> + <div class="pure-u-1 pure-u-md-4-5"></div> + <div class="pure-u-1 pure-u-lg-1-5" style="text-align:right"> + <% if next_continuation %> + <a href="/channel/<%= ucid %>/<%= selected_tab %>?continuation=<%= next_continuation %><% if sort_by != "last" %>&sort_by=<%= URI.encode_www_form(sort_by) %><% end %>"> + <%= translate(locale, "Next page") %> + </a> + <% end %> + </div> </div> diff --git a/src/invidious/views/community.ecr b/src/invidious/views/community.ecr index 3bc29e55..e467a679 100644 --- a/src/invidious/views/community.ecr +++ b/src/invidious/views/community.ecr @@ -50,19 +50,8 @@ <a href="https://redirect.invidious.io<%= env.request.resource %>"><%= translate(locale, "Switch Invidious Instance") %></a> <% end %> </div> - <% if !channel.auto_generated %> - <div class="pure-u-1 pure-md-1-3"> - <a href="/channel/<%= channel.ucid %>"><%= translate(locale, "Videos") %></a> - </div> - <% end %> - <div class="pure-u-1 pure-md-1-3"> - <a href="/channel/<%= channel.ucid %>/playlists"><%= translate(locale, "Playlists") %></a> - </div> - <div class="pure-u-1 pure-md-1-3"> - <% if channel.tabs.includes? "community" %> - <b><%= translate(locale, "Community") %></b> - <% end %> - </div> + + <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, Invidious::Frontend::ChannelPage::TabsAvailable::Community) %> </div> <div class="pure-u-2-3"></div> </div> diff --git a/src/invidious/views/playlists.ecr b/src/invidious/views/playlists.ecr index c8718e7b..56d25ef5 100644 --- a/src/invidious/views/playlists.ecr +++ b/src/invidious/views/playlists.ecr @@ -54,19 +54,7 @@ <% end %> </div> - <div class="pure-u-1 pure-md-1-3"> - <a href="/channel/<%= ucid %>"><%= translate(locale, "Videos") %></a> - </div> - <div class="pure-u-1 pure-md-1-3"> - <% if !channel.auto_generated %> - <b><%= translate(locale, "Playlists") %></b> - <% end %> - </div> - <div class="pure-u-1 pure-md-1-3"> - <% if channel.tabs.includes? "community" %> - <a href="/channel/<%= ucid %>/community"><%= translate(locale, "Community") %></a> - <% end %> - </div> + <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, Invidious::Frontend::ChannelPage::TabsAvailable::Playlists) %> </div> <div class="pure-u-1-3"></div> <div class="pure-u-1-3">