Skip to content

Commit

Permalink
add initial publisher utils #1
Browse files Browse the repository at this point in the history
  • Loading branch information
umputun committed Nov 18, 2018
1 parent 73e6a26 commit ad3b985
Show file tree
Hide file tree
Showing 90 changed files with 20,714 additions and 0 deletions.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/__init__.pyc
Binary file not shown.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/binfuncs.pyc
Binary file not shown.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/frames.pyc
Binary file not shown.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/mp3.pyc
Binary file not shown.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/tag.pyc
Binary file not shown.
File renamed without changes.
Binary file added publisher/utils.old/eyeD3/utils.pyc
Binary file not shown.
File renamed without changes.
File renamed without changes.
196 changes: 196 additions & 0 deletions publisher/utils/cmd/mp3tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package cmd

import (
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strconv"
"strings"
"time"

id3 "github.com/jcs/id3-go"
id3v2 "github.com/jcs/id3-go/v2"
"github.com/pkg/errors"
)

// Mp3TagsCommand with command line flags and env
type Mp3TagsCommand struct {
ShowNumber int `short:"s" long:"show" description:"show number"`
File string `short:"f" long:"file" description:"file name"`
Chapters []string `short:"c" long:"chap" description:"sec::label"`
BitRate int `short:"b" long:"bitrate" default:"80" description:"bitrate"`
HugoLocation string `long:"hugo" default:"../../hugo" description:"location of hugo"`
}

type chapter struct {
element string
startSecs uint32
endSecs uint32
title string
}

var (
reShowMdFile = regexp.MustCompile(`.*rt_podcast([0-9]*)\.mp3`)
reChap = regexp.MustCompile(`^- \[(.*)\]\(.*\) - \*(.*)\*`)
)

// Execute is the entry point for "mp3tags" command, called by flag parser
func (c *Mp3TagsCommand) Execute(args []string) error {
log.Printf("mp3tags started, %+v", c)

if c.File == "" && c.ShowNumber == 0 {
log.Fatalf("file or show number should be defined")
}

fileName := c.File
if fileName == "" {
fileName = fmt.Sprintf("rt_podcast%d", c.ShowNumber)
}

showNum := c.ShowNumber
if showNum == 0 {
parts := reShowMdFile.FindStringSubmatch(fileName)
if len(parts) != 2 {
log.Fatalf("can't extract show number from %s", fileName)
}
var err error
if showNum, err = strconv.Atoi(parts[1]); err != nil {
log.Fatalf("can't extract show number from %s, %s", fileName, err)
}
}

log.Printf("processing %s (%d)", fileName, showNum)
chaps, err := c.addChapters(fileName, showNum)
if err != nil {
log.Fatalf("failed to add chapters, %v", err)
}

log.Printf("mp3-chaps completed, %d chapters", len(chaps))

return nil
}

// based on https://github.com/jcs/mp3chap
func (c *Mp3TagsCommand) addChapters(fileName string, showNum int) ([]chapter, error) {
mp3, err := id3.Open(fileName)
if err != nil {
return nil, errors.Wrapf(err, "can't open %s", fileName)
}

chaps := []chapter{}
tocChaps := []string{}

chaps, tocChaps, err = c.mp3chaps(showNum)
if err != nil {
log.Printf("can't get chapters from md file for %d", showNum)
chaps, tocChaps, err = c.manualMp3Chaps()
if err != nil {
return nil, errors.Wrap(err, "can't get chapters from command line")
}
}

// each chapter ends where the next one starts
for x := range chaps {
if x < len(chaps)-1 {
chaps[x].endSecs = chaps[x+1].startSecs
}
}

finalEnd, err := c.mp3len(fileName, mp3, c.BitRate)
if err != nil {
return nil, errors.Wrap(err, "can't get finalEnd")
}
chaps[len(chaps)-1].endSecs = uint32(finalEnd * 1000)

// ready to modify the file, clear out what's there
mp3.DeleteFrames("CTOC")
mp3.DeleteFrames("CHAP")

// build a new TOC referencing each chapter
ctocft := id3v2.V23FrameTypeMap["CTOC"]
toc := id3v2.NewTOCFrame(ctocft, "toc", true, true, tocChaps)
mp3.AddFrames(toc)

// add each chapter
chapft := id3v2.V23FrameTypeMap["CHAP"]
for _, c := range chaps {
ch := id3v2.NewChapterFrame(chapft, c.element, c.startSecs, c.endSecs, 0, 0, true, c.title, "", "")
mp3.AddFrames(ch)
}

mp3.Close()
return chaps, nil
}

func (c *Mp3TagsCommand) mp3len(file string, mp3 *id3.File, bitrate int) (int, error) {

if tlenf := mp3.Frame("TLEN"); tlenf != nil {
if tlenft, ok := tlenf.(*id3v2.TextFrame); ok {
if tlen, err := strconv.Atoi(tlenft.Text()); err != nil {
return tlen, nil
}
}
}

info, err := os.Stat(file)
if err != nil {
return 0, err
}

return int(info.Size()) * 8 / bitrate, nil
}

func (c *Mp3TagsCommand) mp3chaps(showNumber int) (chaps []chapter, tocChaps []string, err error) {
mdFile := fmt.Sprintf("%s/content/posts/podcast-%d.md", c.HugoLocation, showNumber)
mdData, err := ioutil.ReadFile(mdFile)
if err != nil {
return nil, nil, err
}
lines := strings.Split(string(mdData), "\n")
for _, line := range lines {

parts := reChap.FindStringSubmatch(line)
if len(parts) != 3 {
continue
}
ts, err := time.ParseInLocation("03:04:05", parts[2], time.UTC)
if err != nil {
return nil, nil, err
}
element := fmt.Sprintf("chp%d", len(chaps))
st := ts.Sub(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC))
title := string(parts[1])
ch := chapter{title: title, startSecs: uint32(st.Seconds() * 1000), element: element}
log.Printf("chapter %d - %v", len(chaps), ch)
chaps = append(chaps, ch)
tocChaps = append(tocChaps, element)
}
return chaps, tocChaps, err
}

func (c *Mp3TagsCommand) manualMp3Chaps() (chaps []chapter, tocChaps []string, err error) {

for _, c := range c.Chapters {
elems := strings.Split(c, "::")
if len(elems) != 2 {
log.Fatal("incorrect chapter fromat, expecting sss::label (123:some text here)")
}
st, err := strconv.Atoi(elems[0])
if err != nil {
return nil, nil, errors.Wrapf(err, "incorrect time fromat for %s", elems[0])
}
element := fmt.Sprintf("chp%d", len(chaps))
tocChaps = append(tocChaps, element)

chap := chapter{
element: element,
startSecs: uint32(st * 1000),
endSecs: 0,
title: elems[1],
}
chaps = append(chaps, chap)
}
return chaps, tocChaps, nil
}
1 change: 1 addition & 0 deletions publisher/utils/cmd/mp3tags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package cmd
8 changes: 8 additions & 0 deletions publisher/utils/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/radio-t/utils

require (
github.com/jcs/id3-go v0.0.0-20170531013608-1c3fc9101a81
github.com/jessevdk/go-flags v1.4.0
github.com/pkg/errors v0.8.0
golang.org/x/text v0.3.0 // indirect
)
8 changes: 8 additions & 0 deletions publisher/utils/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/jcs/id3-go v0.0.0-20170531013608-1c3fc9101a81 h1:fXgMFt2wcMe/+XOB7wzvo7qEcZLZoD3ORYePoDExkfE=
github.com/jcs/id3-go v0.0.0-20170531013608-1c3fc9101a81/go.mod h1:axMqcScJoVi4eS4uMZltJK5cuJtKxfgZBH4sWhD/i7M=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
27 changes: 27 additions & 0 deletions publisher/utils/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"log"
"os"

flags "github.com/jessevdk/go-flags"

"github.com/radio-t/utils/cmd"
)

var opts struct {
Mp3Tags cmd.Mp3TagsCommand `command:"mp3tags"`
}

func main() {
log.Printf("rt-utils, %+v", opts)

p := flags.NewParser(&opts, flags.Default)
if _, err := p.Parse(); err != nil {
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
os.Exit(0)
} else {
os.Exit(1)
}
}
}
8 changes: 8 additions & 0 deletions publisher/utils/vendor/github.com/jcs/id3-go/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions publisher/utils/vendor/github.com/jcs/id3-go/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions publisher/utils/vendor/github.com/jcs/id3-go/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Loading

0 comments on commit ad3b985

Please sign in to comment.