Album art collage generator. I was bored so I made this to get a wallpaper for my phone.
This accepts Spotify playlists and converts them into collages for any given resolution as shown below.
With the UI, it is very easy to edit, preview, and crop the collage before saving it to a file.
Have a look at a few screenshots.
- Main window
- Scaling (AUTO will fit the maximum amount of images inside the given output resolution)
- Easy pan & zoom preview
- Results
Please run the following commands from the project directory (the cloned directory).
-
Clone the repo via
git clone https://github.com/vhagedorn/AlbumArt
. -
Create a text file called
content/playlist.txt
with the Spotify links that you wish to get. -
Open a terminal/powershell at the project directory (probably
AlbumArt
).- Option A: (for Linux/MacOS users)
- Make sure your links are in
playlist.txt
! - Run
./fetch_content
and grab a cup of coffee.
- Make sure your links are in
- Option B: (for Windows users)
- Find the links to the album covers with
python3 src/main/python/parse.py
. - Run
python3 src/main/python/download.py
, which will download the album art as.jfif
files.
- Find the links to the album covers with
- Option A: (for Linux/MacOS users)
-
Finally, you can generate the collage via
java -jar target/AlbumArt.jar
.Follow its instructions to generate as many collages as you want!
Initially in Java, it spread to a mess of multiple languages after several attempts.
- Converts
content/playlist.txt
(list Spotify links) ->content/links.txt
(list of links to album art)
This abuses Spotify's OEmbed service, which provides the URL to their album cover CDN.
An example request would return JSON containing thumbnail_url
.
https://open.spotify.com/oembed?url=spotify:track:6c5wQFfJApRMooKE7UQnlH
returns:
{
"html": "<iframe style=\"border-radius: 12px\" width=\"100%\" height=\"80\" title=\"Spotify Embed: durag activity (with Travis Scott)\" frameborder=\"0\" allowfullscreen allow=\"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture\" src=\"https://open.spotify.com/embed/track/6c5wQFfJApRMooKE7UQnlH?utm_source=oembed\"></iframe>",
"width": 456,
"height": 80,
"version": "1.0",
"provider_name": "Spotify",
"provider_url": "https://spotify.com",
"type": "rich",
"title": "durag activity (with Travis Scott)",
"thumbnail_url": "https://i.scdn.co/image/ab67616d00001e021bfa23b13d0504fb90c37b39", # bingo!
"thumbnail_width": 300,
"thumbnail_height": 300
}
- Downloads the album art into
content/revisions/py 3/pics
as.jfif
files
No explanation really needed... Essentially 3 lines of code:
r = requests.get(url, headers=user_agent, allow_redirects=True, stream=True)
with open(filename, 'wb') as f:
shutil.copyfileobj(r.raw, f)
- Combines the downloaded pictures into a collage.
It basically loops through the enclosing square, only placing a photo if it's within the frame to maximize the number of pictures that can fit inside. Here's a diagram of what it's doing:
And here is the main part of the code.
int i = 0;
float last = 0;
for (double x = 0; x < d / scale; x++) {//iterate over (unscaled) X from a little outside {-(d/scale)/2} until the diagonal {d/scale}
int r = rand ? (int) Math.round(Math.random() * scale) : 0;
for (double y = last -= 1; y < (d / scale) + last; y++) {//iterate over (unscaled) Y, staring further outside each time in order to fill the rect
transform = g2d.getTransform();
int xc = (int) Math.round(x * scale),
yc = (int) Math.round(y * scale);
double deltaX = x * Math.cos(theta) - y * Math.sin(theta),
deltaY = x * Math.sin(theta) + y * Math.cos(theta);
deltaX *= scale;
deltaY *= scale;
//only proceed if we're in bounds
boolean inB = inBounds(deltaX, deltaY, w, h) ||
inBounds(deltaX - scale, deltaY + scale, w, h) ||
inBounds(deltaX - scale, deltaY, w, h) ||
inBounds(deltaX, deltaY + scale, w, h);
if (inB) {
g2d.setColor(Color.WHITE);
//rotate around origin
//draw image on rotated coordinate
if (i < images.length) g2d.drawImage(images[i++], xc, yc + r, scale, scale, null);
}
g2d.setTransform(transform);
}
}
Hopefully someone found this interesting!