playlist maker for Volumio On RPi

I have a Raspberry Pi with Volumio on it. I made a simple attempt to write a playlist generator for Volumio using mainly bash. It turned out I also made use of 2 other commands: mutagen-inspect and file.

The idea of the script is simple:

  1. create a playlist for a directory given as argument "mk_playlist.sh " or
  2. create playlists for every directory in the current directory, their subdirectories and so on “mk_playlist.sh -cd”
    The script works currently only for mp3, flac and m4a files, although it can reasonably easy be extended for other audio types.
    The playlist generated is currently using alphabetical order of the file names. At first, I tried to use a m3u file, but soon gave this up. Some names in the script still reflect that.

If you read the code, you will see that the script actually has some more options and capabilities, but that’s more of a coincidence.

Read also below how to install mutagen-inspect and file on a Raspberry Pi

Here’s the code for mk_playlist.sh

[code]#!/bin/bash

#this script requires the applications: mutagen-inspect and file
#how to install mutagen-inspect:
#1. sudo apt-get update
#2. sudo apt-get install python-pip
#3. pip install mutagen
#how to install file:
#1. sudo apt-get update
#2. sudo apt-get install file

#LSARG contains the argument given to ls to scan for audio files.
#The default is to scan for mp3, flac and m4a
#For each extension there should be a getMetadata() function that porcesses the result of mutagen-inspect and extracts
#artist (=AUTH), song title (=TIT) and album (=ALB)
LSARG="*.mp3 *.flac *.m4a"
#using the -ls “your music extensions” option you can override this default
#using the -d option no actual playlists are generated but is a kind of dummy/demo run
#using the -cd option a playlist will be generated for every directory in the current folder

#It’s not the most clear script i’ve ever written.

#some variables
METADATAFILE="/tmp/metadata.txt"
M3UFILETEMP="/tmp/lsdir1.txt"
M3UFILETEMP2="/tmp/playlist.txt"

#the three meta data functions, you will need to create more when youj use other audio file types

function getMp3Metadata()
{
AUTH=$( cat “$1” | egrep “^TPE1” | head -n 1 | sed ‘s/^[^=]*= //’ );
TIT=$( cat “$1” | egrep “^TIT2” | head -n 1 | sed 's/^[^=]
= //’ );
ALB=$( cat “$1” | egrep “^TALB” | head -n 1 | sed 's/^[^=]
= *//’ );
}

function getM4aMetadata()
{
AUTH=$( cat “$1” | egrep “^.ART=” | head -n 1 | sed ‘s/^.ART=//’ );
TIT=$( cat “$1” | egrep “^.nam=” | head -n 1 | sed ‘s/^.nam=//’ );
ALB=$( cat “$1” | egrep “^.alb=” | head -n 1 | sed ‘s/^.alb=//’ );
}

function getFlacMetadata()
{
AUTH=$( cat “$1” | egrep “^ARTIST=” | head -n 1 | sed ‘s/^ARTIST=//’ );
TIT=$( cat “$1” | egrep “^TITLE=” | head -n 1 | sed ‘s/^TITLE=//’ );
ALB=$( cat “$1” | egrep “^ALBUM=” | head -n 1 | sed ‘s/^ALBUM=//’ );
}

function process_start () {

STOPPROCESSING=""
if [ -d “$1” ]; then
PWD=$(pwd);
sourceDir="$1"
if [[ “$sourceDir” == / ]]; then sourceDir=${sourceDir::-1}; fi
if [[ $sourceDir != /
]]; then
sourceDir=$(echo “$PWD”/"$sourceDir")
fi
pushd “$1” 1>/dev/null
ls $LSARG >"$M3UFILE" 2>/dev/null
popd 1>/dev/null
Lin=$(cat “$M3UFILE” | wc -l)
if [[ “$Lin” == 0 ]]; then
STOPPROCESSING=“1”
echo “$1 has no music files”
return
fi
PLAYNAME=$(echo “/data/playlist/$1” | sed ‘s///_/g’ );
else
STOPPROCESSING=“1”
echo “$1 is not a directory”
return
fi
}

function process_info() {

echo “Working on $1” 1>&2;
echo " dirname=$sourceDir" 1>&2;
echo " input file=$M3UFILE" 1>&2;
echo " playlist file=$PLAYNAME" 1>&2;
echo " searching for $LSARG" 1>&2;

#exit 0;
}

function process_file() {

echo “[” >"$M3UFILETEMP2"
pushd “$1” 1>/dev/null
FIRST=“1”
filenr=1
echo -n “working of file "
cat “$M3UFILE” | while read p
do
p=$(echo “$p” | sed ‘s/\r//g’)
FILN=$(echo “$sourceDir/$p” | sed ‘s/\r//’ );
URI=$(echo $FILN | sed ‘s/^.media/USB/’ | sed ‘s/^.data/INTERNAL/INTERNAL/’ );
ALB=”"; AUTH=""; TIT="";
echo -n “$filenr "
filenr=$((filenr+1))
mutagen-inspect “$FILN” >”$METADATAFILE"
key=$([[ “$FILN” = . ]] && echo “.${FILN##*.}” || echo ‘’)
case $key in
.mp3)
getMp3Metadata “$METADATAFILE”
;;
.m4a)
getM4aMetadata “$METADATAFILE”
;;
.flac)
getFlacMetadata “$METADATAFILE”
;;
*) # unknown option
echo “Unknown file extension: $FILN”
;;
esac
if [ -z “$ALB” ] ; then
ALB=“unknown”
fi
if [ -z “$AUTH” ] ; then
AUTH=“unknown”
fi
if [ -z “$TIT” ] ; then
TIT="$p"
fi
if [ “$FIRST” == “1” ]; then
FIRST=“2”;
else
echo “,” >>"$M3UFILETEMP2"
fi
echo ‘{“service”:“mpd”,“uri”:"’$URI’",“title”:"’$TIT’",“artist”:"’$AUTH’",“album”:"’$ALB’"}’ >>"$M3UFILETEMP2"
done
echo “]” >>"$M3UFILETEMP2"

#encoding of the playlist should be something like UTF8, so the stuff below it dows that most of the times

encoding=$(file -i “$M3UFILE” | rev | sed ‘s/=.*$//’ | rev | tr ‘[:lower:]’ ‘[:upper:]’ )
if [ -z “$encoding” ]; then
encoding=“ANSI_X3.110”
fi
iconv -f “$encoding” -t UTF8 “$M3UFILETEMP2” >"$PLAYNAME"
popd 1>/dev/null
echo
echo “Done working”
}

function do_all() {
process_start “$1”
if [ -z “$STOPPROCESSING” ]; then
process_info “$1”
if [ ! -z “$DUMMY” ]; then
PLAYNAME="/dev/null"
echo “This is a dry-run, no playlist file will be generated.”
fi
process_file “$1”
fi
}

while [[ $# -gt 0 ]]
do
key="$1"
#echo “key=$1”
DUMMY=""
CURD=""
EXTS=";.mp3;.m4a;.flac"
filearg=""
case $key in
-d)
DUMMY=“1”
shift # past argument
;;
-ls)
LSARG="$2"
shift # past argument
shift # past argument
;;
-cd)
CURD=“1”
shift # past argument
;;
-ncd)
CURD=""
shift # past argument
;;
*) # unknown option
filearg="$1" # save it in an array for later
do_all “$1”
shift # past argument
;;
esac
done

if [ ! -z “$CURD” ]; then
#echo curdir
shopt -s dotglob
find * -type d | while IFS= read -r d; do
do_all “$d”
done
fi

[/code]

When you copy the code into a file, don’t forget to change the permissions “chmod +x mk_playlist.sh” or whatever you call your version.
Good luck when you try using it. I’m sure it has still quirks, but so far it has worked for me. It is actually pretty slow as it tries to use the metadata in the audio files to determine the name of the album, name of the artist and the name of the song. So be patient when running on a large music collection.
As always, this script comes absolutly without any guarantees and that it does no harm to your system. However, on the other hand, there’s no hidden code here, so you can see what it does.

Nice work!