mirror of
https://github.com/iv-org/invidious.git
synced 2026-09-06 00:52:45 -05:00
Add playlist-backed Trending/Popular feeds
New config lists trending_playlists / popular_playlists. When set, the feed serves the merged content of those local PUBLIC playlists instead of the stock feed: - Swap at the data layer (fetch_trending, popular_videos), so the HTML views and /api/v1/trending|popular emit the same items and API clients (Yattee, Materialious) need no changes. - Playlists merge in config order, each in its own order, duplicates dropped. Missing or non-public entries are skipped and logged, never fatal. - One local Postgres query per playlist — no YouTube call. - PlaylistVideo converts to SearchVideo with neutral defaults for metadata a playlist row lacks (views, description, thumbnails). - Trending category tabs and region are ignored while set. With a single trending playlist, 'View as playlist' links to it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
31fe847126
commit
c644d73def
@ -391,6 +391,24 @@ https_only: false
|
||||
# - 192.168.1.101
|
||||
# logout_url: "https://auth.example.com/logout"
|
||||
|
||||
##
|
||||
## Playlist-backed feeds (ArikTube extension).
|
||||
##
|
||||
## When set, the Trending and/or Popular feed serves the content of these
|
||||
## local PUBLIC playlists instead of the stock feed. Playlists merge in
|
||||
## the listed order, each in its own order, duplicates dropped. The swap
|
||||
## is at the data layer, so /api/v1/trending and /api/v1/popular serve
|
||||
## the same items — API clients need no changes. Missing or non-public
|
||||
## playlists are skipped and logged. Trending category tabs and region
|
||||
## are ignored while a list is set.
|
||||
##
|
||||
## Default: [] (stock feeds)
|
||||
##
|
||||
#trending_playlists:
|
||||
# - IVPLxxxxxxxxxxxxxxxxxxxx
|
||||
#popular_playlists:
|
||||
# - IVPLxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
##
|
||||
## Enable/Disable the captcha challenge on the login page.
|
||||
##
|
||||
|
||||
@ -193,6 +193,11 @@ Invidious::Jobs.register Invidious::Jobs::InstanceListRefreshJob.new
|
||||
Invidious::Jobs.start_all
|
||||
|
||||
def popular_videos
|
||||
# ArikTube: playlist-backed Popular
|
||||
unless CONFIG.popular_playlists.empty?
|
||||
return Invidious::PlaylistFeeds.feed_videos(CONFIG.popular_playlists)
|
||||
end
|
||||
|
||||
Invidious::Jobs::PullPopularVideosJob::POPULAR_VIDEOS.get
|
||||
end
|
||||
|
||||
|
||||
@ -147,6 +147,11 @@ class Config
|
||||
# Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
||||
property use_pubsub_feeds : Bool | Int32 = false
|
||||
property popular_enabled : Bool = true
|
||||
# Playlist-backed feeds (ArikTube extension): when set, the Trending or
|
||||
# Popular feed serves these local PUBLIC playlists (merged in order,
|
||||
# duplicates dropped) instead of the stock feed content.
|
||||
property trending_playlists : Array(String) = [] of String
|
||||
property popular_playlists : Array(String) = [] of String
|
||||
property captcha_enabled : Bool = true
|
||||
property login_enabled : Bool = true
|
||||
property registration_enabled : Bool = true
|
||||
|
||||
58
src/invidious/playlist_feeds.cr
Normal file
58
src/invidious/playlist_feeds.cr
Normal file
@ -0,0 +1,58 @@
|
||||
# Playlist-backed Trending/Popular feeds (ArikTube extension).
|
||||
#
|
||||
# On a personal instance "Trending" and "Popular" mean "what this server's
|
||||
# owner pushes". When `trending_playlists` / `popular_playlists` name local
|
||||
# public playlists, those feeds serve the merged playlist content instead.
|
||||
# The swap happens at the data layer (fetch_trending / popular_videos), so
|
||||
# the HTML views and /api/v1/trending|popular emit the same items and every
|
||||
# API client shows them without client-side support.
|
||||
module Invidious::PlaylistFeeds
|
||||
extend self
|
||||
|
||||
# Merged videos of the configured playlists: config order, each playlist
|
||||
# in its own order, duplicates dropped. Missing or non-public playlists
|
||||
# are skipped with a log line so one bad entry cannot break the feed.
|
||||
def feed_videos(plids : Array(String)) : Array(SearchVideo)
|
||||
videos = [] of SearchVideo
|
||||
seen = Set(String).new
|
||||
|
||||
plids.each do |plid|
|
||||
playlist = Invidious::Database::Playlists.select(id: plid)
|
||||
if playlist.nil?
|
||||
LOGGER.warn("PlaylistFeeds: playlist #{plid} does not exist, skipping")
|
||||
next
|
||||
end
|
||||
if playlist.privacy != PlaylistPrivacy::Public
|
||||
LOGGER.warn("PlaylistFeeds: playlist #{plid} is not public, skipping")
|
||||
next
|
||||
end
|
||||
|
||||
Invidious::Database::PlaylistVideos.select(plid, playlist.index, 0, limit: 200).each do |video|
|
||||
next if seen.includes?(video.id)
|
||||
seen << video.id
|
||||
videos << as_search_video(video)
|
||||
end
|
||||
end
|
||||
|
||||
videos
|
||||
end
|
||||
|
||||
# PlaylistVideo lacks views/description/thumbnails metadata; neutral
|
||||
# defaults keep the SearchVideo JSON shape the feed endpoints promise.
|
||||
private def as_search_video(video : PlaylistVideo) : SearchVideo
|
||||
SearchVideo.new({
|
||||
title: video.title,
|
||||
id: video.id,
|
||||
author: video.author,
|
||||
ucid: video.ucid,
|
||||
published: video.published,
|
||||
views: 0_i64,
|
||||
description_html: "",
|
||||
length_seconds: video.length_seconds,
|
||||
premiere_timestamp: nil,
|
||||
author_verified: false,
|
||||
author_thumbnail: nil,
|
||||
badges: video.live_now ? VideoBadges::LiveNow : VideoBadges::None,
|
||||
})
|
||||
end
|
||||
end
|
||||
@ -1,4 +1,12 @@
|
||||
def fetch_trending(trending_type, region, locale)
|
||||
# ArikTube: playlist-backed Trending. Category tabs and region are
|
||||
# ignored on purpose — the owner's list is the feed.
|
||||
unless CONFIG.trending_playlists.empty?
|
||||
plids = CONFIG.trending_playlists
|
||||
plid = plids.size == 1 ? plids[0] : nil
|
||||
return {Invidious::PlaylistFeeds.feed_videos(plids), plid}
|
||||
end
|
||||
|
||||
region ||= "US"
|
||||
region = region.upcase
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user