I’m sure I’ll be modifying this more over time. But, it reads from a text file (podcasts.txt) in the given DOWNLOAD_PATH–this file contains the RSS URL(s) for the podcast(s). It organizes the podcasts into directories, if those directories don’t already exist. It uses eyeD3 to add metadata (including cover art). Works fairly well, though I’m still stomping bugs.

Maybe next I’ll put together a nice little frontend for it–maybe convert the whole thing to a Blazor app. But, for now, it does the thing and it’s fun being a script kiddie 🙂

#!/bin/bash

create_path() {
    TITLE_PATH="${DOWNLOAD_PATH}/${1}"

    if [ ! -d "${TITLE_PATH}" ]; then
       mkdir "${TITLE_PATH}"
    fi
}

sanitize_filename() {
  local filename="$1"
  # Replace unfriendly characters with underscore
  sanitized=$(echo "$filename" | sed 's/[\/:*?"<>|]/_/g')
  echo "$sanitized"
}

dl_podcast() {
    local RSS_FEED_URL=$1

    curl -s "$RSS_FEED_URL" > /tmp/rss_feed.xml

    title=$(get_podcast_title "${RSS_FEED_URL}")

    create_path "${title}"

    # Initialize arrays to store episode titles and enclosure URLs
    titles=()
    urls=()

    # Extract episode titles and enclosure URLs
    mapfile -t titles < <(xmllint --xpath '//item/title/text()' /tmp/rss_feed.xml)
    mapfile -t urls < <(xmllint --xpath '//item/enclosure/@url' /tmp/rss_feed.xml)

    # Print the episode titles and enclosure URLs
    j=${#titles[@]}
    padtowidth=${#j}
    for ((i=0; i<${#titles[@]}; i++)); do
	ep_title=$(echo "${titles[$i]}" | sed -e 's/<!\[CDATA\[//' -e 's/\]\]>//')
        url=`echo ${urls[$i]} | sed "s/url=//g"`
        url=`echo ${url} | sed "s/\"//g"`
        filenum=`printf "%0*d\n" $padtowidth $j`
        file="${filenum} $ep_title.mp3"
        file=$(sanitize_filename "${file}")

        if [ ! -f "${TITLE_PATH}/${file}" ]; then
            echo "Downloading: ${file} (${url})"
            wget -qO "${TITLE_PATH}/${file}" "${url}"
	    /usr/bin/eyeD3 --track "${filenum}" --disc-num "1" "${TITLE_PATH}/${file}"
	    /usr/bin/eyeD3 --add-image="/tmp/cover.jpg":FRONT_COVER "${TITLE_PATH}/${file}"
        fi
        j=`expr ${j} - 1`
    done

    unset ${TITLE_PATH}
}

get_podcast_title() {
    local url="${1}"
    local title="$(curl -s "$url" | grep -oP '<title>\K[^<]+' | sed -n '2p')"
    echo "${title}"
}

get_podcast_cover() {
    local url=$1
    local cover_url=$(curl -s "$url" | grep -oP '<itunes:image\s+href="\K[^"]+' | head -n 1)

    curl -s -o /tmp/cover.jpg ${cover_url}
}

cleanup() {
    rm /tmp/cover.jpg
    rm /tmp/rss_feed.xml
}

read_lines_into_array() {
    local file=$1

    # Check if file exists
    if [ ! -f "$file" ]; then
        echo "Error: File $file not found."
        exit 1
    fi

    # Read the file line by line and append each line to the array
    mapfile -t lines_array < "${file}"

    # Return the array
    echo "${lines_array[@]}"
}

process_podcasts() {
    local -n podcasts=$1

    for link in "${podcasts[@]}"; do
        get_podcast_cover "$link"

        title=$(get_podcast_title "$link")

        dl_podcast $link
    done
}

main()
{
    DOWNLOAD_PATH="<PODCAST DIRECTORY GOES HERE>"
    TITLE_PATH=${DOWNLOAD_PATH}

    if [ $# -ne 1 ]; then
        echo "Usage: $0 <rss url>"
        exit 1
    fi

    file=$1

    # Call the function and store the result in an array
    declare -A links
    links=$(read_lines_into_array "$file")

    # Print the contents of the resulting array
    process_podcasts links
    cleanup
}

main "$@"

Been working on a podcast downloader for use with Plex, since Plex decided to take away podcasts–basically I keep the ones I wanna retain long-term in a library collection now. The downloader is a simple BASH script. Seems to be nearly perfected, even adds metadata (track #, cover art, etc) to the downloaded mp3.

I think my last little issue is that I need to have it rename all the files whenever episodes hit a factor of 10 (e.g., if there are 10 episodes, episode one should be “01 – Title”, when it hits 100, episode one should be renamed to “001 – Title”). It’s a little thing–I just like my files sorting properly by name, no matter what OS I’m listing them in. And Linux sorts in lexicographical by default, as opposed to natural order 🙄

Some guys work in the garage on Saturday mornings–I work on code 🤣

Windows Terminal handles opacity better than any other CLI ever did. I played with opacity some time back with Powershell before Windows Terminal came along, but the whole window became opaque, as opposed to just the content pane. I tend to set console opacity first-thing whenever I get a Mac, and it’s good that it can now be integrated into my Windows setup habits 😀 One can do this with the entirety of Windows Terminal, or narrow it to any specific command-line app you want.

So, one thing I’ve really gotten into over the years has been emulation. It’s the best way of going back to the things you used to love in computing without actually going back in time–and without having to put a boat anchor of a CRT on your desktop 😉

VICE is one of those emulators I really dig. Our first family computer was the Commodore VIC-20. Using VICE, I can run the very first software that I ever ran (and even coded).

While I guess I wouldn’t totally mind the notion of setting up a full VIC-20 rig, this sure is a great way of getting a blast from the past without 😎