One-button Spotify automation across your phone and laptop. Like the currently-playing track with a headset pause-play pattern (Android) or a global keyboard hotkey (Windows tray; macOS / Linux CLI). On top of "like", a small rule engine runs per like: remove from an archive playlist (Discover Weekly clean-up), promote a track to a "best-of" playlist when you've liked it N times across devices, auto-follow an artist after N liked tracks. Counters live in Supabase or Google Sheets so phone + laptop see the same numbers.
The desktop side is a pluggable framework, not a single tool. Five extension points — Trigger, MusicProvider, Storage, PreLikeAction, PostLikeAction — discover at startup via a filesystem convention (each extension is a folder with a manifest.json and a TRIGGER / MUSIC_PROVIDER / STORAGE / PRE_LIKE_ACTION / POST_LIKE_ACTION factory). Drop a folder, restart, your code runs in the like pipeline. See CONTRIBUTING.md for the plugin-author guide.
Keywords for the search-engine crowd: spotify like hotkey, spotify automation, headset pause-play like, spotify scrobbler alternative, spotify plugin framework, cross-device like counter.
- Trigger — pause-play your headset (Android) or press a hotkey (desktop)
- Like — the current track is added to your Spotify Liked Songs
- Archive cleanup — if the track is in your archive playlist, it gets removed
- Best-of promotion — like a track 3 times across devices and it's added to your best-of playlist
- Artist follow — like 5+ tracks from an artist and they get auto-followed
There are several adjacent projects in this space; they solve overlapping problems but none solve all four of one-press cross-device like + rule engine + headset-button trigger on phone + plugin framework on desktop.
| Project | One-press like | Headset trigger (phone) | Hotkey trigger (desktop) | Rule engine (archive/best-of/follow) | Cross-device counters | Pluggable | Use theirs when |
|---|---|---|---|---|---|---|---|
| Like Spotify (this) | ✓ | ✓ Android | ✓ Windows tray + mac/linux CLI | ✓ | ✓ Supabase / Sheets | ✓ 5 typed seams + manifest discovery | n/a |
| Pano Scrobbler | partial (love via UI) | — (notification scrape) | — | — (scrobble target only) | — | provider seam only (write target) | you want scrobbling history to last.fm/listenbrainz/librefm/pleroma. Pano is the right answer for "where did my listens go" — we don't try to replace it. |
| SpotifyHotKeys.ahk | ✓ (like / unlike) | — | ✓ Windows only (AutoHotKey) | — | — | — | you already live in AutoHotKey and want a small single-file script you can paste & edit. We're heavier (Python install) but cross-platform and rule-capable. |
| Music Assistant | partial (per-provider) | — | via Home Assistant | extensive (queue / library / sync) | — (per-instance) | ✓ ~60 providers | you want Home Assistant-grade music orchestration — multi-provider library merging, multi-room sync, queue scripting. We don't try to be your music server; we sit next to your existing Spotify client. |
| n8n / Zapier / IFTTT | only via polling | — | — | yes (general workflows) | yes (workflow vars) | ✓ generic | you want a generic workflow engine with a UI and 400+ integrations. We're the inverse — narrow to "like + post-like rules", but one button press and ~30 ms latency vs minutes of polling. |
- Go to developer.spotify.com/dashboard
- Create an app
- Add redirect URIs:
likespotify://auth-callback(Android)http://127.0.0.1:8793/callback(Desktop)
- Copy your Client ID
# Clone and setup
git clone https://github.com/Osasuwu/like_spotify_mobile_app.git
cd like_spotify_mobile_app
# Configure
cp .env.example .env
# Edit .env — set SPOTIFY_CLIENT_ID (and optionally SUPABASE_URL/KEY)
# Build
flutter pub get
flutter build apk --release --dart-define-from-file=.envInstall the APK, connect Spotify in the app, enable the listener service.
The desktop side ships as a pluggable Python package (like_spotify/) —
a tray host + global hotkey on Windows, a CLI fallback (like-once) on
macOS / Linux, and a multi-backend counter Storage (Supabase or Google
Sheets).
One-liner installs. Run from a fresh clone:
# Windows (PowerShell)
git clone https://github.com/Osasuwu/like_spotify_mobile_app.git
cd like_spotify_mobile_app
.\install.ps1# macOS / Linux
git clone https://github.com/Osasuwu/like_spotify_mobile_app.git
cd like_spotify_mobile_app
./install.shThe installer checks for Python 3.11+, installs pipx if missing,
installs the like-spotify package, then walks you through the
interactive setup wizard:
- Spotify — paste a Client ID from
developer.spotify.com/dashboard
(redirect URI:
http://127.0.0.1:8793/callback); a browser opens for PKCE OAuth. - Storage — pick
supabase,sheets, ornone(likes work without a counter; you'd just lose cross-device aggregation). - Autostart — Windows: toggle the
HKCU\…\Runentry. macOS / Linux: instructions for a Launch Agent /.desktopfile are printed (no auto-config — too platform-fragmented).
The wizard is re-runnable; existing tokens are kept unless you pass
--reauth (or -Reauth on PowerShell).
After install:
like-spotify # Windows: tray host with the hotkey (default Ctrl+Shift+Alt+W)
like-spotify like-once # any OS: like the currently-playing track and exit
like-spotify remove-once # any OS: remove the current track from the archive playlist (no like)
like-spotify --config # print config + token pathslike-spotify is a console-subsystem executable, so any of the above
briefly shows a terminal window. On Windows, a windowed twin is also
installed — like-spotify-gui — that runs the exact same commands with no
console at all. Autostart uses it automatically; if you trigger like-once
/ remove-once from an external hotkey tool (AutoHotkey, a macro app, a
Stream Deck, etc.), point it at like-spotify-gui like-once instead of
like-spotify like-once to avoid the flash. (--setup / --config still
need like-spotify, since they read from the terminal.)
On Windows the tray host also binds a second global hotkey (default
Ctrl+Shift+Alt+Q) that removes the currently-playing track from your
Discover-Weekly archive playlist without liking it — for tracks you
want gone but not in your Liked Songs. It's active only once you set an
archive playlist name in --setup; if it collides with the like hotkey
it's skipped. Audio feedback is audible through the default sound device
and distinct per action (like / remove / error).
Single-file .exe (for users without Python): build via
tools\build.bat → dist\LikeSpotify.exe.
Pick a backend during --setup:
Counters live in Supabase Postgres (free tier).
- Create a Supabase project
- Run the setup SQL:
CREATE TABLE public.track_likes ( user_id TEXT NOT NULL, track_id TEXT NOT NULL, count INTEGER NOT NULL DEFAULT 1, updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (user_id, track_id) ); CREATE OR REPLACE FUNCTION increment_track_like(p_user_id TEXT, p_track_id TEXT) RETURNS INTEGER LANGUAGE plpgsql SECURITY DEFINER AS $$ DECLARE new_count INTEGER; BEGIN INSERT INTO public.track_likes (user_id, track_id, count, updated_at) VALUES (p_user_id, p_track_id, 1, now()) ON CONFLICT (user_id, track_id) DO UPDATE SET count = track_likes.count + 1, updated_at = now() RETURNING count INTO new_count; RETURN new_count; END; $$; ALTER TABLE public.track_likes ENABLE ROW LEVEL SECURITY; CREATE POLICY "anon_full_access" ON public.track_likes FOR ALL USING (true) WITH CHECK (true);
- Android: add
SUPABASE_URLandSUPABASE_ANON_KEYto.env. Desktop: paste both into the wizard when prompted for thesupabasebackend.
If you'd rather see counts in a spreadsheet you control:
- Create a Google Sheet with header row
user_id | track_id | count | backfilled | updated_aton a tab namedLikes. Optionally add anArtistTrackstab for the follow-artist rule. - Create a Google Cloud OAuth client (type: Desktop app) at console.cloud.google.com/apis/credentials. Enable the Google Sheets API for the project. Note the Client ID + secret.
- Run
like-spotify --setup, picksheets, paste the spreadsheet ID (from the URL), Client ID, and secret. A browser opens for Google authorization — tokens are refreshed automatically afterwards.
Without a backend, counters are silently skipped — likes still write to your Spotify Liked Songs.
Android (Flutter + Kotlin) Desktop (Python framework)
┌──────────────────────┐ ┌──────────────────────────┐
│ MediaSession │ │ Trigger (hotkey/tray) │
│ pause-play pattern │ │ ↓ │
│ ↓ │ │ MusicProvider (Spotify) │
│ SpotifyLikeWorker │ │ • like track │
│ • like track │ │ Storage → #22 │
│ • remove from │ │ PostLikeAction → #23/26 │
│ archive │ │ · archive remove │
│ • Supabase counter │ │ · best-of promote │
│ • best-of / follow │ │ · artist follow │
└──────┬───────────────┘ └──────┬───────────────────┘
│ │
└──────────┬───────────────────────┘
↓
Spotify Web API (shared state)
Supabase (shared counters)
lib/— Flutter app (Dart): UI, state management (Riverpod), Spotify OAuthandroid/.../kotlin/— Native Android: foreground service, MediaSession, background workerlike_spotify/— Python desktop package:core/(ABCs),hosts/(tray runtime),extensions/(default Spotify provider + tray-hotkey trigger),samples/(alt-flavor examples)
| Setting | Android | Desktop |
|---|---|---|
| Trigger pattern / hotkey | In-app UI | ~/.like_spotify/config.json → trigger.hotkey (default Ctrl+Shift+Alt+W) |
| Remove-from-archive hotkey | n/a (one trigger on headphones) | ~/.like_spotify/config.json → trigger.remove_hotkey (default Ctrl+Shift+Alt+Q) |
| Archive playlist name | In-app UI | ~/.like_spotify/config.json → actions.archive_remove.playlist_name (blank = archive-remove disabled) |
| Spotify client_id | .env (SPOTIFY_CLIENT_ID) |
like-spotify --setup → ~/.like_spotify/config.json |
| Spotify tokens | FlutterSecureStorage |
~/.like_spotify/spotify_token.json |
| Storage backend | (Supabase only) | ~/.like_spotify/config.json → storage.backend (supabase / sheets / none) |
| Google Sheets tokens | n/a | ~/.like_spotify/google_token.json (refreshed automatically) |
| Best-of / follow | In-app UI | ~/.like_spotify/config.json → actions.{promote_to_best_of,follow_artist} |
Contributions are welcome — the desktop side is a plugin framework precisely so that other people's triggers, providers, storages, and actions can live in it.
- CONTRIBUTING.md — repo layout, the five extension points with code, the add-an-extension checklist, and how to run the tests. It also lists what's known to be easy to land.
- Good first issues · Help wanted
- CODE_OF_CONDUCT.md
- SECURITY.md — please report vulnerabilities privately, not as a public issue.
- CHANGELOG.md