feeder/cmd/add.go

214 lines
5.3 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/arenzana/id3v2"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
colgate "github.com/tcolgate/mp3"
"gitlab.com/iarenzana/feeder/objects"
)
var mp3File string
// addCmd represents the add command
var addCmd = &cobra.Command{
Use: "add",
Short: "Add an mp3 to the episodes JSON file",
Long: `Add reads an mp3 ID3 tags `,
Run: func(cmd *cobra.Command, args []string) {
pubTime := time.Now()
var s *session.Session
//Read MP3 file
sourceStat, err := os.Stat(mp3File)
if os.IsExist(err) {
if !sourceStat.Mode().IsRegular() {
log.WithFields(log.Fields{"payload": mp3File}).Error("Not a regular file")
os.Exit(-1)
}
}
source, err := id3v2.ScanFile(mp3File)
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error opening MP3 file")
os.Exit(-1)
}
//Get Current episodes
scannedComments := source.Lookup(id3v2.FrameCOMM)
scannedTitle := source.Lookup(id3v2.FrameTIT2)
if scannedTitle == nil {
log.WithFields(log.Fields{"payload": err}).Error("Error reading file ID3 tags")
os.Exit(-1)
}
summary, err := scannedComments.Text()
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error reading file comments")
os.Exit(-1)
}
formattedTitle, err := scannedTitle.Text()
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error reading title")
os.Exit(-1)
}
durationInSeconds, err := getMP3DurationInSeconds(mp3File)
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error parsing MP3 file")
os.Exit(-1)
}
uuidWithHyphen := uuid.New()
newEpisode := objects.Episode{
Title: formattedTitle,
Summary: summary,
PubDate: pubTime.Format(layout),
Bytes: sourceStat.Size(),
Duration: fmt.Sprintf("%v", durationInSeconds),
GUID: strings.Replace(uuidWithHyphen.String(), "-", "", -1),
}
if verbose {
log.WithFields(log.Fields{"payload": fmt.Sprintf("%+v", newEpisode)}).Info("Got good episode")
}
episodesInJSON, err := getPodcastEpisodesFromJSON(GlobalCfg.Items)
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error getting episodes from JSON")
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)
}
file := filepath.Base(mp3File)
mp3URL, err := uploadFile(s, mp3File, fmt.Sprintf("episodes/%v", file))
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error uploading to S3")
os.Exit(-1)
}
if verbose {
log.WithFields(log.Fields{"payload": mp3URL}).Info("MP3 successfully uploaded to S3")
}
newEpisode.FileURL = mp3URL
}
//Prepend Element to the list
var newEpisodesInJSON []objects.Episode
var newEpisodeNumber int
newEpisodesInJSON = append(newEpisodesInJSON, newEpisode)
for _, existingEpisode := range episodesInJSON.Episodes {
if existingEpisode.Episode > newEpisodeNumber {
newEpisodeNumber = existingEpisode.Episode
}
newEpisodesInJSON = append(newEpisodesInJSON, existingEpisode)
}
newEpisodesInJSON[0].Link = fmt.Sprintf("%v/podcast/%v.html", GlobalCfg.Link, newEpisodeNumber+1)
newEpisodesInJSON[0].Episode = newEpisodeNumber + 1
newEpisodesInJSON[0].Title = fmt.Sprintf("%v: %v", newEpisodeNumber+1, formattedTitle)
episodesInJSON.Episodes = newEpisodesInJSON
//Save Episode to file
outputJSON, _ := json.MarshalIndent(episodesInJSON, "", " ")
err = backupFile(GlobalCfg.Items)
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error backing up current JSON file")
os.Exit(-1)
}
saveStringToFile(string(outputJSON), GlobalCfg.Items)
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error saving RSS file. Backup still in place")
os.Exit(-1)
}
//Generate Web
if renderWeb {
err = renderEpisodeHTML(GlobalCfg, newEpisodesInJSON[0])
if err != nil {
log.WithFields(log.Fields{"payload": err}).Error("Error rendering HTML.")
os.Exit(-1)
}
if upload {
episodeURL, err := uploadFile(s, fmt.Sprintf("%v.html", newEpisodeNumber+1), fmt.Sprintf("podcast/%v.html", newEpisodeNumber+1))
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": episodeURL}).Info("HTML successfully uploaded to S3")
}
}
}
},
}
func init() {
rootCmd.AddCommand(addCmd)
addCmd.Flags().StringVarP(&mp3File, "mp3", "f", "", "Path to MP3 file")
}
func saveStringToFile(rss string, file string) error {
out, err := os.Create(file)
if err != nil {
return err
}
defer out.Close()
_, err = io.WriteString(out, rss)
if err != nil {
return err
}
return out.Sync()
}
func getMP3DurationInSeconds(file string) (int64, error) {
f, err := os.Open(file)
if err != nil {
return 0, err
}
skipped := 0
d := colgate.NewDecoder(f)
var frames int64
var fr colgate.Frame
for {
if err := d.Decode(&fr, &skipped); err != nil {
break
}
frames = frames + 1
}
sampleRate := int64(fr.Header().SampleRate())
duration := frames * int64(fr.Samples()) / sampleRate
return duration, nil
}