mirror of
https://github.com/navidrome/navidrome.git
synced 2025-12-23 23:18:05 -05:00
* fix: handle UTF-8 BOM in lyrics and playlist files Added UTF-8 BOM (Byte Order Mark) detection and stripping for external lyrics files and playlist files. This ensures that files with BOM markers are correctly parsed and recognized as synced lyrics or valid playlists. The fix introduces a new ioutils package with UTF8Reader and UTF8ReadFile functions that automatically detect and remove UTF-8, UTF-16 LE, and UTF-16 BE BOMs. These utilities are now used when reading external lyrics and playlist files to ensure consistent parsing regardless of BOM presence. Added comprehensive tests for BOM handling in both lyrics and playlists, including test fixtures with actual BOM markers to verify correct behavior. * test: add test for UTF-16 LE encoded LRC files Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
52 lines
1.3 KiB
Go
52 lines
1.3 KiB
Go
package lyrics
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path"
|
|
|
|
"github.com/navidrome/navidrome/log"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/utils/ioutils"
|
|
)
|
|
|
|
func fromEmbedded(ctx context.Context, mf *model.MediaFile) (model.LyricList, error) {
|
|
if mf.Lyrics != "" {
|
|
log.Trace(ctx, "embedded lyrics found in file", "title", mf.Title)
|
|
return mf.StructuredLyrics()
|
|
}
|
|
|
|
log.Trace(ctx, "no embedded lyrics for file", "path", mf.Title)
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func fromExternalFile(ctx context.Context, mf *model.MediaFile, suffix string) (model.LyricList, error) {
|
|
basePath := mf.AbsolutePath()
|
|
ext := path.Ext(basePath)
|
|
|
|
externalLyric := basePath[0:len(basePath)-len(ext)] + suffix
|
|
|
|
contents, err := ioutils.UTF8ReadFile(externalLyric)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
log.Trace(ctx, "no lyrics found at path", "path", externalLyric)
|
|
return nil, nil
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lyrics, err := model.ToLyrics("xxx", string(contents))
|
|
if err != nil {
|
|
log.Error(ctx, "error parsing lyric external file", "path", externalLyric, err)
|
|
return nil, err
|
|
} else if lyrics == nil {
|
|
log.Trace(ctx, "empty lyrics from external file", "path", externalLyric)
|
|
return nil, nil
|
|
}
|
|
|
|
log.Trace(ctx, "retrieved lyrics from external file", "path", externalLyric)
|
|
|
|
return model.LyricList{*lyrics}, nil
|
|
}
|