{"id":16229727,"url":"https://github.com/jerboa88/playlist-archiver-for-spotify","last_synced_at":"2025-03-19T14:30:21.179Z","repository":{"id":204579566,"uuid":"702697351","full_name":"jerboa88/Playlist-Archiver-for-Spotify","owner":"jerboa88","description":"Automatically archive Spotify playlists using Python \u0026 GitHub Actions. Never lose your Discover Weekly playlist again!","archived":false,"fork":false,"pushed_at":"2025-01-20T01:19:26.000Z","size":66,"stargazers_count":1,"open_issues_count":6,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-15T00:35:10.514Z","etag":null,"topics":["automation","discover-weekly","release-radar","scheduler","spotify","spotify-api","spotify-playlist","spotify-playlist-generator","spotify-playlists"],"latest_commit_sha":null,"homepage":"https://johng.io/p/playlist-archiver-for-spotify","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jerboa88.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-09T20:27:29.000Z","updated_at":"2025-02-19T04:21:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"fd7e2ec6-a06b-49cb-b584-7a6626e62130","html_url":"https://github.com/jerboa88/Playlist-Archiver-for-Spotify","commit_stats":null,"previous_names":["jerboa88/playlist-archiver-for-spotify"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jerboa88%2FPlaylist-Archiver-for-Spotify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jerboa88%2FPlaylist-Archiver-for-Spotify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jerboa88%2FPlaylist-Archiver-for-Spotify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jerboa88%2FPlaylist-Archiver-for-Spotify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jerboa88","download_url":"https://codeload.github.com/jerboa88/Playlist-Archiver-for-Spotify/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243996767,"owners_count":20380978,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","discover-weekly","release-radar","scheduler","spotify","spotify-api","spotify-playlist","spotify-playlist-generator","spotify-playlists"],"created_at":"2024-10-10T12:59:04.386Z","updated_at":"2025-03-19T14:30:21.171Z","avatar_url":"https://github.com/jerboa88.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Project Header --\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003cimg class=\"projectLogo\" src=\"logo.svg\" alt=\"Project logo\" title=\"Project logo\" width=\"256\"\u003e\n\n  \u003ch1 class=\"projectName\"\u003ePlaylist Archiver for Spotify\u003c/h1\u003e\n\n  \u003cp class=\"projectBadges\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/type-CLI_App-f44336.svg\" alt=\"Project type\" title=\"Project type\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/languages/top/jerboa88/Playlist-Archiver-for-Spotify.svg\" alt=\"Language\" title=\"Language\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/jerboa88/Playlist-Archiver-for-Spotify/archive-discover-weekly.yml?logo=spotify\u0026label=Archive%20Discover%20Weekly\" alt=\"GitHub Workflow Status\" title=\"GitHub Workflow Status\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/jerboa88/Playlist-Archiver-for-Spotify/archive-release-radar.yml?logo=spotify\u0026label=Archive%20Release%20Radar\" alt=\"GitHub Workflow Status\" title=\"GitHub Workflow Status\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/repo-size/jerboa88/Playlist-Archiver-for-Spotify.svg\" alt=\"Repository size\" title=\"Repository size\"\u003e\n    \u003ca href=\"LICENSE\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/license/jerboa88/Playlist-Archiver-for-Spotify.svg\" alt=\"Project license\" title=\"Project license\"/\u003e\n    \u003c/a\u003e\n  \u003c/p\u003e\n\n  \u003cp class=\"projectDesc\" data-exposition=\"A CLI app that automatically archives Spotify playlists. Written in Python, this program integrates seamlessly into a CI workflow via GitHub Actions. It was developed to replace a repetitive manual task and explore the capabilities of GitHub Actions and the Spotify API.\"\u003e\n    Automatically archive Spotify playlists using Python \u0026 GitHub Actions. Never lose your Discover Weekly playlist again!\n  \u003c/p\u003e\n\n  \u003cbr/\u003e\n\u003c/div\u003e\n\n\n## About\n\n\u003e [!IMPORTANT]\n\u003e **Spotify has neutered this script.** On November 27, 2024, Spotify implemented [new changes to their Web API] that makes it impossible to retrieve information about \"Algorithmic and Spotify-owned editorial playlists\". You can still use this script to make copies of other types of playlists, but it will no longer work for Discover Weekly, Release Radar, Spotify Wrapped, or any other algorithmic playlists.\n\u003e\n\u003e It is unfortunate that Spotify has chosen to make this change, and disappointing that they did so without warning to developers, many of whom have far more complicated projects that rely on this functionality. If this affects you, you can leave a comment on [this Spotify Community post] to let them know how you feel.\n\nA Python script for making copies of Spotify playlists. This can be used with the provided GitHub Actions workflows to automatically archive Discover Weekly and Release Radar playlists every week, take a yearly snapshot of your Liked Songs playlist, or to make a one-time copy of any playlist.\n\nIf you prefer, you can run the script manually, or with other automation tools like Cron or Windows Task Scheduler instead of GitHub Actions.\n\n\n## Getting Started\n\n### Prerequisites\n- A Spotify account\n- A GitHub account (if you want to use GitHub Actions to run the script)\n- Python 3\n\n### Installation\n1. Create a new app via the [Spotify Developer Dashboard]. Make sure the `Redirect URI` you set matches what is in [constants.py] (it is `http://127.0.0.1:9090` by default). Make note of the `Client ID` and `Client Secret` for later.\n2. Clone or download this repo. If you are planning to use GitHub Actions, you probably want to fork this repo first.\n3. Install the required Python packages with `pip install -r requirements.txt`.\n4. Run `python setup.py SPOTIFY_CLIENT_ID SPOTIFY_CLIENT_SECRET` to grant the script access to your Spotify account. Replace `SPOTIFY_CLIENT_ID` and `SPOTIFY_CLIENT_SECRET` with your own values. After granting the app access, a `tokens.yaml` file will be created in the same directory as the script. This file contains your access and refresh tokens and should be kept secret.\n\n\n## Usage\nTo copy a playlist, you'll need to call [copy-playlist.py] with the ID of the input playlist, a name for the destination playlist, and your Spotify credentials. See [Advanced Script Usage] for more details.\n\nTo find the ID of a playlist, see [Finding the Playlist ID].\n\nFor examples on how to run the script automatically, see [Scheduling].\n\n### Finding the Playlist ID\n#### Manually\nIf you already know the playlist you want to copy, the most reliable way to get its ID is to just copy it from Spotify.\n\n1. Open Spotify and navigate to the playlist you want to copy.\n2. Right-click on the playlist and select `Share` \u003e `Copy link to playlist`.\n3. The ID of the playlist is the last part of the URL. For example, the ID of the playlist `https://open.spotify.com/playlist/37i9dQZF1DXdPec7aLTmlC` is `37i9dQZF1DXdPec7aLTmlC`.\n\n#### Programmatically\nIf you want to programmatically find the ID of a playlist, you can use the [get-playlist-id.py] helper script. This script will search for a playlist with a given name and return its ID. See [Advanced Script Usage] for more details.\n\n\n### Scheduling\n#### With GitHub Actions\nWe can use GitHub Actions to automatically run the script every week.\n\n\u003e [!NOTE]\n\u003e GitHub automatically disables scheduled workflows if there has been no repository activity for some time. When a workflow is about to be disabled, GitHub will send you an email and give you the option to keep running it in the `Actions` tab. Alternatively, you can make a commit every 60 days to keep the repository active.\n\n1. Create four repository secrets in your forked repo with the following names and values (see [Using secrets in GitHub Actions]):\n    - `SPOTIFY_CLIENT_ID`: The client id from step 1\n    - `SPOTIFY_CLIENT_SECRET`: The client secret from step 1\n    - `SPOTIFY_ACCESS_TOKEN`: The access token from step 4\n    - `SPOTIFY_REFRESH_TOKEN`: The refresh token from step 4\n2. Create your own workflows or edit the existing ones under [.github/workflows/]. The existing workflows are set up to archive Discover Weekly and Release Radar playlists every Monday and Friday, respectively. Edit the `cron` schedule to change when the script runs. See below for all available arguments for the script.\n\n\n### Advanced Script Usage\n\n\u003e [!WARNING]\n\u003e When debug mode is enabled, these scripts may print potentially private information from your Spotify account to the console like playlist IDs and names. This is useful for debugging, but if your workflow logs are public and you don't want to share this information, consider disabling debug logging.\n\n#### [setup.py]\nThis script is used to grant access to your Spotify account and save the access and refresh tokens to a file for later use.\n\nThis script can't be run in a headless environment because a browser window needs to be opened to prompt you to grant access to the script. Instead, run this script on your local machine and save the tokens as repository secrets or environment variables on your server.\n\n```\nusage: setup.py [-h] [--debug] client_id client_secret\n\nGrant access to your Spotify account and save the access and refresh tokens to a file.\n\npositional arguments:\n  client_id      Your client ID for Spotify. Get one from https://developer.spotify.com/dashboard\n  client_secret  Your client secret for Spotify. Get one from https://developer.spotify.com/dashboard\n\noptions:\n  -h, --help     show this help message and exit\n  --debug, -d    Whether to print additional information to the console for debugging (default: false)\n```\n\n#### [get-playlist-id.py]\nIf you don't know the ID of a playlist, you can use this helper script to find it. Pass in a list of 1 or more playlist names and it will print the ID of the first playlist that matches.\n\nYou can either use this script as as standalone tool, or you can use the output of this script directly in [copy-playlist.py] as part of your workflow.\n\n```\nusage: get-playlist-id.py [-h] [--debug] client_id client_secret access_token refresh_token playlist_names [playlist_names ...]\n\nGet the ID of a Spotify playlist given a list of names.\n\npositional arguments:\n  client_id       Your client ID for Spotify. Get one from https://developer.spotify.com/dashboard\n  client_secret   Your client secret for Spotify. Get one from https://developer.spotify.com/dashboard\n  access_token    Your access token for Spotify. This can be found in tokens.yaml after the program is run for the first time\n  refresh_token   Your refresh token for Spotify. This can be found in tokens.yaml after the program is run for the first time\n  playlist_names  A list of playlist names you want to find the ID for. If multiple names are entered, we will try to match them to playlists in the order\n                  they are given. One of the names must match exactly\n\noptions:\n  -h, --help      show this help message and exit\n  --debug, -d     Whether to print additional information to the console for debugging (default: false)\n```\n\n#### [copy-playlist.py]\nThis is the main script that copies a playlist. It takes in the ID of the input playlist and the name of the output playlists, and copies all the tracks from the input playlist to the output playlist. If the output playlist does not exist, it will be created.\n\nYou can also set the input playlist ID to `saved_tracks` to make a copy of your 'Liked Songs' playlist.\n\nYou can include [strftime format codes] in the output playlist name to include the date/time in the name. For example, `Discover Weekly - %Y-%m-%d` will create a new playlist with the name `Discover Weekly - 2025-01-01`.\n\n```\nusage: copy-playlist.py [-h] [--debug] [--visibility {auto,private,public}] [--contributions {auto,individual,collaborative}]\n                        client_id client_secret access_token refresh_token input_playlist_id output_playlist_name\n\nMake a copy of a given playlist.\n\npositional arguments:\n  client_id             Your client ID for Spotify. Get one from https://developer.spotify.com/dashboard\n  client_secret         Your client secret for Spotify. Get one from https://developer.spotify.com/dashboard\n  access_token          Your access token for Spotify. This can be found in tokens.yaml after the program is run for the first time\n  refresh_token         Your refresh token for Spotify. This can be found in tokens.yaml after the program is run for the first time\n  input_playlist_id     The ID of the playlist you want to make a copy of, or the special string 'saved_tracks' to make a copy of your 'Liked Songs' playlist\n  output_playlist_name  The name of the output playlist. strftime format codes can be used to include the date/time in the name\n\noptions:\n  -h, --help            show this help message and exit\n  --debug, -d           Whether to print additional information to the console for debugging (default: false)\n  --visibility {auto,private,public}\n                        Set the contribution mode of the output playlist. When set to 'auto', the contribution mode will be set to that of the input playlist\n                        (default: auto)\n  --contributions {auto,individual,collaborative}\n                        Set the contribution mode of the output playlist. When set to 'auto', the contribution mode will be set to that of the input playlist\n                        (default: auto)\n```\n\n### Permissions\nThis currently script requests the following scopes from the Spotify API:\n- `user-library-read`: to read your saved tracks\n- `playlist-read-private`: to read your private playlists\n- `playlist-read-collaborative`: to read your collaborative playlists\n- `playlist-modify-private`: to create and modify your private playlists\n- `playlist-modify-public`: to create and modify your public playlists\n\nIf you aren't using all the features that this script provides, feel free to remove the scopes you don't need from the `SCOPE` variable in [constants.py]. For example, if you are only making copies of public, non-collaborative playlists, you can remove the `user-library-read`, `playlist-read-private`, and `playlist-read-collaborative` scopes.\n\n\n## Limitations\n- The setup script must be run once locally before the GitHub Actions workflows will work. This is because the Spotify API requires user authorization via the browser, which is not possible in a headless environment\n- Playlists can not be placed into folders because there is currently no way to create or manage folders via the Spotify API. If you want the archived playlist to be in a folder, you will have to move them manually\n\n\n## Contributing\nContributions, issues, and forks are welcome but this is a hobby project so don't expect too much from it. [SemVer](http://semver.org/) is used for versioning.\n\n\n## License\nThis project is licensed under the MIT License. See [LICENSE](LICENSE) for details.\n\nThis project includes various resources which carry their own copyright notices and license terms. See [LICENSE-THIRD-PARTY.md](LICENSE-THIRD-PARTY.md) for more details.\n\n\n[Finding the Playlist ID]: #finding-the-playlist-id\n[Scheduling]: #scheduling\n[Advanced Script Usage]: #advanced-script-usage\n[setup.py]: scripts/setup.py\n[get-playlist-id.py]: scripts/get-playlist-id.py\n[copy-playlist.py]: scripts/copy-playlist.py\n[constants.py]: scripts/utils/constants.py\n[.github/workflows/]: .github/workflows/\n[Spotify Developer Dashboard]: https://developer.spotify.com/dashboard\n[Using secrets in GitHub Actions]: https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions\n[strftime format codes]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes\n[new changes to their Web API]: https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api\n[this Spotify Community post]: https://community.spotify.com/t5/Spotify-for-Developers/Changes-to-Web-API/m-p/6540414\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjerboa88%2Fplaylist-archiver-for-spotify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjerboa88%2Fplaylist-archiver-for-spotify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjerboa88%2Fplaylist-archiver-for-spotify/lists"}