Giter Site home page Giter Site logo

id3-go's People

Contributors

gerow avatar jrwren avatar mikkyang avatar viking avatar xhenner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

id3-go's Issues

Tagger.SetComments()

I noticed this functionality doesn't exist. Is this something you'd be interested in?

Thanks.

bug: tagging not idempotent (panic)

First of: thanks for an excellently designed library, the code looks very clean.

Now for the bug report: on some files, trying to Open/Close a file multiple times (without even changing the tags) causes a panic after a few tries (3 in this case, I believe).

One can reproduce like this:

  1. Fetch the "retag" branch of my sndcld project: https://github.com/aktau/sndcld/tree/retag (basically a soundcloud downloader like SoundScrape).
  2. Execute go test -v in the main folder

What it does? Downloads 2 mp3 files (if they don't exist yet) and attempts to tag them with the correct artist and title (yet it doesn't tag if those tags already exist). For the first mp3 file (https://soundcloud.com/purple_oslo/sleepers) this if fine, no matter how many times I tag. The test succeeds. However for the second file (https://soundcloud.com/justinfaustmusic/justin-faust-la-fete-free) this is not the case.

You can probably also reproduce this by downloading the files yourself and using id3.Open()/id3.Close() in succession (that's basically what my test does).

Oh, and another small question: sometimes id3-go tells me it can't open the file. I think this is because the mp3 file doesn't contain any tags at all. How do I add id3v2 headers where none existed before?

EDIT: it looks like the panic is related to issue #10. However, this probably shouldn't be papered over, but fixed at the root.

Bitrate?

Hi,

Please advise how to pull bitrate value?

Also, is "id3-go" choosing ID3 version automatically if I import just "github.com/mikkyang/id3-go"?

Thank you!

Writing new comments

I'm attempting to add a SetComment method so I can write comment fields on v2 files. This is what I have so far and it almost works:

id3v2.go

func (t *Tag) SetComment(text string) {
	t.setTextFrameText(t.commonMap["Comments"], text)
}

then in testing:

file, err := id3.Open(filePath, false)
if err != nil {
	panic(err)
}

file.SetComment("this is my test comment with absolutely no special characters woohoo")

err = file.Close()
if err != nil {
	panic(err)
}

The ID3 spec defines the Comments frame as such:

<Header for 'Comment', ID: "COMM">
Text encoding           $xx
Language                $xx xx xx
Short content descrip.  <text string according to encoding> $00 (00)
The actual text         <full text string according to encoding>

It seems like the comment text is actually ending up in the "Short content description" portion instead of "the actual text".

I'd love any tips and I'll be sure to create a PR and share back my improvements when I get this working

go 1.6 panic

panic: runtime error: cgo argument has Go pointer to Go pointer

goroutine 1 [running]:
panic(0x797660, 0xc8203e2070)
        /opt/go/src/runtime/panic.go:464 +0x3e6
github.com/djimenez/iconv-go.(*Converter).Convert(0xc820070f50, 0xc8203e2020, 0x4, 0x8, 0xc8203e2028, 0x8, 0x8, 0x0, 0x0, 0x0, ...)
        fakePath/dependencies/src/github.com/djimenez/iconv-go/converter.go:83 +0x2a4
github.com/djimenez/iconv-go.(*Converter).ConvertString(0xc820070f50, 0xc8203d6408, 0x4, 0x0, 0x0, 0x0, 0x0)
        fakePath/dependencies/src/github.com/djimenez/iconv-go/converter.go:123 +0x1f2
github.com/mikkyang/id3-go/encodedbytes.EncodedDiff(0x80d403, 0xc8203d6408, 0x4, 0x450400, 0xc8203d6408, 0x4, 0xc820000180, 0x0, 0x0)
        fakePath/dependencies/src/github.com/mikkyang/id3-go/encodedbytes/util.go:141 +0x69
github.com/mikkyang/id3-go/v2.(*TextFrame).SetEncoding(0xc820378000, 0x80d478, 0x5, 0x0, 0x0)
        fakePath/dependencies/src/github.com/mikkyang/id3-go/v2/frame.go:250 +0x170
github.com/mikkyang/id3-go/v2.(*Tag).setTextFrameText(0xc820288280, 0x80d220, 0x4, 0x85cb20, 0x1c, 0x8b5cf0, 0xc8203d6408, 0x4)
        fakePath/dependencies/src/github.com/mikkyang/id3-go/v2/id3v2.go:286 +0x510
github.com/mikkyang/id3-go/v2.(*Tag).SetArtist(0xc820288280, 0xc8203d6408, 0x4)
        fakePath/dependencies/src/github.com/mikkyang/id3-go/v2/id3v2.go:247 +0xd5
modules/downloader.DownloadAlbum(0x7fffeb3c45f3, 0x19, 0xc82006c380, 0x0, 0x0, 0x0, 0x0)
        fakePath/src/modules/someMyCode.go:68 +0x114c
main.main()

How to set/get a cover image?

I have played around with the library and since there's no default way (at least I didn't see one) of setting a cover-image for an MP3 file, I put this into the frame.go-file (since it uses internal variables of ImageFrame):

func NewImageFrame(ft FrameType, mime_type string, image_data []byte) *ImageFrame{
    data_frame := NewDataFrame(ft, image_data)
    data_frame.size += 1 // Add space for the pictureType (do we need this??)
    image_frame := &ImageFrame{
        DataFrame: *data_frame, // DataFrame header
        pictureType: byte(0x03), // Image Type, in this case Front Cover (http://id3.org/id3v2.3.0#Attached_picture)
    }
    image_frame.SetEncoding("UTF-8")
    image_frame.SetMIMEType(mime_type)
    return image_frame
}

However, this does not work. Am I missing something or is there an easier way?

Also, when I use this image_frame := mp3.Tagger.Frame("APIC") to see if the file already has a cover-art (which it does), it returns nil.

How to add tags to a tagless file?

Sometimes id3-go tells me it can't open an mp3 file. From studying the source I believe this must be because it can't find a idv1 nor idv2 tag header (or footer). Is it possible to add id3v2 headers where none existed before?

Support for embedding album artwork

Hey,

I really like your library -- it seems quite complete and well thought out, and in pure Go. I'm working on a little pet project to download and format soundcloud files for personal use -- and one thing that'd be cool is to be able to embed album art directly into the files. This is more valuable than normal, since most music on soundcloud is pretty indie, or remixes, so standard album artwork lookup doesn't tend to work.

From what I can tell, you already support ImageFrames to some degree (at least for basic parsing). Assuming I find the motivation, would you be willing to accept a patch to basically just add a NewImageFrame function that takes a path to an image and jams it in?

(I'm not really an id3 expert at this point, but it doesn't look too crazy to implement.)

Having issues with id3-go on go1.7.1 darwin/amd64

Hello there,

I used to do active development on a go 1.5.X setup on my macbook. I recently upgraded to go 1.7.1 for darwin and I am seeing runtime errors when trying to run some code that uses id3-go. The following function is fairly simple, it takes in a file extension as a string, and a path as a string, and recursively walks through the directory tree starting at the path, and returns a slice of SongFile{} representing an MP3 file.

type SongFile struct {
        RawArtist string `json:"raw_artist"`
        RawAlbum  string `json:"raw_album"`
        RawTitle  string `json:"raw_title"`
        Path      string `json:"path"`
        FileName  string `json:"filename"`
        AlbumArt  string `json"album_art"`
}

func checkExt(ext string, path string) []SongFile {
        var files []SongFile
        filepath.Walk(path, func(p string, f os.FileInfo, _ error) error {
                if !f.IsDir() {
                        r, err := regexp.MatchString(ext, f.Name())
                        if err == nil && r {
                                mp3File, err := id3.Open(p)
                                defer mp3File.Close()
                                if err == nil {
                                        // Sometimes the strings come out bad with null bytes, so I do a string replace
                                        artist := strings.Replace(mp3File.Artist(), "\u0000", "", -1)
                                        album := strings.Replace(mp3File.Album(), "\u0000", "", -1)
                                        title := strings.Replace(mp3File.Title(), "\u0000", "", -1)

                                        if artist == "" {
                                                artist = "Unknown Artist"
                                        }
                                        if album == "" {
                                                album = "Unknown Album"
                                        }
                                        if title == "" {
                                                title = "Unknown Title"
                                        }

                                        sf := SongFile{Path: p, FileName: f.Name(), RawArtist: artist, RawAlbum: album, RawTitle: title}
                                        files = append(files, sf)
                                } else {
                                        fmt.Println(err.Error())
                                        fmt.Println("! " + p + " !")
                                }
                        }
                }
                return nil
        })
        return files
}

The exact stack trace I am seeing when I call this function is as follows

panic: runtime error: cgo argument has Go pointer to Go pointer

goroutine 1 [running]:
panic(0x428d620, 0xc42027e5f0)
    /usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/djimenez/iconv-go.(*Converter).Convert(0xc420019360, 0xc42027e5a8, 0x5, 0x8, 0xc42027e5b0, 0xa, 0xa, 0x40415bb, 0x10, 0x4277ca0, ...)
    /Users/david.shure/go/src/github.com/djimenez/iconv-go/converter.go:83 +0x55c
github.com/djimenez/iconv-go.(*Converter).ConvertString(0xc420019360, 0xc4204b34b8, 0x5, 0x5, 0xc4204b34b8, 0x5, 0x4013418)
    /Users/david.shure/go/src/github.com/djimenez/iconv-go/converter.go:123 +0x184
github.com/mikkyang/id3-go/encodedbytes.(*Reader).ReadRestString(0xc4204b3528, 0xc42000cf00, 0x6, 0x0, 0x0, 0x6)
    /Users/david.shure/go/src/github.com/mikkyang/id3-go/encodedbytes/reader.go:69 +0xaa
github.com/mikkyang/id3-go/v2.ParseTextFrame(0x42daac4, 0x4, 0x42e4613, 0x22, 0x42ff9b0, 0x600000000, 0x0, 0xc42027e59a, 0x6, 0x6, ...)
    /Users/david.shure/go/src/github.com/mikkyang/id3-go/v2/frame.go:233 +0x152
github.com/mikkyang/id3-go/v2.ParseV23Frame(0x4401540, 0xc420472118, 0xc420472118, 0x4401540)
    /Users/david.shure/go/src/github.com/mikkyang/id3-go/v2/id3v23.go:150 +0x389
github.com/mikkyang/id3-go/v2.ParseTag(0x4404040, 0xc420472118, 0x2)
    /Users/david.shure/go/src/github.com/mikkyang/id3-go/v2/id3v2.go:74 +0x11b
github.com/mikkyang/id3-go.Open(0xc42011ebd0, 0x2f, 0xc42011ebf1, 0xe, 0x476e701)
    /Users/david.shure/go/src/github.com/mikkyang/id3-go/id3.go:58 +0xd0
main.checkExt.func1(0xc42011ebd0, 0x2f, 0x4406680, 0xc42025edd0, 0x0, 0x0, 0x0, 0x0)
    /Users/david.shure/stash/griffon/server/griffon.go:94 +0x152
path/filepath.walk(0xc42011ebd0, 0x2f, 0x4406680, 0xc42025edd0, 0xc4200cc8e0, 0x0, 0x0)
    /usr/local/go/src/path/filepath/path.go:351 +0x81
path/filepath.walk(0xc42030e8a0, 0x20, 0x4406680, 0xc42025ed00, 0xc4200cc8e0, 0x0, 0x0)
    /usr/local/go/src/path/filepath/path.go:376 +0x344
path/filepath.walk(0xc42030e760, 0x1e, 0x4406680, 0xc42025eb60, 0xc4200cc8e0, 0x0, 0x0)
    /usr/local/go/src/path/filepath/path.go:376 +0x344
path/filepath.walk(0xc4202a3600, 0x1c, 0x4406680, 0xc420076820, 0xc4200cc8e0, 0x0, 0x0)
    /usr/local/go/src/path/filepath/path.go:376 +0x344
path/filepath.walk(0x7fff5fbff58c, 0x13, 0x4406680, 0xc420077a00, 0xc4200cc8e0, 0x0, 0x1)
    /usr/local/go/src/path/filepath/path.go:376 +0x344
path/filepath.Walk(0x7fff5fbff58c, 0x13, 0xc4200cc8e0, 0x1c, 0x42ff9b0)
    /usr/local/go/src/path/filepath/path.go:398 +0xd5
main.checkExt(0x42dad2d, 0x5, 0x7fff5fbff58c, 0x13, 0x8, 0x42ff9b8, 0x42da786)
    /Users/david.shure/stash/griffon/server/griffon.go:121 +0xce
main.main()
    /Users/david.shure/stash/griffon/server/griffon.go:139 +0x153

After I first encountered this issue, I deleted the source code of id3-go from my $GOPATH, and re-ran go get github.com/mikkyang/id3-go but this hasn't fixed the issue. Please let me know if you need any additional information from my environment. Any information on this would be greatly appreciated. Thanks!

How to get and print Popularimeter frame

I would like to read the Popularimeter frame from a file with id3-go.

This is how the frame looks like when printing with mutagen-inspect:

$ mutagen-inspect samples/with_popm.mp3 | grep POPM
[email protected]=0 255/255

I would like to read the value (255/255) from the file. As I could not find any documentation, my naive approach is:

popFrame := mp3File.Frame("POPM")
log.Println(popFrame.String())

But when I run this (on a file with and also without a popularimeter tag), I get segmentation faults:

$ ./popm-read samples/with_popm.mp3 
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x4ac302]

goroutine 1 [running]:
main.main()
	/home/ifischer/src/rivamp/rivamp-dist/id3-go-popm-example/main.go:21 +0xd2

$ ./popm-read samples/without_popm.mp3 
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x40 pc=0x4ac302]

goroutine 1 [running]:
main.main()
	/home/ifischer/src/rivamp/rivamp-dist/id3-go-popm-example/main.go:21 +0xd2

I setup a sample repository containing two sample files (one with, one without popularimeter frame) here: https://github.com/ifischer/id3-go-popm-example

Metadata alters mp3 duration

This component somehow alters mp3 file duration in a really strange format. On my phone, the result is songs lasting 40 minutes, on VLC (on desktop) they have reasonable duration, but lasting time decrease three times faster.
I use your code this way:

track_mp3, err := id3.Open((*arg_folder) + "/" + track.FilenameTemp + track.FilenameExt)
if err != nil {
	logger.Fatal("Something bad happened while opening " + track.Filename + ": " + err.Error() + ".")
} else {
	track_mp3.SetTitle(track.Title)
	track_mp3.SetArtist(track.Artist)
	track_mp3.SetAlbum(track.Album)
	track_mp3.Close()
}

Opening read-only files.

Currently, opening a read-only file fails. This is because id3.Open opens the files in read write mode (os.OpenFile(name, os.O_RDWR, 0666)).

One thought I had would be to fallback on read-only mode if readwrite mode fails. Then we could just throw an error if someone tries to write to the object. (is it still considered a breaking change if it changes when an error is given?)

Probably the least offensive change would be adding another function, maybe called Read, which would be just like Load, except with os.O_RDONLY. Would that be more confusing?

UnsynchTextFrame round trip fails

Comment frames don't seem to be parsed back the same way they were written:

package main

import (
    "fmt"
    id3 "github.com/mikkyang/id3-go"
    "github.com/mikkyang/id3-go/v2"
    "io/ioutil"
    "os"
)

func main() {
    var (
        tempfile    *os.File
        err         error
        f           *id3.File
        tagger      *v2.Tag
        ft          v2.FrameType
        utextFrame  *v2.UnsynchTextFrame
        parsedFrame v2.Framer
    )

    tempfile, err = ioutil.TempFile("", "id3v2")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    tagger = v2.NewTag(3)
    ft = v2.V23FrameTypeMap["COMM"]
    utextFrame = v2.NewUnsynchTextFrame(ft, "Comment", "Foo")
    tagger.AddFrames(utextFrame)

    _, err = tempfile.Write(tagger.Bytes())
    tempfile.Close()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    f, err = id3.Open(tempfile.Name())
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    parsedFrame = f.Frame("COMM")
    fmt.Printf("=== Expected:\n%v\n=== Got:\n%v\n", utextFrame, parsedFrame)
}

Outputs:

=== Expected:
eng     Comment:
Foo
=== Got:
eng     :
CommentFoo

Panic when reading tags concurrently

I'm writing a program that indexes a music library. I'm experimenting with making some operations concurrent to improve performance for very large libraries.

id3-go is panicking when I have several goroutines calling id3.Open() at the same time [1].

I'm happy to put in a pull request to fix this, but first I'd like to get your input on which approach to take.

I think the issue is coming from reader.go#L69, in ReadRestString():

return Decoders[encoding].ConvertString(string(b))

Decoders are defined at the package level as vars (see here. I guess they have some kind of internal state, so they're not happy when multiple goroutines call ConvertString().

I can think of two ways to fix this:

  • have a set of mutexes - a mutex for each member of Decoders and Encoders
  • just initialize decoders and encoders on-demand in the Reader & the Writer

I think the second one is cleaner and simpler, and involves less contention - but I don't have any context on the cost of creating them.

I've made the second change locally and id3-go is still blazing fast.

Let me know. Keen to put in a PR if I get your feedback.

[1]

panic: runtime error: slice bounds out of range

goroutine 19 [running]:
github.com/djimenez/iconv-go.(*Converter).ConvertString(0xc4200705d0, 0xc4200369b8, 0x10, 0x10, 0xc4200369b8, 0x10, 0x0)
        /home/cera/src/vir/backend/vendor/src/github.com/djimenez/iconv-go/converter.go:155 +0x513
github.com/mikkyang/id3-go/encodedbytes.(*Reader).ReadRestString(0xc420036a90, 0x0, 0xc42000c980, 0x11, 0x11, 0x11)
        /home/cera/src/vir/backend/vendor/src/github.com/mikkyang/id3-go/encodedbytes/reader.go:69 +0x14f
github.com/mikkyang/id3-go/v2.ParseTextFrame(0x5d9829, 0x4, 0x5de24a, 0x1c, 0x5e2100, 0x1100000000, 0x0, 0xc42000c980, 0x11, 0x11, ...)
        /home/cera/src/vir/backend/vendor/src/github.com/mikkyang/id3-go/v2/frame.go:233 +0x266
github.com/mikkyang/id3-go/v2.ParseV23Frame(0x88ff00, 0xc42000e028, 0xc42000e028, 0x88ff00)
        /home/cera/src/vir/backend/vendor/src/github.com/mikkyang/id3-go/v2/id3v23.go:150 +0x43b
github.com/mikkyang/id3-go/v2.ParseTag(0x890880, 0xc42000e028, 0x2)
        /home/cera/src/vir/backend/vendor/src/github.com/mikkyang/id3-go/v2/id3v2.go:74 +0x19e
github.com/mikkyang/id3-go.Open(0xc4200b4700, 0x3f, 0x123dea0, 0x0, 0x0)
        /home/cera/src/vir/backend/vendor/src/github.com/mikkyang/id3-go/id3.go:58 +0x140
vir.loadTrackMetadataFromFile(0xc4200b4700, 0x3f, 0x0, 0x0, 0x0)
        /home/cera/src/vir/backend/src/vir/metadata.go:22 +0x82
vir.loadMetadataConcurrent.func1(0xc420070770, 0xc42006e120, 0xc42006e180)
        /home/cera/src/vir/backend/src/vir/index.go:192 +0x14e
created by vir.loadMetadataConcurrent
        /home/cera/src/vir/backend/src/vir/index.go:210 +0xfb

Cant `go get` id3-go on windows

When i try to do a go get github.com/mikkyang/id3-go on windows it fails. I just install gcc with MinGW and it is a fresh install so i doubt it come from this part.

go get -x github.com/mikkyang/id3-go
WORK=C:\Users\admin\AppData\Local\Temp\go-build230481106
mkdir -p $WORK\github.com\djimenez\iconv-go\_obj\
mkdir -p $WORK\github.com\djimenez\
cd D:\Pro\go\src\github.com\djimenez\iconv-go
CGO_LDFLAGS="-g" "-O2" "-liconv" "C:\\Go\\pkg\\tool\\windows_amd64\\cgo.exe" -objdir "C:\\Users\\admin\\AppData
\\Local\\Temp\\go-build230481106\\github.com\\djimenez\\iconv-go\\_obj\\" -importpath github.com/djimenez/iconv
-go -- -I "C:\\Users\\admin\\AppData\\Local\\Temp\\go-build230481106\\github.com\\djimenez\\iconv-go\\_obj\\" c
onverter.go
go build github.com/djimenez/iconv-go: C:\Go\pkg\tool\windows_amd64\cgo.exe: exit status 2

ID3 v2.4 support

I think this library must also support it, because it's necessary for some projects (for example, for mine)
Hopefully I will try to make it and contribute on this weekend

Can not set tags with UTF-8 contents

func tagIt(filename string, title string, album string, artist string, genre string) {
mp3File, err := id3.Open(filename)
if err != nil {
panic(err)
}
defer mp3File.Close()
mp3File.SetArtist(artist + "x")
mp3File.SetAlbum("ๅ“ˆๅ“ˆ")
mp3File.SetTitle(title + "x")
mp3File.SetGenre(genre + "x")
}

pure English works, but Chinese not.

Should I convert the Chinese string to some other encoding first?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.