kopia lustrzana https://github.com/jcs/id3-go
Add v1 subpackage
rodzic
9ee5a6a8ec
commit
56f44276d3
55
id3.go
55
id3.go
|
@ -4,6 +4,8 @@
|
|||
package id3
|
||||
|
||||
import (
|
||||
"errors"
|
||||
v1 "github.com/mikkyang/id3-go/v1"
|
||||
v2 "github.com/mikkyang/id3-go/v2"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -40,6 +42,10 @@ type File struct {
|
|||
file *os.File
|
||||
}
|
||||
|
||||
const (
|
||||
fileEndFlag = 2
|
||||
)
|
||||
|
||||
// Opens a new tagged file
|
||||
func Open(name string) (*File, error) {
|
||||
fi, err := os.OpenFile(os.Args[1], os.O_RDWR, 0666)
|
||||
|
@ -47,33 +53,50 @@ func Open(name string) (*File, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
tag := v2.ParseTag(fi)
|
||||
file := &File{file: fi}
|
||||
|
||||
return &File{tag, tag.Size(), fi}, nil
|
||||
if v2Tag := v2.ParseTag(fi); v2Tag != nil {
|
||||
file.Tagger = v2Tag
|
||||
file.originalSize = v2Tag.Size()
|
||||
} else if v1Tag := v1.ParseTag(fi); v1Tag != nil {
|
||||
file.Tagger = v1Tag
|
||||
} else {
|
||||
return nil, errors.New("Open: unknown tag format")
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
|
||||
// Saves any edits to the tagged file
|
||||
func (f *File) Close() error {
|
||||
defer f.file.Close()
|
||||
|
||||
if f.Size() > f.originalSize {
|
||||
stat, err := f.file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
switch f.Tagger.(type) {
|
||||
case (*v1.Tag):
|
||||
f.file.Seek(-v1.TagSize, fileEndFlag)
|
||||
f.file.Write(f.Tagger.Bytes())
|
||||
case (*v2.Tag):
|
||||
if f.Size() > f.originalSize {
|
||||
stat, err := f.file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
start := f.originalSize + v2.HeaderSize
|
||||
end := stat.Size()
|
||||
offset := f.Tagger.Size() - f.originalSize
|
||||
|
||||
err = f.shiftBytesBack(int64(start), end, int64(offset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
start := f.originalSize + v2.HeaderSize
|
||||
end := stat.Size()
|
||||
offset := f.Tagger.Size() - f.originalSize
|
||||
|
||||
err = f.shiftBytesBack(int64(start), end, int64(offset))
|
||||
if err != nil {
|
||||
if _, err := f.file.WriteAt(f.Tagger.Bytes(), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := f.file.WriteAt(f.Tagger.Bytes(), 0); err != nil {
|
||||
return err
|
||||
default:
|
||||
return errors.New("Close: unknown tag version")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2013 Michael Yang. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
package v1
|
||||
|
||||
import (
|
||||
v2 "github.com/mikkyang/id3-go/v2"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
TagSize = 128
|
||||
fileEndFlag = 2
|
||||
)
|
||||
|
||||
var (
|
||||
Genres = []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",
|
||||
}
|
||||
)
|
||||
|
||||
// Tag represents an ID3v1 tag
|
||||
type Tag struct {
|
||||
title, artist, album, year, comment string
|
||||
genre byte
|
||||
}
|
||||
|
||||
func ParseTag(readSeeker io.ReadSeeker) *Tag {
|
||||
readSeeker.Seek(-TagSize, fileEndFlag)
|
||||
|
||||
data := make([]byte, TagSize)
|
||||
n, err := io.ReadFull(readSeeker, data)
|
||||
if n < TagSize || err != nil || string(data[:3]) != "TAG" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Tag{
|
||||
title: string(data[3:33]),
|
||||
artist: string(data[33:63]),
|
||||
album: string(data[63:93]),
|
||||
year: string(data[93:97]),
|
||||
comment: string(data[97:127]),
|
||||
genre: data[127],
|
||||
}
|
||||
}
|
||||
|
||||
func (t Tag) Title() string { return t.title }
|
||||
func (t Tag) Artist() string { return t.artist }
|
||||
func (t Tag) Album() string { return t.album }
|
||||
func (t Tag) Year() string { return t.year }
|
||||
|
||||
func (t Tag) Genre() string {
|
||||
if int(t.genre) < len(Genres) {
|
||||
return Genres[t.genre]
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t Tag) Comments() []string {
|
||||
return []string{t.comment}
|
||||
}
|
||||
|
||||
func (t *Tag) SetTitle(text string) {
|
||||
t.title = text
|
||||
}
|
||||
|
||||
func (t *Tag) SetArtist(text string) {
|
||||
t.artist = text
|
||||
}
|
||||
|
||||
func (t *Tag) SetAlbum(text string) {
|
||||
t.album = text
|
||||
}
|
||||
|
||||
func (t *Tag) SetYear(text string) {
|
||||
t.year = text
|
||||
}
|
||||
|
||||
func (t *Tag) SetGenre(text string) {
|
||||
t.genre = 255
|
||||
for i, genre := range Genres {
|
||||
if text == genre {
|
||||
t.genre = byte(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t Tag) Bytes() []byte {
|
||||
data := make([]byte, TagSize)
|
||||
|
||||
copy(data[:3], []byte("TAG"))
|
||||
copy(data[3:33], []byte(t.title))
|
||||
copy(data[33:63], []byte(t.artist))
|
||||
copy(data[63:93], []byte(t.album))
|
||||
copy(data[93:97], []byte(t.year))
|
||||
copy(data[97:127], []byte(t.comment))
|
||||
data[127] = t.genre
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func (t Tag) Size() int {
|
||||
return TagSize
|
||||
}
|
||||
|
||||
func (t Tag) Version() string {
|
||||
return "1.0"
|
||||
}
|
||||
|
||||
// Dummy methods to satisfy Tagger interface
|
||||
func (t Tag) Padding() uint { return 0 }
|
||||
func (t Tag) AllFrames() []v2.Framer { return []v2.Framer{} }
|
||||
func (t Tag) Frame(id string) v2.Framer { return nil }
|
||||
func (t Tag) Frames(id string) []v2.Framer { return []v2.Framer{} }
|
||||
func (t Tag) DeleteFrames(id string) []v2.Framer { return []v2.Framer{} }
|
||||
func (t Tag) AddFrame(f v2.Framer) {}
|
Ładowanie…
Reference in New Issue