Album cover collage generator for Last.fm and ListenBrainz.
- Dual provider support (Last.fm and ListenBrainz)
- Customizable grid layouts (1×1 to 10×10)
- Flexible image sizing (50-300px)
- Optional borders between covers
- Intelligent filesystem caching with dynamic TTL
- Fast image processing with Sharp
- Docker deployment ready
- Node.js 20+
- pnpm (
npm install -g pnpm) - Last.fm API key (Get one here)
-
Clone the repository
git clone https://github.com/jee-r/patchwork-astro.git cd patchwork-astro -
Install dependencies
pnpm install
-
Configure environment variables
cp .env.example .env # Edit .env and add your LASTFM_API_KEY -
Start development server
pnpm dev
git clone https://github.com/jee-r/patchwork-astro.git
cd patchwork-astro
cp .env.example .env
# Edit .env and add your LASTFM_API_KEY
docker-compose up -dApplication available at http://localhost:3000
- Select a provider (Last.fm or ListenBrainz)
- Enter your username
- Choose time period (overall, 7day, 1month, 3month, 6month, 12month)
- Configure grid size (1-10 rows/columns)
- Set image size (50-300px)
- Toggle borders if desired
- Generate patchwork
patchwork-astro/
├── src/
│ ├── pages/
│ │ ├── index.astro
│ │ ├── patchwork.jpg.ts
│ │ └── api/cache-stats.json.ts
│ ├── services/
│ │ ├── cache-manager.ts
│ │ ├── lastfm.ts
│ │ ├── listenbrainz.ts
│ │ └── patchwork-generator.ts
│ └── styles/main.css
├── public/assets/
├── cache/
├── Dockerfile
├── docker-compose.yml
└── astro.config.mjs
Create a .env file from .env.example:
cp .env.example .envRequired:
| Variable | Description | Default |
|---|---|---|
LASTFM_API_KEY |
Your Last.fm API key (Get one) | - |
Cache TTL Configuration (Optional):
| Variable | Description | Default |
|---|---|---|
CACHE_TTL_7DAY |
Cache duration for 7-day period (hours) | 6 |
CACHE_TTL_1MONTH |
Cache duration for 1-month period (hours) | 12 |
CACHE_TTL_3MONTH |
Cache duration for 3-month period (hours) | 24 |
CACHE_TTL_6MONTH |
Cache duration for 6-month period (hours) | 48 |
CACHE_TTL_12MONTH |
Cache duration for 12-month period (hours) | 72 |
CACHE_TTL_OVERALL |
Cache duration for overall period (hours) | 168 |
Cache Size Limits (Optional):
| Variable | Description | Default |
|---|---|---|
CACHE_MAX_SIZE_MB |
Maximum cache size in MB | 1024 (1GB) |
CACHE_MAX_ENTRIES |
Maximum number of cached images | 10000 |
The cache uses dynamic TTL based on the time period:
- Short periods (
7day) have shorter cache (6h) to keep data fresh - Long periods (
overall) have longer cache (7 days) since data changes slowly - Expired entries are automatically cleaned up when new images are generated
GET /patchwork.jpg?username=USER&provider=lastfm&period=overall&rows=3&cols=3&size=150&border=normal
Query Parameters:
username(required) - Last.fm or ListenBrainz usernameprovider(optional) -lastfmorlistenbrainz(default:lastfm)period(optional) -overall,7day,1month,3month,6month,12month(default:overall)rows(optional) - 1-10 (default: 3)cols(optional) - 1-10 (default: 3)size(optional) - 50-300 pixels (default: 150)border(optional) -normalornone(default:normal)
Response Headers:
X-Cache-HITorMISSX-Generation-Time- Generation duration (only on MISS)X-Image-Width- Image width in pixelsX-Image-Height- Image height in pixels
GET /api/cache-stats.json
Returns cache statistics in JSON format.
- First generation: ~2-3 seconds (network + image processing)
- Cached requests: < 50ms (filesystem read)
- CDN cached: < 10ms
This is a complete rewrite of the original PHP version with improvements:
- TypeScript for type safety
- ListenBrainz support added
- Intelligent caching with dynamic TTL
- Modern stack (Astro + Sharp vs PHP + GD)
- Query parameter URLs
- Better developer experience
Contributions welcome. Please submit a Pull Request.
MIT License - see LICENSE file.