summaryrefslogtreecommitdiff
path: root/vendor/github.com/dhowden
diff options
context:
space:
mode:
authorJames Mills <prologic@shortcircuit.net.au>2020-03-21 08:20:16 +1000
committerJames Mills <prologic@shortcircuit.net.au>2020-03-21 08:20:16 +1000
commitd7a1eab5beba4241dab4402c5cd268432d7b46cd (patch)
tree6383b4ebf511b58597d827dc5af00b71c72caf38 /vendor/github.com/dhowden
parent13ffd7117180d1a3093ff291481caeb07a8b71de (diff)
Migrate to Go111Modules, Add Dockerfile and GoRelaser support
Diffstat (limited to 'vendor/github.com/dhowden')
-rw-r--r--vendor/github.com/dhowden/tag/.editorconfig19
-rw-r--r--vendor/github.com/dhowden/tag/.travis.yml5
-rw-r--r--vendor/github.com/dhowden/tag/LICENSE23
-rw-r--r--vendor/github.com/dhowden/tag/README.md72
-rw-r--r--vendor/github.com/dhowden/tag/dsf.go110
-rw-r--r--vendor/github.com/dhowden/tag/flac.go89
-rw-r--r--vendor/github.com/dhowden/tag/id.go81
-rw-r--r--vendor/github.com/dhowden/tag/id3v1.go144
-rw-r--r--vendor/github.com/dhowden/tag/id3v2.go434
-rw-r--r--vendor/github.com/dhowden/tag/id3v2frames.go638
-rw-r--r--vendor/github.com/dhowden/tag/id3v2metadata.go141
-rw-r--r--vendor/github.com/dhowden/tag/internal/id3v1_test/NOTICE.txt3
-rw-r--r--vendor/github.com/dhowden/tag/mp4.go372
-rw-r--r--vendor/github.com/dhowden/tag/ogg.go119
-rw-r--r--vendor/github.com/dhowden/tag/sum.go219
-rw-r--r--vendor/github.com/dhowden/tag/tag.go147
-rw-r--r--vendor/github.com/dhowden/tag/util.go81
-rw-r--r--vendor/github.com/dhowden/tag/vorbis.go255
18 files changed, 0 insertions, 2952 deletions
diff --git a/vendor/github.com/dhowden/tag/.editorconfig b/vendor/github.com/dhowden/tag/.editorconfig
deleted file mode 100644
index 57515d0..0000000
--- a/vendor/github.com/dhowden/tag/.editorconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# EditorConfig helps developers define and maintain consistent
-# coding styles between different editors and IDEs
-# editorconfig.org
-
-root = true
-
-[*.go]
-indent_style = tab
-indent_size = 3
-
-[*.md]
-trim_trailing_whitespace = false
-
-[*]
-# We recommend you to keep these unchanged
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
diff --git a/vendor/github.com/dhowden/tag/.travis.yml b/vendor/github.com/dhowden/tag/.travis.yml
deleted file mode 100644
index 3a81bf9..0000000
--- a/vendor/github.com/dhowden/tag/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-language: go
-
-go:
- - 1.7
- - tip \ No newline at end of file
diff --git a/vendor/github.com/dhowden/tag/LICENSE b/vendor/github.com/dhowden/tag/LICENSE
deleted file mode 100644
index dfd760c..0000000
--- a/vendor/github.com/dhowden/tag/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-Copyright 2015, David Howden
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- Redistributions in binary form must reproduce the above copyright notice, this
- list of conditions and the following disclaimer in the documentation and/or
- other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/dhowden/tag/README.md b/vendor/github.com/dhowden/tag/README.md
deleted file mode 100644
index de81883..0000000
--- a/vendor/github.com/dhowden/tag/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# MP3/MP4/OGG/FLAC metadata parsing library
-[![Build Status](https://travis-ci.org/dhowden/tag.svg?branch=master)](https://travis-ci.org/dhowden/tag)
-[![GoDoc](https://godoc.org/github.com/dhowden/tag?status.svg)](https://godoc.org/github.com/dhowden/tag)
-
-This package provides MP3 (ID3v1,2.{2,3,4}) and MP4 (ACC, M4A, ALAC), OGG and FLAC metadata detection, parsing and artwork extraction.
-
-Detect and parse tag metadata from an `io.ReadSeeker` (i.e. an `*os.File`):
-
-```go
-m, err := tag.ReadFrom(f)
-if err != nil {
- log.Fatal(err)
-}
-log.Print(m.Format()) // The detected format.
-log.Print(m.Title()) // The title of the track (see Metadata interface for more details).
-```
-
-Parsed metadata is exported via a single interface (giving a consistent API for all supported metadata formats).
-
-```go
-// Metadata is an interface which is used to describe metadata retrieved by this package.
-type Metadata interface {
- Format() Format
- FileType() FileType
-
- Title() string
- Album() string
- Artist() string
- AlbumArtist() string
- Composer() string
- Genre() string
- Year() int
-
- Track() (int, int) // Number, Total
- Disc() (int, int) // Number, Total
-
- Picture() *Picture // Artwork
- Lyrics() string
- Comment() string
-
- Raw() map[string]interface{} // NB: raw tag names are not consistent across formats.
-}
-```
-
-## Audio Data Checksum (SHA1)
-
-This package also provides a metadata-invariant checksum for audio files: only the audio data is used to
-construct the checksum.
-
-[http://godoc.org/github.com/dhowden/tag#Sum](http://godoc.org/github.com/dhowden/tag#Sum)
-
-## Tools
-
-There are simple command-line tools which demonstrate basic tag extraction and summing:
-
-```console
-$ go get github.com/dhowden/tag/...
-$ cd $GOPATH/bin
-$ ./tag 11\ High\ Hopes.m4a
-Metadata Format: MP4
-Title: High Hopes
-Album: The Division Bell
-Artist: Pink Floyd
-Composer: Abbey Road Recording Studios/David Gilmour/Polly Samson
-Year: 1994
-Track: 11 of 11
-Disc: 1 of 1
-Picture: Picture{Ext: jpeg, MIMEType: image/jpeg, Type: , Description: , Data.Size: 606109}
-
-$ ./sum 11\ High\ Hopes.m4a
-2ae208c5f00a1f21f5fac9b7f6e0b8e52c06da29
-```
diff --git a/vendor/github.com/dhowden/tag/dsf.go b/vendor/github.com/dhowden/tag/dsf.go
deleted file mode 100644
index d826a74..0000000
--- a/vendor/github.com/dhowden/tag/dsf.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "errors"
- "io"
-)
-
-// ReadDSFTags reads DSF metadata from the io.ReadSeeker, returning the resulting
-// metadata in a Metadata implementation, or non-nil error if there was a problem.
-// samples: http://www.2l.no/hires/index.html
-func ReadDSFTags(r io.ReadSeeker) (Metadata, error) {
- dsd, err := readString(r, 4)
- if err != nil {
- return nil, err
- }
- if dsd != "DSD " {
- return nil, errors.New("expected 'DSD '")
- }
-
- _, err = r.Seek(int64(16), io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- n4, err := readBytes(r, 8)
- if err != nil {
- return nil, err
- }
- id3Pointer := getIntLittleEndian(n4)
-
- _, err = r.Seek(int64(id3Pointer), io.SeekStart)
- if err != nil {
- return nil, err
- }
-
- id3, err := ReadID3v2Tags(r)
- if err != nil {
- return nil, err
- }
-
- return metadataDSF{id3}, nil
-}
-
-type metadataDSF struct {
- id3 Metadata
-}
-
-func (m metadataDSF) Format() Format {
- return m.id3.Format()
-}
-
-func (m metadataDSF) FileType() FileType {
- return DSF
-}
-
-func (m metadataDSF) Title() string {
- return m.id3.Title()
-}
-
-func (m metadataDSF) Album() string {
- return m.id3.Album()
-}
-
-func (m metadataDSF) Artist() string {
- return m.id3.Artist()
-}
-
-func (m metadataDSF) AlbumArtist() string {
- return m.id3.AlbumArtist()
-}
-
-func (m metadataDSF) Composer() string {
- return m.id3.Composer()
-}
-
-func (m metadataDSF) Year() int {
- return m.id3.Year()
-}
-
-func (m metadataDSF) Genre() string {
- return m.id3.Genre()
-}
-
-func (m metadataDSF) Track() (int, int) {
- return m.id3.Track()
-}
-
-func (m metadataDSF) Disc() (int, int) {
- return m.id3.Disc()
-}
-
-func (m metadataDSF) Picture() *Picture {
- return m.id3.Picture()
-}
-
-func (m metadataDSF) Lyrics() string {
- return m.id3.Lyrics()
-}
-
-func (m metadataDSF) Comment() string {
- return m.id3.Comment()
-}
-
-func (m metadataDSF) Raw() map[string]interface{} {
- return m.id3.Raw()
-}
diff --git a/vendor/github.com/dhowden/tag/flac.go b/vendor/github.com/dhowden/tag/flac.go
deleted file mode 100644
index c370467..0000000
--- a/vendor/github.com/dhowden/tag/flac.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "errors"
- "io"
-)
-
-// blockType is a type which represents an enumeration of valid FLAC blocks
-type blockType byte
-
-// FLAC block types.
-const (
- // Stream Info Block 0
- // Padding Block 1
- // Application Block 2
- // Seektable Block 3
- // Cue Sheet Block 5
- vorbisCommentBlock blockType = 4
- pictureBlock blockType = 6
-)
-
-// ReadFLACTags reads FLAC metadata from the io.ReadSeeker, returning the resulting
-// metadata in a Metadata implementation, or non-nil error if there was a problem.
-func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
- flac, err := readString(r, 4)
- if err != nil {
- return nil, err
- }
- if flac != "fLaC" {
- return nil, errors.New("expected 'fLaC'")
- }
-
- m := &metadataFLAC{
- newMetadataVorbis(),
- }
-
- for {
- last, err := m.readFLACMetadataBlock(r)
- if err != nil {
- return nil, err
- }
-
- if last {
- break
- }
- }
- return m, nil
-}
-
-type metadataFLAC struct {
- *metadataVorbis
-}
-
-func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
- blockHeader, err := readBytes(r, 1)
- if err != nil {
- return
- }
-
- if getBit(blockHeader[0], 7) {
- blockHeader[0] ^= (1 << 7)
- last = true
- }
-
- blockLen, err := readInt(r, 3)
- if err != nil {
- return
- }
-
- switch blockType(blockHeader[0]) {
- case vorbisCommentBlock:
- err = m.readVorbisComment(r)
-
- case pictureBlock:
- err = m.readPictureBlock(r)
-
- default:
- _, err = r.Seek(int64(blockLen), io.SeekCurrent)
- }
- return
-}
-
-func (m *metadataFLAC) FileType() FileType {
- return FLAC
-}
diff --git a/vendor/github.com/dhowden/tag/id.go b/vendor/github.com/dhowden/tag/id.go
deleted file mode 100644
index 2410356..0000000
--- a/vendor/github.com/dhowden/tag/id.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package tag
-
-import (
- "fmt"
- "io"
-)
-
-// Identify identifies the format and file type of the data in the ReadSeeker.
-func Identify(r io.ReadSeeker) (format Format, fileType FileType, err error) {
- b, err := readBytes(r, 11)
- if err != nil {
- return
- }
-
- _, err = r.Seek(-11, io.SeekCurrent)
- if err != nil {
- err = fmt.Errorf("could not seek back to original position: %v", err)
- return
- }
-
- switch {
- case string(b[0:4]) == "fLaC":
- return VORBIS, FLAC, nil
-
- case string(b[0:4]) == "OggS":
- return VORBIS, OGG, nil
-
- case string(b[4:8]) == "ftyp":
- b = b[8:11]
- fileType = UnknownFileType
- switch string(b) {
- case "M4A":
- fileType = M4A
-
- case "M4B":
- fileType = M4B
-
- case "M4P":
- fileType = M4P
- }
- return MP4, fileType, nil
-
- case string(b[0:3]) == "ID3":
- b := b[3:]
- switch uint(b[0]) {
- case 2:
- format = ID3v2_2
- case 3:
- format = ID3v2_3
- case 4:
- format = ID3v2_4
- case 0, 1:
- fallthrough
- default:
- err = fmt.Errorf("ID3 version: %v, expected: 2, 3 or 4", uint(b[0]))
- return
- }
- return format, MP3, nil
- }
-
- n, err := r.Seek(-128, io.SeekEnd)
- if err != nil {
- return
- }
-
- tag, err := readString(r, 3)
- if err != nil {
- return
- }
-
- _, err = r.Seek(-n, io.SeekCurrent)
- if err != nil {
- return
- }
-
- if tag != "TAG" {
- err = ErrNoTagsFound
- return
- }
- return ID3v1, MP3, nil
-}
diff --git a/vendor/github.com/dhowden/tag/id3v1.go b/vendor/github.com/dhowden/tag/id3v1.go
deleted file mode 100644
index 0953f0b..0000000
--- a/vendor/github.com/dhowden/tag/id3v1.go
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "errors"
- "io"
- "strconv"
- "strings"
-)
-
-// id3v1Genres is a list of genres as given in the ID3v1 specification.
-var id3v1Genres = [...]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", "Psychadelic", "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", "Acapella", "Euro-House", "Dance Hall",
-}
-
-// ErrNotID3v1 is an error which is returned when no ID3v1 header is found.
-var ErrNotID3v1 = errors.New("invalid ID3v1 header")
-
-// ReadID3v1Tags reads ID3v1 tags from the io.ReadSeeker. Returns ErrNotID3v1
-// if there are no ID3v1 tags, otherwise non-nil error if there was a problem.
-func ReadID3v1Tags(r io.ReadSeeker) (Metadata, error) {
- _, err := r.Seek(-128, io.SeekEnd)
- if err != nil {
- return nil, err
- }
-
- if tag, err := readString(r, 3); err != nil {
- return nil, err
- } else if tag != "TAG" {
- return nil, ErrNotID3v1
- }
-
- title, err := readString(r, 30)
- if err != nil {
- return nil, err
- }
-
- artist, err := readString(r, 30)
- if err != nil {
- return nil, err
- }
-
- album, err := readString(r, 30)
- if err != nil {
- return nil, err
- }
-
- year, err := readString(r, 4)
- if err != nil {
- return nil, err
- }
-
- commentBytes, err := readBytes(r, 30)
- if err != nil {
- return nil, err
- }
-
- var comment string
- var track int
- if commentBytes[28] == 0 {
- comment = trimString(string(commentBytes[:28]))
- track = int(commentBytes[29])
- } else {
- comment = trimString(string(commentBytes))
- }
-
- var genre string
- genreID, err := readBytes(r, 1)
- if err != nil {
- return nil, err
- }
- if int(genreID[0]) < len(id3v1Genres) {
- genre = id3v1Genres[int(genreID[0])]
- }
-
- m := make(map[string]interface{})
- m["title"] = trimString(title)
- m["artist"] = trimString(artist)
- m["album"] = trimString(album)
- m["year"] = trimString(year)
- m["comment"] = trimString(comment)
- m["track"] = track
- m["genre"] = genre
-
- return metadataID3v1(m), nil
-}
-
-func trimString(x string) string {
- return strings.TrimSpace(strings.Trim(x, "\x00"))
-}
-
-// metadataID3v1 is the implementation of Metadata used for ID3v1 tags.
-type metadataID3v1 map[string]interface{}
-
-func (metadataID3v1) Format() Format { return ID3v1 }
-func (metadataID3v1) FileType() FileType { return MP3 }
-func (m metadataID3v1) Raw() map[string]interface{} { return m }
-
-func (m metadataID3v1) Title() string { return m["title"].(string) }
-func (m metadataID3v1) Album() string { return m["album"].(string) }
-func (m metadataID3v1) Artist() string { return m["artist"].(string) }
-func (m metadataID3v1) Genre() string { return m["genre"].(string) }
-
-func (m metadataID3v1) Year() int {
- y := m["year"].(string)
- n, err := strconv.Atoi(y)
- if err != nil {
- return 0
- }
- return n
-}
-
-func (m metadataID3v1) Track() (int, int) { return m["track"].(int), 0 }
-
-func (m metadataID3v1) AlbumArtist() string { return "" }
-func (m metadataID3v1) Composer() string { return "" }
-func (metadataID3v1) Disc() (int, int) { return 0, 0 }
-func (m metadataID3v1) Picture() *Picture { return nil }
-func (m metadataID3v1) Lyrics() string { return "" }
-func (m metadataID3v1) Comment() string { return m["comment"].(string) }
diff --git a/vendor/github.com/dhowden/tag/id3v2.go b/vendor/github.com/dhowden/tag/id3v2.go
deleted file mode 100644
index 063e6cb..0000000
--- a/vendor/github.com/dhowden/tag/id3v2.go
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-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
- Unsynchronisation bool
- ExtendedHeader bool
- Experimental bool
- Size int
-}
-
-// readID3v2Header reads the ID3v2 header from the given io.Reader.
-// offset it number of bytes of header that was read
-func readID3v2Header(r io.Reader) (h *id3v2Header, offset int, err error) {
- offset = 10
- b, err := readBytes(r, offset)
- if err != nil {
- return nil, 0, fmt.Errorf("expected to read 10 bytes (ID3v2Header): %v", err)
- }
-
- if string(b[0:3]) != "ID3" {
- return nil, 0, fmt.Errorf("expected to read \"ID3\"")
- }
-
- b = b[3:]
- var vers Format
- switch uint(b[0]) {
- case 2:
- vers = ID3v2_2
- case 3:
- vers = ID3v2_3
- case 4:
- vers = ID3v2_4
- case 0, 1:
- fallthrough
- default:
- return nil, 0, fmt.Errorf("ID3 version: %v, expected: 2, 3 or 4", uint(b[0]))
- }
-
- // NB: We ignore b[1] (the revision) as we don't currently rely on it.
- h = &id3v2Header{
- Version: vers,
- Unsynchronisation: getBit(b[2], 7),
- ExtendedHeader: getBit(b[2], 6),
- Experimental: getBit(b[2], 5),
- Size: get7BitChunkedInt(b[3:7]),
- }
-
- if h.ExtendedHeader {
- switch vers {
- case ID3v2_3:
- b, err := readBytes(r, 4)
- if err != nil {
- return nil, 0, fmt.Errorf("expected to read 4 bytes (ID3v23 extended header len): %v", err)
- }
- // skip header, size is excluding len bytes
- extendedHeaderSize := getInt(b)
- _, err = readBytes(r, extendedHeaderSize)
- if err != nil {
- return nil, 0, fmt.Errorf("expected to read %d bytes (ID3v23 skip extended header): %v", extendedHeaderSize, err)
- }
- offset += extendedHeaderSize
- case ID3v2_4:
- b, err := readBytes(r, 4)
- if err != nil {
- return nil, 0, fmt.Errorf("expected to read 4 bytes (ID3v24 extended header len): %v", err)
- }
- // skip header, size is synchsafe int including len bytes
- extendedHeaderSize := get7BitChunkedInt(b) - 4
- _, err = readBytes(r, extendedHeaderSize)
- if err != nil {
- return nil, 0, fmt.Errorf("expected to read %d bytes (ID3v24 skip extended header): %v", extendedHeaderSize, err)
- }
- offset += extendedHeaderSize
- default:
- // nop, only 2.3 and 2.4 should have extended header
- }
- }
-
- return h, offset, nil
-}
-
-// id3v2FrameFlags is a type which represents the flags which can be set on an ID3v2 frame.
-type id3v2FrameFlags struct {
- // Message (ID3 2.3.0 and 2.4.0)
- TagAlterPreservation bool
- FileAlterPreservation bool
- ReadOnly bool
-
- // Format (ID3 2.3.0 and 2.4.0)
- Compression bool
- Encryption bool
- GroupIdentity bool
- // ID3 2.4.0 only (see http://id3.org/id3v2.4.0-structure sec 4.1)
- Unsynchronisation bool
- DataLengthIndicator bool
-}
-
-func readID3v23FrameFlags(r io.Reader) (*id3v2FrameFlags, error) {
- b, err := readBytes(r, 2)
- if err != nil {
- return nil, err
- }
-
- msg := b[0]
- fmt := b[1]
-
- return &id3v2FrameFlags{
- TagAlterPreservation: getBit(msg, 7),
- FileAlterPreservation: getBit(msg, 6),
- ReadOnly: getBit(msg, 5),
- Compression: getBit(fmt, 7),
- Encryption: getBit(fmt, 6),
- GroupIdentity: getBit(fmt, 5),
- }, nil
-}
-
-func readID3v24FrameFlags(r io.Reader) (*id3v2FrameFlags, error) {
- b, err := readBytes(r, 2)
- if err != nil {
- return nil, err
- }
-
- msg := b[0]
- fmt := b[1]
-
- return &id3v2FrameFlags{
- TagAlterPreservation: getBit(msg, 6),
- FileAlterPreservation: getBit(msg, 5),
- ReadOnly: getBit(msg, 4),
- GroupIdentity: getBit(fmt, 6),
- Compression: getBit(fmt, 3),
- Encryption: getBit(fmt, 2),
- Unsynchronisation: getBit(fmt, 1),
- DataLengthIndicator: getBit(fmt, 0),
- }, nil
-
-}
-
-func readID3v2_2FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
- name, err = readString(r, 3)
- if err != nil {
- return
- }
- size, err = readInt(r, 3)
- if err != nil {
- return
- }
- headerSize = 6
- return
-}
-
-func readID3v2_3FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
- name, err = readString(r, 4)
- if err != nil {
- return
- }
- size, err = readInt(r, 4)
- if err != nil {
- return
- }
- headerSize = 8
- return
-}
-
-func readID3v2_4FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
- name, err = readString(r, 4)
- if err != nil {
- return
- }
- size, err = read7BitChunkedInt(r, 4)
- if err != nil {
- return
- }
- headerSize = 8
- return
-}
-
-// readID3v2Frames reads ID3v2 frames from the given reader using the ID3v2Header.
-func readID3v2Frames(r io.Reader, offset int, h *id3v2Header) (map[string]interface{}, error) {
- result := make(map[string]interface{})
-
- for offset < h.Size {
- var err error
- var name string
- var size, headerSize int
- var flags *id3v2FrameFlags
-
- switch h.Version {
- case ID3v2_2:
- name, size, headerSize, err = readID3v2_2FrameHeader(r)
-
- case ID3v2_3:
- name, size, headerSize, err = readID3v2_3FrameHeader(r)
- if err != nil {
- return nil, err
- }
- flags, err = readID3v23FrameFlags(r)
- headerSize += 2
-
- case ID3v2_4:
- name, size, headerSize, err = readID3v2_4FrameHeader(r)
- if err != nil {
- return nil, err
- }
- flags, err = readID3v24FrameFlags(r)
- headerSize += 2
- }
-
- if err != nil {
- return nil, err
- }
-
- // FIXME: Do we still need this?
- // if size=0, we certainly are in a padding zone. ignore the rest of
- // the tags
- if size == 0 {
- break
- }
-
- offset += headerSize + size
-
- // Avoid corrupted padding (see http://id3.org/Compliance%20Issues).
- if !validID3Frame(h.Version, name) && offset > h.Size {
- break
- }
-
- if flags != nil {
- if flags.Compression {
- _, err = read7BitChunkedInt(r, 4) // read 4
- if err != nil {
- return nil, err
- }
- size -= 4
- }
-
- if flags.Encryption {
- _, err = readBytes(r, 1) // read 1 byte of encryption method
- if err != nil {
- return nil, err
- }
- size -= 1
- }
- }
-
- b, err := readBytes(r, size)
- if err != nil {
- return nil, err
- }
-
- // There can be multiple tag with the same name. Append a number to the
- // name if there is more than one.
- rawName := name
- if _, ok := result[rawName]; ok {
- for i := 0; ok; i++ {
- rawName = name + "_" + strconv.Itoa(i)
- _, ok = result[rawName]
- }
- }
-
- switch {
- case name == "TXXX" || name == "TXX":
- t, err := readTextWithDescrFrame(b, false, true) // no lang, but enc
- if err != nil {
- return nil, err
- }
- result[rawName] = t
-
- case name[0] == 'T':
- txt, err := readTFrame(b)
- if err != nil {
- return nil, err
- }
- result[rawName] = txt
-
- case name == "UFID" || name == "UFI":
- t, err := readUFID(b)
- if err != nil {
- return nil, err
- }
- result[rawName] = t
-
- case name == "WXXX" || name == "WXX":
- t, err := readTextWithDescrFrame(b, false, false) // no lang, no enc
- if err != nil {
- return nil, err
- }
- result[rawName] = t
-
- case name[0] == 'W':
- txt, err := readWFrame(b)
- if err != nil {
- return nil, err
- }
- result[rawName] = txt
-
- case name == "COMM" || name == "COM" || name == "USLT" || name == "ULT":
- t, err := readTextWithDescrFrame(b, true, true) // both lang and enc
- if err != nil {
- return nil, err
- }
- result[rawName] = t
-
- case name == "APIC":
- p, err := readAPICFrame(b)
- if err != nil {
- return nil, err
- }
- result[rawName] = p
-
- case name == "PIC":
- p, err := readPICFrame(b)
- if err != nil {
- return nil, err
- }
- result[rawName] = p
-
- default:
- result[rawName] = b
- }
- }
- return result, nil
-}
-
-type unsynchroniser struct {
- io.Reader
- ff bool
-}
-
-// filter io.Reader which skip the Unsynchronisation bytes
-func (r *unsynchroniser) Read(p []byte) (int, error) {
- b := make([]byte, 1)
- i := 0
- for i < len(p) {
- if n, err := r.Reader.Read(b); err != nil || n == 0 {
- return i, err
- }
- if r.ff && b[0] == 0x00 {
- r.ff = false
- continue
- }
- p[i] = b[0]
- i++
- r.ff = (b[0] == 0xFF)
- }
- return i, nil
-}
-
-// ReadID3v2Tags parses ID3v2.{2,3,4} tags from the io.ReadSeeker into a Metadata, returning
-// non-nil error on failure.
-func ReadID3v2Tags(r io.ReadSeeker) (Metadata, error) {
- h, offset, err := readID3v2Header(r)
- if err != nil {
- return nil, err
- }
-
- var ur io.Reader = r
- if h.Unsynchronisation {
- ur = &unsynchroniser{Reader: r}
- }
-
- f, err := readID3v2Frames(ur, offset, h)
- if err != nil {
- return nil, err
- }
- return metadataID3v2{header: h, frames: f}, nil
-}
-
-var id3v2genreRe = regexp.MustCompile(`(.*[^(]|.* |^)\(([0-9]+)\) *(.*)$`)
-
-// id3v2genre parse a id3v2 genre tag and expand the numeric genres
-func id3v2genre(genre string) string {
- c := true
- for c {
- orig := genre
- if match := id3v2genreRe.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/vendor/github.com/dhowden/tag/id3v2frames.go b/vendor/github.com/dhowden/tag/id3v2frames.go
deleted file mode 100644
index a92afa1..0000000
--- a/vendor/github.com/dhowden/tag/id3v2frames.go
+++ /dev/null
@@ -1,638 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "strings"
- "unicode/utf16"
-)
-
-// DefaultUTF16WithBOMByteOrder is the byte order used when the "UTF16 with BOM" encoding
-// is specified without a corresponding BOM in the data.
-var DefaultUTF16WithBOMByteOrder binary.ByteOrder = binary.LittleEndian
-
-// ID3v2.2.0 frames (see http://id3.org/id3v2-00, sec 4).
-var id3v22Frames = map[string]string{
- "BUF": "Recommended buffer size",
-
- "CNT": "Play counter",
- "COM": "Comments",
- "CRA": "Audio encryption",
- "CRM": "Encrypted meta frame",
-
- "ETC": "Event timing codes",
- "EQU": "Equalization",
-
- "GEO": "General encapsulated object",
-
- "IPL": "Involved people list",
-
- "LNK": "Linked information",
-
- "MCI": "Music CD Identifier",
- "MLL": "MPEG location lookup table",
-
- "PIC": "Attached picture",
- "POP": "Popularimeter",
-
- "REV": "Reverb",
- "RVA": "Relative volume adjustment",
-
- "SLT": "Synchronized lyric/text",
- "STC": "Synced tempo codes",
-
- "TAL": "Album/Movie/Show title",
- "TBP": "BPM (Beats Per Minute)",
- "TCM": "Composer",
- "TCO": "Content type",
- "TCR": "Copyright message",
- "TDA": "Date",
- "TDY": "Playlist delay",
- "TEN": "Encoded by",
- "TFT": "File type",
- "TIM": "Time",
- "TKE": "Initial key",
- "TLA": "Language(s)",
- "TLE": "Length",
- "TMT": "Media type",
- "TOA": "Original artist(s)/performer(s)",
- "TOF": "Original filename",
- "TOL": "Original Lyricist(s)/text writer(s)",
- "TOR": "Original release year",
- "TOT": "Original album/Movie/Show title",
- "TP1": "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group",
- "TP2": "Band/Orchestra/Accompaniment",
- "TP3": "Conductor/Performer refinement",
- "TP4": "Interpreted, remixed, or otherwise modified by",
- "TPA": "Part of a set",
- "TPB": "Publisher",
- "TRC": "ISRC (International Standard Recording Code)",
- "TRD": "Recording dates",
- "TRK": "Track number/Position in set",
- "TSI": "Size",
- "TSS": "Software/hardware and settings used for encoding",
- "TT1": "Content group description",
- "TT2": "Title/Songname/Content description",
- "TT3": "Subtitle/Description refinement",
- "TXT": "Lyricist/text writer",
- "TXX": "User defined text information frame",
- "TYE": "Year",
-
- "UFI": "Unique file identifier",
- "ULT": "Unsychronized lyric/text transcription",
-
- "WAF": "Official audio file webpage",
- "WAR": "Official artist/performer webpage",
- "WAS": "Official audio source webpage",
- "WCM": "Commercial information",
- "WCP": "Copyright/Legal information",
- "WPB": "Publishers official webpage",
- "WXX": "User defined URL link frame",
-}
-
-// ID3v2.3.0 frames (see http://id3.org/id3v2.3.0#Declared_ID3v2_frames).
-var id3v23Frames = map[string]string{
- "AENC": "Audio encryption]",
- "APIC": "Attached picture",
- "COMM": "Comments",
- "COMR": "Commercial frame",
- "ENCR": "Encryption method registration",
- "EQUA": "Equalization",
- "ETCO": "Event timing codes",
- "GEOB": "General encapsulated object",
- "GRID": "Group identification registration",
- "IPLS": "Involved people list",
- "LINK": "Linked information",
- "MCDI": "Music CD identifier",
- "MLLT": "MPEG location lookup table",
- "OWNE": "Ownership frame",
- "PRIV": "Private frame",
- "PCNT": "Play counter",
- "POPM": "Popularimeter",
- "POSS": "Position synchronisation frame",
- "RBUF": "Recommended buffer size",
- "RVAD": "Relative volume adjustment",
- "RVRB": "Reverb",
- "SYLT": "Synchronized lyric/text",
- "SYTC": "Synchronized tempo codes",
- "TALB": "Album/Movie/Show title",
- "TBPM": "BPM (beats per minute)",
- "TCMP": "iTunes Compilation Flag",
- "TCOM": "Composer",
- "TCON": "Content type",
- "TCOP": "Copyright message",
- "TDAT": "Date",
- "TDLY": "Playlist delay",
- "TENC": "Encoded by",
- "TEXT": "Lyricist/Text writer",
- "TFLT": "File type",
- "TIME": "Time",
- "TIT1": "Content group description",
- "TIT2": "Title/songname/content description",
- "TIT3": "Subtitle/Description refinement",
- "TKEY": "Initial key",
- "TLAN": "Language(s)",
- "TLEN": "Length",
- "TMED": "Media type",
- "TOAL": "Original album/movie/show title",
- "TOFN": "Original filename",
- "TOLY": "Original lyricist(s)/text writer(s)",
- "TOPE": "Original artist(s)/performer(s)",
- "TORY": "Original release year",
- "TOWN": "File owner/licensee",
- "TPE1": "Lead performer(s)/Soloist(s)",
- "TPE2": "Band/orchestra/accompaniment",
- "TPE3": "Conductor/performer refinement",
- "TPE4": "Interpreted, remixed, or otherwise modified by",
- "TPOS": "Part of a set",
- "TPUB": "Publisher",
- "TRCK": "Track number/Position in set",
- "TRDA": "Recording dates",
- "TRSN": "Internet radio station name",
- "TRSO": "Internet radio station owner",
- "TSIZ": "Size",
- "TSO2": "iTunes uses this for Album Artist sort order",
- "TSOC": "iTunes uses this for Composer sort order",
- "TSRC": "ISRC (international standard recording code)",
- "TSSE": "Software/Hardware and settings used for encoding",
- "TYER": "Year",
- "TXXX": "User defined text information frame",
- "UFID": "Unique file identifier",
- "USER": "Terms of use",
- "USLT": "Unsychronized lyric/text transcription",
- "WCOM": "Commercial information",
- "WCOP": "Copyright/Legal information",
- "WOAF": "Official audio file webpage",
- "WOAR": "Official artist/performer webpage",
- "WOAS": "Official audio source webpage",
- "WORS": "Official internet radio station homepage",
- "WPAY": "Payment",
- "WPUB": "Publishers official webpage",
- "WXXX": "User defined URL link frame",
-}
-
-// ID3v2.4.0 frames (see http://id3.org/id3v2.4.0-frames, sec 4).
-var id3v24Frames = map[string]string{
- "AENC": "Audio encryption",
- "APIC": "Attached picture",
- "ASPI": "Audio seek point index",
-
- "COMM": "Comments",
- "COMR": "Commercial frame",
-
- "ENCR": "Encryption method registration",
- "EQU2": "Equalisation (2)",
- "ETCO": "Event timing codes",
-
- "GEOB": "General encapsulated object",
- "GRID": "Group identification registration",
-
- "LINK": "Linked information",
-
- "MCDI": "Music CD identifier",
- "MLLT": "MPEG location lookup table",
-
- "OWNE": "Ownership frame",
-
- "PRIV": "Private frame",
- "PCNT": "Play counter",
- "POPM": "Popularimeter",
- "POSS": "Position synchronisation frame",
-
- "RBUF": "Recommended buffer size",
- "RVA2": "Relative volume adjustment (2)",
- "RVRB": "Reverb",
-
- "SEEK": "Seek frame",
- "SIGN": "Signature frame",
- "SYLT": "Synchronised lyric/text",
- "SYTC": "Synchronised tempo codes",
-
- "TALB": "Album/Movie/Show title",
- "TBPM": "BPM (beats per minute)",
- "TCMP": "iTunes Compilation Flag",
- "TCOM": "Composer",
- "TCON": "Content type",
- "TCOP": "Copyright message",
- "TDEN": "Encoding time",
- "TDLY": "Playlist delay",
- "TDOR": "Original release time",
- "TDRC": "Recording time",
- "TDRL": "Release time",
- "TDTG": "Tagging time",
- "TENC": "Encoded by",
- "TEXT": "Lyricist/Text writer",
- "TFLT": "File type",
- "TIPL": "Involved people list",
- "TIT1": "Content group description",
- "TIT2": "Title/songname/content description",
- "TIT3": "Subtitle/Description refinement",
- "TKEY": "Initial key",
- "TLAN": "Language(s)",
- "TLEN": "Length",
- "TMCL": "Musician credits list",
- "TMED": "Media type",
- "TMOO": "Mood",
- "TOAL": "Original album/movie/show title",
- "TOFN": "Original filename",
- "TOLY": "Original lyricist(s)/text writer(s)",
- "TOPE": "Original artist(s)/performer(s)",
- "TOWN": "File owner/licensee",
- "TPE1": "Lead performer(s)/Soloist(s)",
- "TPE2": "Band/orchestra/accompaniment",
- "TPE3": "Conductor/performer refinement",
- "TPE4": "Interpreted, remixed, or otherwise modified by",
- "TPOS": "Part of a set",
- "TPRO": "Produced notice",
- "TPUB": "Publisher",
- "TRCK": "Track number/Position in set",
- "TRSN": "Internet radio station name",
- "TRSO": "Internet radio station owner",
- "TSO2": "iTunes uses this for Album Artist sort order",
- "TSOA": "Album sort order",
- "TSOC": "iTunes uses this for Composer sort order",
- "TSOP": "Performer sort order",
- "TSOT": "Title sort order",
- "TSRC": "ISRC (international standard recording code)",
- "TSSE": "Software/Hardware and settings used for encoding",
- "TSST": "Set subtitle",
- "TXXX": "User defined text information frame",
-
- "UFID": "Unique file identifier",
- "USER": "Terms of use",
- "USLT": "Unsynchronised lyric/text transcription",
-
- "WCOM": "Commercial information",
- "WCOP": "Copyright/Legal information",
- "WOAF": "Official audio file webpage",
- "WOAR": "Official artist/performer webpage",
- "WOAS": "Official audio source webpage",
- "WORS": "Official Internet radio station homepage",
- "WPAY": "Payment",
- "WPUB": "Publishers official webpage",
- "WXXX": "User defined URL link frame",
-}
-
-// ID3 frames that are defined in the specs.
-var id3Frames = map[Format]map[string]string{
- ID3v2_2: id3v22Frames,
- ID3v2_3: id3v23Frames,
- ID3v2_4: id3v24Frames,
-}
-
-func validID3Frame(version Format, name string) bool {
- names, ok := id3Frames[version]
- if !ok {
- return false
- }
- _, ok = names[name]
- return ok
-}
-
-func readWFrame(b []byte) (string, error) {
- // Frame text is always encoded in ISO-8859-1
- b = append([]byte{0}, b...)
- return readTFrame(b)
-}
-
-func readTFrame(b []byte) (string, error) {
- if len(b) == 0 {
- return "", nil
- }
-
- txt, err := decodeText(b[0], b[1:])
- if err != nil {
- return "", err
- }
- return strings.Join(strings.Split(txt, string(singleZero)), ""), nil
-}
-
-const (
- encodingISO8859 byte = 0
- encodingUTF16WithBOM byte = 1
- encodingUTF16 byte = 2
- encodingUTF8 byte = 3
-)
-
-func decodeText(enc byte, b []byte) (string, error) {
- if len(b) == 0 {
- return "", nil
- }
-
- switch enc {
- case encodingISO8859: // ISO-8859-1
- return decodeISO8859(b), nil
-
- case encodingUTF16WithBOM: // UTF-16 with byte order marker
- if len(b) == 1 {
- return "", nil
- }
- return decodeUTF16WithBOM(b)
-
- case encodingUTF16: // UTF-16 without byte order (assuming BigEndian)
- if len(b) == 1 {
- return "", nil
- }
- return decodeUTF16(b, binary.BigEndian)
-
- case encodingUTF8: // UTF-8
- return string(b), nil
-
- default: // Fallback to ISO-8859-1
- return decodeISO8859(b), nil
- }
-}
-
-var (
- singleZero = []byte{0}
- doubleZero = []byte{0, 0}
-)
-
-func dataSplit(b []byte, enc byte) [][]byte {
- delim := singleZero
- if enc == encodingUTF16 || enc == encodingUTF16WithBOM {
- delim = doubleZero
- }
-
- result := bytes.SplitN(b, delim, 2)
- if len(result) != 2 {
- return result
- }
-
- if len(result[1]) == 0 {
- return result
- }
-
- if result[1][0] == 0 {
- // there was a double (or triple) 0 and we cut too early
- result[0] = append(result[0], result[1][0])
- result[1] = result[1][1:]
- }
- return result
-}
-
-func decodeISO8859(b []byte) string {
- r := make([]rune, len(b))
- for i, x := range b {
- r[i] = rune(x)
- }
- return string(r)
-}
-
-func decodeUTF16WithBOM(b []byte) (string, error) {
- if len(b) < 2 {
- return "", errors.New("invalid encoding: expected at least 2 bytes for UTF-16 byte order mark")
- }
-
- var bo binary.ByteOrder
- switch {
- case b[0] == 0xFE && b[1] == 0xFF:
- bo = binary.BigEndian
- b = b[2:]
-
- case b[0] == 0xFF && b[1] == 0xFE:
- bo = binary.LittleEndian
- b = b[2:]
-
- default:
- bo = DefaultUTF16WithBOMByteOrder
- }
- return decodeUTF16(b, bo)
-}
-
-func decodeUTF16(b []byte, bo binary.ByteOrder) (string, error) {
- if len(b)%2 != 0 {
- return "", errors.New("invalid encoding: expected even number of bytes for UTF-16 encoded text")
- }
- s := make([]uint16, 0, len(b)/2)
- for i := 0; i < len(b); i += 2 {
- s = append(s, bo.Uint16(b[i:i+2]))
- }
- return string(utf16.Decode(s)), nil
-}
-
-// Comm is a type used in COMM, UFID, TXXX, WXXX and USLT tag.
-// It's a text with a description and a specified language
-// For WXXX, TXXX and UFID, we don't set a Language
-type Comm struct {
- Language string
- Description string
- Text string
-}
-
-// String returns a string representation of the underlying Comm instance.
-func (t Comm) String() string {
- if t.Language != "" {
- return fmt.Sprintf("Text{Lang: '%v', Description: '%v', %v lines}",
- t.Language, t.Description, strings.Count(t.Text, "\n"))
- }
- return fmt.Sprintf("Text{Description: '%v', %v}", t.Description, t.Text)
-}
-
-// IDv2.{3,4}
-// -- Header
-// <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT">
-// <Header for 'Comment', ID: "COMM">
-// -- readTextWithDescrFrame(data, true, true)
-// Text encoding $xx
-// Language $xx xx xx
-// Content descriptor <text string according to encoding> $00 (00)
-// Lyrics/text <full text string according to encoding>
-// -- Header
-// <Header for 'User defined text information frame', ID: "TXXX">
-// <Header for 'User defined URL link frame', ID: "WXXX">
-// -- readTextWithDescrFrame(data, false, <isDataEncoded>)
-// Text encoding $xx
-// Description <text string according to encoding> $00 (00)
-// Value <text string according to encoding>
-func readTextWithDescrFrame(b []byte, hasLang bool, encoded bool) (*Comm, error) {
- enc := b[0]
- b = b[1:]
-
- c := &Comm{}
- if hasLang {
- c.Language = string(b[:3])
- b = b[3:]
- }
-
- descTextSplit := dataSplit(b, enc)
- if len(descTextSplit) < 1 {
- return nil, fmt.Errorf("error decoding tag description text: invalid encoding")
- }
-
- desc, err := decodeText(enc, descTextSplit[0])
- if err != nil {
- return nil, fmt.Errorf("error decoding tag description text: %v", err)
- }
- c.Description = desc
-
- if len(descTextSplit) == 1 {
- return c, nil
- }
-
- if !encoded {
- enc = byte(0)
- }
- text, err := decodeText(enc, descTextSplit[1])
- if err != nil {
- return nil, fmt.Errorf("error decoding tag text: %v", err)
- }
- c.Text = text
-
- return c, nil
-}
-
-// UFID is composed of a provider (frequently a URL and a binary identifier)
-// The identifier can be a text (Musicbrainz use texts, but not necessary)
-type UFID struct {
- Provider string
- Identifier []byte
-}
-
-func (u UFID) String() string {
- return fmt.Sprintf("%v (%v)", u.Provider, string(u.Identifier))
-}
-
-func readUFID(b []byte) (*UFID, error) {
- result := bytes.SplitN(b, singleZero, 2)
- if len(result) != 2 {
- return nil, errors.New("expected to split UFID data into 2 pieces")
- }
-
- return &UFID{
- Provider: string(result[0]),
- Identifier: result[1],
- }, nil
-}
-
-var pictureTypes = map[byte]string{
- 0x00: "Other",
- 0x01: "32x32 pixels 'file icon' (PNG only)",
- 0x02: "Other file icon",
- 0x03: "Cover (front)",
- 0x04: "Cover (back)",
- 0x05: "Leaflet page",
- 0x06: "Media (e.g. lable side of CD)",
- 0x07: "Lead artist/lead performer/soloist",
- 0x08: "Artist/performer",
- 0x09: "Conductor",
- 0x0A: "Band/Orchestra",
- 0x0B: "Composer",
- 0x0C: "Lyricist/text writer",
- 0x0D: "Recording Location",
- 0x0E: "During recording",
- 0x0F: "During performance",
- 0x10: "Movie/video screen capture",
- 0x11: "A bright coloured fish",
- 0x12: "Illustration",
- 0x13: "Band/artist logotype",
- 0x14: "Publisher/Studio logotype",
-}
-
-// Picture is a type which represents an attached picture extracted from metadata.
-type Picture struct {
- Ext string // Extension of the picture file.
- MIMEType string // MIMEType of the picture.
- Type string // Type of the picture (see pictureTypes).
- Description string // Description.
- Data []byte // Raw picture data.
-}
-
-// String returns a string representation of the underlying Picture instance.
-func (p Picture) String() string {
- return fmt.Sprintf("Picture{Ext: %v, MIMEType: %v, Type: %v, Description: %v, Data.Size: %v}",
- p.Ext, p.MIMEType, p.Type, p.Description, len(p.Data))
-}
-
-// IDv2.2
-// -- Header
-// Attached picture "PIC"
-// Frame size $xx xx xx
-// -- readPICFrame
-// Text encoding $xx
-// Image format $xx xx xx
-// Picture type $xx
-// Description <textstring> $00 (00)
-// Picture data <binary data>
-func readPICFrame(b []byte) (*Picture, error) {
- enc := b[0]
- ext := string(b[1:4])
- picType := b[4]
-
- descDataSplit := dataSplit(b[5:], enc)
- if len(descDataSplit) != 2 {
- return nil, errors.New("error decoding PIC description text: invalid encoding")
- }
- desc, err := decodeText(enc, descDataSplit[0])
- if err != nil {
- return nil, fmt.Errorf("error decoding PIC description text: %v", err)
- }
-
- var mimeType string
- switch ext {
- case "jpeg", "jpg":
- mimeType = "image/jpeg"
- case "png":
- mimeType = "image/png"
- }
-
- return &Picture{
- Ext: ext,
- MIMEType: mimeType,
- Type: pictureTypes[picType],
- Description: desc,
- Data: descDataSplit[1],
- }, nil
-}
-
-// IDv2.{3,4}
-// -- Header
-// <Header for 'Attached picture', ID: "APIC">
-// -- readAPICFrame
-// Text encoding $xx
-// MIME type <text string> $00
-// Picture type $xx
-// Description <text string according to encoding> $00 (00)
-// Picture data <binary data>
-func readAPICFrame(b []byte) (*Picture, error) {
- enc := b[0]
- mimeDataSplit := bytes.SplitN(b[1:], singleZero, 2)
- mimeType := string(mimeDataSplit[0])
-
- b = mimeDataSplit[1]
- if len(b) < 1 {
- return nil, fmt.Errorf("error decoding APIC mimetype")
- }
- picType := b[0]
-
- descDataSplit := dataSplit(b[1:], enc)
- if len(descDataSplit) != 2 {
- return nil, errors.New("error decoding APIC description text: invalid encoding")
- }
- desc, err := decodeText(enc, descDataSplit[0])
- if err != nil {
- return nil, fmt.Errorf("error decoding APIC description text: %v", err)
- }
-
- var ext string
- switch mimeType {
- case "image/jpeg":
- ext = "jpg"
- case "image/png":
- ext = "png"
- }
-
- return &Picture{
- Ext: ext,
- MIMEType: mimeType,
- Type: pictureTypes[picType],
- Description: desc,
- Data: descDataSplit[1],
- }, nil
-}
diff --git a/vendor/github.com/dhowden/tag/id3v2metadata.go b/vendor/github.com/dhowden/tag/id3v2metadata.go
deleted file mode 100644
index 6185963..0000000
--- a/vendor/github.com/dhowden/tag/id3v2metadata.go
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "strconv"
- "strings"
-)
-
-type frameNames map[string][2]string
-
-func (f frameNames) Name(s string, fm Format) string {
- l, ok := f[s]
- if !ok {
- return ""
- }
-
- switch fm {
- case ID3v2_2:
- return l[0]
- case ID3v2_3:
- return l[1]
- case ID3v2_4:
- if s == "year" {
- return "TDRC"
- }
- return l[1]
- }
- return ""
-}
-
-var frames = frameNames(map[string][2]string{
- "title": [2]string{"TT2", "TIT2"},
- "artist": [2]string{"TP1", "TPE1"},
- "album": [2]string{"TAL", "TALB"},
- "album_artist": [2]string{"TP2", "TPE2"},
- "composer": [2]string{"TCM", "TCOM"},
- "year": [2]string{"TYE", "TYER"},
- "track": [2]string{"TRK", "TRCK"},
- "disc": [2]string{"TPA", "TPOS"},
- "genre": [2]string{"TCO", "TCON"},
- "picture": [2]string{"PIC", "APIC"},
- "lyrics": [2]string{"", "USLT"},
- "comment": [2]string{"COM", "COMM"},
-})
-
-// metadataID3v2 is the implementation of Metadata used for ID3v2 tags.
-type metadataID3v2 struct {
- header *id3v2Header
- frames map[string]interface{}
-}
-
-func (m metadataID3v2) getString(k string) string {
- v, ok := m.frames[k]
- if !ok {
- return ""
- }
- return v.(string)
-}
-
-func (m metadataID3v2) Format() Format { return m.header.Version }
-func (m metadataID3v2) FileType() FileType { return MP3 }
-func (m metadataID3v2) Raw() map[string]interface{} { return m.frames }
-
-func (m metadataID3v2) Title() string {
- return m.getString(frames.Name("title", m.Format()))
-}
-
-func (m metadataID3v2) Artist() string {
- return m.getString(frames.Name("artist", m.Format()))
-}
-
-func (m metadataID3v2) Album() string {
- return m.getString(frames.Name("album", m.Format()))
-}
-
-func (m metadataID3v2) AlbumArtist() string {
- return m.getString(frames.Name("album_artist", m.Format()))
-}
-
-func (m metadataID3v2) Composer() string {
- return m.getString(frames.Name("composer", m.Format()))
-}
-
-func (m metadataID3v2) Genre() string {
- return id3v2genre(m.getString(frames.Name("genre", m.Format())))
-}
-
-func (m metadataID3v2) Year() int {
- year, _ := strconv.Atoi(m.getString(frames.Name("year", m.Format())))
- return year
-}
-
-func parseXofN(s string) (x, n int) {
- xn := strings.Split(s, "/")
- if len(xn) != 2 {
- x, _ = strconv.Atoi(s)
- return x, 0
- }
- x, _ = strconv.Atoi(strings.TrimSpace(xn[0]))
- n, _ = strconv.Atoi(strings.TrimSpace(xn[1]))
- return x, n
-}
-
-func (m metadataID3v2) Track() (int, int) {
- return parseXofN(m.getString(frames.Name("track", m.Format())))
-}
-
-func (m metadataID3v2) Disc() (int, int) {
- return parseXofN(m.getString(frames.Name("disc", m.Format())))
-}
-
-func (m metadataID3v2) Lyrics() string {
- t, ok := m.frames[frames.Name("lyrics", m.Format())]
- if !ok {
- return ""
- }
- return t.(*Comm).Text
-}
-
-func (m metadataID3v2) Comment() string {
- t, ok := m.frames[frames.Name("comment", m.Format())]
- if !ok {
- return ""
- }
- // id3v23 has Text, id3v24 has Description
- if t.(*Comm).Description == "" {
- return trimString(t.(*Comm).Text)
- }
- return trimString(t.(*Comm).Description)
-}
-
-func (m metadataID3v2) Picture() *Picture {
- v, ok := m.frames[frames.Name("picture", m.Format())]
- if !ok {
- return nil
- }
- return v.(*Picture)
-}
diff --git a/vendor/github.com/dhowden/tag/internal/id3v1_test/NOTICE.txt b/vendor/github.com/dhowden/tag/internal/id3v1_test/NOTICE.txt
deleted file mode 100644
index f7e01d8..0000000
--- a/vendor/github.com/dhowden/tag/internal/id3v1_test/NOTICE.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-All files in this directory are subject to the CC0 1.0 Universal (CC0 1.0)
-Public Domain Dedication license. Its contents can be found at:
-http://creativecommons.org/publicdomain/zero/1.0
diff --git a/vendor/github.com/dhowden/tag/mp4.go b/vendor/github.com/dhowden/tag/mp4.go
deleted file mode 100644
index 4c3dd59..0000000
--- a/vendor/github.com/dhowden/tag/mp4.go
+++ /dev/null
@@ -1,372 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "strconv"
- "strings"
-)
-
-var atomTypes = map[int]string{
- 0: "implicit", // automatic based on atom name
- 1: "text",
- 13: "jpeg",
- 14: "png",
- 21: "uint8",
-}
-
-// NB: atoms does not include "----", this is handled separately
-var atoms = atomNames(map[string]string{
- "\xa9alb": "album",
- "\xa9art": "artist",
- "\xa9ART": "artist",
- "aART": "album_artist",
- "\xa9day": "year",
- "\xa9nam": "title",
- "\xa9gen": "genre",
- "trkn": "track",
- "\xa9wrt": "composer",
- "\xa9too": "encoder",
- "cprt": "copyright",
- "covr": "picture",
- "\xa9grp": "grouping",
- "keyw": "keyword",
- "\xa9lyr": "lyrics",
- "\xa9cmt": "comment",
- "tmpo": "tempo",
- "cpil": "compilation",
- "disk": "disc",
-})
-
-// Detect PNG image if "implicit" class is used
-var pngHeader = []byte{137, 80, 78, 71, 13, 10, 26, 10}
-
-type atomNames map[string]string
-
-func (f atomNames) Name(n string) []string {
- res := make([]string, 1)
- for k, v := range f {
- if v == n {
- res = append(res, k)
- }
- }
- return res
-}
-
-// metadataMP4 is the implementation of Metadata for MP4 tag (atom) data.
-type metadataMP4 struct {
- fileType FileType
- data map[string]interface{}
-}
-
-// ReadAtoms reads MP4 metadata atoms from the io.ReadSeeker into a Metadata, returning
-// non-nil error if there was a problem.
-func ReadAtoms(r io.ReadSeeker) (Metadata, error) {
- m := metadataMP4{
- data: make(map[string]interface{}),
- fileType: UnknownFileType,
- }
- err := m.readAtoms(r)
- return m, err
-}
-
-func (m metadataMP4) readAtoms(r io.ReadSeeker) error {
- for {
- name, size, err := readAtomHeader(r)
- if err != nil {
- if err == io.EOF {
- return nil
- }
- return err
- }
-
- switch name {
- case "meta":
- // next_item_id (int32)
- _, err := readBytes(r, 4)
- if err != nil {
- return err
- }
- fallthrough
-
- case "moov", "udta", "ilst":
- return m.readAtoms(r)
- }
-
- _, ok := atoms[name]
- var data []string
- if name == "----" {
- name, data, err = readCustomAtom(r, size)
- if err != nil {
- return err
- }
-
- if name != "----" {
- ok = true
- size = 0 // already read data
- }
- }
-
- if !ok {
- _, err := r.Seek(int64(size-8), io.SeekCurrent)
- if err != nil {
- return err
- }
- continue
- }
-
- err = m.readAtomData(r, name, size-8, data)
- if err != nil {
- return err
- }
- }
-}
-
-func (m metadataMP4) readAtomData(r io.ReadSeeker, name string, size uint32, processedData []string) error {
- var b []byte
- var err error
- var contentType string
- if len(processedData) > 0 {
- b = []byte(strings.Join(processedData, ";")) // add delimiter if multiple data fields
- contentType = "text"
- } else {
- // read the data
- b, err = readBytes(r, int(size))
- if err != nil {
- return err
- }
- if len(b) < 8 {
- return fmt.Errorf("invalid encoding: expected at least %d bytes, got %d", 8, len(b))
- }
-
- // "data" + size (4 bytes each)
- b = b[8:]
-
- if len(b) < 3 {
- return fmt.Errorf("invalid encoding: expected at least %d bytes, for class, got %d", 3, len(b))
- }
- class := getInt(b[1:4])
- var ok bool
- contentType, ok = atomTypes[class]
- if !ok {
- return fmt.Errorf("invalid content type: %v (%x) (%x)", class, b[1:4], b)
- }
-
- // 4: atom version (1 byte) + atom flags (3 bytes)
- // 4: NULL (usually locale indicator)
- if len(b) < 8 {
- return fmt.Errorf("invalid encoding: expected at least %d bytes, for atom version and flags, got %d", 8, len(b))
- }
- b = b[8:]
- }
-
- if name == "trkn" || name == "disk" {
- if len(b) < 6 {
- return fmt.Errorf("invalid encoding: expected at least %d bytes, for track and disk numbers, got %d", 6, len(b))
- }
-
- m.data[name] = int(b[3])
- m.data[name+"_count"] = int(b[5])
- return nil
- }
-
- if contentType == "implicit" {
- if name == "covr" {
- if bytes.HasPrefix(b, pngHeader) {
- contentType = "png"
- }
- // TODO(dhowden): Detect JPEG formats too (harder).
- }
- }
-
- var data interface{}
- switch contentType {
- case "implicit":
- if _, ok := atoms[name]; ok {
- return fmt.Errorf("unhandled implicit content type for required atom: %q", name)
- }
- return nil
-
- case "text":
- data = string(b)
-
- case "uint8":
- if len(b) < 1 {
- return fmt.Errorf("invalid encoding: expected at least %d bytes, for integer tag data, got %d", 1, len(b))
- }
- data = getInt(b[:1])
-
- case "jpeg", "png":
- data = &Picture{
- Ext: contentType,
- MIMEType: "image/" + contentType,
- Data: b,
- }
- }
- m.data[name] = data
-
- return nil
-}
-
-func readAtomHeader(r io.ReadSeeker) (name string, size uint32, err error) {
- err = binary.Read(r, binary.BigEndian, &size)
- if err != nil {
- return
- }
- name, err = readString(r, 4)
- return
-}
-
-// Generic atom.
-// Should have 3 sub atoms : mean, name and data.
-// We check that mean is "com.apple.iTunes" and we use the subname as
-// the name, and move to the data atom.
-// Data atom could have multiple data values, each with a header.
-// If anything goes wrong, we jump at the end of the "----" atom.
-func readCustomAtom(r io.ReadSeeker, size uint32) (_ string, data []string, _ error) {
- subNames := make(map[string]string)
-
- for size > 8 {
- subName, subSize, err := readAtomHeader(r)
- if err != nil {
- return "", nil, err
- }
-
- // Remove the size of the atom from the size counter
- if size >= subSize {
- size -= subSize
- } else {
- return "", nil, errors.New("--- invalid size")
- }
-
- b, err := readBytes(r, int(subSize-8))
- if err != nil {
- return "", nil, err
- }
-
- if len(b) < 4 {
- return "", nil, fmt.Errorf("invalid encoding: expected at least %d bytes, got %d", 4, len(b))
- }
- switch subName {
- case "mean", "name":
- subNames[subName] = string(b[4:])
- case "data":
- data = append(data, string(b[4:]))
- }
- }
-
- // there should remain only the header size
- if size != 8 {
- err := errors.New("---- atom out of bounds")
- return "", nil, err
- }
-
- if subNames["mean"] != "com.apple.iTunes" || subNames["name"] == "" || len(data) == 0 {
- return "----", nil, nil
- }
- return subNames["name"], data, nil
-}
-
-func (metadataMP4) Format() Format { return MP4 }
-func (m metadataMP4) FileType() FileType { return m.fileType }
-
-func (m metadataMP4) Raw() map[string]interface{} { return m.data }
-
-func (m metadataMP4) getString(n []string) string {
- for _, k := range n {
- if x, ok := m.data[k]; ok {
- return x.(string)
- }
- }
- return ""
-}
-
-func (m metadataMP4) getInt(n []string) int {
- for _, k := range n {
- if x, ok := m.data[k]; ok {
- return x.(int)
- }
- }
- return 0
-}
-
-func (m metadataMP4) Title() string {
- return m.getString(atoms.Name("title"))
-}
-
-func (m metadataMP4) Artist() string {
- return m.getString(atoms.Name("artist"))
-}
-
-func (m metadataMP4) Album() string {
- return m.getString(atoms.Name("album"))
-}
-
-func (m metadataMP4) AlbumArtist() string {
- return m.getString(atoms.Name("album_artist"))
-}
-
-func (m metadataMP4) Composer() string {
- return m.getString(atoms.Name("composer"))
-}
-
-func (m metadataMP4) Genre() string {
- return m.getString(atoms.Name("genre"))
-}
-
-func (m metadataMP4) Year() int {
- date := m.getString(atoms.Name("year"))
- if len(date) >= 4 {
- year, _ := strconv.Atoi(date[:4])
- return year
- }
- return 0
-}
-
-func (m metadataMP4) Track() (int, int) {
- x := m.getInt([]string{"trkn"})
- if n, ok := m.data["trkn_count"]; ok {
- return x, n.(int)
- }
- return x, 0
-}
-
-func (m metadataMP4) Disc() (int, int) {
- x := m.getInt([]string{"disk"})
- if n, ok := m.data["disk_count"]; ok {
- return x, n.(int)
- }
- return x, 0
-}
-
-func (m metadataMP4) Lyrics() string {
- t, ok := m.data["\xa9lyr"]
- if !ok {
- return ""
- }
- return t.(string)
-}
-
-func (m metadataMP4) Comment() string {
- t, ok := m.data["\xa9cmt"]
- if !ok {
- return ""
- }
- return t.(string)
-}
-
-func (m metadataMP4) Picture() *Picture {
- v, ok := m.data["covr"]
- if !ok {
- return nil
- }
- p, _ := v.(*Picture)
- return p
-}
diff --git a/vendor/github.com/dhowden/tag/ogg.go b/vendor/github.com/dhowden/tag/ogg.go
deleted file mode 100644
index bc26d4a..0000000
--- a/vendor/github.com/dhowden/tag/ogg.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "errors"
- "io"
-)
-
-const (
- idType int = 1
- commentType int = 3
-)
-
-// ReadOGGTags reads OGG metadata from the io.ReadSeeker, returning the resulting
-// metadata in a Metadata implementation, or non-nil error if there was a problem.
-// See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
-// and http://www.xiph.org/ogg/doc/framing.html for details.
-func ReadOGGTags(r io.ReadSeeker) (Metadata, error) {
- oggs, err := readString(r, 4)
- if err != nil {
- return nil, err
- }
- if oggs != "OggS" {
- return nil, errors.New("expected 'OggS'")
- }
-
- // Skip 22 bytes of Page header to read page_segments length byte at position 26
- // See http://www.xiph.org/ogg/doc/framing.html
- _, err = r.Seek(22, io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- nS, err := readInt(r, 1)
- if err != nil {
- return nil, err
- }
-
- // Seek and discard the segments
- _, err = r.Seek(int64(nS), io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- // First packet type is identification, type 1
- t, err := readInt(r, 1)
- if err != nil {
- return nil, err
- }
- if t != idType {
- return nil, errors.New("expected 'vorbis' identification type 1")
- }
-
- // Seek and discard 29 bytes from common and identification header
- // See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-610004.2
- _, err = r.Seek(29, io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- // Beginning of a new page. Comment packet is on a separate page
- // See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2
- oggs, err = readString(r, 4)
- if err != nil {
- return nil, err
- }
- if oggs != "OggS" {
- return nil, errors.New("expected 'OggS'")
- }
-
- // Skip page 2 header, same as line 30
- _, err = r.Seek(22, io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- nS, err = readInt(r, 1)
- if err != nil {
- return nil, err
- }
-
- _, err = r.Seek(int64(nS), io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- // Packet type is comment, type 3
- t, err = readInt(r, 1)
- if err != nil {
- return nil, err
- }
- if t != commentType {
- return nil, errors.New("expected 'vorbis' comment type 3")
- }
-
- // Seek and discard 6 bytes from common header
- _, err = r.Seek(6, io.SeekCurrent)
- if err != nil {
- return nil, err
- }
-
- m := &metadataOGG{
- newMetadataVorbis(),
- }
-
- err = m.readVorbisComment(r)
- return m, err
-}
-
-type metadataOGG struct {
- *metadataVorbis
-}
-
-func (m *metadataOGG) FileType() FileType {
- return OGG
-}
diff --git a/vendor/github.com/dhowden/tag/sum.go b/vendor/github.com/dhowden/tag/sum.go
deleted file mode 100644
index 97b27a7..0000000
--- a/vendor/github.com/dhowden/tag/sum.go
+++ /dev/null
@@ -1,219 +0,0 @@
-package tag
-
-import (
- "crypto/sha1"
- "encoding/binary"
- "errors"
- "fmt"
- "hash"
- "io"
-)
-
-// Sum creates a checksum of the audio file data provided by the io.ReadSeeker which is metadata
-// (ID3, MP4) invariant.
-func Sum(r io.ReadSeeker) (string, error) {
- b, err := readBytes(r, 11)
- if err != nil {
- return "", err
- }
-
- _, err = r.Seek(-11, io.SeekCurrent)
- if err != nil {
- return "", fmt.Errorf("could not seek back to original position: %v", err)
- }
-
- switch {
- case string(b[0:4]) == "fLaC":
- return SumFLAC(r)
-
- case string(b[4:11]) == "ftypM4A":
- return SumAtoms(r)
-
- case string(b[0:3]) == "ID3":
- return SumID3v2(r)
- }
-
- h, err := SumID3v1(r)
- if err != nil {
- if err == ErrNotID3v1 {
- return SumAll(r)
- }
- return "", err
- }
- return h, nil
-}
-
-// SumAll returns a checksum of the content from the reader (until EOF).
-func SumAll(r io.ReadSeeker) (string, error) {
- h := sha1.New()
- _, err := io.Copy(h, r)
- if err != nil {
- return "", nil
- }
- return hashSum(h), nil
-}
-
-// SumAtoms constructs a checksum of MP4 audio file data provided by the io.ReadSeeker which is
-// metadata invariant.
-func SumAtoms(r io.ReadSeeker) (string, error) {
- for {
- var size uint32
- err := binary.Read(r, binary.BigEndian, &size)
- if err != nil {
- if err == io.EOF {
- return "", fmt.Errorf("reached EOF before audio data")
- }
- return "", err
- }
-
- name, err := readString(r, 4)
- if err != nil {
- return "", err
- }
-
- switch name {
- case "meta":
- // next_item_id (int32)
- _, err := r.Seek(4, io.SeekCurrent)
- if err != nil {
- return "", err
- }
- fallthrough
-
- case "moov", "udta", "ilst":
- continue
-
- case "mdat": // stop when we get to the data
- h := sha1.New()
- _, err := io.CopyN(h, r, int64(size-8))
- if err != nil {
- return "", fmt.Errorf("error reading audio data: %v", err)
- }
- return hashSum(h), nil
- }
-
- _, err = r.Seek(int64(size-8), io.SeekCurrent)
- if err != nil {
- return "", fmt.Errorf("error reading '%v' tag: %v", name, err)
- }
- }
-}
-
-func sizeToEndOffset(r io.ReadSeeker, offset int64) (int64, error) {
- n, err := r.Seek(-128, io.SeekEnd)
- if err != nil {
- return 0, fmt.Errorf("error seeking end offset (%d bytes): %v", offset, err)
- }
-
- _, err = r.Seek(-n, io.SeekCurrent)
- if err != nil {
- return 0, fmt.Errorf("error seeking back to original position: %v", err)
- }
- return n, nil
-}
-
-// SumID3v1 constructs a checksum of MP3 audio file data (assumed to have ID3v1 tags) provided
-// by the io.ReadSeeker which is metadata invariant.
-func SumID3v1(r io.ReadSeeker) (string, error) {
- n, err := sizeToEndOffset(r, 128)
- if err != nil {
- return "", fmt.Errorf("error determining read size to ID3v1 header: %v", err)
- }
-
- // TODO: improve this check???
- if n <= 0 {
- return "", fmt.Errorf("file size must be greater than 128 bytes (ID3v1 header size) for MP3")
- }
-
- h := sha1.New()
- _, err = io.CopyN(h, r, n)
- if err != nil {
- return "", fmt.Errorf("error reading %v bytes: %v", n, err)
- }
- return hashSum(h), nil
-}
-
-// SumID3v2 constructs a checksum of MP3 audio file data (assumed to have ID3v2 tags) provided by the
-// io.ReadSeeker which is metadata invariant.
-func SumID3v2(r io.ReadSeeker) (string, error) {
- header, _, err := readID3v2Header(r)
- if err != nil {
- return "", fmt.Errorf("error reading ID3v2 header: %v", err)
- }
-
- _, err = r.Seek(int64(header.Size), io.SeekCurrent)
- if err != nil {
- return "", fmt.Errorf("error seeking to end of ID3V2 header: %v", err)
- }
-
- n, err := sizeToEndOffset(r, 128)
- if err != nil {
- return "", fmt.Errorf("error determining read size to ID3v1 header: %v", err)
- }
-
- // TODO: remove this check?????
- if n < 0 {
- return "", fmt.Errorf("file size must be greater than 128 bytes for MP3: %v bytes", n)
- }
-
- h := sha1.New()
- _, err = io.CopyN(h, r, n)
- if err != nil {
- return "", fmt.Errorf("error reading %v bytes: %v", n, err)
- }
- return hashSum(h), nil
-}
-
-// SumFLAC costructs a checksum of the FLAC audio file data provided by the io.ReadSeeker (ignores
-// metadata fields).
-func SumFLAC(r io.ReadSeeker) (string, error) {
- flac, err := readString(r, 4)
- if err != nil {
- return "", err
- }
- if flac != "fLaC" {
- return "", errors.New("expected 'fLaC'")
- }
-
- for {
- last, err := skipFLACMetadataBlock(r)
- if err != nil {
- return "", err
- }
-
- if last {
- break
- }
- }
-
- h := sha1.New()
- _, err = io.Copy(h, r)
- if err != nil {
- return "", fmt.Errorf("error reading data bytes from FLAC: %v", err)
- }
- return hashSum(h), nil
-}
-
-func skipFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
- blockHeader, err := readBytes(r, 1)
- if err != nil {
- return
- }
-
- if getBit(blockHeader[0], 7) {
- blockHeader[0] ^= (1 << 7)
- last = true
- }
-
- blockLen, err := readInt(r, 3)
- if err != nil {
- return
- }
-
- _, err = r.Seek(int64(blockLen), io.SeekCurrent)
- return
-}
-
-func hashSum(h hash.Hash) string {
- return fmt.Sprintf("%x", h.Sum([]byte{}))
-}
diff --git a/vendor/github.com/dhowden/tag/tag.go b/vendor/github.com/dhowden/tag/tag.go
deleted file mode 100644
index 306f1d7..0000000
--- a/vendor/github.com/dhowden/tag/tag.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package tag provides MP3 (ID3: v1, 2.2, 2.3 and 2.4), MP4, FLAC and OGG metadata detection,
-// parsing and artwork extraction.
-//
-// Detect and parse tag metadata from an io.ReadSeeker (i.e. an *os.File):
-// m, err := tag.ReadFrom(f)
-// if err != nil {
-// log.Fatal(err)
-// }
-// log.Print(m.Format()) // The detected format.
-// log.Print(m.Title()) // The title of the track (see Metadata interface for more details).
-package tag
-
-import (
- "errors"
- "fmt"
- "io"
-)
-
-// ErrNoTagsFound is the error returned by ReadFrom when the metadata format
-// cannot be identified.
-var ErrNoTagsFound = errors.New("no tags found")
-
-// ReadFrom detects and parses audio file metadata tags (currently supports ID3v1,2.{2,3,4}, MP4, FLAC/OGG).
-// Returns non-nil error if the format of the given data could not be determined, or if there was a problem
-// parsing the data.
-func ReadFrom(r io.ReadSeeker) (Metadata, error) {
- b, err := readBytes(r, 11)
- if err != nil {
- return nil, err
- }
-
- _, err = r.Seek(-11, io.SeekCurrent)
- if err != nil {
- return nil, fmt.Errorf("could not seek back to original position: %v", err)
- }
-
- switch {
- case string(b[0:4]) == "fLaC":
- return ReadFLACTags(r)
-
- case string(b[0:4]) == "OggS":
- return ReadOGGTags(r)
-
- case string(b[4:8]) == "ftyp":
- return ReadAtoms(r)
-
- case string(b[0:3]) == "ID3":
- return ReadID3v2Tags(r)
-
- case string(b[0:4]) == "DSD ":
- return ReadDSFTags(r)
- }
-
- m, err := ReadID3v1Tags(r)
- if err != nil {
- if err == ErrNotID3v1 {
- err = ErrNoTagsFound
- }
- return nil, err
- }
- return m, nil
-}
-
-// Format is an enumeration of metadata types supported by this package.
-type Format string
-
-// Supported tag formats.
-const (
- UnknownFormat Format = "" // Unknown Format.
- ID3v1 Format = "ID3v1" // ID3v1 tag format.
- ID3v2_2 Format = "ID3v2.2" // ID3v2.2 tag format.
- ID3v2_3 Format = "ID3v2.3" // ID3v2.3 tag format (most common).
- ID3v2_4 Format = "ID3v2.4" // ID3v2.4 tag format.
- MP4 Format = "MP4" // MP4 tag (atom) format (see http://www.ftyps.com/ for a full file type list)
- VORBIS Format = "VORBIS" // Vorbis Comment tag format.
-)
-
-// FileType is an enumeration of the audio file types supported by this package, in particular
-// there are audio file types which share metadata formats, and this type is used to distinguish
-// between them.
-type FileType string
-
-// Supported file types.
-const (
- UnknownFileType FileType = "" // Unknown FileType.
- MP3 FileType = "MP3" // MP3 file
- M4A FileType = "M4A" // M4A file Apple iTunes (ACC) Audio
- M4B FileType = "M4B" // M4A file Apple iTunes (ACC) Audio Book
- M4P FileType = "M4P" // M4A file Apple iTunes (ACC) AES Protected Audio
- ALAC FileType = "ALAC" // Apple Lossless file FIXME: actually detect this
- FLAC FileType = "FLAC" // FLAC file
- OGG FileType = "OGG" // OGG file
- DSF FileType = "DSF" // DSF file DSD Sony format see https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
-)
-
-// Metadata is an interface which is used to describe metadata retrieved by this package.
-type Metadata interface {
- // Format returns the metadata Format used to encode the data.
- Format() Format
-
- // FileType returns the file type of the audio file.
- FileType() FileType
-
- // Title returns the title of the track.
- Title() string
-
- // Album returns the album name of the track.
- Album() string
-
- // Artist returns the artist name of the track.
- Artist() string
-
- // AlbumArtist returns the album artist name of the track.
- AlbumArtist() string
-
- // Composer returns the composer of the track.
- Composer() string
-
- // Year returns the year of the track.
- Year() int
-
- // Genre returns the genre of the track.
- Genre() string
-
- // Track returns the track number and total tracks, or zero values if unavailable.
- Track() (int, int)
-
- // Disc returns the disc number and total discs, or zero values if unavailable.
- Disc() (int, int)
-
- // Picture returns a picture, or nil if not available.
- Picture() *Picture
-
- // Lyrics returns the lyrics, or an empty string if unavailable.
- Lyrics() string
-
- // Comment returns the comment, or an empty string if unavailable.
- Comment() string
-
- // Raw returns the raw mapping of retrieved tag names and associated values.
- // NB: tag/atom names are not standardised between formats.
- Raw() map[string]interface{}
-}
diff --git a/vendor/github.com/dhowden/tag/util.go b/vendor/github.com/dhowden/tag/util.go
deleted file mode 100644
index ff9c4f1..0000000
--- a/vendor/github.com/dhowden/tag/util.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "encoding/binary"
- "io"
-)
-
-func getBit(b byte, n uint) bool {
- x := byte(1 << n)
- return (b & x) == x
-}
-
-func get7BitChunkedInt(b []byte) int {
- var n int
- for _, x := range b {
- n = n << 7
- n |= int(x)
- }
- return n
-}
-
-func getInt(b []byte) int {
- var n int
- for _, x := range b {
- n = n << 8
- n |= int(x)
- }
- return n
-}
-
-func getIntLittleEndian(b []byte) int {
- var n int
- for i := len(b) - 1; i >= 0; i-- {
- n = n << 8
- n |= int(b[i])
- }
- return n
-}
-
-func readBytes(r io.Reader, n int) ([]byte, error) {
- b := make([]byte, n)
- _, err := io.ReadFull(r, b)
- if err != nil {
- return nil, err
- }
- return b, nil
-}
-
-func readString(r io.Reader, n int) (string, error) {
- b, err := readBytes(r, n)
- if err != nil {
- return "", err
- }
- return string(b), nil
-}
-
-func readInt(r io.Reader, n int) (int, error) {
- b, err := readBytes(r, n)
- if err != nil {
- return 0, err
- }
- return getInt(b), nil
-}
-
-func read7BitChunkedInt(r io.Reader, n int) (int, error) {
- b, err := readBytes(r, n)
- if err != nil {
- return 0, err
- }
- return get7BitChunkedInt(b), nil
-}
-
-func readInt32LittleEndian(r io.Reader) (int, error) {
- var n int32
- err := binary.Read(r, binary.LittleEndian, &n)
- return int(n), err
-}
diff --git a/vendor/github.com/dhowden/tag/vorbis.go b/vendor/github.com/dhowden/tag/vorbis.go
deleted file mode 100644
index 9f5ecb8..0000000
--- a/vendor/github.com/dhowden/tag/vorbis.go
+++ /dev/null
@@ -1,255 +0,0 @@
-// Copyright 2015, David Howden
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package tag
-
-import (
- "errors"
- "fmt"
- "io"
- "strconv"
- "strings"
- "time"
-)
-
-func newMetadataVorbis() *metadataVorbis {
- return &metadataVorbis{
- c: make(map[string]string),
- }
-}
-
-type metadataVorbis struct {
- c map[string]string // the vorbis comments
- p *Picture
-}
-
-func (m *metadataVorbis) readVorbisComment(r io.Reader) error {
- vendorLen, err := readInt32LittleEndian(r)
- if err != nil {
- return err
- }
-
- if vendorLen < 0 {
- return fmt.Errorf("invalid encoding: expected positive length, got %d", vendorLen)
- }
-
- vendor, err := readString(r, vendorLen)
- if err != nil {
- return err
- }
- m.c["vendor"] = vendor
-
- commentsLen, err := readInt32LittleEndian(r)
- if err != nil {
- return err
- }
-
- for i := 0; i < commentsLen; i++ {
- l, err := readInt32LittleEndian(r)
- if err != nil {
- return err
- }
- s, err := readString(r, l)
- if err != nil {
- return err
- }
- k, v, err := parseComment(s)
- if err != nil {
- return err
- }
- m.c[strings.ToLower(k)] = v
- }
- return nil
-}
-
-func (m *metadataVorbis) readPictureBlock(r io.Reader) error {
- b, err := readInt(r, 4)
- if err != nil {
- return err
- }
- pictureType, ok := pictureTypes[byte(b)]
- if !ok {
- return fmt.Errorf("invalid picture type: %v", b)
- }
- mimeLen, err := readInt(r, 4)
- if err != nil {
- return err
- }
- mime, err := readString(r, mimeLen)
- if err != nil {
- return err
- }
-
- ext := ""
- switch mime {
- case "image/jpeg":
- ext = "jpg"
- case "image/png":
- ext = "png"
- case "image/gif":
- ext = "gif"
- }
-
- descLen, err := readInt(r, 4)
- if err != nil {
- return err
- }
- desc, err := readString(r, descLen)
- if err != nil {
- return err
- }
-
- // We skip width <32>, height <32>, colorDepth <32>, coloresUsed <32>
- _, err = readInt(r, 4) // width
- if err != nil {
- return err
- }
- _, err = readInt(r, 4) // height
- if err != nil {
- return err
- }
- _, err = readInt(r, 4) // color depth
- if err != nil {
- return err
- }
- _, err = readInt(r, 4) // colors used
- if err != nil {
- return err
- }
-
- dataLen, err := readInt(r, 4)
- if err != nil {
- return err
- }
- data := make([]byte, dataLen)
- _, err = io.ReadFull(r, data)
- if err != nil {
- return err
- }
-
- m.p = &Picture{
- Ext: ext,
- MIMEType: mime,
- Type: pictureType,
- Description: desc,
- Data: data,
- }
- return nil
-}
-
-func parseComment(c string) (k, v string, err error) {
- kv := strings.SplitN(c, "=", 2)
- if len(kv) != 2 {
- err = errors.New("vorbis comment must contain '='")
- return
- }
- k = kv[0]
- v = kv[1]
- return
-}
-
-func (m *metadataVorbis) Format() Format {
- return VORBIS
-}
-
-func (m *metadataVorbis) Raw() map[string]interface{} {
- raw := make(map[string]interface{}, len(m.c))
- for k, v := range m.c {
- raw[k] = v
- }
- return raw
-}
-
-func (m *metadataVorbis) Title() string {
- return m.c["title"]
-}
-
-func (m *metadataVorbis) Artist() string {
- // PERFORMER
- // The artist(s) who performed the work. In classical music this would be the
- // conductor, orchestra, soloists. In an audio book it would be the actor who
- // did the reading. In popular music this is typically the same as the ARTIST
- // and is omitted.
- if m.c["performer"] != "" {
- return m.c["performer"]
- }
- return m.c["artist"]
-}
-
-func (m *metadataVorbis) Album() string {
- return m.c["album"]
-}
-
-func (m *metadataVorbis) AlbumArtist() string {
- // This field isn't actually included in the standard, though
- // it is commonly assigned to albumartist.
- return m.c["albumartist"]
-}
-
-func (m *metadataVorbis) Composer() string {
- // ARTIST
- // The artist generally considered responsible for the work. In popular music
- // this is usually the performing band or singer. For classical music it would
- // be the composer. For an audio book it would be the author of the original text.
- if m.c["composer"] != "" {
- return m.c["composer"]
- }
- if m.c["performer"] == "" {
- return ""
- }
- return m.c["artist"]
-}
-
-func (m *metadataVorbis) Genre() string {
- return m.c["genre"]
-}
-
-func (m *metadataVorbis) Year() int {
- var dateFormat string
-
- // The date need to follow the international standard https://en.wikipedia.org/wiki/ISO_8601
- // and obviously the VorbisComment standard https://wiki.xiph.org/VorbisComment#Date_and_time
- switch len(m.c["date"]) {
- case 0:
- return 0
- case 4:
- dateFormat = "2006"
- case 7:
- dateFormat = "2006-01"
- case 10:
- dateFormat = "2006-01-02"
- }
-
- t, _ := time.Parse(dateFormat, m.c["date"])
- return t.Year()
-}
-
-func (m *metadataVorbis) Track() (int, int) {
- x, _ := strconv.Atoi(m.c["tracknumber"])
- // https://wiki.xiph.org/Field_names
- n, _ := strconv.Atoi(m.c["tracktotal"])
- return x, n
-}
-
-func (m *metadataVorbis) Disc() (int, int) {
- // https://wiki.xiph.org/Field_names
- x, _ := strconv.Atoi(m.c["discnumber"])
- n, _ := strconv.Atoi(m.c["disctotal"])
- return x, n
-}
-
-func (m *metadataVorbis) Lyrics() string {
- return m.c["lyrics"]
-}
-
-func (m *metadataVorbis) Comment() string {
- if m.c["comment"] != "" {
- return m.c["comment"]
- }
- return m.c["description"]
-}
-
-func (m *metadataVorbis) Picture() *Picture {
- return m.p
-}