Skip to content

Instantly share code, notes, and snippets.

@geberl
Last active November 2, 2019 21:20
Show Gist options
  • Save geberl/da3f54a86811e22bce098a5ca10d8230 to your computer and use it in GitHub Desktop.
Save geberl/da3f54a86811e22bce098a5ca10d8230 to your computer and use it in GitHub Desktop.
Get metadata and stream info from a flac audio file
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/mewkiz/flac"
"github.com/mewkiz/flac/meta"
)
// go run get_flac_info.go "/home/guenther/Downloads/[2010] Odd Blood/04 - i remember.flac"
// go run get_flac_info.go "/home/guenther/Downloads/05 - holiday in cambodia (live).flac"
var typeName = map[meta.Type]string{
meta.TypeVorbisComment: "VORBIS_COMMENT",
}
func main() {
flag.Parse()
if flag.NArg() < 1 {
fmt.Fprintln(os.Stderr, "Exiting, no path(s) supplied")
os.Exit(1)
}
for _, path := range flag.Args() {
err := list(path)
if err != nil {
log.Fatalln(err)
}
}
}
func list(path string) error {
// Open FLAC stream.
stream, err := flac.ParseFile(path)
if err != nil {
return err
}
// Get general file info
// File owner and file creation date are non-cross-platform (but possible)
// https://stackoverflow.com/questions/20875336/how-can-i-get-a-files-ctime-atime-mtime-and-change-them-using-golang
fi, err := os.Stat(path)
if err != nil {
return err
}
listStreamInfo(stream.Info, fi)
fmt.Printf("---\n")
listComments(stream.Blocks)
return nil
}
// listComments prints selected metadata tags present in the flac file
func listComments(bs []*meta.Block) {
vc := getVorbisComment(bs, false)
fmt.Printf("album : %s\n", getTag("ALBUM", vc))
fmt.Printf("album artist : %s\n", getTag("ALBUMARTIST", vc))
fmt.Printf("artist : %s\n", getTag("ARTIST", vc))
fmt.Printf("date : %s\n", getTag("DATE", vc))
fmt.Printf("discnumber : %s\n", getTag("DISCNUMBER", vc))
fmt.Printf("disctotal : %s\n", getTag("DISCTOTAL", vc))
fmt.Printf("genre : %s\n", getTag("GENRE", vc))
fmt.Printf("title : %s\n", getTag("TITLE", vc))
fmt.Printf("tracknumber : %s\n", getTag("TRACKNUMBER", vc))
fmt.Printf("totaltracks : %s\n", getTag("TOTALTRACKS", vc))
}
// getVorbisComment iterates through all the blocks, and returns the one containing the vorbis comment
func getVorbisComment(bs []*meta.Block, print bool) *meta.VorbisComment {
for _, block := range bs {
switch body := block.Body.(type) {
case *meta.VorbisComment:
if print {
for _, tag := range body.Tags {
fmt.Printf(" %s=%s\n", tag[0], tag[1])
}
}
return body
}
}
return nil
}
// getTag iterates through all the tags in a vorbis comment, and returns the specified one
func getTag(t string, vc *meta.VorbisComment) string {
for _, tag := range vc.Tags {
if tag[0] == t {
return tag[1]
}
}
return ""
}
// listStreamInfo prints technical info about the flac file
func listStreamInfo(si *meta.StreamInfo, fi os.FileInfo) {
fileSize := fi.Size()
runTime := si.NSamples / uint64(si.SampleRate)
bitRate := fileSize / 125 / int64(runTime)
fmt.Printf("file size : %d bytes\n", fileSize)
fmt.Printf("file name : %s\n", fi.Name())
fmt.Printf("file mode : %s\n", fi.Mode())
fmt.Printf("file mod time : %s\n", fi.ModTime())
fmt.Printf("run time : %d seconds\n", runTime)
fmt.Printf("bit rate : %d kbps\n", bitRate)
fmt.Printf("min blocksize : %d samples\n", si.BlockSizeMin)
fmt.Printf("max blocksize : %d samples\n", si.BlockSizeMax)
fmt.Printf("min framesize : %d bytes\n", si.FrameSizeMin)
fmt.Printf("max framesize : %d bytes\n", si.FrameSizeMax)
fmt.Printf("sample rate : %d Hz\n", si.SampleRate)
fmt.Printf("channels : %d\n", si.NChannels)
fmt.Printf("bits per sample : %d\n", si.BitsPerSample)
fmt.Printf("total samples : %d\n", si.NSamples)
fmt.Printf("MD5 : %x\n", si.MD5sum)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment