Have you ever played a playlist for hours, gone to a club, listened to that song you have heard 100 times, and you could not even name the artist? Or would you like to know how your taste evolves over time?
The idea first came to me when I was trying to remember the names of songs and I could not name a single one. So, I wanted to use Remnote's spaced repetition algorithm to be able to build flashcards that I could use to better remember the names of the songs.
But then, I started thinking that I could also track that as a time series and maybe be able to perform analysis on that data (in the future).
As of right now, this is an MVP that will allow you to poll data from your Spotify account, store that data in a TimescaleDB and, if you want, create Remnote flashcards where you can practice with the songs you listened to recently.
- Permanent Listening History: Automatically polls services like Spotify to capture your listening data before it's lost, storing it in your own database.
- Time-Series First: Built on TimescaleDB, allowing for powerful and efficient temporal analysis of your listening habits over months and years.
- Metadata Enrichment: Goes beyond basic track info by enriching your data with metadata from external sources like MusicBrainz, adding details like composers, sub-genres, and country of origin.
- Extensible Provider System: Designed from the ground up to be provider-agnostic. While starting with Spotify, the architecture makes it easy to add other sources like Apple Music or YouTube Music in the future.
- Ready for Self-Hosting: If you don't want me to see and judge your Spotify history, you can also selfhost this. Follow
If you want to contribute, I'd love to get help and get roasted over my questionable design decisions. This is an overview of the project architecture and design..<>
This project is built using principles from Domain-Driven Design (DDD). The app isseparated into three distinct layers:
-
Domain Layer(The Core): It contains the pure business logic and models (User,Song,Listen) and the interfaces for our repositories and external services. This layer has zero dependencies on any framework or external tool. -
Application Layer(The Orchestrator): This layer drives the business workflows. It contains the application services (e.g.,AuthService,SyncService) that orchestrate the domain models and repositories to perform tasks. Our FastAPI application and Celery/ARQ workers live here. -
Infrastructure Layer(The Details): This layer contains the concrete implementation of the interfaces defined in the Domain. This includes database repositories (the TimescaleDB implementation), API clients (for Spotify, MusicMetadataFetcher), and authentication providers.
This separation allows us to easily swap out technical details—like changing the database or adding a new music service—without affecting the core business logic of the application.
- Backend API: FastAPI
- Database: PostgreSQL with the TimescaleDB extension. Timescale is free if you selfhost, they also have a free trial for their cloud service.
- Asynchronous Task Queue: Celery / ARQ with Redis
You can get the entire application stack running on your local machine in minutes.
-
Clone the repository:
git clone https://github.com/your-username/tunetrack.git cd tunetrack -
Configure your environment:
- Copy the example environment file:
cp .env.example .env - Edit the
.envfile and add your Spotify Developer API credentials (SPOTIFY_CLIENT_ID,SPOTIFY_CLIENT_SECRET).
- Copy the example environment file:
-
Run the application:
docker-compose up --build
This command will build the Docker images for the API, the database, and the background worker, and start them all. Your API will be available at http://localhost:8000.
The project follows the layered architecture described above:
.
├── docker-compose.yml
├── Dockerfile
├── .env.example
└── src/
├── domain/ # Core models (User, Song) and repository interfaces
├── application/ # FastAPI app, Celery workers, and application services
└── infrastructure/ # TimescaleDB repositories, Spotify API client, etc.