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 Frequently Asked Questions (FAQ)",
"crash_page_search_issue": "searched for existing issues on GitHub",
"crash_page_report_issue": "If none of the above helped, please open a new issue on GitHub (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. Click here for the playlist home page."
+ "error_video_not_in_playlist": "The requested video doesn't exist in this playlist. Click here for the playlist home page.",
+ "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 << %(
"
+ 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 @@
<%= translate(locale, "Switch Invidious Instance") %>
<% end %>
- <% if !channel.auto_generated %>
-
- <%= translate(locale, "Videos") %>
-
- <% end %>
-
-
+
+ <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, selected_tab) %>
@@ -111,7 +96,12 @@
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 @@
<%= translate(locale, "Switch Invidious Instance") %>
<% end %>
- <% if !channel.auto_generated %>
-
- <% end %>
-
-
- <% if channel.tabs.includes? "community" %>
- <%= translate(locale, "Community") %>
- <% end %>
-
+
+ <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, Invidious::Frontend::ChannelPage::TabsAvailable::Community) %>
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 %>
-
-
- <% if !channel.auto_generated %>
- <%= translate(locale, "Playlists") %>
- <% end %>
-
-
+ <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, Invidious::Frontend::ChannelPage::TabsAvailable::Playlists) %>