playlist maker for Volumio On RPi

Discuss about Hardware diy and tweaks

Ads helps Volumio remain Free and Open Source. Please consider donating to help us continue to serve you.

playlist maker for Volumio On RPi

Postby bens » Wed Sep 11 2019 18:04

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 <a directory>" 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: Select all
#!/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 get<ext>Metadata() 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



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.
Random avatar
bens
Fresh off the boat
Fresh off the boat
 
Posts: 1
Joined: Wed Sep 11 2019 17:30

Ads helps Volumio remain Free and Open Source. Please consider donating to help us continue to serve you.


playlist maker for Volumio On RPi

Postby romi » Sat Sep 14 2019 12:58

Nice work!
Random avatar
romi
Fresh off the boat
Fresh off the boat
 
Posts: 1
Joined: Sat Sep 14 2019 12:52


Return to Diy and Tweaks

Who is online

Users browsing this forum: No registered users and 0 guests