{"id":25425277,"url":"https://github.com/emoore29/cadence","last_synced_at":"2025-07-18T09:33:10.046Z","repository":{"id":269390167,"uuid":"877721104","full_name":"emoore29/cadence","owner":"emoore29","description":"Playlist generator based on track features (e.g. bpm, key, mood).","archived":false,"fork":false,"pushed_at":"2025-06-02T05:38:30.000Z","size":6922,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-02T15:52:56.187Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://cadencetracks.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emoore29.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2024-10-24T06:08:25.000Z","updated_at":"2025-06-02T05:55:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"88778e7f-8c06-4fb5-8596-3db86712c2e2","html_url":"https://github.com/emoore29/cadence","commit_stats":null,"previous_names":["emoore29/cadence-demo","emoore29/cadence"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/emoore29/cadence","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emoore29%2Fcadence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emoore29%2Fcadence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emoore29%2Fcadence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emoore29%2Fcadence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emoore29","download_url":"https://codeload.github.com/emoore29/cadence/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emoore29%2Fcadence/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265734052,"owners_count":23819465,"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":[],"created_at":"2025-02-16T23:43:48.990Z","updated_at":"2025-07-18T09:33:10.037Z","avatar_url":"https://github.com/emoore29.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cadence\n\nA Spotify-integrated playlist generator based on track features.\n\nCadence is self-hosted and is therefore not available 24/7. This was a deliberate decision as the main goal of this project is learning, and self-hosting was a good opportunity to learn more about Docker and Nginx. I do my best to keep it online as often as possible!\n\n**Note**: Until an extension request is granted by Spotify, only whitelisted users can access the full features of the app. Non-whitelisted users can still filter public Spotify playlists but won't be able to save the playlist to their Spotify account or view their saved/top tracks. You can always [run the project locally](#how-to-run-locally) if you want to try the full features.\n\n## Contents\n\n- [demo](#demo)\n- [development todos](#development-todos)\n- [development history](#development-history)\n- [how it works](#how-it-works)\n- [authorization](#authorization-code-flow)\n- [how to run locally](#how-to-run-locally)\n\n\n## Demo\n\n![Personal playlist generation for a whitelisted user](./demo1.gif)\n\n## Development TODOs\n\n- [ ] Inform users about app limitations on website (e.g. whitelisting, explain where features are sourced from and why they may not be accurate)\n- [ ] Display track features in a modal\n- [ ] Add FAQ\n- [ ] Improve keyboard accessibility of track table\n- [ ] Improve Footer design\n- [ ] Apply for Spotify extension program\n- [ ] Create flowcharts to summarise API integration\n- [ ] Update \"how it works\" section of README for better documentation\n\n## Development History\n\nCadence was originally intended to be accessible for all Spotify users to create customised playlists from their personal Spotify libraries. Unfortunately, in November 2024 towards the end of Cadence's development, [Spotify deprecated the following endpoints without warning](https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api), which were needed for Cadence to function as intended:\n\n- Recommendations\n- Audio Features\n- 30-second preview URLs\n- Get available genre seeds\n\nThese are no longer available to existing apps that are still in development mode without a pending extension request, which applies to Cadence. The user access tokens granted by Cadence's Client ID will not provide access to the above endpoints anymore, so fetch requests will return 403 or 404 status codes.\n\nIt's difficult to find APIs that offer similar data. [Deezer](https://developers.deezer.com/myapps) has an API that provides track BPM, but currently isn't accepting new developer applications. Even using the open API, it looks like many popular songs are missing BPM data.\n\nAcousticBrainz, which offers similar features to Spotify, including track BPM, is unfortunately no longer collecting data as of 2022. Their database of over 7 million unique tracks is [available for download](https://acousticbrainz.org/download).\n\nTo finalise the project, I decided to use AcousticBrainz's data to retrieve track audio features. This results in a version of Cadence closest to what was originally intended, albeit with some track audio features unavailable.\n\n## How it works\n\nCadence has multiple \"sources\" of tracks, which users can filter by features such as tempo (BPM).\n\nOnce a user has granted Cadence permission to access their Spotify data, they can load their Spotify saved tracks, top tracks, and top artists. When the user's saved and top tracks are fetched, fetches are now made to MusicBrainz and AcousticBrainz to get each track's features and tags (pre-Spotify-deprecation, requests were made to Spotify). Tracks that exist in both the user's Spotify library as well as AcousticBrainz's database can then be stored in IndexedDB stores:\n\n- \"savedTracks\" - a user's saved tracks and features\n- \"topTracks\" - a user's top 500 tracks and features from the last 12 months\n- \"topArtists\" - a user's top 50 artists from the last 12 months\n\nThe user could then choose to filter these stores based on the track features available (currently BPM, chords key and chords scale - pre-Spotify-deprecation, more features were available).\n\nPrior to Spotify deprecation, users also had the option to get recommendations from Spotify based on custom \"seeds\", such as their favourite genre(s), track(s), and/or artist(s), alongside any desired track features. Now, the input fields to search for these seeds are still functional, but as there is no way to demonstrate this feature with sample data, clicking submit will display an error notification and won't return any tracks.\n\n## Authorization Code Flow\n\nTo make any requests to the Spotify API, users need an access token. For this, users need to \"log in\" and authorize Cadence to access their Spotify data, and this will grant them an access token.\n\nThe code uses the [Authorization Code Flow](https://developer.spotify.com/documentation/web-api/tutorials/code-flow). After the user authorizes Cadence, they are redirected back to the app with access and refresh tokens. These tokens are stored in browser local storage, and a refresh request is sent every hour just before the current access token expires.\n\nPost-deprecation, this is still functional, so users can \"log in\" to Cadence. This means that when the playlist tracks are displayed, each track's saved status will match the track's saved status in that user's Spotify account and the user can save or unsave a track if they want to. If the user doesn't log in, a warning indicates that the saved statuses may not match their Spotify library and they won't be able to save or unsave any tracks. They also won't be able to save any playlists created with the demo data unless they are logged in.\n\n\n## How to run locally\n\nClone the repository with GitHub desktop or via a terminal and open the project root folder in a terminal.\n\nRun the frontend:\n\n```\ncd client\nnpm install\nnpm run dev\n```\n\nRun the backend:\n\n```\ncd server\nnpm install\nnpm run dev\n```\n\nTo use the authorization flow described above, create an app in the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard) and save the Client ID and Client Secret in a .env file inside /server:\n\n```\nSPOTIFY_CLIENT_ID=\"\u003cinsert ID here\u003e\"\nSPOTIFY_CLIENT_SECRET=\"\u003cinsert secret here\u003e\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femoore29%2Fcadence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femoore29%2Fcadence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femoore29%2Fcadence/lists"}