#!/bin/bash # Display usage information usage() { echo "Usage: $0 --url --cloudfolder [--cloudfilename ] [--ntfy ]" echo "Example: $0 --url https://kinder.wdr.de/radio/diemaus/audio/diemaus-60/diemaus-60-106.podcast --cloudfolder Maus/Podcasts --cloudfilename latest.taf --ntfy https://ntfy.sh/mypodcast" echo "" echo "Arguments:" echo " --url URL of the podcast feed" echo " --cloudfolder Subfolder in TeddyCloud library (without leading/trailing slashes)" echo " --cloudfilename Optional: Custom filename for the .taf file (default: latest.taf)" echo " --ntfy Optional: Complete ntfy URL for notifications" echo " --force Optional: Force download even if episode was already processed" echo " --debug Optional: Enable detailed debug output" exit 1 } # Initialize variables url="" TEDDY_SUBFOLDER="" TEDDY_FILENAME="latest.taf" # Default value NTFY_URL="" FORCE_DOWNLOAD=false DEBUG_MODE=false # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in --url) url="$2" shift 2 ;; --cloudfolder) TEDDY_SUBFOLDER="$2" shift 2 ;; --cloudfilename) TEDDY_FILENAME="$2" shift 2 ;; --ntfy) NTFY_URL="$2" shift 2 ;; --force) FORCE_DOWNLOAD=true shift ;; --debug) DEBUG_MODE=true shift ;; --help) usage ;; *) echo "Unknown parameter: $1" usage ;; esac done # Check if required arguments are provided if [ -z "$url" ] || [ -z "$TEDDY_SUBFOLDER" ]; then echo "Error: Required arguments missing." usage fi # Configuration variables output_folder="/tmp/podcasts" tonie_input_dir="/tmp/tonie_input" tonie_output_dir="/tmp/tonie_output" history_file="$HOME/.podcast_history.json" debug_log="/tmp/podcast_debug.log" # TeddyCloud configuration TEDDY_CLOUD_BASE="/opt/teddycloud-0.6.3/data/library" # Create required folders mkdir -p "$output_folder" mkdir -p "$tonie_input_dir" mkdir -p "$tonie_output_dir" mkdir -p "$(dirname "$history_file")" # Initialize or clear debug log if debug mode is enabled if [ "$DEBUG_MODE" = true ]; then echo "Debug mode enabled - logging to $debug_log" echo "=== Podcast Download Debug Log $(date) ===" > "$debug_log" fi # Debug logging function debug_log() { if [ "$DEBUG_MODE" = true ]; then echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$debug_log" echo "[DEBUG] $1" fi } # Send notification via ntfy.sh (if enabled) send_notification() { # Skip if no ntfy URL is specified if [ -z "$NTFY_URL" ]; then return 0 fi title="$1" message="$2" priority="${3:-default}" curl -s -H "Title: $title" \ -H "Priority: $priority" \ -d "$message" \ "$NTFY_URL" } # Create history file if it doesn't exist or is empty if [ ! -s "$history_file" ]; then debug_log "Creating new history file at $history_file" echo "{}" > "$history_file" fi echo "Fetching latest podcast episode from: $url" #echo "Will save to: $TEDDY_CLOUD_BASE/$TEDDY_SUBFOLDER/$TEDDY_FILENAME" # Get the podcast XML podcast_xml=$(curl -s "$url") if [ -z "$podcast_xml" ]; then error_msg="Error: Failed to fetch podcast XML from $url" echo "$error_msg" debug_log "$error_msg" # send_notification "Podcast Download Error" "$error_msg" "high" exit 1 fi debug_log "Fetched podcast XML from $url (length: ${#podcast_xml} bytes)" # Save the XML for debugging if debug mode is enabled if [ "$DEBUG_MODE" = true ]; then echo "$podcast_xml" > "/tmp/podcast_xml_debug.xml" debug_log "Saved podcast XML to /tmp/podcast_xml_debug.xml" fi # Extract the latest episode URL - FIXED SED EXPRESSIONS latest_episode_url="" # Method 1: Find enclosure tag and extract URL attribute if [ -z "$latest_episode_url" ]; then # Use grep to find lines with ]*>.*' | sed -E 's|]*>||; s|||' | tr -d '[:space:]') fi debug_log "GUID extraction method 1 (guid tag): $episode_guid" fi # Method 2: Try to get episode ID from URL if GUID is empty if [ -z "$episode_guid" ]; then # Extract episode ID from URL (common pattern in many podcast feeds) episode_id=$(echo "$latest_episode_url" | grep -o '[0-9]\{5,\}' | tail -1) if [ -n "$episode_id" ]; then episode_guid="episode-$episode_id" fi debug_log "GUID extraction method 2 (URL ID): $episode_guid" fi # Method 3: Try to extract episode title using grep and cut episode_title_raw="" if [ -z "$episode_title_raw" ]; then # Try to find item titles item_line=$(echo "$podcast_xml" | grep -m 1 '' -A 20 | grep -m 1 '') if [ -n "$item_line" ]; then episode_title_raw=$(echo "$item_line" | sed -E 's/.*<title>(.*)<\/title>.*/\1/' | tr -d '[:space:]') fi debug_log "Title extraction method 1 (item title): $episode_title_raw" fi if [ -z "$episode_title_raw" ]; then # Try any title tag title_line=$(echo "$podcast_xml" | grep -m 2 '<title>' | tail -1) if [ -n "$title_line" ]; then episode_title_raw=$(echo "$title_line" | sed 's/.*<title>$.*$<\/title>.*/\1/' | tr -d '[:space:]') fi debug_log "Title extraction method 2 (any title): $episode_title_raw" fi # Method 4: Try to extract publication date pub_date_raw="" if [ -z "$pub_date_raw" ]; then date_line=$(echo "$podcast_xml" | grep -m 1 '<pubDate>') if [ -n "$date_line" ]; then pub_date_raw=$(echo "$date_line" | sed -E 's/.*<pubDate>(.*)<\/pubDate>.*/\1/') fi debug_log "Date extraction method 1 (pubDate): $pub_date_raw" fi # If GUID is still empty, create one from title and date if [ -z "$episode_guid" ]; then if [ -n "$episode_title_raw" ] || [ -n "$pub_date_raw" ]; then episode_guid="${episode_title_raw}${pub_date_raw}" debug_log "GUID extraction method 3 (title+date): $episode_guid" fi fi # Final fallback - just use the URL if we still don't have a GUID if [ -z "$episode_guid" ]; then episode_guid="$latest_episode_url" debug_log "GUID extraction method 4 (URL fallback): $episode_guid" fi # Create a clean key for the episode guid (remove any problematic characters) clean_guid=$(echo "$episode_guid" | md5sum | cut -d ' ' -f 1) debug_log "Final clean GUID (MD5): $clean_guid" # Create a podcast key for history file podcast_key=$(echo "$url" | md5sum | cut -d ' ' -f 1) debug_log "Podcast key (MD5): $podcast_key" # Check if this episode has already been downloaded already_downloaded=false if [ "$FORCE_DOWNLOAD" = false ]; then # Dump history file content for debugging debug_log "History file content: $(cat "$history_file")" # Check if the podcast key exists in the history file if jq -e ".\"$podcast_key\"" "$history_file" >/dev/null 2>&1; then debug_log "Found podcast key in history file" # Check if the episode GUID exists in the podcast entry if jq -e ".\"$podcast_key\".\"$clean_guid\"" "$history_file" >/dev/null 2>&1; then already_downloaded=true debug_log "Episode already downloaded (found in history)" else debug_log "Episode GUID not found in history file" echo "Will save to: $TEDDY_CLOUD_BASE/$TEDDY_SUBFOLDER/$TEDDY_FILENAME" fi else debug_log "Podcast key not found in history file" echo "Will save to: $TEDDY_CLOUD_BASE/$TEDDY_SUBFOLDER/$TEDDY_FILENAME" fi fi if [ "$already_downloaded" = true ]; then message="Episode with GUID $clean_guid already downloaded. Skipping." echo "$message" debug_log "$message" exit 0 fi # Extract the episode title for the filename (more robust method) episode_title="" if [ -n "$episode_title_raw" ]; then episode_title=$(echo "$episode_title_raw" | sed 's/[^a-zA-Z0-9]/_/g') else # Try to extract title with grep title_line=$(echo "$podcast_xml" | grep -m 2 '<title>' | tail -1) if [ -n "$title_line" ]; then episode_title=$(echo "$title_line" | sed 's/.*<title>$.*$<\/title>.*/\1/' | sed 's/[^a-zA-Z0-9]/_/g') fi fi if [ -z "$episode_title" ]; then # Final fallback for title episode_title="podcast_episode_$(date +%s)" fi debug_log "Final episode title for filename: $episode_title" # Get the date of the episode for better filename organization episode_date="" if [ -n "$pub_date_raw" ]; then # Try to parse the date, fallback to current date if it fails episode_date=$(date -d "$pub_date_raw" "+%Y-%m-%d" 2>/dev/null) || episode_date=$(date "+%Y-%m-%d") else episode_date=$(date "+%Y-%m-%d") fi debug_log "Using episode date: $episode_date" # Download the episode echo "Downloading latest episode: $episode_title" output_file="$output_folder/${episode_date}_${episode_title}.mp3" debug_log "Downloading from: $latest_episode_url" debug_log "Downloading to: $output_file" curl -s -L "$latest_episode_url" -o "$output_file" if [ $? -ne 0 ] || [ ! -s "$output_file" ]; then error_msg="Error downloading episode or file is empty." echo "$error_msg" debug_log "$error_msg" send_notification "Podcast Download Error" "$error_msg" "high" exit 1 fi file_size=$(du -h "$output_file" | cut -f1) echo "Successfully downloaded latest episode to: $output_file ($file_size)" debug_log "Download successful ($file_size)" # Copy the downloaded file to the TonieToolbox input directory mp3_filename=$(basename "$output_file") cp "$output_file" "$tonie_input_dir/$mp3_filename" debug_log "Copied to TonieToolbox input: $tonie_input_dir/$mp3_filename" echo "Running TonieToolbox conversion..." # Use TonieToolbox to convert the file docker run --rm \ -v "$tonie_input_dir:/tonietoolbox/input" \ -v "$tonie_output_dir:/tonietoolbox/output" \ quentendo64/tonietoolbox \ "input/$mp3_filename" conversion_result=$? debug_log "TonieToolbox conversion exit code: $conversion_result" if [ $conversion_result -ne 0 ]; then error_msg="Error during TonieToolbox conversion." echo "$error_msg" debug_log "$error_msg" send_notification "Podcast Conversion Error" "$error_msg" "high" exit 1 fi debug_log "TonieToolbox conversion completed" # Find the generated .taf file taf_file=$(find "$tonie_output_dir" -name "*.taf" -type f -print -quit) if [ -z "$taf_file" ]; then error_msg="Error: No .taf file was generated." echo "$error_msg" debug_log "$error_msg" send_notification "Podcast Conversion Error" "$error_msg" "high" exit 1 fi taf_size=$(du -h "$taf_file" | cut -f1) debug_log "Found .taf file: $taf_file ($taf_size)" # Create destination directory if it doesn't exist target_dir="$TEDDY_CLOUD_BASE/$TEDDY_SUBFOLDER" mkdir -p "$target_dir" debug_log "Created target directory: $target_dir" # Move the file to the TeddyCloud library with the specified name echo "Moving .taf file to TeddyCloud library..." cp "$taf_file" "$target_dir/$TEDDY_FILENAME" if [ $? -ne 0 ]; then error_msg="Error moving .taf file to TeddyCloud library." echo "$error_msg" debug_log "$error_msg" send_notification "Podcast File Error" "$error_msg" "high" exit 1 fi echo "File successfully moved to: $target_dir/$TEDDY_FILENAME" debug_log "File moved to: $target_dir/$TEDDY_FILENAME" # Update history file to mark this episode as downloaded debug_log "Updating history file for podcast key $podcast_key and guid $clean_guid" # Make sure history file exists and is valid JSON if [ ! -s "$history_file" ] || ! jq empty "$history_file" 2>/dev/null; then debug_log "Creating new history file (empty or invalid)" echo "{}" > "$history_file" fi # Update history with new entry temp_file=$(mktemp) jq ".\"$podcast_key\" = (.\"$podcast_key\" // {}) | .\"$podcast_key\".\"$clean_guid\" = true" "$history_file" > "$temp_file" if [ $? -ne 0 ]; then echo "Warning: Failed to update history file. Next run might download the same episode again." debug_log "Failed to update history file with jq" else # Make sure the generated file is valid JSON before replacing the history file if jq empty "$temp_file" 2>/dev/null; then mv "$temp_file" "$history_file" debug_log "Successfully updated history file" # Debug output the history file content if [ "$DEBUG_MODE" = true ]; then debug_log "New history file content: $(cat "$history_file")" fi else echo "Warning: Generated history file is invalid. Keeping original history file." debug_log "Generated history file is invalid JSON. Keeping original." fi fi # Clean up temporary files rm -f "$temp_file" 2>/dev/null rm -rf "$tonie_input_dir"/* rm -rf "$tonie_output_dir"/* # Uncomment the following line if you want to remove the downloaded mp3 file as well rm "$output_file" success_msg="Successfully downloaded and converted podcast: $episode_title" echo "Script completed successfully!" debug_log "Script completed successfully" # Send success notification send_notification "Podcast Download Complete" "$success_msg" "default"