ye
This commit is contained in:
@@ -140,6 +140,7 @@ func run() error {
|
|||||||
PublicPlaylists: cfg.PublicPlaylists,
|
PublicPlaylists: cfg.PublicPlaylists,
|
||||||
Concurrency: cfg.Concurrency,
|
Concurrency: cfg.Concurrency,
|
||||||
LikedName: cfg.LikedPlaylist,
|
LikedName: cfg.LikedPlaylist,
|
||||||
|
TargetPlaylistID: cfg.TargetPlaylistID,
|
||||||
Progress: func(msg string) {
|
Progress: func(msg string) {
|
||||||
fmt.Printf("\r%-140s", msg)
|
fmt.Printf("\r%-140s", msg)
|
||||||
},
|
},
|
||||||
@@ -644,12 +645,12 @@ func buildPlaylistPlans(cfg config.Config, fileEntries []jobconfig.PlaylistEntry
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cfg.TargetPlaylistID > 0 {
|
if cfg.TargetPlaylistID > 0 {
|
||||||
uniqueIDs := map[string]struct{}{}
|
// Apply the global target to all plans that don't already have a per-playlist target.
|
||||||
for id := range plans {
|
for id, plan := range plans {
|
||||||
uniqueIDs[id] = struct{}{}
|
if plan.TargetPlaylistID == 0 {
|
||||||
|
plan.TargetPlaylistID = cfg.TargetPlaylistID
|
||||||
|
plans[id] = plan
|
||||||
}
|
}
|
||||||
if len(uniqueIDs) != 1 {
|
|
||||||
return nil, nil, fmt.Errorf("--target-playlist-id can only be used with exactly one source playlist URL")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func Load() (Config, error) {
|
|||||||
flag.Var(&playlists, "playlist", "Playlist name to transfer (repeatable)")
|
flag.Var(&playlists, "playlist", "Playlist name to transfer (repeatable)")
|
||||||
flag.Var(&playlistURLs, "playlist-url", "Spotify playlist URL/URI/ID to transfer (repeatable)")
|
flag.Var(&playlistURLs, "playlist-url", "Spotify playlist URL/URI/ID to transfer (repeatable)")
|
||||||
|
|
||||||
if err := flag.CommandLine.Parse(parseArgs); err != nil {
|
if err := flag.CommandLine.Parse(preprocessArgs(parseArgs)); err != nil {
|
||||||
return Config{}, err
|
return Config{}, err
|
||||||
}
|
}
|
||||||
cfg.Command = command
|
cfg.Command = command
|
||||||
@@ -158,9 +158,6 @@ func (c Config) Validate() error {
|
|||||||
if c.TargetPlaylistID < 0 {
|
if c.TargetPlaylistID < 0 {
|
||||||
return fmt.Errorf("target-playlist-id must be >= 0")
|
return fmt.Errorf("target-playlist-id must be >= 0")
|
||||||
}
|
}
|
||||||
if c.TargetPlaylistID > 0 && !c.Monitor {
|
|
||||||
return fmt.Errorf("target-playlist-id is currently supported with --monitor mode")
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(c.SessionPath) == "" {
|
if strings.TrimSpace(c.SessionPath) == "" {
|
||||||
return fmt.Errorf("session file path cannot be empty")
|
return fmt.Errorf("session file path cannot be empty")
|
||||||
}
|
}
|
||||||
@@ -190,6 +187,48 @@ func splitComma(s string) []string {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type boolFlag interface {
|
||||||
|
IsBoolFlag() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// preprocessArgs moves non-flag positional arguments to the end so that flags
|
||||||
|
// can appear in any order relative to non-flag arguments.
|
||||||
|
func preprocessArgs(args []string) []string {
|
||||||
|
boolFlagNames := make(map[string]bool)
|
||||||
|
flag.CommandLine.VisitAll(func(f *flag.Flag) {
|
||||||
|
if bf, ok := f.Value.(boolFlag); ok && bf.IsBoolFlag() {
|
||||||
|
boolFlagNames[f.Name] = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var flagArgs []string
|
||||||
|
var positional []string
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for i < len(args) {
|
||||||
|
arg := args[i]
|
||||||
|
if !strings.HasPrefix(arg, "-") {
|
||||||
|
positional = append(positional, arg)
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
flagArgs = append(flagArgs, arg)
|
||||||
|
i++
|
||||||
|
name := strings.TrimLeft(arg, "-")
|
||||||
|
if idx := strings.Index(name, "="); idx >= 0 {
|
||||||
|
continue // value embedded in --flag=value form
|
||||||
|
}
|
||||||
|
if boolFlagNames[name] {
|
||||||
|
continue // bool flags don't consume a following value
|
||||||
|
}
|
||||||
|
if i < len(args) && !strings.HasPrefix(args[i], "-") {
|
||||||
|
flagArgs = append(flagArgs, args[i])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(flagArgs, positional...)
|
||||||
|
}
|
||||||
|
|
||||||
func envOr(key, fallback string) string {
|
func envOr(key, fallback string) string {
|
||||||
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
|
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
|
||||||
return v
|
return v
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type Config struct {
|
|||||||
PublicPlaylists bool
|
PublicPlaylists bool
|
||||||
Concurrency int
|
Concurrency int
|
||||||
LikedName string
|
LikedName string
|
||||||
|
TargetPlaylistID int64 // when set, add tracks to this existing playlist instead of creating a new one
|
||||||
Progress ProgressFunc
|
Progress ProgressFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,14 +88,21 @@ func processPlaylist(ctx context.Context, cfg Config, writer QobuzWriter, matche
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var playlistID int64
|
||||||
|
if cfg.TargetPlaylistID > 0 {
|
||||||
|
playlistID = cfg.TargetPlaylistID
|
||||||
|
res.TargetID = playlistID
|
||||||
|
} else {
|
||||||
notify(cfg, fmt.Sprintf("Transfer %d/%d creating playlist: %s", playlistIndex, playlistTotal, shortName(pl.Name)))
|
notify(cfg, fmt.Sprintf("Transfer %d/%d creating playlist: %s", playlistIndex, playlistTotal, shortName(pl.Name)))
|
||||||
playlistID, err := writer.CreatePlaylist(ctx, pl.Name, sanitizeDescription(pl.Description), cfg.PublicPlaylists)
|
created, err := writer.CreatePlaylist(ctx, pl.Name, sanitizeDescription(pl.Description), cfg.PublicPlaylists)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Errors = append(res.Errors, fmt.Sprintf("create playlist: %v", err))
|
res.Errors = append(res.Errors, fmt.Sprintf("create playlist: %v", err))
|
||||||
notify(cfg, fmt.Sprintf("Transfer %d/%d failed creating playlist: %s", playlistIndex, playlistTotal, shortName(pl.Name)))
|
notify(cfg, fmt.Sprintf("Transfer %d/%d failed creating playlist: %s", playlistIndex, playlistTotal, shortName(pl.Name)))
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
playlistID = created
|
||||||
res.TargetID = playlistID
|
res.TargetID = playlistID
|
||||||
|
}
|
||||||
|
|
||||||
ids := uniqueIDs(matched)
|
ids := uniqueIDs(matched)
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
|
|||||||
6393
transfer-report.json
6393
transfer-report.json
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user