From d60e83176ca797a2aa4d8d6027fc5eaf9057f4ec Mon Sep 17 00:00:00 2001 From: Kendall Garner <17521368+kgarner7@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:01:37 +0000 Subject: [PATCH] feat(cli): support getting playlists via cli (#3634) * feat(cli): support getting playlists via cli * address initial nit * use csv writer and csv instead --- cmd/pls.go | 105 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 10 deletions(-) diff --git a/cmd/pls.go b/cmd/pls.go index 1d390c1e8..4dbc6ff3b 100644 --- a/cmd/pls.go +++ b/cmd/pls.go @@ -2,8 +2,12 @@ package cmd import ( "context" + "encoding/csv" + "encoding/json" "errors" + "fmt" "os" + "strconv" "github.com/Masterminds/squirrel" "github.com/navidrome/navidrome/core/auth" @@ -15,25 +19,51 @@ import ( ) var ( - playlistID string - outputFile string + playlistID string + outputFile string + userID string + outputFormat string ) +type displayPlaylist struct { + Id string `json:"id"` + Name string `json:"name"` + OwnerName string `json:"ownerName"` + OwnerId string `json:"ownerId"` + Public bool `json:"public"` +} + +type displayPlaylists []displayPlaylist + func init() { plsCmd.Flags().StringVarP(&playlistID, "playlist", "p", "", "playlist name or ID") plsCmd.Flags().StringVarP(&outputFile, "output", "o", "", "output file (default stdout)") _ = plsCmd.MarkFlagRequired("playlist") rootCmd.AddCommand(plsCmd) + + listCommand.Flags().StringVarP(&userID, "user", "u", "", "username or ID") + listCommand.Flags().StringVarP(&outputFormat, "format", "f", "csv", "output format [supported values: csv, json]") + plsCmd.AddCommand(listCommand) } -var plsCmd = &cobra.Command{ - Use: "pls", - Short: "Export playlists", - Long: "Export Navidrome playlists to M3U files", - Run: func(cmd *cobra.Command, args []string) { - runExporter() - }, -} +var ( + plsCmd = &cobra.Command{ + Use: "pls", + Short: "Export playlists", + Long: "Export Navidrome playlists to M3U files", + Run: func(cmd *cobra.Command, args []string) { + runExporter() + }, + } + + listCommand = &cobra.Command{ + Use: "list", + Short: "List playlists", + Run: func(cmd *cobra.Command, args []string) { + runList() + }, + } +) func runExporter() { sqlDB := db.Db() @@ -69,3 +99,58 @@ func runExporter() { log.Fatal("Error writing to the output file", "file", outputFile, err) } } + +func runList() { + if outputFormat != "csv" && outputFormat != "json" { + log.Fatal("Invalid output format. Must be one of csv, json", "format", outputFormat) + } + + sqlDB := db.Db() + ds := persistence.New(sqlDB) + ctx := auth.WithAdminUser(context.Background(), ds) + + options := model.QueryOptions{Sort: "owner_name"} + + if userID != "" { + user, err := ds.User(ctx).FindByUsername(userID) + + if err != nil && !errors.Is(err, model.ErrNotFound) { + log.Fatal("Error retrieving user by name", "name", userID, err) + } + + if errors.Is(err, model.ErrNotFound) { + user, err = ds.User(ctx).Get(userID) + if err != nil { + log.Fatal("Error retrieving user by id", "id", userID, err) + } + } + + options.Filters = squirrel.Eq{"owner_id": user.ID} + } + + playlists, err := ds.Playlist(ctx).GetAll(options) + if err != nil { + log.Fatal(ctx, "Failed to retrieve playlists", err) + } + + if outputFormat == "csv" { + w := csv.NewWriter(os.Stdout) + _ = w.Write([]string{"playlist id", "playlist name", "owner id", "owner name", "public"}) + for _, playlist := range playlists { + _ = w.Write([]string{playlist.ID, playlist.Name, playlist.OwnerID, playlist.OwnerName, strconv.FormatBool(playlist.Public)}) + } + w.Flush() + } else { + display := make(displayPlaylists, len(playlists)) + for idx, playlist := range playlists { + display[idx].Id = playlist.ID + display[idx].Name = playlist.Name + display[idx].OwnerId = playlist.OwnerID + display[idx].OwnerName = playlist.OwnerName + display[idx].Public = playlist.Public + } + + j, _ := json.Marshal(display) + fmt.Printf("%s\n", j) + } +}