215 lines
5.4 KiB
Go
215 lines
5.4 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")
|
|
}
|
|
os.Exit(-1)
|
|
|
|
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
|
|
}
|