You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.0 KiB
146 lines
4.0 KiB
package podcast |
|
|
|
import ( |
|
"encoding/xml" |
|
"fmt" |
|
"time" |
|
"unicode/utf8" |
|
) |
|
|
|
// Item represents a single entry in a podcast. |
|
// |
|
// Article minimal requirements are: |
|
// - Title |
|
// - Description |
|
// - Link |
|
// |
|
// Audio minimal requirements are: |
|
// - Title |
|
// - Description |
|
// - Enclosure (HREF, Type and Length all required) |
|
// - IEpisode (iTunes episode number) |
|
// |
|
// Recommendations: |
|
// - Setting the minimal fields sets most of other fields, including iTunes. |
|
// - Use the Published time.Time setting instead of PubDate. |
|
// - Always set an Enclosure.Length, to be nice to your downloaders. |
|
// - Use Enclosure.Type instead of setting TypeFormatted for valid extensions. |
|
type Item struct { |
|
XMLName xml.Name `xml:"item"` |
|
GUID string `xml:"guid"` |
|
Title string `xml:"title"` |
|
Link string `xml:"link"` |
|
Description string `xml:"description"` |
|
Author *Author `xml:"-"` |
|
AuthorFormatted string `xml:"author,omitempty"` |
|
Category string `xml:"category,omitempty"` |
|
Comments string `xml:"comments,omitempty"` |
|
Source string `xml:"source,omitempty"` |
|
PubDate *time.Time `xml:"-"` |
|
PubDateFormatted string `xml:"pubDate,omitempty"` |
|
Enclosure *Enclosure |
|
|
|
// https://help.apple.com/itc/podcasts_connect/#/itcb54353390 |
|
IAuthor string `xml:"itunes:author,omitempty"` |
|
IEpisode int `xml:"itunes:episode"` |
|
ISubtitle string `xml:"itunes:subtitle,omitempty"` |
|
ISummary *ISummary |
|
IImage *IImage |
|
IDuration string `xml:"itunes:duration,omitempty"` |
|
IExplicit string `xml:"itunes:explicit,omitempty"` |
|
IIsClosedCaptioned string `xml:"itunes:isClosedCaptioned,omitempty"` |
|
IOrder string `xml:"itunes:order,omitempty"` |
|
} |
|
|
|
// AddEnclosure adds the downloadable asset to the podcast Item. |
|
func (i *Item) AddEnclosure( |
|
url string, enclosureType EnclosureType, lengthInBytes int64) { |
|
i.Enclosure = &Enclosure{ |
|
URL: url, |
|
Type: enclosureType, |
|
Length: lengthInBytes, |
|
} |
|
} |
|
|
|
// AddImage adds the image as an iTunes-only IImage. RSS 2.0 does not have |
|
// the specification of Images at the Item level. |
|
// |
|
// Podcast feeds contain artwork that is a minimum size of |
|
// 1400 x 1400 pixels and a maximum size of 3000 x 3000 pixels, |
|
// 72 dpi, in JPEG or PNG format with appropriate file |
|
// extensions (.jpg, .png), and in the RGB colorspace. To optimize |
|
// images for mobile devices, Apple recommends compressing your |
|
// image files. |
|
func (i *Item) AddImage(url string) { |
|
if len(url) > 0 { |
|
i.IImage = &IImage{HREF: url} |
|
} |
|
} |
|
|
|
// AddPubDate adds the datetime as a parsed PubDate. |
|
// |
|
// UTC time is used by default. |
|
func (i *Item) AddPubDate(datetime *time.Time) { |
|
i.PubDate = datetime |
|
i.PubDateFormatted = parseDateRFC1123Z(i.PubDate) |
|
} |
|
|
|
// AddSummary adds the iTunes summary. |
|
// |
|
// Limit: 4000 characters |
|
// |
|
// Note that this field is a CDATA encoded field which allows for rich text |
|
// such as html links: `<a href="http://www.apple.com">Apple</a>`. |
|
func (i *Item) AddSummary(summary string) { |
|
count := utf8.RuneCountInString(summary) |
|
if count > 4000 { |
|
s := []rune(summary) |
|
summary = string(s[0:4000]) |
|
} |
|
i.ISummary = &ISummary{ |
|
Text: summary, |
|
} |
|
} |
|
|
|
// AddDuration adds the duration to the iTunes duration field. |
|
func (i *Item) AddDuration(durationInSeconds int64) { |
|
if durationInSeconds <= 0 { |
|
return |
|
} |
|
i.IDuration = parseDuration(durationInSeconds) |
|
} |
|
|
|
var parseDuration = func(duration int64) string { |
|
h := duration / 3600 |
|
duration = duration % 3600 |
|
|
|
m := duration / 60 |
|
duration = duration % 60 |
|
|
|
s := duration |
|
|
|
// HH:MM:SS |
|
if h > 9 { |
|
return fmt.Sprintf("%02d:%02d:%02d", h, m, s) |
|
} |
|
|
|
// H:MM:SS |
|
if h > 0 { |
|
return fmt.Sprintf("%d:%02d:%02d", h, m, s) |
|
} |
|
|
|
// MM:SS |
|
if m > 9 { |
|
return fmt.Sprintf("%02d:%02d", m, s) |
|
} |
|
|
|
// M:SS |
|
return fmt.Sprintf("%d:%02d", m, s) |
|
} |
|
|
|
var parseDateRFC1123Z = func(t *time.Time) string { |
|
if t != nil && !t.IsZero() { |
|
return t.Format(time.RFC1123Z) |
|
} |
|
return time.Now().UTC().Format(time.RFC1123Z) |
|
}
|
|
|