diff --git a/cmd/gonic/gonic.go b/cmd/gonic/gonic.go index 4548904c..176200c2 100644 --- a/cmd/gonic/gonic.go +++ b/cmd/gonic/gonic.go @@ -65,6 +65,7 @@ func main() { flag.Var(&confMusicPaths, "music-path", "path to music") confPlaylistsPath := flag.String("playlists-path", "", "path to your list of new or existing m3u playlists that gonic can manage") + confPlaylistsRelative := flag.Bool("playlists-relative", false, "make song file paths relative in the m3u playlists gonic generates") confDBPath := flag.String("db-path", "gonic.db", "path to database (optional)") @@ -147,6 +148,7 @@ func main() { DBPath: *confDBPath, OriginalMusicPath: confMusicPaths[0].path, PlaylistsPath: *confPlaylistsPath, + PlaylistsRelative: *confPlaylistsRelative, PodcastsPath: *confPodcastPath, }) if err != nil { @@ -215,7 +217,7 @@ func main() { listenbrainzClient := listenbrainz.NewClient() lastfmClient := lastfm.NewClient(lastfmClientKeySecretFunc) - playlistStore, err := playlist.NewStore(*confPlaylistsPath) + playlistStore, err := playlist.NewStore(*confPlaylistsPath, *confPlaylistsRelative) if err != nil { log.Panicf("error creating playlists store: %v", err) } diff --git a/db/migrations.go b/db/migrations.go index 447bfdf6..5eeb8e28 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -23,6 +23,7 @@ type MigrationContext struct { DBPath string OriginalMusicPath string PlaylistsPath string + PlaylistsRelative bool PodcastsPath string } @@ -507,7 +508,7 @@ func migratePlaylistsToM3U(tx *gorm.DB, ctx MigrationContext) error { return "" } - store, err := playlist.NewStore(ctx.PlaylistsPath) + store, err := playlist.NewStore(ctx.PlaylistsPath, ctx.PlaylistsRelative) if err != nil { return fmt.Errorf("create playlists store: %w", err) } diff --git a/playlist/playlist.go b/playlist/playlist.go index e51dbc16..9ff13af7 100644 --- a/playlist/playlist.go +++ b/playlist/playlist.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io/fs" + "log" "os" "path/filepath" "strconv" @@ -37,10 +38,11 @@ type Playlist struct { type Store struct { basePath string + relative bool mu sync.Mutex } -func NewStore(basePath string) (*Store, error) { +func NewStore(basePath string, relative bool) (*Store, error) { if basePath == "" { return nil, ErrInvalidBasePath } @@ -50,6 +52,7 @@ func NewStore(basePath string) (*Store, error) { return &Store{ basePath: basePath, + relative: relative, }, nil } @@ -126,6 +129,12 @@ func (s *Store) Read(relPath string) (*Playlist, error) { if strings.HasPrefix(line, "#") { continue } + + // file path might be relative if using -playlists-relative + if !filepath.IsAbs(line) { + line = filepath.Join(filepath.Dir(absPath), line) + } + playlist.Items = append(playlist.Items, line) } @@ -178,9 +187,17 @@ func (s *Store) Write(relPath string, playlist *Playlist) error { fmt.Fprintln(file, encodeAttr(attrCommment, playlist.Comment)) fmt.Fprintln(file, encodeAttr(attrIsPublic, fmt.Sprint(playlist.IsPublic))) for _, line := range playlist.Items { + if s.relative { + // transform to path relative to playlist's dir + relativePath, err := filepath.Rel(filepath.Dir(absPath), line) + if err == nil { + line = relativePath + } else { + log.Printf("Warning: could not make playlist entry path's relative - %v\n", err) + } + } fmt.Fprintln(file, line) } - return nil } diff --git a/playlist/playlist_test.go b/playlist/playlist_test.go index 10b62344..e0b6cb53 100644 --- a/playlist/playlist_test.go +++ b/playlist/playlist_test.go @@ -11,7 +11,7 @@ func TestPlaylist(t *testing.T) { t.Parallel() tmp := t.TempDir() - store, err := playlist.NewStore(tmp) + store, err := playlist.NewStore(tmp, false) require.NoError(t, err) playlistIDs, err := store.List() @@ -32,9 +32,9 @@ Example comment It has multiple lines 👍 `, Items: []string{ - "item 1.flac", - "item 2.flac", - "item 3.flac", + "/item 1.flac", + "/item 2.flac", + "/item 3.flac", }, IsPublic: true, }