- 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:
Sorrow446
2024-01-30 22:02:06 +00:00
committed by GitHub
parent 467689a441
commit 8773ee4341
4 changed files with 134 additions and 16 deletions

View File

@@ -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()

View File

@@ -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
View File

@@ -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,

View File

@@ -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
}