Files

199 lines
4.1 KiB
Go
Raw Permalink Normal View History

2020-03-07 17:25:55 -08:00
package feed
import (
"context"
"fmt"
"sort"
2020-03-07 17:25:55 -08:00
"strconv"
2022-01-02 13:17:28 +02:00
"strings"
2020-03-07 17:25:55 -08:00
"time"
itunes "github.com/eduncan911/podcast"
"github.com/pkg/errors"
"github.com/mxpv/podsync/pkg/model"
)
// sort.Interface implementation
type timeSlice []*model.Episode
func (p timeSlice) Len() int {
return len(p)
}
// In descending order
func (p timeSlice) Less(i, j int) bool {
return p[i].PubDate.After(p[j].PubDate)
}
func (p timeSlice) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
2022-01-02 14:57:10 +02:00
func Build(_ctx context.Context, feed *model.Feed, cfg *Config, hostname string) (*itunes.Podcast, error) {
2020-03-07 17:25:55 -08:00
const (
podsyncGenerator = "Podsync generator (support us at https://github.com/mxpv/podsync)"
defaultCategory = "TV & Film"
)
2020-03-07 22:32:51 -08:00
var (
now = time.Now().UTC()
author = feed.Title
title = feed.Title
description = feed.Description
2022-06-24 00:21:28 +02:00
feedLink = feed.ItemURL
2020-03-07 22:32:51 -08:00
)
2020-03-07 17:25:55 -08:00
if cfg.Custom.Author != "" {
author = cfg.Custom.Author
}
if cfg.Custom.Title != "" {
title = cfg.Custom.Title
}
if cfg.Custom.Description != "" {
description = cfg.Custom.Description
}
2022-06-24 00:21:28 +02:00
if cfg.Custom.Link != "" {
feedLink = cfg.Custom.Link
}
p := itunes.New(title, feedLink, description, &feed.PubDate, &now)
2020-03-07 17:25:55 -08:00
p.Generator = podsyncGenerator
p.AddSubTitle(title)
p.IAuthor = author
p.AddSummary(description)
2020-03-07 17:25:55 -08:00
2022-04-02 10:34:33 +02:00
if feed.PrivateFeed {
2022-04-02 10:28:22 +02:00
p.IBlock = "yes"
}
if cfg.Custom.OwnerName != "" && cfg.Custom.OwnerEmail != "" {
p.IOwner = &itunes.Author{
Name: cfg.Custom.OwnerName,
Email: cfg.Custom.OwnerEmail,
}
}
2020-03-07 22:32:51 -08:00
if cfg.Custom.CoverArt != "" {
p.AddImage(cfg.Custom.CoverArt)
} else {
p.AddImage(feed.CoverArt)
}
if cfg.Custom.Category != "" {
2020-10-04 14:00:51 -07:00
p.AddCategory(cfg.Custom.Category, cfg.Custom.Subcategories)
2020-03-07 22:32:51 -08:00
} else {
2020-10-04 14:00:51 -07:00
p.AddCategory(defaultCategory, cfg.Custom.Subcategories)
2020-03-07 22:32:51 -08:00
}
if cfg.Custom.Explicit {
2020-03-07 17:25:55 -08:00
p.IExplicit = "yes"
} else {
p.IExplicit = "no"
}
2020-03-07 22:32:51 -08:00
if cfg.Custom.Language != "" {
p.Language = cfg.Custom.Language
2020-03-07 17:25:55 -08:00
}
for _, episode := range feed.Episodes {
if episode.PubDate.IsZero() {
episode.PubDate = now
}
}
// Sort all episodes in descending order
sort.Sort(timeSlice(feed.Episodes))
2020-03-07 17:25:55 -08:00
for i, episode := range feed.Episodes {
if episode.Status != model.EpisodeDownloaded {
// Skip episodes that are not yet downloaded or have been removed
2020-03-07 17:25:55 -08:00
continue
}
item := itunes.Item{
GUID: episode.ID,
Link: episode.VideoURL,
Title: episode.Title,
Description: episode.Description,
ISubtitle: episode.Title,
// Some app prefer 1-based order
IOrder: strconv.Itoa(i + 1),
2020-03-07 17:25:55 -08:00
}
item.AddPubDate(&episode.PubDate)
2020-03-07 17:25:55 -08:00
item.AddSummary(episode.Description)
item.AddImage(episode.Thumbnail)
item.AddDuration(episode.Duration)
enclosureType := itunes.MP4
if feed.Format == model.FormatAudio {
2020-04-05 13:09:40 +02:00
enclosureType = itunes.MP3
2020-03-07 17:25:55 -08:00
}
if feed.Format == model.FormatCustom {
enclosureType = EnclosureFromExtension(cfg)
}
2022-01-02 13:17:28 +02:00
var (
episodeName = EpisodeName(cfg, episode)
downloadURL = fmt.Sprintf("%s/%s/%s", strings.TrimRight(hostname, "/"), cfg.ID, episodeName)
)
2020-03-07 17:25:55 -08:00
item.AddEnclosure(downloadURL, enclosureType, episode.Size)
// p.AddItem requires description to be not empty, use workaround
if item.Description == "" {
item.Description = " "
}
2020-03-07 22:32:51 -08:00
if cfg.Custom.Explicit {
2020-03-07 17:25:55 -08:00
item.IExplicit = "yes"
} else {
item.IExplicit = "no"
}
if _, err := p.AddItem(item); err != nil {
return nil, errors.Wrapf(err, "failed to add item to podcast (id %q)", episode.ID)
}
}
return &p, nil
}
2022-01-02 14:57:10 +02:00
func EpisodeName(feedConfig *Config, episode *model.Episode) string {
2020-03-07 17:25:55 -08:00
ext := "mp4"
if feedConfig.Format == model.FormatAudio {
ext = "mp3"
}
if feedConfig.Format == model.FormatCustom {
2022-10-29 02:22:45 +02:00
ext = feedConfig.CustomFormat.Extension
2020-03-07 17:25:55 -08:00
}
return fmt.Sprintf("%s.%s", episode.ID, ext)
}
func EnclosureFromExtension(feedConfig *Config) itunes.EnclosureType {
ext := feedConfig.CustomFormat.Extension
switch {
case ext == "m4a":
return itunes.M4A
case ext == "m4v":
return itunes.M4V
case ext == "mp4":
return itunes.MP4
case ext == "mp3":
return itunes.MP3
case ext == "mov":
return itunes.MOV
case ext == "pdf":
return itunes.PDF
case ext == "epub":
return itunes.EPUB
}
return -1
}