forked from midou/invidious
Channels: Add support for releases and podcasts tabs (#3980)
This commit is contained in:
commit
598ba7bade
@ -474,6 +474,8 @@
|
|||||||
"channel_tab_videos_label": "Videos",
|
"channel_tab_videos_label": "Videos",
|
||||||
"channel_tab_shorts_label": "Shorts",
|
"channel_tab_shorts_label": "Shorts",
|
||||||
"channel_tab_streams_label": "Livestreams",
|
"channel_tab_streams_label": "Livestreams",
|
||||||
|
"channel_tab_podcasts_label": "Podcasts",
|
||||||
|
"channel_tab_releases_label": "Releases",
|
||||||
"channel_tab_playlists_label": "Playlists",
|
"channel_tab_playlists_label": "Playlists",
|
||||||
"channel_tab_community_label": "Community",
|
"channel_tab_community_label": "Community",
|
||||||
"channel_tab_channels_label": "Channels"
|
"channel_tab_channels_label": "Channels"
|
||||||
|
@ -26,3 +26,21 @@ def fetch_channel_playlists(ucid, author, continuation, sort_by)
|
|||||||
|
|
||||||
return extract_items(initial_data, author, ucid)
|
return extract_items(initial_data, author, ucid)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_channel_podcasts(ucid, author, continuation)
|
||||||
|
if continuation
|
||||||
|
initial_data = YoutubeAPI.browse(continuation)
|
||||||
|
else
|
||||||
|
initial_data = YoutubeAPI.browse(ucid, params: "Eghwb2RjYXN0c_IGBQoDugEA")
|
||||||
|
end
|
||||||
|
return extract_items(initial_data, author, ucid)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_channel_releases(ucid, author, continuation)
|
||||||
|
if continuation
|
||||||
|
initial_data = YoutubeAPI.browse(continuation)
|
||||||
|
else
|
||||||
|
initial_data = YoutubeAPI.browse(ucid, params: "EghyZWxlYXNlc_IGBQoDsgEA")
|
||||||
|
end
|
||||||
|
return extract_items(initial_data, author, ucid)
|
||||||
|
end
|
||||||
|
@ -5,6 +5,8 @@ module Invidious::Frontend::ChannelPage
|
|||||||
Videos
|
Videos
|
||||||
Shorts
|
Shorts
|
||||||
Streams
|
Streams
|
||||||
|
Podcasts
|
||||||
|
Releases
|
||||||
Playlists
|
Playlists
|
||||||
Community
|
Community
|
||||||
Channels
|
Channels
|
||||||
|
@ -245,7 +245,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
channel = nil # Make the compiler happy
|
channel = nil # Make the compiler happy
|
||||||
get_channel()
|
get_channel()
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
JSON.build do |json|
|
JSON.build do |json|
|
||||||
json.object do
|
json.object do
|
||||||
@ -257,7 +257,65 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
json.field "continuation", continuation
|
json.field "continuation", next_continuation if next_continuation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.podcasts(env)
|
||||||
|
locale = env.get("preferences").as(Preferences).locale
|
||||||
|
|
||||||
|
env.response.content_type = "application/json"
|
||||||
|
|
||||||
|
ucid = env.params.url["ucid"]
|
||||||
|
continuation = env.params.query["continuation"]?
|
||||||
|
|
||||||
|
# Use the macro defined above
|
||||||
|
channel = nil # Make the compiler happy
|
||||||
|
get_channel()
|
||||||
|
|
||||||
|
items, next_continuation = fetch_channel_podcasts(channel.ucid, channel.author, continuation)
|
||||||
|
|
||||||
|
JSON.build do |json|
|
||||||
|
json.object do
|
||||||
|
json.field "playlists" do
|
||||||
|
json.array do
|
||||||
|
items.each do |item|
|
||||||
|
item.to_json(locale, json) if item.is_a?(SearchPlaylist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "continuation", next_continuation if next_continuation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.releases(env)
|
||||||
|
locale = env.get("preferences").as(Preferences).locale
|
||||||
|
|
||||||
|
env.response.content_type = "application/json"
|
||||||
|
|
||||||
|
ucid = env.params.url["ucid"]
|
||||||
|
continuation = env.params.query["continuation"]?
|
||||||
|
|
||||||
|
# Use the macro defined above
|
||||||
|
channel = nil # Make the compiler happy
|
||||||
|
get_channel()
|
||||||
|
|
||||||
|
items, next_continuation = fetch_channel_releases(channel.ucid, channel.author, continuation)
|
||||||
|
|
||||||
|
JSON.build do |json|
|
||||||
|
json.object do
|
||||||
|
json.field "playlists" do
|
||||||
|
json.array do
|
||||||
|
items.each do |item|
|
||||||
|
item.to_json(locale, json) if item.is_a?(SearchPlaylist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
json.field "continuation", next_continuation if next_continuation
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -27,7 +27,7 @@ module Invidious::Routes::Channels
|
|||||||
item.author
|
item.author
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
items = items.select(SearchPlaylist).map(&.as(SearchPlaylist))
|
items = items.select(SearchPlaylist)
|
||||||
items.each(&.author = "")
|
items.each(&.author = "")
|
||||||
else
|
else
|
||||||
sort_options = {"newest", "oldest", "popular"}
|
sort_options = {"newest", "oldest", "popular"}
|
||||||
@ -105,13 +105,53 @@ module Invidious::Routes::Channels
|
|||||||
channel.ucid, channel.author, continuation, (sort_by || "last")
|
channel.ucid, channel.author, continuation, (sort_by || "last")
|
||||||
)
|
)
|
||||||
|
|
||||||
items = items.select(SearchPlaylist).map(&.as(SearchPlaylist))
|
items = items.select(SearchPlaylist)
|
||||||
items.each(&.author = "")
|
items.each(&.author = "")
|
||||||
|
|
||||||
selected_tab = Frontend::ChannelPage::TabsAvailable::Playlists
|
selected_tab = Frontend::ChannelPage::TabsAvailable::Playlists
|
||||||
templated "channel"
|
templated "channel"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.podcasts(env)
|
||||||
|
data = self.fetch_basic_information(env)
|
||||||
|
return data if !data.is_a?(Tuple)
|
||||||
|
|
||||||
|
locale, user, subscriptions, continuation, ucid, channel = data
|
||||||
|
|
||||||
|
sort_by = ""
|
||||||
|
sort_options = [] of String
|
||||||
|
|
||||||
|
items, next_continuation = fetch_channel_podcasts(
|
||||||
|
channel.ucid, channel.author, continuation
|
||||||
|
)
|
||||||
|
|
||||||
|
items = items.select(SearchPlaylist)
|
||||||
|
items.each(&.author = "")
|
||||||
|
|
||||||
|
selected_tab = Frontend::ChannelPage::TabsAvailable::Podcasts
|
||||||
|
templated "channel"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.releases(env)
|
||||||
|
data = self.fetch_basic_information(env)
|
||||||
|
return data if !data.is_a?(Tuple)
|
||||||
|
|
||||||
|
locale, user, subscriptions, continuation, ucid, channel = data
|
||||||
|
|
||||||
|
sort_by = ""
|
||||||
|
sort_options = [] of String
|
||||||
|
|
||||||
|
items, next_continuation = fetch_channel_releases(
|
||||||
|
channel.ucid, channel.author, continuation
|
||||||
|
)
|
||||||
|
|
||||||
|
items = items.select(SearchPlaylist)
|
||||||
|
items.each(&.author = "")
|
||||||
|
|
||||||
|
selected_tab = Frontend::ChannelPage::TabsAvailable::Releases
|
||||||
|
templated "channel"
|
||||||
|
end
|
||||||
|
|
||||||
def self.community(env)
|
def self.community(env)
|
||||||
data = self.fetch_basic_information(env)
|
data = self.fetch_basic_information(env)
|
||||||
if !data.is_a?(Tuple)
|
if !data.is_a?(Tuple)
|
||||||
|
@ -118,6 +118,8 @@ module Invidious::Routing
|
|||||||
get "/channel/:ucid/videos", Routes::Channels, :videos
|
get "/channel/:ucid/videos", Routes::Channels, :videos
|
||||||
get "/channel/:ucid/shorts", Routes::Channels, :shorts
|
get "/channel/:ucid/shorts", Routes::Channels, :shorts
|
||||||
get "/channel/:ucid/streams", Routes::Channels, :streams
|
get "/channel/:ucid/streams", Routes::Channels, :streams
|
||||||
|
get "/channel/:ucid/podcasts", Routes::Channels, :podcasts
|
||||||
|
get "/channel/:ucid/releases", Routes::Channels, :releases
|
||||||
get "/channel/:ucid/playlists", Routes::Channels, :playlists
|
get "/channel/:ucid/playlists", Routes::Channels, :playlists
|
||||||
get "/channel/:ucid/community", Routes::Channels, :community
|
get "/channel/:ucid/community", Routes::Channels, :community
|
||||||
get "/channel/:ucid/channels", Routes::Channels, :channels
|
get "/channel/:ucid/channels", Routes::Channels, :channels
|
||||||
@ -228,6 +230,9 @@ module Invidious::Routing
|
|||||||
get "/api/v1/channels/:ucid", {{namespace}}::Channels, :home
|
get "/api/v1/channels/:ucid", {{namespace}}::Channels, :home
|
||||||
get "/api/v1/channels/:ucid/shorts", {{namespace}}::Channels, :shorts
|
get "/api/v1/channels/:ucid/shorts", {{namespace}}::Channels, :shorts
|
||||||
get "/api/v1/channels/:ucid/streams", {{namespace}}::Channels, :streams
|
get "/api/v1/channels/:ucid/streams", {{namespace}}::Channels, :streams
|
||||||
|
get "/api/v1/channels/:ucid/podcasts", {{namespace}}::Channels, :podcasts
|
||||||
|
get "/api/v1/channels/:ucid/releases", {{namespace}}::Channels, :releases
|
||||||
|
|
||||||
get "/api/v1/channels/:ucid/channels", {{namespace}}::Channels, :channels
|
get "/api/v1/channels/:ucid/channels", {{namespace}}::Channels, :channels
|
||||||
|
|
||||||
{% for route in {"videos", "latest", "playlists", "community", "search"} %}
|
{% for route in {"videos", "latest", "playlists", "community", "search"} %}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
when .streams? then "/channel/#{ucid}/streams"
|
when .streams? then "/channel/#{ucid}/streams"
|
||||||
when .playlists? then "/channel/#{ucid}/playlists"
|
when .playlists? then "/channel/#{ucid}/playlists"
|
||||||
when .channels? then "/channel/#{ucid}/channels"
|
when .channels? then "/channel/#{ucid}/channels"
|
||||||
|
when .podcasts? then "/channel/#{ucid}/podcasts"
|
||||||
|
when .releases? then "/channel/#{ucid}/releases"
|
||||||
else
|
else
|
||||||
"/channel/#{ucid}"
|
"/channel/#{ucid}"
|
||||||
end
|
end
|
||||||
|
@ -408,8 +408,8 @@ private module Parsers
|
|||||||
# Returns nil when the given object isn't a RichItemRenderer
|
# Returns nil when the given object isn't a RichItemRenderer
|
||||||
#
|
#
|
||||||
# A richItemRenderer seems to be a simple wrapper for a videoRenderer, used
|
# A richItemRenderer seems to be a simple wrapper for a videoRenderer, used
|
||||||
# by the result page for hashtags. It is located inside a continuationItems
|
# by the result page for hashtags and for the podcast tab on channels.
|
||||||
# container.
|
# It is located inside a continuationItems container for hashtags.
|
||||||
#
|
#
|
||||||
module RichItemRendererParser
|
module RichItemRendererParser
|
||||||
def self.process(item : JSON::Any, author_fallback : AuthorFallback)
|
def self.process(item : JSON::Any, author_fallback : AuthorFallback)
|
||||||
@ -421,6 +421,7 @@ private module Parsers
|
|||||||
private def self.parse(item_contents, author_fallback)
|
private def self.parse(item_contents, author_fallback)
|
||||||
child = VideoRendererParser.process(item_contents, author_fallback)
|
child = VideoRendererParser.process(item_contents, author_fallback)
|
||||||
child ||= ReelItemRendererParser.process(item_contents, author_fallback)
|
child ||= ReelItemRendererParser.process(item_contents, author_fallback)
|
||||||
|
child ||= PlaylistRendererParser.process(item_contents, author_fallback)
|
||||||
return child
|
return child
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user