1
0
mirror of https://github.com/mxpv/podsync.git synced 2024-05-11 05:55:04 +00:00

add support for descengind playlists

This commit is contained in:
Matej Drobnic
2021-12-28 08:06:10 +01:00
parent c1130f3f97
commit 52293e4ad2
5 changed files with 56 additions and 20 deletions

View File

@@ -78,6 +78,7 @@ vimeo = [ # Multiple keys will be rotated.
update_period = "12h" # How often query for updates, examples: "60m", "4h", "2h45m" update_period = "12h" # How often query for updates, examples: "60m", "4h", "2h45m"
quality = "high" # or "low" quality = "high" # or "low"
format = "video" # or "audio" format = "video" # or "audio"
playlist_sort = "asc" # or "desc", which will fetch playlist items from the end
# custom.cover_art_quality use "high" or "low" to special cover image quality from channel cover default is equal with "quality" and disable when custom.cover_art was set. # custom.cover_art_quality use "high" or "low" to special cover image quality from channel cover default is equal with "quality" and disable when custom.cover_art was set.
# custom = { title = "Level1News", description = "News sections of Level1Techs, in a podcast feed!", author = "Level1Tech", cover_art = "{IMAGE_URL}", cover_art_quality = "high", category = "TV", subcategories = ["Documentary", "Tech News"], explicit = true, lang = "en" } # Optional feed customizations # custom = { title = "Level1News", description = "News sections of Level1Techs, in a podcast feed!", author = "Level1Tech", cover_art = "{IMAGE_URL}", cover_art_quality = "high", category = "TV", subcategories = ["Documentary", "Tech News"], explicit = true, lang = "en" } # Optional feed customizations
# max_height = 720 # Optional maximal height of video, example: 720, 1080, 1440, 2160, ... # max_height = 720 # Optional maximal height of video, example: 720, 1080, 1440, 2160, ...

View File

@@ -330,11 +330,14 @@ func (yt *YouTubeBuilder) queryVideoDescriptions(ctx context.Context, playlist m
return nil return nil
} }
// Cost: (3 units + 5 units) * X pages = 8 units per page // Cost:
// ASC mode = (3 units + 5 units) * X pages = 8 units per page
// DESC mode = 3 units * (number of pages in the entire playlist) + 5 units
func (yt *YouTubeBuilder) queryItems(ctx context.Context, feed *model.Feed) error { func (yt *YouTubeBuilder) queryItems(ctx context.Context, feed *model.Feed) error {
var ( var (
token string token string
count int count int
allSnippets []*youtube.PlaylistItemSnippet
) )
for { for {
@@ -346,25 +349,39 @@ func (yt *YouTubeBuilder) queryItems(ctx context.Context, feed *model.Feed) erro
token = pageToken token = pageToken
if len(items) == 0 { if len(items) == 0 {
return nil break
} }
// Extract playlist snippets // Extract playlist snippets
snippets := map[string]*youtube.PlaylistItemSnippet{}
for _, item := range items { for _, item := range items {
snippets[item.Snippet.ResourceId.VideoId] = item.Snippet allSnippets = append(allSnippets, item.Snippet)
count++ count++
} }
// Query video descriptions from the list of ids if (feed.PlaylistSort != model.SortingDesc && count >= feed.PageSize) || token == "" {
if err := yt.queryVideoDescriptions(ctx, snippets, feed); err != nil { break
return err
}
if count >= feed.PageSize || token == "" {
return nil
} }
} }
if len(allSnippets) > feed.PageSize {
if feed.PlaylistSort != model.SortingDesc {
allSnippets = allSnippets[:feed.PageSize]
} else {
allSnippets = allSnippets[len(allSnippets)-feed.PageSize:]
}
}
snippets := map[string]*youtube.PlaylistItemSnippet{}
for _, snippet := range allSnippets {
snippets[snippet.ResourceId.VideoId] = snippet
}
// Query video descriptions from the list of ids
if err := yt.queryVideoDescriptions(ctx, snippets, feed); err != nil {
return err
}
return nil
} }
func (yt *YouTubeBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) { func (yt *YouTubeBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) {
@@ -374,13 +391,14 @@ func (yt *YouTubeBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.F
} }
feed := &model.Feed{ feed := &model.Feed{
ItemID: info.ItemID, ItemID: info.ItemID,
Provider: info.Provider, Provider: info.Provider,
LinkType: info.LinkType, LinkType: info.LinkType,
Format: cfg.Format, Format: cfg.Format,
Quality: cfg.Quality, Quality: cfg.Quality,
PageSize: cfg.PageSize, PageSize: cfg.PageSize,
UpdatedAt: time.Now().UTC(), PlaylistSort: cfg.PlaylistSort,
UpdatedAt: time.Now().UTC(),
} }
if feed.PageSize == 0 { if feed.PageSize == 0 {

View File

@@ -45,6 +45,8 @@ type Feed struct {
YouTubeDLArgs []string `toml:"youtube_dl_args"` YouTubeDLArgs []string `toml:"youtube_dl_args"`
// Included in OPML file // Included in OPML file
OPML bool `toml:"opml"` OPML bool `toml:"opml"`
// Playlist sort
PlaylistSort model.Sorting `toml:"playlist_sort"`
} }
type Filters struct { type Filters struct {
@@ -237,5 +239,9 @@ func (c *Config) applyDefaults(configPath string) {
if feed.PageSize == 0 { if feed.PageSize == 0 {
feed.PageSize = model.DefaultPageSize feed.PageSize = model.DefaultPageSize
} }
if feed.PlaylistSort == "" {
feed.PlaylistSort = model.SortingAsc
}
} }
} }

View File

@@ -40,6 +40,7 @@ timeout = 15
format = "audio" format = "audio"
quality = "low" quality = "low"
filters = { title = "regex for title here" } filters = { title = "regex for title here" }
playlist_sort = "desc"
clean = { keep_last = 10 } clean = { keep_last = 10 }
[feeds.XYZ.custom] [feeds.XYZ.custom]
cover_art = "http://img" cover_art = "http://img"
@@ -80,6 +81,7 @@ timeout = 15
assert.EqualValues(t, "low", feed.Quality) assert.EqualValues(t, "low", feed.Quality)
assert.EqualValues(t, "regex for title here", feed.Filters.Title) assert.EqualValues(t, "regex for title here", feed.Filters.Title)
assert.EqualValues(t, 10, feed.Clean.KeepLast) assert.EqualValues(t, 10, feed.Clean.KeepLast)
assert.EqualValues(t, model.SortingDesc, feed.PlaylistSort)
assert.EqualValues(t, "http://img", feed.Custom.CoverArt) assert.EqualValues(t, "http://img", feed.Custom.CoverArt)
assert.EqualValues(t, "high", feed.Custom.CoverArtQuality) assert.EqualValues(t, "high", feed.Custom.CoverArtQuality)

View File

@@ -20,6 +20,14 @@ const (
FormatVideo = Format("video") FormatVideo = Format("video")
) )
// Playlist sorting style
type Sorting string
const (
SortingDesc = Sorting("desc")
SortingAsc = Sorting("asc")
)
type Episode struct { type Episode struct {
// ID of episode // ID of episode
ID string `json:"id"` ID string `json:"id"`
@@ -54,6 +62,7 @@ type Feed struct {
ItemURL string `json:"item_url"` // Platform specific URL ItemURL string `json:"item_url"` // Platform specific URL
Episodes []*Episode `json:"-"` // Array of episodes Episodes []*Episode `json:"-"` // Array of episodes
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
PlaylistSort Sorting `json:"playlist_sort"`
} }
type EpisodeStatus string type EpisodeStatus string