Wow, this is a neat font.
2022-12-06
2022-11-17
[GNOME] GNOME Files and custom file icons: setting a cute 2x2 image preview for photo albums
Update: credit to David in the comments of my previous post, there's a much fancier implementation of this here: https://github.com/flozz/cover-thumbnailer
Going further in my delight at belatedly discovering the "metadata::custom-icon" GVFS attribute used by Nautilus, I extended beyond just music album covers to write a script that did a fun 2x2 grid for photo album covers.
From this:

To this:

This script is uglier, so maybe write your own, but you can have a look-see to see what I did. I learned some new syntax for ImageMagick in the process (using ^ when scaling to treat the geometry as a minimum rather than a maximum, using "-gravity center" to crop from the center, etc.),
#!/bin/sh # Run in a directory containing photo album folders. Will generate 2x2 grid thumbnail images of photos within, and set them as the # folder icon. (Recurses down through all subfolders.) # set GVFS attribute "metadata::custom-icon" # e.g. gio set /path/to/album/dir "metadata::custom-icon" "file:///home/USER/files/music/ARTIST NAME/ALBUM NAME/cover.jpg" # to reset it: # gio set /path/to/album/dir "metadata::custom-icon" -d function crop { FILE="${1}"; DIM="${2}"; # e.g. "200x200" # scale so that the min-dimension is 200 (we'll crop out whatever exceeds it in the max dimension) # so if we're given an 400x1000 photo here, we'll scale it to 200x500, thanks to ^ convert "${FILE}" -scale "${DIM}+0+0^" "${FILE}.scaled"; # crop a 200x200 square from the center, so if we have a 200x500, we'll lose the top and bottom 50 convert "${FILE}.scaled" -gravity center -crop "${DIM}+0+0" "${FILE}.cropped" # now we have a nice 200x200 version, centered # emit the name of the newly cropped file echo "${FILE}.cropped"; } # provide a '-f' option to regenerate existing photo album covers; by default, it skips dirs where one already exists if [ "${1}" == -f ]; then FORCE=1 else FORCE=0 fi find ./ -type d | while read DIR; do # skip . hidden directories if basename "${DIR}" | grep "^\."; then continue; fi echo "${DIR}..."; # check if a generated photo album already exists and skip redoing it (unless -f set) if [ -f "${DIR}/.npac_cover.jpg" ] && [ "${FORCE}" -eq 0 ]; then echo " Already generated, skipping (use -f to force regeneration)"; continue; fi # create a temporary directory to do image cropping and stitching in TMPDIR="$(mktemp -d)"; # find 4 images below dir for potential thumbnailing; use 'sort -R' to randomize the list find "${DIR}" -regextype egrep -iregex ".*\.(jpg|jpeg|png|webp)$" | sort -R | while read COVER_PART; do # because I sometimes have duplicate files for various reasons, and # I don't want an image repeated, I work with them using their hash HASH="$(md5sum "${COVER_PART}" | cut -b 1-32)"; if ! [ -f "${TMPDIR}/${HASH}" ]; then echo " ${COVER_PART}"; cp "${COVER_PART}" "${TMPDIR}/${HASH}.part" fi if [ "$(ls "${TMPDIR}" | wc -l)" -ge 4 ]; then break; fi done; # lets create a 2x2 grid of 4 images, but also support fewer if necessary ( cd "${TMPDIR}"; NUM_PARTS="$(ls | wc -l)"; P1="$(ls | head -n 1 | tail -n 1)"; P2="$(ls | head -n 2 | tail -n 1)"; P3="$(ls | head -n 3 | tail -n 1)"; P4="$(ls | head -n 4 | tail -n 1)"; if [ "${NUM_PARTS}" -ge 3 ]; then # stitch the first two together side-by-side for the top half of a 3 or 4 grid convert "$(crop "${P1}" 200x200)" "$(crop "${P2}" 200x200)" -background black +append "top.jpg" if [ "${NUM_PARTS}" -ge 4 ]; then # stitch two together for the bottom, then stitch top and bottom together for the grid, yay convert "$(crop "${P3}" 200x200)" "$(crop "${P4}" 200x200)" -background black +append "bottom.jpg" convert "top.jpg" "bottom.jpg" -background black -append "grid.jpg" elif [ "${NUM_PARTS}" -eq 3 ]; then # only have 3 images, so make the 3rd one take up the whole bottom convert "top.jpg" "$(crop "${P3}" 400x200)" -background black -append "grid.jpg" fi elif [ "${NUM_PARTS}" -eq 2 ]; then # only have two, so stack them vertically convert "$(crop "${P1}" 400x200)" "$(crop "${P2}" 400x200)" -background black -append "grid.jpg" elif [ "${NUM_PARTS}" -eq 1 ]; then # only have one, so it'll be the whole grid! cp "$(crop "${P1}" 400x400)" grid.jpg else echo "WARNING: nautilus_photo_album_cover.sh: no images found for dir '${DIR}' in tmpdir '${TMPDIR}'."; fi ) # if we successfully generated a grid of images, copy it to the photo album dir as a # hidden thumbnail image (.npac_cover.jpg), set "metadata::custom-icon" in GVFS, and then remove the temp dir if [ -f "${TMPDIR}/grid.jpg" ]; then cp "${TMPDIR}/grid.jpg" "${DIR}/.npac_cover.jpg" gio set "${DIR}" metadata::custom-icon "file://$(realpath "${DIR}/.npac_cover.jpg")"; rm -rf "${TMPDIR}" fi done
To do:
- Add a cute folder emblem to the bottom right of the 2x2 icons, and maybe put a border around it, to make it more obviously still a folder!
- It fails on some folders for some reason, look into it :D
- Correct orientation issues
[GNOME] GNOME Files and custom file icons: setting album art on directories!
Update: credit to David in the comments, there's a much fancier implementation of this here: https://github.com/flozz/cover-thumbnailer
While playing with GNOME 43 on my recent upgrade to Fedora 37, I saw that nautilus aka GNOME Files lets me set arbitrary images as a custom icon for files and folders, replacing the default icon/thumbnail. (The support for "metadata::custom-icon" has apparently been around for a while already.)
I quickly hopped into my music folder and wrote a small script to replace all of the (legally purchased) folders of albums of music's icons with images of their album art if an image was already present.
My Camera Obscura band's folder of albums went from this:
to this
Cool!
The quick code:
#!/bin/sh find ./ -type d | while read DIR; do if basename "${DIR}" | grep "^\."; then # skip . directories continue; fi echo "${DIR}..."; touch /tmp/.naa.coversearch # ranked cover options by preference, as some dirs have multiple; # break after we find highest one echo "front.(jpg|png) cover.(jpg|png) [Ff]older.(jpg|png) box.jpg album\-[0-9a-f]+\-[0-9a-f]+\.jpeg" | while read COVER_PATTERN; do # echo " ${COVER_PATTERN}..."; find "${DIR}" -regextype egrep -regex ".*/${COVER_PATTERN}$" | head -n 1 | # grab first and go while read COVER_RELPATH; do rm /tmp/.naa.coversearch # we found a cover, end search echo " found cover ${COVER_RELPATH}!"; COVER_ABSPATH="$(realpath "${COVER_RELPATH}")"; gio set "${DIR}" metadata::custom-icon "file://${COVER_ABSPATH}" done # if we're not still searching, skip other patterns and go to next dir test -f /tmp/.naa.coversearch || break done done
For the curious, I purchased a lot of legally-licensed, DRM-free music through eMusic back in the day, before streaming took over everything. I still purchase CDs as merch at shows sometimes, and then extract those to OGG Vorbis (sorry, not FLAC). Sometimes, I still open up Rhythmbox and play actual files, ooo.
To do:
- corner folder icons: Generate album folder thumbnails that have a little folder icon in the bottom corner still, so I can tell that it's still a folder
- artist custom icons as potential grids: My folder structure is artist/album/track.ogg. So right now, the artist folder also acquires the first album cover it finds. If an artist has multiple album covers available, I want to do a small grid of up to 2x2.
- photo albums: do something similar for photo albums folders.