This project provides a serverless backend for easily adding songs to your Spotify playlists using custom API keys, designed to be integrated seamlessly with tools like iPhone Shortcuts. Built on Hono, Cloudflare Workers, and Cloudflare D1.
| Area | Stack |
|---|---|
| Framework | Hono (with JSX templating) |
| Hosting | Cloudflare Workers |
| DB | Cloudflare D1 (SQLite) |
| OAuth Provider | Spotify |
This application aims to simplify adding music to Spotify playlists, especially from mobile devices without opening the Spotify app.
Motivation: Shazam (Apple) and other iOS actions or shortcuts do not directly provide a way to add shazamed or identified songs to Spotify playlists. This application acts as a bridge, allowing you to create an iOS shortcut that sends the song information to this web app, which then handles adding it to your specified Spotify playlist.
- Spotify Authentication: Users can securely authenticate with their Spotify account using the Authorization Code Flow.
- Personal API Token: Upon first login, each user is issued a unique, secure API token. This token acts as a lightweight, per-user authentication mechanism for the
/addendpoint. - API Token Management: Users can view their API token on a dashboard, regenerate it (invalidating the old one), or delete their entire account and token.
- iPhone Shortcut Integration: The core functionality enables a simple HTTP GET request from an iPhone Shortcut (or similar automation tool) to add a song to a specified playlist. The API key can be provided either as a query parameter or in the
Authorizationheader:- Query parameter:
https://yourapp.com/add?query=SONG_QUERY&playlist=PLAYLIST_NAME&token=YOUR_API_KEY - Authorization header:
GET https://yourapp.com/add?query=SONG_QUERY&playlist=PLAYLIST_NAME Authorization: Bearer YOUR_API_KEY
- Query parameter:
- Automatic Token Refresh: The application automatically handles the refreshing of Spotify access tokens in the background, ensuring long-lived API key validity.
This project is specifically designed to work with Apple's iOS Shortcuts. You can use the provided template to quickly set up a shortcut that adds a song to your Spotify playlist.
Download the "Add to Spotify Playlist" Shortcut Template
- Download the Shortcut: Tap the link above on your iOS device to add the shortcut to your Shortcuts app.
- Edit the Shortcut:
- Open the Shortcuts app and find the "Add to Spotify Playlist" shortcut.
- Edit the "URL" action:
- Replace
yourapp.comwith the actual domain of your deployed Cloudflare Worker (e.g.,your-worker-name.workers.devor your custom domain). - Replace
YOUR_API_KEYwith the API key generated from your dashboard (/dashboard) after logging into the web application.
- Replace
- Edit the "Text" action for
Playlist Name:- Enter the exact name of the Spotify playlist you want to add songs to.
- Run the Shortcut:
- You can run this shortcut manually from the Shortcuts app, or by integrating it with other actions (e.g., after Shazaming a song, share it to this shortcut).
- When prompted, enter the song name.
The shortcut will then call your deployed Worker, which will search for the song on Spotify and add it to your specified playlist.
The application uses a single users table to store Spotify user authentication details and their associated API key.
CREATE TABLE users (
id TEXT PRIMARY KEY, -- Spotify user ID
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
expires_at INTEGER NOT NULL, -- UNIX timestamp (when access_token expires)
api_key TEXT NOT NULL -- Secure token used in /add endpoint
);| Route | Method | Description |
|---|---|---|
/ |
GET | Landing page with "Log in with Spotify" button. |
/login |
GET | Initiates the Spotify OAuth Authorization Code Flow. |
/callback |
GET | Handles the redirect from Spotify after user authorization, exchanges code for tokens, saves/updates user data in D1, and redirects to dashboard. |
/dashboard |
GET | User's dashboard to view their API key, regenerate it, or delete their account. Requires authentication. |
/dashboard/logout |
POST | Clears the session cookie to log the user out. |
/api/generate |
POST | Regenerates the API key for the current authenticated user. Requires authentication. |
/api/delete |
POST | Deletes the current user's account and all associated data from D1. Requires authentication. |
/add |
GET | The primary endpoint for adding songs. Accepts query, playlist (query parameters). Authentication via token query parameter or Authorization: Bearer <token> header. |
To get the project running on your local machine:
- Node.js (v18.0.0 or higher recommended)
- npm (or yarn/pnpm)
- A Spotify Developer Account: https://developer.spotify.com/dashboard/
- A Cloudflare account (for D1 database, though local D1 emulator works without one)
git clone https://github.com/your-username/spotify-shortcut-helper.git
cd spotify-shortcut-helpernpm install- Go to your Spotify Developer Dashboard.
- Create a new application.
- In your app's settings, add the following to Redirect URIs:
http://localhost:8787/auth/callback(for local development usingnpm run dev)http://127.0.0.1:8787/auth/callback(alternative for local development, depending on how you access it)https://your-worker-name.your-account.workers.dev/auth/callback(for production, replace with your actual Cloudflare Worker URL)- If using a custom domain:
https://your-custom-domain.com/auth/callbackIt's crucial that these URIs exactly match what your application will use, including the/auth/callbackpath.
- Note down your Client ID and Client Secret.
-
Create a D1 Database: This needs to be done once to get a
database_id.wrangler d1 create PlaylistUrlify-db
- Note the
database_idfrom the output (e.g.,fc67ed8f-f638-438b-995b-cd343fe2b37b).
- Note the
-
Configure
wrangler.jsonc: Openwrangler.jsoncand update thed1_databasessection with yourdatabase_id: -
Create D1 Migrations Directory:
mkdir -p migrations
-
Create
schema.sql: Create a file namedschema.sqlin the project root (schema.sql) with the D1 schema:-- schema.sql CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, access_token TEXT NOT NULL, refresh_token TEXT NOT NULL, expires_at INTEGER NOT NULL, api_key TEXT NOT NULL );
-
Generate Initial Migration File:
wrangler d1 migrations create playlisturlify-db init_schema
This will create a file like
migrations/<timestamp>_init_schema.sql. -
Populate Migration File: Manually copy the entire content of
schema.sqlinto the newly createdmigrations/<timestamp>_init_schema.sqlfile. (Do not leave the migration file empty). -
Apply Migrations to Local D1 Emulator:
wrangler d1 migrations apply playlisturlify-db --local
Confirm you want to apply the migration. You should see "status: OK" or similar success message.
-
Verify Table Creation (Optional but recommended):
wrangler d1 execute playlisturlify-db --local --command "SELECT name FROM sqlite_master WHERE type='table' AND name='users';"Expected output:
[ { "name": "users" } ]
Create a .dev.vars file in your project root (.dev.vars) and fill it with your Spotify app credentials:
# .dev.vars
SPOTIFY_CLIENT_ID="YOUR_SPOTIFY_CLIENT_ID"
SPOTIFY_CLIENT_SECRET="YOUR_SPOTIFY_CLIENT_SECRET"
Run this command to update your TypeScript types based on your wrangler.jsonc and .dev.vars:
npm run cf-typegennpm run devThe application will be accessible at http://localhost:8787 (or similar port).
-
Set Production Secrets: For production, environment variables are stored as secrets in your Cloudflare Worker.
wrangler secret put SPOTIFY_CLIENT_ID wrangler secret put SPOTIFY_CLIENT_SECRET
(Enter your respective values when prompted.)
-
Apply Migrations to Remote D1: If you haven't already, apply your database schema to your live Cloudflare D1 instance.
wrangler d1 migrations apply playlisturlify-db --remote
-
Deploy the Worker:
npm run deploy
Wrangler will build your project using Vite and deploy it to your Cloudflare account. Your app will be accessible at the Worker's URL (e.g.,
your-app-name.your-worker-subdomain.workers.dev). You can then configure a custom domain via Cloudflare DNS settings if desired.
(Optional: Add sections for how others can contribute, e.g., bug reports, feature requests, pull requests.)
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "PlaylistUrlify", "compatibility_date": "2024-04-01", "main": "./src/index.tsx", "d1_databases": [ { "binding": "DB", "database_name": "PlaylistUrlify-db", "database_id": "YOUR_D1_DATABASE_ID_HERE", # <--- REPLACE THIS "migrations_dir": "migrations" } ] }