Skip to content

Instantly share code, notes, and snippets.

@rkok
Last active July 6, 2023 10:10
Show Gist options
  • Save rkok/b71d8fee81830f2e12de0ffced6b65ba to your computer and use it in GitHub Desktop.
Save rkok/b71d8fee81830f2e12de0ffced6b65ba to your computer and use it in GitHub Desktop.
Convert .m3u to .audpl (Audacious playlist file)
#!/bin/bash
############################################################################################
# m3u2audpl.sh
#
# Creates an Audacious playlist,
# pre-indexed faster than Audacious does it over network mounts
# Supported formats: basic m3u, extended m3u.
#
# Usage:
# 1. Create an empty playlist in Audacious
# 2. Shut down Audacious
# 3. Check which filename it got:
# ls -ltr ~/.config/audacious/playlists | tail -1
# 4. ./m3u2audpl.sh /full/path/to/m3ufile > ~/.config/audacious/playlists/NNNN.audpl
#
# For best results, configure Audacious as follows:
# - Settings > Song Info > Guess missing metadata from file path
# - Settings > Song Info > Do not load metadata for songs until played
#
# Known issues:
# - .audpl song durations are always up to 1 second higher due to lack of m3u ms precision
############################################################################################
set -e
# Source: https://gist.github.com/cdown/1163649
urlencode() {
# urlencode <string>
old_lc_collate=$LC_COLLATE
LC_COLLATE=C
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9/.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
LC_COLLATE=$old_lc_collate
}
if [ -z "$1" ]; then
echo "Usage: $0 /full/path/to/m3ufile" >&2
exit 1
fi
M3UFILE="$1"
if ! [ -f "$M3UFILE" ]; then
echo "File not found: $M3UFILE" >&2
exit 1
fi
IS_EXTM3U=false
if [ "$(head $M3UFILE | grep '^#EXTM3U$')" ]; then
IS_EXTM3U=true
fi
# OUTPUT: playlist title
echo "title=$(urlencode "Playlist from $(basename $M3UFILE) @ $(date '+%Y-%m-%d %H:%M:%S')")"
NLINES="$(wc -l $M3UFILE | awk '{print $1}')"
LINENUM=0
INFOLINE=
cat "$M3UFILE" | grep -vE '^(#EXTM3U)?$' | while read LINE
do
# Output progress
LINENUM=$[$LINENUM +1]
echo -ne "$LINENUM/$NLINES\r" >&2
if [ "$IS_EXTM3U" == "true" ] && [ "$(echo "$LINE" | grep '^#')" ]; then
INFOLINE="$LINE"
continue
fi
AUDFILE="$LINE"
if [ "${LINE:0:1}" != "/" ]; then
M3UDIR="$(dirname "$M3UFILE")"
if [ "$M3UDIR" == "." ]; then
M3UDIR="$(pwd)"
fi
AUDFILE="$M3UDIR/$LINE"
fi
PATH_ENCODED="$(urlencode "$AUDFILE")"
# OUTPUT: audio file path
echo "uri=file://$PATH_ENCODED"
if [ "$IS_EXTM3U" == "true" ]; then
TITLE="$(echo "$INFOLINE" | sed -r 's/^#EXTINF:[0-9]*( [^,]+)?,(.*)$/\2/g')"
DURATION="$(echo "$INFOLINE" | sed -r 's/^#EXTINF:([0-9]*).*$/\1/g')"
fi
if ! [ "$TITLE" ]; then
TITLE="$(basename "$AUDFILE")"
fi
# OUTPUT: song title
echo "title=$(urlencode "$TITLE")"
# OUTPUT: duration
[ "$DURATION" ] && echo "length=$((DURATION+1))000"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment