Skip to content

Repository files navigation

About

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.

Examples

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.

UI

  • Main window

Main UI

  • Scaling (AUTO will fit the maximum amount of images inside the given output resolution)

Scaling

  • Easy pan & zoom preview

Pan and Save

  • Results

Result (downscaled)

Generated Image (full resolution)

iPhone

Usage

Please run the following commands from the project directory (the cloned directory).

  1. Clone the repo via git clone https://github.com/vhagedorn/AlbumArt.

  2. Create a text file called content/playlist.txt with the Spotify links that you wish to get.

  3. Open a terminal/powershell at the project directory (probably AlbumArt).

    • Option A: (for Linux/MacOS users)
      1. Make sure your links are in playlist.txt!
      2. Run ./fetch_content and grab a cup of coffee.
    • Option B: (for Windows users)
      1. Find the links to the album covers with python3 src/main/python/parse.py.
      2. Run python3 src/main/python/download.py, which will download the album art as .jfif files.
  4. Finally, you can generate the collage via java -jar target/AlbumArt.jar.

    Follow its instructions to generate as many collages as you want!

Explanation

The main logic is in Java, but I didn't rewrite the cover art downloader, so it remains in Python.

Python

parse.py

  • 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:6FBPOJLxUZEair6x4kLDhf returns:

{
  "html": "\u003Ciframe style=\"border-radius: 12px\" width=\"100%\" height=\"152\" title=\"Spotify Embed: Any Colour You Like\" frameborder=\"0\" allowfullscreen allow=\"autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture\" loading=\"lazy\" src=\"https://open.spotify.com/embed/track/6FBPOJLxUZEair6x4kLDhf?utm_source=oembed\"\u003E\u003C/iframe\u003E",
  "iframe_url": "https://open.spotify.com/embed/track/6FBPOJLxUZEair6x4kLDhf?utm_source=oembed",
  "width": 456,
  "height": 152,
  "version": "1.0",
  "provider_name": "Spotify",
  "provider_url": "https://spotify.com",
  "type": "rich",
  "title": "Any Colour You Like",
  "thumbnail_url": "https://image-cdn-fa.spotifycdn.com/image/ab67616d00001e0217cb878012a0c769091e8045",
  "thumbnail_width": 300,
  "thumbnail_height": 300
}

download.py

  • 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)

Java

AlbumArt.java

  • 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: collage diagram

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
					g2d.rotate(theta);

					//draw image on rotated coordinate
					if (i < images.length) g2d.drawImage(images[i++], xc, yc + r, scale, scale, null);
				}

				g2d.setTransform(transform);
			}
		}

End

Hopefully someone found this interesting!

About

Album art collage generator.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages