#!/bin/bash # ============================================ # Nostr Playlist Fetcher for Hugo # ============================================ # Configuration PUBKEY="3f11abb2e235da2d4dda5d6deb2f123173476a745a3ca56895a1d0f632a42f40" RELAY="wss://drops.basspistol.org" DATA_DIR="data/playlists" NAK_BIN="nak" JQ_BIN="jq" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' mkdir -p "$DATA_DIR" log() { echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"; } log_success() { echo -e "${GREEN}✅ $1${NC}"; } log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; } log_error() { echo -e "${RED}❌ $1${NC}"; } # ============================================ # Step 1: Fetch playlist events # ============================================ log "Fetching playlist events (kind 34139) from $RELAY..." PLAYLISTS_JSON=$(mktemp) $NAK_BIN req -k 34139 -a "$PUBKEY" "$RELAY" | $JQ_BIN -s '.' > "$PLAYLISTS_JSON" if [ ! -s "$PLAYLISTS_JSON" ]; then log_error "No playlist data received." rm -f "$PLAYLISTS_JSON" exit 1 fi PLAYLIST_COUNT=$(cat "$PLAYLISTS_JSON" | $JQ_BIN 'length') log_success "Found $PLAYLIST_COUNT playlist(s)" # ============================================ # Step 2: Fetch ALL tracks # ============================================ log "Fetching ALL tracks (kind 36787) from $PUBKEY..." ALL_TRACKS_JSON=$(mktemp) $NAK_BIN req -k 36787 -a "$PUBKEY" "$RELAY" | $JQ_BIN -s '.' > "$ALL_TRACKS_JSON" TRACK_COUNT=$(cat "$ALL_TRACKS_JSON" | $JQ_BIN 'length' 2>/dev/null || echo "0") log_success "Found $TRACK_COUNT total tracks from pubkey" # ============================================ # Step 3: Build playlist data # ============================================ log "Building playlist data structure..." OUTPUT_FILE="$DATA_DIR/playlists.json" FLATTENED_OUTPUT="$DATA_DIR/tracks.json" # Create a file with track lookup by d-tag TRACK_LOOKUP=$(mktemp) cat "$ALL_TRACKS_JSON" | $JQ_BIN -r ' .[] | . as $track | (.tags[] | select(.[0] == "d") | .[1]) as $d_tag | "\($d_tag)|\($track | tojson)" ' > "$TRACK_LOOKUP" # Build the playlists JSON echo '{"playlists": []}' > "$OUTPUT_FILE" # Process each playlist cat "$PLAYLISTS_JSON" | $JQ_BIN -c '.[]' | while read -r playlist; do # Extract playlist metadata PLAYLIST_ID=$(echo "$playlist" | $JQ_BIN -r '.id') PLAYLIST_CREATED=$(echo "$playlist" | $JQ_BIN -r '.created_at') # FIX: Extract name from "title" tag (not "name") PLAYLIST_NAME=$(echo "$playlist" | $JQ_BIN -r '.tags[] | select(.[0] == "title") | .[1] // ""') PLAYLIST_DESC=$(echo "$playlist" | $JQ_BIN -r '.tags[] | select(.[0] == "description") | .[1] // ""') PLAYLIST_IMAGE=$(echo "$playlist" | $JQ_BIN -r '.tags[] | select(.[0] == "image") | .[1] // ""') # Debug: show what was extracted echo " Playlist: '$PLAYLIST_NAME'" >&2 # Get track references from 'a' tags TRACK_REFS=$(echo "$playlist" | $JQ_BIN -r '.tags[] | select(.[0] == "a") | .[1]') # Build tracks array for this playlist TRACKS_JSON="[]" while read -r ref; do if [ -n "$ref" ]; then # Extract identifier (the part after the second colon) IDENTIFIER=$(echo "$ref" | cut -d':' -f3-) # Find the track in the lookup TRACK_DATA=$(grep "^$IDENTIFIER|" "$TRACK_LOOKUP" | head -1 | cut -d'|' -f2-) if [ -n "$TRACK_DATA" ] && [ "$TRACK_DATA" != "null" ]; then # Extract track fields TRACK_TITLE=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "title") | .[1] // "Untitled"') TRACK_ARTIST=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "artist") | .[1] // "Unknown Artist"') TRACK_ALBUM=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "album") | .[1] // ""') TRACK_URL=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "url") | .[1] // ""') TRACK_IMAGE=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "image") | .[1] // ""') TRACK_DURATION=$(echo "$TRACK_DATA" | $JQ_BIN -r '.tags[] | select(.[0] == "duration") | .[1] // ""') TRACK_ID=$(echo "$TRACK_DATA" | $JQ_BIN -r '.id') TRACK_CREATED=$(echo "$TRACK_DATA" | $JQ_BIN -r '.created_at') TRACK_TAGS=$(echo "$TRACK_DATA" | $JQ_BIN -r '[.tags[] | select(.[0] == "t") | .[1]] | join(",")') # Build track JSON object TRACK_JSON=$(cat < "${OUTPUT_FILE}.tmp" mv "${OUTPUT_FILE}.tmp" "$OUTPUT_FILE" done # ============================================ # Step 4: Flattened tracks file # ============================================ log "Generating flattened tracks file..." cat "$ALL_TRACKS_JSON" | $JQ_BIN ' .[] | { id: .id, created_at: .created_at, title: (.tags[] | select(.[0] == "title") | .[1] // "Untitled"), artist: (.tags[] | select(.[0] == "artist") | .[1] // "Unknown Artist"), album: (.tags[] | select(.[0] == "album") | .[1] // ""), url: (.tags[] | select(.[0] == "url") | .[1] // ""), image: (.tags[] | select(.[0] == "image") | .[1] // ""), duration: (.tags[] | select(.[0] == "duration") | .[1] // ""), tags: [.tags[] | select(.[0] == "t") | .[1]], d_tag: (.tags[] | select(.[0] == "d") | .[1] // "") } ' | $JQ_BIN -s '.' > "$FLATTENED_OUTPUT" # ============================================ # Step 5: Save raw data # ============================================ cp "$PLAYLISTS_JSON" "$DATA_DIR/playlists-raw.json" cp "$ALL_TRACKS_JSON" "$DATA_DIR/tracks-raw.json" # ============================================ # Step 6: Cleanup # ============================================ rm -f "$PLAYLISTS_JSON" "$ALL_TRACKS_JSON" "$TRACK_LOOKUP" # ============================================ # Step 7: Summary # ============================================ echo "" echo -e "${BLUE}========================================${NC}" echo -e "${GREEN}📊 Playlist Summary${NC}" echo -e "${BLUE}========================================${NC}" echo -e " 📀 Playlists: $PLAYLIST_COUNT" echo -e " 🎵 Total tracks found: $TRACK_COUNT" echo -e " 📁 Data saved to: $DATA_DIR/" echo -e "${BLUE}========================================${NC}" # Show playlist names echo "" echo -e "${BLUE}📝 Playlist Names:${NC}" cat "$OUTPUT_FILE" | $JQ_BIN -r '.playlists[].name' 2>/dev/null | while read -r name; do if [ -n "$name" ]; then echo " 🎵 $name" else echo " ⚠️ (unnamed)" fi done