diff --git a/id3v2.go b/id3v2.go index c6f406d..bf1b20f 100644 --- a/id3v2.go +++ b/id3v2.go @@ -7,9 +7,41 @@ package tag import ( "fmt" "io" + "regexp" "strconv" + "strings" ) +var id3v2Genres = [...]string{ + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", + "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", + "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", + "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", + "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", + "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", + "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", + "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", + "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", + "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", + "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", + "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", + "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", + "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock", + "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", + "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", + "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", + "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", + "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", + "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", + "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", + "Britpop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", + "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", + "Christian Rock ", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "Synthpop", +} + // id3v2Header is a type which represents an ID3v2 tag header. type id3v2Header struct { Version Format @@ -342,3 +374,27 @@ func ReadID3v2Tags(r io.ReadSeeker) (Metadata, error) { } return metadataID3v2{header: h, frames: f}, nil } + +// id3v2genre parse a id3v2 genre tag and expand the numeric genres +func id3v2genre(genre string) string { + c := true + for c { + orig := genre + re := regexp.MustCompile("(.*[^(]|.* |^)\\(([0-9]+)\\) *(.*)$") + if match := re.FindStringSubmatch(genre); len(match) > 0 { + if genreId, err := strconv.Atoi(match[2]); err == nil { + if genreId < len(id3v2Genres) { + genre = id3v2Genres[genreId] + if match[1] != "" { + genre = strings.TrimSpace(match[1]) + " " + genre + } + if match[3] != "" { + genre = genre + " " + match[3] + } + } + } + } + c = (orig != genre) + } + return strings.Replace(genre, "((", "(", -1) +} diff --git a/id3v2_test.go b/id3v2_test.go index 03e6035..4630409 100644 --- a/id3v2_test.go +++ b/id3v2_test.go @@ -129,3 +129,24 @@ func TestUnsynchroniserSplitReads(t *testing.T) { } } } + +func TestGenreExpension(t *testing.T) { + var tests = map[string]string{ + "Test": "Test", + "((17)": "(17)", + "(17) Test": "Rock Test", + "(17)Test": "Rock Test", + "(17)": "Rock", + "Test(17)": "Test Rock", + "Test (17)": "Test Rock", + "(17)(93)": "Rock Psychedelic Rock", + "(17)Test(93)": "Rock Test Psychedelic Rock", + } + for g, r := range tests { + got := id3v2genre(g) + + if got != r { + t.Errorf("[%v] got: %v, expected %v", g, got, r) + } + } +} diff --git a/id3v2metadata.go b/id3v2metadata.go index 6573a3b..9662efc 100644 --- a/id3v2metadata.go +++ b/id3v2metadata.go @@ -87,7 +87,7 @@ func (m metadataID3v2) Composer() string { } func (m metadataID3v2) Genre() string { - return m.getString(frames.Name("genre", m.Format())) + return id3v2genre(m.getString(frames.Name("genre", m.Format()))) } func (m metadataID3v2) Year() int {