Category Archives: Programming

Automatic download of album covers

Automatic download of album covers (with a Simple Bash Script)

Managing a digital music library can be both fun and a little obsessive. If you’re like me, you don’t just want your tracks properly tagged, you need them to look good too. Having the album cover right there makes browsing way more satisfying (and helps music servers like Navidrome or Jellyfin look polished).

That’s why I put together a small Bash script that automatically fetches album art using Last.fm. No need to manually copy-paste images anymore, just run the script in your album folder, and it does the heavy lifting for you.

How It Works

The idea is simple:

  1. Guess the album artist and title from the current folder (with some prompts if you want).
  2. Construct the right Last.fm album page URL.
  3. Parse the page to find the cover image.
  4. Download it to cover.jpg.

That’s it. Nothing magical, but it saves a lot of clicking.

Here’s the script itself:

#!/bin/bash

set -e

_error()
{
    echo "$(basename "$0" .sh): $1" >&2
    exit "$2"
}

_info()
{
        echo "[INFO] $*"
}

urlencode()
{
        local length="${#1}"

        for ((i=0; i<length; i++)); do
                local c="${1:i:1}"

                case $c in
                        [a-zA-Z0-9.~_-])
                                printf '%s' "$c"
                                ;;
                        ' ')
                                printf "%%20"
                                ;;
                        *)
                                printf '%%%02X' "'$c"
                                ;;
                esac
        done
        echo
}

##
# Init
#
umask 0002
output="cover.jpg"
batch=

##
# Checks
#
[[ ! -r $output ]] || _error "$output exists" 2
[[ $1 = '--batch' ]] && batch=1

##
# Main
#
defaultArtist="$(cd .. && basename "$(pwd)")"
defaultAlbum="$(basename "$(pwd)")"
if [[ $batch -ne 1 ]]; then
        read -p "artist [$defaultArtist]: " artist
        read -p "album [$defaultAlbum]: " album
fi
[[ -z $artist ]] && artist="$defaultArtist"
[[ -z $album ]] && album="$defaultAlbum"

{
        url="https://www.last.fm/music/$(urlencode "$artist")/$(urlencode "$album")"
        _info "search cover url in $url"
        cover_url="$(wget "$url" -O - | pup 'div.album-overview-cover-art img attr{src}')"
        [[ -n $cover_url ]] || _error 'cannot find cover_url' 5
        _info "download cover url $cover_url"
        curl -s "$cover_url" >"$output"
        [[ -r $output ]]
} || _error "cannot find cover" 99

echo
echo "Done"
exit 0

Usage

Run this script inside your album’s folder. For example:

~/music/navidrome/Afterhours/Ballate per piccole iene$ download-album-cover.sh
artist [Afterhours]:
album [Ballate per piccole iene]:
[INFO] search cover url in https://www.last.fm/music/Afterhours/Ballate%20per%20piccole%20iene
--2025-09-11 09:42:43--  https://www.last.fm/music/Afterhours/Ballate%20per%20piccole%20iene
Resolving www.last.fm (www.last.fm)... 151.101.241.188, 2a04:4e42:39::444
Connecting to www.last.fm (www.last.fm)|151.101.241.188|:443... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: /music/Afterhours/Ballate+Per+Piccole+Iene [following]
--2025-09-11 09:42:48--  https://www.last.fm/music/Afterhours/Ballate+Per+Piccole+Iene
Reusing existing connection to www.last.fm:443.
HTTP request sent, awaiting response... 200 OK
Length: 632693 (618K) [text/html]
Saving to: ‘STDOUT’

-                                      100%[=========================================================================>] 617.86K  4.00MB/s    in 0.2s

2025-09-11 09:42:50 (4.00 MB/s) - written to stdout [632693/632693]

[INFO] download cover url https://lastfm.freetls.fastly.net/i/u/500x500/d0993bb25c9ea5085beb29486dcb5408.jpg

Done

When executed, it will suggest the folder names as defaults for artist and album. You can simply hit enter if they’re correct, or type something else if not.

  • By default, it downloads the cover as cover.jpg.
  • If you already have a cover.jpg file, it won’t overwrite it.
  • There’s also a --batch mode to skip interaction, which can be handy if you want automation.

Dependencies

You’ll need:

  • wget (to fetch the Last.fm HTML)
  • pup (for HTML parsing)
  • curl (to download the image)

On most Linux distros, these are easy to install with your package manager.

Why This Is Handy

For someone running a headless server or managing a huge MP3/FLAC collection, this is a lifesaver. Media players and tools like Navidrome, Jellyfin, or even plain old file explorers look so much better with consistent artwork. And because it’s just a shell script, you can tweak it however you like, change defaults, switch sources, or even integrate into a bigger tagging pipeline.

Override DNS new release (v5.1.0)

Changelog

  • Make everything faster
  • New feature: the app can use DNS servers listening on alternate ports (ur0011)
  • New feature: the app can now be activated as a Device Administrator (ur0020)
  • New feature: support for 64-bit architectures in setools-android
  • New feature: auto clear notification (ur0031)
  • New feature: custom notification priority (ur0032)
  • Migrate root library from RootCommands to libsuperuser
  • Add OpenDNS on port 443 in the predefined list of available servers
  • Ask again for root permissions after an upgrade
  • Add iptables cleanup procedure in the Advanced settings
  • Upgrade gradle, EventBus, setools-android, android-rate, showcaseview, dashclock-api
  • New library: vntnumberpickerpreference
  • bugfix when busybox replaces toolbox/toybox
  • bugfixes

Override DNS is #malicious-harmful!?

Hi guys,
my app is temporarily out of the Play Store. I hope it’s really a temporary thing.

It seems that my last beta (beta78), the one available only to the beta testers, was not compliant to the 4.4 section of the Developer Distribution Agreement. But let me explain in the right order.

50 minutes ago I received an e-mail from the Google Play Support. It was notifying me of some kind of violation. The e-mail was referring to the app: “Virtual Button ROOT MENU” (package ID jp.ne.neko.freewing.VirtualButtonRootMenu).
It seems that that app, which disables SELinux, violates the Developer Distribution Agreement

Don’t transmit or link to… items that may introduce security vulnerabilities to or harm user devices, apps, or personal data.

OK.

I’m serious it wasn’t some kind of phishing, they simply sent me the right notice but referring to someone else.

My latest beta has an advanced option which, if chosen, temporary lowers the device security by disabling SELinux on the device. It applies the DNS and brings SELinux back again. So it seems I’m guilty.

And now

Disabling SELinux is not approved by the Play Store.

In my humble opinion it was not so obvious, but anyway, I repackaged a stable release and a beta without the SELinux thing. I’m waiting to see my app online again.

Statically compile redis 3.0.2 on CentOS 5 (RHEL 5)

How to statically compile redis 3.0.2 on CentOS 5 (RHEL 5)

wget http://download.redis.io/releases/redis-3.0.2.tar.gz
wget http://prdownloads.sourceforge.net/tcl/tcl8.5.18-src.tar.gz

Install tcl8.5

tar xfz tcl8.5.18-src.tar.gz
cd tcl8.5.18/unix
./configure
make
make test
make install

Compile redis

Statically linked binaries

make CFLAGS="-static" EXEEXT="-static" LDFLAGS="-I/usr/local/include/"

Dynamically linked binaries

make LDFLAGS="-I/usr/local/include/"

How to manually install redis

cd src/
cp redis-{server,cli} /usr/local/bin/
chown root: /usr/local/bin/redis-{server,cli}
chmod 755 /usr/local/bin/redis-{server,cli}
mkdir /{var,etc}/redis /var/redis/6379
chmod 775 /{var,etc}/redis
cp redis.conf /etc/redis/6379.conf
sed -i 's/daemonize no/daemonize yes/' /etc/redis/6379.conf
sed -i 's,pidfile /var/run/redis.pid,pidfile /var/run/redis_6379.pid,' /etc/redis/6379.conf
sed -i 's/^# bind 127.0.0.1/bind 127.0.0.1/' /etc/redis/6379.conf
sed -i 's,logfile "",logfile "/var/log/redis_6379.log",' /etc/redis/6379.conf
sed -i 's,dir ./,dir /var/redis/6379,' /etc/redis/6379.conf

How to compile rsync for Android in Ubuntu

My situation

My machine

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04 LTS
Release:    14.04
Codename:   trusty

The latest rsync version to compile (for me it was rsync-3.1.0.tar.gz)

$ curl -s http://rsync.samba.org/ftp/rsync/ \
    | sed -r 's/^.*href="([^"]*)".*$/\1/' | grep 'rsync-[0-9].*\.tar\.gz$'

Procedure

  1. save the tarball name in a variable
    $ RSYNCTGZ="rsync-3.1.0.tar.gz"
    
  2. install needed software
    $ sudo aptitude install gcc-arm-linux-gnueabi
    
  3. download sources
    $ wget http://rsync.samba.org/ftp/rsync/$RSYNCTGZ
    $ tar xzf $RSYNCTGZ
    $ cd rsync-[0-9]*
    
  4. compile
    $ ./configure --host=arm-linux-gnueabi CFLAGS=-static
    $ make
    
  5. install on the device
    $ adb push rsync /data/local/tmp && adb shell chmod 775 /data/local/tmp/rsync
    
  6. test execution
    $ adb shell /data/local/tmp/rsync
    

References