mirror of
https://github.com/zhaarey/go-mp4tag.git
synced 2025-10-23 15:11:07 +00:00
- Issue #11 implemented. - Fixed assignment to nil map error for the custom field. - UpperCustom func, pass false to disable uppercasing custom tags' names for read & write.
This commit is contained in:
11
mp4tag.go
11
mp4tag.go
@@ -7,6 +7,10 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func (mp4 *MP4) UpperCustom(b bool) {
|
||||
mp4.upperCustom = b
|
||||
}
|
||||
|
||||
func (mp4 *MP4) Close() error {
|
||||
return mp4.f.Close()
|
||||
}
|
||||
@@ -59,7 +63,12 @@ func Open(trackPath string) (*MP4, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mp4 := &MP4{f: f, size : stat.Size(), path: trackPath}
|
||||
mp4 := &MP4{
|
||||
f: f,
|
||||
size : stat.Size(),
|
||||
path: trackPath,
|
||||
upperCustom: true,
|
||||
}
|
||||
err = mp4.checkHeader()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
|
||||
@@ -62,6 +62,7 @@ type MP4 struct {
|
||||
f *os.File
|
||||
path string
|
||||
size int64
|
||||
upperCustom bool
|
||||
}
|
||||
|
||||
type MP4Box struct {
|
||||
@@ -297,6 +298,7 @@ type MP4Tags struct {
|
||||
ItunesArtistID int32
|
||||
Lyrics string
|
||||
Narrator string
|
||||
OtherCustom map[string][]string
|
||||
Pictures []*MP4Picture
|
||||
Publisher string
|
||||
Title string
|
||||
|
||||
59
read.go
59
read.go
@@ -229,7 +229,18 @@ func (mp4 MP4) readTrknDisk(boxes MP4Boxes, boxName string) (int16, int16, error
|
||||
return num, total, nil
|
||||
}
|
||||
|
||||
func (mp4 MP4) readCustom(boxes MP4Boxes) (map[string]string, error) {
|
||||
func addToOthers(others map[string][]string, key, val string) map[string][]string {
|
||||
existingOthers, ok := others[key]
|
||||
if ok {
|
||||
existingOthers = append(existingOthers, val)
|
||||
others[key] = existingOthers
|
||||
} else {
|
||||
others[key] = []string{val}
|
||||
}
|
||||
return others
|
||||
}
|
||||
|
||||
func (mp4 MP4) readCustom(boxes MP4Boxes) (map[string]string, map[string][]string, error) {
|
||||
var (
|
||||
names []string
|
||||
values []string
|
||||
@@ -237,38 +248,67 @@ func (mp4 MP4) readCustom(boxes MP4Boxes) (map[string]string, error) {
|
||||
path := "moov.udta.meta.ilst.----"
|
||||
nameBoxes := boxes.getBoxesByPath(path+".name")
|
||||
if nameBoxes == nil {
|
||||
return nil, nil
|
||||
return nil, nil, nil
|
||||
}
|
||||
for _, box := range nameBoxes {
|
||||
_, err := mp4.f.Seek(box.StartOffset+12, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
name, err := mp4.readString(box.BoxSize-12)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if mp4.upperCustom {
|
||||
name = strings.ToUpper(name)
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
others := map[string][]string{}
|
||||
|
||||
dataBoxes := boxes.getBoxesByPath(path+".data")
|
||||
|
||||
var (
|
||||
prev int64
|
||||
idx int
|
||||
)
|
||||
|
||||
for _, box := range dataBoxes {
|
||||
_, err := mp4.f.Seek(box.StartOffset+16, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
value, err := mp4.readString(box.BoxSize-16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if box.StartOffset == prev {
|
||||
others = addToOthers(others, names[idx-1], value)
|
||||
prev = box.EndOffset
|
||||
continue
|
||||
}
|
||||
values = append(values, value)
|
||||
prev = box.EndOffset
|
||||
idx++
|
||||
}
|
||||
|
||||
custom := map[string]string{}
|
||||
for idx, name := range names {
|
||||
custom[name] = values[idx]
|
||||
_, ok := custom[name]
|
||||
if ok {
|
||||
existingOthers, ok := others[name]
|
||||
if ok {
|
||||
existingOthers = append(existingOthers, values[idx])
|
||||
others[name] = existingOthers
|
||||
} else {
|
||||
others[name] = []string{values[idx]}
|
||||
}
|
||||
} else {
|
||||
custom[name] = values[idx]
|
||||
}
|
||||
}
|
||||
return custom, nil
|
||||
return custom, others, nil
|
||||
}
|
||||
|
||||
func (mp4 MP4) readITAlbumID(boxes MP4Boxes) (int32, error) {
|
||||
@@ -373,7 +413,7 @@ func (mp4 MP4) readTags(boxes MP4Boxes) (*MP4Tags, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
custom, err := mp4.readCustom(boxes)
|
||||
custom, otherCustom, err := mp4.readCustom(boxes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -455,6 +495,7 @@ func (mp4 MP4) readTags(boxes MP4Boxes) (*MP4Tags, error) {
|
||||
ItunesArtistID: artistID,
|
||||
Lyrics: lyrics,
|
||||
Narrator: narrator,
|
||||
OtherCustom: otherCustom,
|
||||
Pictures: pics,
|
||||
Publisher: publisher,
|
||||
Title: title,
|
||||
|
||||
78
write.go
78
write.go
@@ -20,6 +20,16 @@ func overwriteTags(mergedTags, tags *MP4Tags, delStrings []string) *MP4Tags{
|
||||
} else if containsStr(delStrings, "allcustom") {
|
||||
mergedTags.Custom = map[string]string{}
|
||||
}
|
||||
if containsStr(delStrings, "allothercustom") {
|
||||
mergedTags.OtherCustom = map[string][]string{}
|
||||
}
|
||||
|
||||
if mergedTags.Custom == nil {
|
||||
mergedTags.Custom = map[string]string{}
|
||||
}
|
||||
if mergedTags.OtherCustom == nil {
|
||||
mergedTags.OtherCustom = map[string][]string{}
|
||||
}
|
||||
|
||||
if containsStr(delStrings, "album") {
|
||||
mergedTags.Album = ""
|
||||
@@ -265,11 +275,27 @@ func overwriteTags(mergedTags, tags *MP4Tags, delStrings []string) *MP4Tags{
|
||||
}
|
||||
|
||||
for k, v := range tags.Custom {
|
||||
if containsStr(delStrings, "custom:"+k) {
|
||||
continue
|
||||
}
|
||||
if v != "" {
|
||||
mergedTags.Custom[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range tags.OtherCustom {
|
||||
if containsStr(delStrings, "custom:"+k) || len(v) < 1 {
|
||||
continue
|
||||
}
|
||||
_, ok := mergedTags.OtherCustom[k]
|
||||
if ok {
|
||||
mergedTags.OtherCustom[k] = append(mergedTags.OtherCustom[k], v...)
|
||||
} else {
|
||||
mergedTags.OtherCustom[k] = v
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var filteredPics []*MP4Picture
|
||||
|
||||
for idx, p := range mergedTags.Pictures {
|
||||
@@ -595,13 +621,25 @@ func writeItunesArtistID(f *os.File, artistID int32) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func writeCustom(f *os.File, name, value string) error {
|
||||
nameUpperBytes := []byte(strings.ToUpper(name))
|
||||
func writeCustom(f *os.File, name, value string, upper bool, others map[string][]string) error {
|
||||
valueBytes := []byte(value)
|
||||
nameSize := len(nameUpperBytes)
|
||||
valueSize := len(valueBytes)
|
||||
|
||||
sizeBytes := putI32BE(int32(nameSize+valueSize)+64)
|
||||
if upper {
|
||||
name = strings.ToUpper(name)
|
||||
}
|
||||
nameUpperBytes := []byte(name)
|
||||
nameSize := len(nameUpperBytes)
|
||||
|
||||
totalSize := nameSize+valueSize+64
|
||||
otherCust, _ := others[name]
|
||||
|
||||
for _, other := range otherCust {
|
||||
totalSize += len([]byte(other)) + 16
|
||||
}
|
||||
|
||||
// 48
|
||||
sizeBytes := putI32BE(int32(totalSize))
|
||||
_, err := f.Write(sizeBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -658,7 +696,35 @@ func writeCustom(f *os.File, name, value string) error {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(valueBytes)
|
||||
return err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
for _, v := range otherCust {
|
||||
valueBytes = []byte(v)
|
||||
valueSize = len(valueBytes)
|
||||
sizeBytes = putI32BE(int32(valueSize)+16)
|
||||
_, err = f.Write(sizeBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.WriteString("data")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(
|
||||
[]byte{0x0, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(valueBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPicFormat(imageType ImageType, magic []byte) uint8 {
|
||||
@@ -993,7 +1059,7 @@ func (mp4 MP4) writeTags(boxes MP4Boxes, tags *MP4Tags, tempPath string) error {
|
||||
}
|
||||
|
||||
for k, v := range tags.Custom {
|
||||
err = writeCustom(f, k, v)
|
||||
err = writeCustom(f, k, v, mp4.upperCustom, tags.OtherCustom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user