Skip to content

Instantly share code, notes, and snippets.

@bonelifer
Forked from SydLambert/somafm-mpd-playlists.sh
Last active January 26, 2025 19:06
Show Gist options
  • Save bonelifer/b0236f57280489f35caebcec58e21bac to your computer and use it in GitHub Desktop.
Save bonelifer/b0236f57280489f35caebcec58e21bac to your computer and use it in GitHub Desktop.
Add SomaFM channels as individual playlists in specified directories. Supports multiple playlist types (highestpls-aac, fastpls-mp3, fastpls-aacp, slowpls-aacp). Will delete existing playlists before creating new ones. Requires curl, awk, grep, and basic shell tools. You can specify which playlist types to create by passing arguments, or leave b…
#!/usr/bin/env bash
# Script to create SomaFM playlists based on XML channel data
# The script will create playlists in directories named after the playlist type (e.g., fastpls-mp3).
# It can handle multiple types of playlists, and will clean up existing playlists before creating new ones.
# Base directory for all playlists
BASE_DIR="./playlists"
# Define valid playlist types and their mappings using an associative array
# This maps playlist types to XML tags and format attributes in the SomaFM channel data
declare -A TYPES=(
["highestpls-aac"]="highestpls aac" # Highest quality AAC format
["fastpls-mp3"]="fastpls mp3" # Fast MP3 format
["fastpls-aacp"]="fastpls aacp" # Fast AAC+ format
["slowpls-aacp"]="slowpls aacp" # Slow AAC+ format
)
# Function to remove all directories and their contents within BASE_DIR
# This is useful to clean up before creating new playlists
cleanup_all_playlists() {
if [[ -d "$BASE_DIR" ]]; then
# Delete all files and subdirectories in the BASE_DIR
find "$BASE_DIR" -mindepth 1 -delete || {
echo "Error removing directories and files in $BASE_DIR: $?"
return 1
}
fi
}
# Function to create playlists for a given type
# This function processes the channel XML data, extracts the playlist URL based on type,
# and saves it as a .m3u file in the appropriate directory
create_playlists() {
local type="$1"
# Look up the type from the TYPES array and ensure it's valid
local type_name="${TYPES[$type]}" || { echo "Error: Invalid type $type"; return 1; }
local type_name_parts=(${type_name// / })
local type_name_main="${type_name_parts[0]}" # The XML tag (e.g., fastpls, highestpls)
local type_name_format="${type_name_parts[1]}" # The format (e.g., mp3, aac)
# Create the directory for this type of playlist
mkdir -p "$BASE_DIR/$type" || { echo "Error creating directory $BASE_DIR/$type: $?" ; return 1; }
# More robust XML handling with error checking
# Fetch the channel XML, process each channel, and extract relevant playlist URLs
if ! curl -s https://somafm.com/channels.xml | \
awk 'BEGIN { RS="</channel>"; ORS="</channel>\n" } { gsub("\n", " "); print }' | \
grep -Po '(<channel id="[^"]+">.*?</channel>)' | while read -r channel; do
# Extract the channel name (title) and URL based on the requested playlist type
CHANNEL_NAME=$(echo "$channel" | grep -Po '(?<=<title><!\[CDATA\[).+?(?=\]\]></title>)') || continue
URL=$(echo "$channel" | grep -Po "(?<=<${type_name_main} format=\"${type_name_format}\">).+?(?=</${type_name_main}>)")
# If no URL is found for the given type, skip this channel
if [[ -z "$URL" ]]; then
echo "No ${type_name_main} (${type_name_format}) URL found for channel: ${CHANNEL_NAME}"
continue
fi
# Create the playlist file for the channel
PLAYLIST_FILE="$BASE_DIR/$type/${CHANNEL_NAME}.m3u"
echo "$URL" > "$PLAYLIST_FILE" || { echo "Error writing to file $PLAYLIST_FILE: $?" ; rm -rf "$BASE_DIR/$type"; return 1; }
echo "Created playlist: $PLAYLIST_FILE"
done; then
# If there was an error fetching or processing the XML, clean up and return an error
echo "Error fetching or processing SomaFM channel data."
rm -rf "$BASE_DIR/$type"
return 1
fi
}
# Main script logic: First, clean everything; then create playlists.
cleanup_all_playlists
# If no arguments are provided, create playlists for all types
if [[ "$#" -eq 0 ]]; then
for type in "${!TYPES[@]}"; do
create_playlists "$type" || exit 1
done
else
# If arguments are provided, create only the specified playlist types
for arg in "$@"; do
# Check if the argument matches a valid type from the TYPES array
if [[ -v "TYPES[$arg]" ]]; then
create_playlists "$arg" || exit 1
else
echo "Invalid type: $arg. Valid types: ${!TYPES[@]}"
exit 1
fi
done
fi
# Exit the script successfully
exit 0
@bonelifer
Copy link
Author

Add SomaFM channels as individual playlists in specified directories. Supports multiple playlist types (highestpls-aac, fastpls-mp3, fastpls-aacp, slowpls-aacp). Will delete existing playlists before creating new ones. Requires curl, awk, grep, and basic shell tools. You can specify which playlist types to create by passing arguments, or leave blank to create all playlist types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment