mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-29 14:20:36 +02:00
fix: extract cover art from M4A/ALAC files for conversion
Add extractCoverFromM4A() that reads the covr atom from the MP4 box tree (moov/udta/meta/ilst/covr/data). Wire it into ExtractCoverToFile so ALAC-to-FLAC conversion preserves cover art.
This commit is contained in:
@@ -1694,6 +1694,8 @@ func ExtractCoverToFile(audioPath string, outputPath string) error {
|
|||||||
|
|
||||||
if strings.HasSuffix(lower, ".flac") {
|
if strings.HasSuffix(lower, ".flac") {
|
||||||
coverData, err = ExtractCoverArt(audioPath)
|
coverData, err = ExtractCoverArt(audioPath)
|
||||||
|
} else if strings.HasSuffix(lower, ".m4a") || strings.HasSuffix(lower, ".aac") {
|
||||||
|
coverData, err = extractCoverFromM4A(audioPath)
|
||||||
} else if strings.HasSuffix(lower, ".mp3") {
|
} else if strings.HasSuffix(lower, ".mp3") {
|
||||||
coverData, _, err = extractMP3CoverArt(audioPath)
|
coverData, _, err = extractMP3CoverArt(audioPath)
|
||||||
} else if strings.HasSuffix(lower, ".opus") || strings.HasSuffix(lower, ".ogg") {
|
} else if strings.HasSuffix(lower, ".opus") || strings.HasSuffix(lower, ".ogg") {
|
||||||
|
|||||||
@@ -663,6 +663,79 @@ func extractLyricsFromM4A(filePath string) (string, error) {
|
|||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractCoverFromM4A(filePath string) ([]byte, error) {
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileSize := fi.Size()
|
||||||
|
|
||||||
|
moov, found, err := findAtomInRange(f, 0, fileSize, "moov", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("moov not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStart := moov.offset + moov.headerSize
|
||||||
|
bodySize := moov.size - moov.headerSize
|
||||||
|
|
||||||
|
udta, found, err := findAtomInRange(f, bodyStart, bodySize, "udta", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("udta not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStart = udta.offset + udta.headerSize
|
||||||
|
bodySize = udta.size - udta.headerSize
|
||||||
|
|
||||||
|
meta, found, err := findAtomInRange(f, bodyStart, bodySize, "meta", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("meta not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStart = meta.offset + meta.headerSize + 4
|
||||||
|
bodySize = meta.size - meta.headerSize - 4
|
||||||
|
|
||||||
|
ilst, found, err := findAtomInRange(f, bodyStart, bodySize, "ilst", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("ilst not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyStart = ilst.offset + ilst.headerSize
|
||||||
|
bodySize = ilst.size - ilst.headerSize
|
||||||
|
|
||||||
|
covr, found, err := findAtomInRange(f, bodyStart, bodySize, "covr", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("cover atom not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStart := covr.offset + covr.headerSize
|
||||||
|
dataSize := covr.size - covr.headerSize
|
||||||
|
|
||||||
|
dataAtom, found, err := findAtomInRange(f, dataStart, dataSize, "data", fileSize)
|
||||||
|
if err != nil || !found {
|
||||||
|
return nil, fmt.Errorf("data atom not found in cover")
|
||||||
|
}
|
||||||
|
|
||||||
|
// data atom: header + 4 bytes type indicator + 4 bytes locale
|
||||||
|
imgStart := dataAtom.offset + dataAtom.headerSize + 8
|
||||||
|
imgLen := dataAtom.size - dataAtom.headerSize - 8
|
||||||
|
if imgLen <= 0 {
|
||||||
|
return nil, fmt.Errorf("empty cover data")
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, imgLen)
|
||||||
|
if _, err := f.ReadAt(buf, imgStart); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
func extractLyricsFromSidecarLRC(filePath string) (string, error) {
|
func extractLyricsFromSidecarLRC(filePath string) (string, error) {
|
||||||
ext := filepath.Ext(filePath)
|
ext := filepath.Ext(filePath)
|
||||||
base := strings.TrimSuffix(filePath, ext)
|
base := strings.TrimSuffix(filePath, ext)
|
||||||
|
|||||||
Reference in New Issue
Block a user