Skip to content

Commit

Permalink
Handle CR, LF and CRLF line endings when importing Playlists
Browse files Browse the repository at this point in the history
  • Loading branch information
deluan committed Aug 19, 2020
1 parent 45e708f commit b836871
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 1 deletion.
29 changes: 28 additions & 1 deletion scanner/playlist_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package scanner

import (
"bufio"
"bytes"
"context"
"fmt"
"io/ioutil"
Expand Down Expand Up @@ -73,7 +74,9 @@ func (s *playlistSync) parsePlaylist(ctx context.Context, playlistFile string, b
UpdatedAt: info.ModTime(),
}

mediaFileRepository := s.ds.MediaFile(ctx)
scanner := bufio.NewScanner(file)
scanner.Split(scanLines)
for scanner.Scan() {
path := scanner.Text()
// Skip extended info
Expand All @@ -83,7 +86,7 @@ func (s *playlistSync) parsePlaylist(ctx context.Context, playlistFile string, b
if !filepath.IsAbs(path) {
path = filepath.Join(baseDir, path)
}
mf, err := s.ds.MediaFile(ctx).FindByPath(path)
mf, err := mediaFileRepository.FindByPath(path)
if err != nil {
log.Warn(ctx, "Path in playlist not found", "playlist", playlistFile, "path", path, err)
continue
Expand Down Expand Up @@ -118,3 +121,27 @@ func (s *playlistSync) updatePlaylist(ctx context.Context, newPls *model.Playlis
}
return s.ds.Playlist(ctx).Put(newPls)
}

// From https://stackoverflow.com/a/41433698
func scanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexAny(data, "\r\n"); i >= 0 {
if data[i] == '\n' {
// We have a line terminated by single newline.
return i + 1, data[0:i], nil
}
advance = i + 1
if len(data) > i+1 && data[i+1] == '\n' {
advance += 1
}
return advance, data[0:i], nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), data, nil
}
// Request more data.
return 0, nil, nil
}
47 changes: 47 additions & 0 deletions scanner/playlist_sync_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package scanner

import (
"context"

"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/persistence"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("playlistSync", func() {
Describe("parsePlaylist", func() {
var ds model.DataStore
var ps *playlistSync
ctx := context.TODO()
BeforeEach(func() {
ds = &persistence.MockDataStore{
MockedMediaFile: &mockedMediaFile{},
}
ps = newPlaylistSync(ds)
})

It("parses well-formed playlists", func() {
pls, err := ps.parsePlaylist(ctx, "lf-ended.m3u", "tests/fixtures/playlists")
Expect(err).To(BeNil())
Expect(pls.Tracks).To(HaveLen(2))
})

It("parses playlists using CR ending (old Mac format)", func() {
pls, err := ps.parsePlaylist(ctx, "cr-ended.m3u", "tests/fixtures/playlists")
Expect(err).To(BeNil())
Expect(pls.Tracks).To(HaveLen(2))
})
})
})

type mockedMediaFile struct {
model.MediaFileRepository
}

func (r *mockedMediaFile) FindByPath(s string) (*model.MediaFile, error) {
return &model.MediaFile{
ID: "123",
Path: s,
}, nil
}
Empty file removed tests/fixtures/playlist.m3u
Empty file.
1 change: 1 addition & 0 deletions tests/fixtures/playlists/cr-ended.m3u
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# This is a commentabc.mp3def.mp3
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/playlists/lf-ended.m3u
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This is a comment
abc.mp3
def.mp3

0 comments on commit b836871

Please sign in to comment.