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