274 lines
6.1 KiB
Go
274 lines
6.1 KiB
Go
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/arenzana/podcast"
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
"gitlab.com/iarenzana/feeder/objects"
|
|
)
|
|
|
|
var layout = "2006-01-02T15:04:05 MST"
|
|
|
|
// generateCmd represents the generate command
|
|
var generateCmd = &cobra.Command{
|
|
Use: "generate",
|
|
Short: "Generate an RSS feed",
|
|
Long: `Generate an RSS feed out of JSON episode and the settings`,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
lastBuildTime := time.Now()
|
|
pubTime := time.Now()
|
|
var s *session.Session
|
|
|
|
log.SetFormatter(&log.TextFormatter{
|
|
DisableColors: false,
|
|
FullTimestamp: true,
|
|
})
|
|
log.SetOutput(os.Stdout)
|
|
|
|
//Create podcast
|
|
// instantiate a new Podcast
|
|
p := podcast.New(
|
|
GlobalCfg.Title,
|
|
GlobalCfg.Link,
|
|
GlobalCfg.Description,
|
|
&pubTime, &lastBuildTime,
|
|
)
|
|
|
|
p.ISubtitle = GlobalCfg.Description
|
|
p.AddSummary(GlobalCfg.Description)
|
|
p.AddImage(GlobalCfg.Image)
|
|
p.IAuthor = GlobalCfg.Author
|
|
p.AddAuthor(GlobalCfg.Author, GlobalCfg.OwnerEmail)
|
|
p.IExplicit = GlobalCfg.IsExplicit
|
|
p.Language = "es"
|
|
p.INewFeedURL = GlobalCfg.RSSURL
|
|
p.Copyright = GlobalCfg.Copyright
|
|
p.IOwner = &podcast.Author{
|
|
Email: GlobalCfg.OwnerEmail,
|
|
Name: GlobalCfg.Author,
|
|
}
|
|
p.AddAtomLink(GlobalCfg.RSSURL)
|
|
for _, category := range GlobalCfg.Categories {
|
|
p.AddCategory(category, nil)
|
|
}
|
|
//Gather podcast items
|
|
|
|
episodesInJSON, err := getPodcastEpisodesFromJSON(GlobalCfg.Items)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error getting episodes from JSON")
|
|
os.Exit(-1)
|
|
|
|
}
|
|
podcastEpisodes, err := getPodcastEpisodesFromItem(episodesInJSON)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error getting episodes from config")
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
for _, episode := range podcastEpisodes {
|
|
if _, err := p.AddItem(episode); err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Item validation error")
|
|
os.Exit(-1)
|
|
}
|
|
}
|
|
|
|
if verbose {
|
|
if err := p.Encode(os.Stdout); err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error displaying RSS")
|
|
os.Exit(-1)
|
|
}
|
|
}
|
|
|
|
//Save RSS to file
|
|
|
|
err = backupFile(GlobalCfg.RSSOut)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error backing up current RSS feed")
|
|
os.Exit(-1)
|
|
}
|
|
|
|
saveToFile(p, GlobalCfg.RSSOut)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error saving RSS file. Backup still in place")
|
|
os.Exit(-1)
|
|
}
|
|
|
|
//Upload file if desired
|
|
if upload {
|
|
s, err = createS3Session()
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error establishing S3 session")
|
|
os.Exit(-1)
|
|
}
|
|
|
|
rssFileName := filepath.Base(GlobalCfg.RSSOut)
|
|
|
|
rssURL, err := uploadFile(s, GlobalCfg.RSSOut, rssFileName)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error uploading to S3")
|
|
os.Exit(-1)
|
|
}
|
|
if verbose {
|
|
log.WithFields(log.Fields{"payload": rssURL}).Info("RSS Feed successfully uploaded to S3")
|
|
}
|
|
}
|
|
|
|
//Generate and upload Index file
|
|
if renderWeb {
|
|
err = renderIndexHTML(GlobalCfg, episodesInJSON)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error rendering HTML.")
|
|
os.Exit(-1)
|
|
}
|
|
if upload {
|
|
indexURL, err := uploadFile(s, "index.html", "index.html")
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"payload": err}).Error("Error uploading HTML to S3")
|
|
os.Exit(-1)
|
|
}
|
|
|
|
if verbose {
|
|
log.WithFields(log.Fields{"payload": indexURL}).Info("HTML successfully uploaded to S3")
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(generateCmd)
|
|
}
|
|
|
|
func backupFile(file string) error {
|
|
layout := "02150405"
|
|
backupFile := fmt.Sprintf("%v.%v", file, time.Now().Format(layout))
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
source, err := os.Open(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer source.Close()
|
|
|
|
destination, err := os.Create(backupFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer destination.Close()
|
|
|
|
_, err = io.Copy(destination, source)
|
|
if err != nil {
|
|
return fmt.Errorf("Error generating backup file - %v", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func saveToFile(rss podcast.Podcast, file string) error {
|
|
out, err := os.Create(file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer out.Close()
|
|
|
|
if err := rss.Encode(out); err != nil {
|
|
return err
|
|
}
|
|
|
|
return out.Sync()
|
|
}
|
|
|
|
func getPodcastEpisodesFromJSON(file string) (objects.Items, error) {
|
|
var items objects.Items
|
|
|
|
jsonFile, err := os.Open(file)
|
|
if err != nil {
|
|
return items, fmt.Errorf("Error opening episodes JSON file - %v", err)
|
|
}
|
|
|
|
if verbose {
|
|
log.WithFields(log.Fields{"payload": ""}).Info("Opened episodes JSON file")
|
|
}
|
|
|
|
defer jsonFile.Close()
|
|
|
|
byteValue, err := ioutil.ReadAll(jsonFile)
|
|
if err != nil {
|
|
return items, err
|
|
}
|
|
|
|
json.Unmarshal(byteValue, &items)
|
|
if len(items.Episodes) < 1 {
|
|
return items, fmt.Errorf("No episodes found")
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
func getPodcastEpisodesFromItem(items objects.Items) ([]podcast.Item, error) {
|
|
var outputEpisodes []podcast.Item
|
|
|
|
for _, episode := range items.Episodes {
|
|
item, err := createItem(episode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
outputEpisodes = append(outputEpisodes, item)
|
|
}
|
|
|
|
return outputEpisodes, nil
|
|
}
|
|
|
|
func createItem(episode objects.Episode) (podcast.Item, error) {
|
|
pubdate, err := time.Parse(layout, episode.PubDate)
|
|
if err != nil {
|
|
return podcast.Item{}, err
|
|
}
|
|
|
|
item := podcast.Item{
|
|
Title: episode.Title,
|
|
Description: episode.Description,
|
|
ISubtitle: episode.Subtitle,
|
|
PubDate: &pubdate,
|
|
}
|
|
item.IEpisode = episode.Episode
|
|
if len(episode.GUID) != 0 {
|
|
item.GUID = episode.GUID
|
|
}
|
|
item.AddImage(GlobalCfg.Image)
|
|
item.AddSummary(episode.Summary)
|
|
if strings.Contains(episode.Duration, ":") {
|
|
item.IDuration = episode.Duration
|
|
} else {
|
|
i, err := strconv.ParseInt(episode.Duration, 10, 64)
|
|
if err != nil {
|
|
return podcast.Item{}, err
|
|
}
|
|
|
|
item.AddDuration(i)
|
|
|
|
}
|
|
|
|
item.AddEnclosure(episode.FileURL, podcast.MP3, episode.Bytes)
|
|
|
|
return item, nil
|
|
}
|