Inspiration

We both love music and we both love to travel. However, we often find ourselves unable to choose what to play on journeys, or similarly, finding our playlists don't hit the spot. We wanted a map‑powered mixtape that changes with your route, your tastes, and the places you pass by.

What it does

GeoGroove builds a route‑aware playlist in real time:

  • You pick a route and choose a few tags/genres you’re into.
  • We fetch candidate tracks from a refined music dataset and geolocate artists by region.
  • Our scheduler assembles a playlist that balances three things: geographic proximity (where you’re driving), your musical preferences (rank/score), and track quality (ratings).
  • It ensures variety (no dupes, artist caps, light randomness) and occasionally inserts short artist “bio” snippets to keep the experience rich and contextual.

How we built it

Simple two‑dev split with lots of pairing:

  • James owned the backend: Supabase Edge Functions (Deno), Postgres (RPC/functions), and data migration tools to wrangle the MusicBrainz‑derived dataset.
  • Alex owned the frontend: Swift‑UI with a Spotify integration.
  • We pair‑programmed the harder bits: the scheduler (distance + rank + score, specifically debugging it), and the API + UI wire‑up.

Challenges we ran into

1) Data collation and refinement

  • We had to quickly stand up a migration pipeline to subset and reshape a MusicBrainz‑style dataset for our use case.
  • Later on that we'd like to admit, we accidentally allowed duplicates (same track showing up multiple times per journey). We fixed this by:
    • Normalizing tags case‑insensitively (lowercasing inputs and tags).
    • De‑duplicating in SQL (DISTINCT ON per track before ranking).
    • Enforcing a unique index on (journey_id, track_id) and using upserts correctly.

2) Getting the playlist collation algorithm to work

  • Balancing geography vs. taste is subtle. Distance is in km; rank/score are unitless. We had to normalise and scale each signal so one didn’t swamp the others.
  • We added a cost‑based scoring model with normalised distance, normalised rank, a rating‑aware score, an artist recency penalty, and a top‑K randomised pick to avoid identical runs.

We minimise the total cost

$$ C = w_d\cdot D + w_r\cdot R + w_s\cdot (1 - S) + P_{\text{artist}}, $$

where $D, R \in [0,1]$ are the normalised distance and rank (0 is best), $S \in [0,1]$ is the normalised preference score (1 is best), and $P_{\text{artist}} \ge 0$ is a small recency penalty. Lower $C$ is better.

  • We advanced “route points” based on accumulated track duration so the playlist truly follows the map instead of getting stuck on one segment.

Accomplishments that we’re proud of

  • A genuinely route‑aware playlist that feels contextual to place, not just preference.
  • A clean (as possible in the time), fast, serverless backend.
  • Seamless Spotify integration in‑app.
  • A resilient candidate pipeline: case‑insensitive matching, dedupe at the source, and a unique index to guarantee data quality.
  • A scheduler that blends proximity, taste, and quality with just enough variety to keep it fresh.

What we learned

  • Data hygiene is everything. Small issues like case sensitivity and missing constraints cascade into big UX problems.
  • Normalise your signals before combining them. Distance, ranks, and ratings live on different scales.
  • A hybrid of deterministic scoring and controlled randomness produces better playlists than either alone.

What’s next for GeoGroove

  • AI integration: generate bios/summaries for artists and regions to deepen the storytelling between tracks.
  • Refining the dataset and algorithm even further for better geocoding coverage, smarter variety controls, and improved UX.
  • Personalisation: learn per‑user tastes over time, not just per‑journey preferences.

Built With

Share this project:

Updates

Submission history