This is more of a discussion than a call for help. However, I never pass up good advice! If you can suggest improvements to my script, please do! Also, there's a "To-Do" list near the end so if you have ideas/answers it would be greatly appreciated.
The motivation: I noticed many of my music collection folders did not have ".m3u" files in them. Further digging revealed many folders where file names had changed but the m3u file was not updated so it was (at least partially) invalid. I searched for an easy way to update/create these en masse, but could find no suitable options. I normally listen to my music via Plex so the m3u files aren't really necessary (which is why I hadn't noticed the deficiencies) but when I'm on my PC it's great to be able to just click on an m3u file and launch an entire album with Amarok.
So I set out on "batching" this task.
Some things that made this task easier in my specific case:
and here's one from a file my script created:
A perfect pattern match!
For those unfamiliar with these files;
As well as the To-Do's I would also love to hear suggestions on shortening the code or making it more efficient.
Building the array of files and folders takes considerable time because of the "sort -u" action I used to grab folder names and paths. By "considerable time" it's about 16 seconds after launch before the first file creation is started. My system is fairly powerful, but the files are being accessed via NFS file sharing and are stored on a NAS platter drive. My collection is also quite large.
Here's the entire script with comments
The motivation: I noticed many of my music collection folders did not have ".m3u" files in them. Further digging revealed many folders where file names had changed but the m3u file was not updated so it was (at least partially) invalid. I searched for an easy way to update/create these en masse, but could find no suitable options. I normally listen to my music via Plex so the m3u files aren't really necessary (which is why I hadn't noticed the deficiencies) but when I'm on my PC it's great to be able to just click on an m3u file and launch an entire album with Amarok.
So I set out on "batching" this task.
Some things that made this task easier in my specific case:
- My collection is entirely made up of FLAC and MP3 files only. If I get some music in another format like OPUS or WAV I convert them before posting them in my collection.
- My collection follows a strict folder and file naming structure the Plex requires.
- All my music is on my media server and mounted on my computer at "/shared/Music/".
- I took an existing ".m3u" file from one album, made sure it launched Amarok as desired, then duplicated it's format.
- Manipulating the artist, album, and song names to separate them and combine them in the proper formats.
- Acting on multiple file formats in one go.
- Figuring out how to get the song length.
Code:
#EXTM3U #EXTINF:250,Red Hot Chili Peppers - The Getaway 01 - The Getaway.flac #EXTINF:302,Red Hot Chili Peppers - Dark Necessities 02 - Dark Necessities.flac #EXTINF:200,Red Hot Chili Peppers - We Turn Red 03 - We Turn Red.flac
Code:
#EXTM3U #EXTINF:173,311 - Down 01 - Down.flac #EXTINF:187,311 - Random 02 - Random.flac #EXTINF:204,311 - Jackolantern’s Weather 03 - Jackolantern’s Weather.flac
For those unfamiliar with these files;
- The header - #EXTM3U - indicates the m3u content format is the "extended" version and contains more info than a basic playlist.
- Each line beginning with #EXTINF is some song info. Here, I used only length in seconds, album artist, and song title.
- Each line following the #EXTINF lines contains the actual filename to be played. The full file path is only necessary if the m3u file is not in the same directory as the audio files.
- Creates a list of folders that contain MP3 or FLAC files
- Create the M3U file with header in each folder
- Calculates each song length to nearest second
- Creates a list of songs (mp3 or flac) in the M3U file
- Outputs progress to the console so the user can see the activity
- Have a simple GUI instead of console use only.
- Allow inputting of a single folder or group of folders rather than the whole collection.
- Allow an option to use the full path name in the m3u file.
- Preserve an existing m3u file or offer the option to replace (or not) existing m3u files.
- Detect a file change in a folder and/or skip folders that have an existing m3u file that is newer than the folder contents.
As well as the To-Do's I would also love to hear suggestions on shortening the code or making it more efficient.
Building the array of files and folders takes considerable time because of the "sort -u" action I used to grab folder names and paths. By "considerable time" it's about 16 seconds after launch before the first file creation is started. My system is fairly powerful, but the files are being accessed via NFS file sharing and are stored on a NAS platter drive. My collection is also quite large.
Here's the entire script with comments
Code:
#!/bin/bash
# set script variables
HEADER='#EXTM3U'
LINE='#EXTINF:'
MUSICPATH='/shared/Music'
# Allow spaces in folder and file names
IFS=$'\t\n'
# create array of folders containing music file types
declare -a FOLDERS=(`find "$MUSICPATH" \( -name "*.mp3" -o -name "*.flac" \) -printf "%h\n" | sort -u`)
# start loop for each folder
for DIR in "${FOLDERS[@]}"; do
# create inital .m3u file
M3UFILE=`echo -n $DIR;echo $DIR | awk -F'/' '{ print "/"$5".m3u" }'`
# add first line to file
printf '%s\n' $HEADER > $M3UFILE
# console progress output
echo "Processing "$DIR"... "
# get list of music files in the folder
readarray -d '' FILES < <(find "${DIR}" \( -name "*.mp3" -o -name "*.flac" \) -print0 | sort -z)
# start loop for each file
for FILE in "${FILES[@]}"; do
# get file length and round to nearest second
DURATION=(`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 $FILE`)
ROUNDED=$(printf "%.0f\n" $DURATION)
# get album artists name
ARTIST=`echo $FILE | awk -F'/' '{ print $4" - "}'`
## get album and file names
# song name with extension
SONGFILE=`echo $FILE | awk -F'/' '{ print $NF}'`
# song name without extension for label
SONG2=`echo $SONGFILE | awk -F' - ' '{ print $2}'`
SONGTITLE=`echo "${SONG2%.*}"`
# put file info and file name in m3u file
printf '%s\n' $LINE$ROUNDED,$ARTIST$SONGTITLE >> $M3UFILE
printf '%s\n' $SONGFILE >> $M3UFILE
# console progress output
echo -ne $SONGFILE\\r
# loop to next file
done
#loop to next folder
done
# done
echo "Complete"
exit



