From 3be8dd5dae91ba4604ac8cfa05b46b958037b274 Mon Sep 17 00:00:00 2001 From: Sean Reifschneider Date: Sat, 13 Jan 2024 10:43:53 -0700 Subject: [PATCH] copy_all_playlists added, thanks to CyanideLion --- README.md | 8 +++++++ pyproject.toml | 1 + spotify2ytmusic/cli.py | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/README.md b/README.md index 6717ee1..cdc5e08 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,14 @@ individually copy them. ## Copy Your Playlists +You can either copy **all** playlists, or do a more surgical copy of individual playlists. +Copying all playlists will use the name of the Spotify playlist as the destination +playlist name on YTMusic. To copy all playlists, run: + +`s2yt_copy_all_playlists` + +**NOTE**: This does not copy the Liked playlist (see above to do that). + In the list output above, find the "playlist id" (the first column) of the Spotify playlist, and of the YTMusic playlist, and then run: diff --git a/pyproject.toml b/pyproject.toml index 0621467..7ab692f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,5 +17,6 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] s2yt_load_liked = "spotify2ytmusic.cli:load_liked" s2yt_copy_playlist = "spotify2ytmusic.cli:copy_playlist" +s2yt_copy_all_playlists = "spotify2ytmusic.cli:copy_all_playlists" s2yt_create_playlist = "spotify2ytmusic.cli:create_playlist" s2yt_list_playlists = "spotify2ytmusic.cli:list_playlists" diff --git a/spotify2ytmusic/cli.py b/spotify2ytmusic/cli.py index 297fd05..acc0529 100644 --- a/spotify2ytmusic/cli.py +++ b/spotify2ytmusic/cli.py @@ -182,6 +182,7 @@ def parse_arguments(): print(f"Looking up playlist '{pl_name}': id={dst_pl_id}") if dst_pl_id is None: dst_pl_id = yt.create_playlist(title=pl_name, description=pl_name) + time.sleep(1) # seems to be needed to avoid missing playlist ID error # create_playlist returns a dict if there was an error if isinstance(dst_pl_id, dict): @@ -192,6 +193,54 @@ def parse_arguments(): copier(src_pl_id, dst_pl_id, args.dry_run, args.track_sleep, yt=yt) +def copy_all_playlists(): + """ + Copy all Spotify playlists (except Liked Songs) to YTMusic playlists + """ + yt = YTMusic("oauth.json") + + def parse_arguments(): + parser = ArgumentParser() + parser.add_argument( + "--track-sleep", + type=float, + default=0.1, + help="Time to sleep between each track that is added (default: 0.1)", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Do not add songs to destination playlist (default: False)", + ) + + return parser.parse_args() + + args = parse_arguments() + spotify_pls = json.load(open("playlists.json", "r")) + + for src_pl in spotify_pls["playlists"]: + if str(src_pl.get("name")) == "Liked Songs": + continue + + pl_name = src_pl["name"] + dst_pl_id = get_playlist_id_by_name(yt, pl_name) + print(f"Looking up playlist '{pl_name}': id={dst_pl_id}") + if dst_pl_id is None: + dst_pl_id = yt.create_playlist(title=pl_name, description=pl_name) + time.sleep(1) # seems to be needed to avoid missing playlist ID error + + # create_playlist returns a dict if there was an error + if isinstance(dst_pl_id, dict): + print(f"ERROR: Failed to create playlist: {dst_pl_id}") + sys.exit(1) + print(f"NOTE: Created playlist '{pl_name}' with ID: {dst_pl_id}") + + copier(src_pl["id"], dst_pl_id, args.dry_run, args.track_sleep) + print("\nPlaylist done!\n") + + print("All done!") + + def copier( src_pl_id: Optional[str] = None, dst_pl_id: Optional[str] = None,