#!/bin/bash # ============================================================================= # ingestEpisode.sh # ============================================================================= # Descripció: # Script unificat per al processament d'episodis de podcast. # S'executa automàticament des de FlexGet un cop finalitzada la descàrrega. # # Flux d'execució: # 1. Processa l'arxiu d'àudio (metadades + portada via ffmpeg) # 2. Regenera el feed RSS del podcast corresponent # 3. Envia una notificació NTFY amb el resum de l'operació # # Ús: # ./ingestEpisode.sh "YYYY-MM-DD" "Títol" "Autor" "/ruta/base/podcast" # # Paràmetres: # $1 rss_pubdate Data de publicació de l'episodi (format: YYYY-MM-DD) # $2 titol Títol de l'episodi (també s'usa com a nom d'arxiu) # $3 autor Autor / nom del podcast # $4 path Ruta absoluta al directori base del podcast # (ex: /data/podcast/NomDelPodcast) # # Dependències: # - ffmpeg Processament d'àudio i incrustació de metadades # - curl Enviament de notificacions a NTFY # - find / sort Generació del feed RSS # # Arxius esperats al directori base ($path): # - YYYYMMDD.mp3 o YYYYMMDD.m4a Arxiu d'àudio descarregat per FlexGet # - cover.jpg Portada del podcast (opcional) # - .ntfyToken Token d'autenticació NTFY (a /config/) # # Sortida: # - $path/$titol/$titol.mp3|m4a Arxiu processat amb metadades i portada # - $path/$titol/cover.jpg Còpia de la portada (si existeix) # - /data/podcast/$DIR_NAME.xml Feed RSS regenerat # # Configuració: # Les constants de la secció "Config RSS & NTFY" s'han d'adaptar # si canvia el servidor, el domini o l'estructura de directoris. # # ============================================================================= set -e rss_pubdate="$1" titol="$2" autor="$3" path="$4" # --- Config RSS & NTFY ----------------------------------------------------------- # BASE_DIR: directori arrel on resideixen tots els podcasts # OUTPUT_DIR: on es desen els feeds XML generats (normalment el mateix que BASE_DIR) # LINK_BASE: URL pública base des d'on s'accedeix als arxius # NTFY_SERVER: URL interna del contenidor NTFY # NTFY_TOPIC: tema NTFY on s'envien les notificacions BASE_DIR="/data/podcast" OUTPUT_DIR="/data/podcast" LINK_BASE="https://podcast.tuServidor.org" NTFY_SERVER="http://ntfy:80" NTFY_TOPIC="podcast-ingest" NTFY_TOKEN="$(cat /config/.ntfyToken | tr -d '\r\n')" [ -z "$NTFY_TOKEN" ] && { echo "Token NTFY vacio"; exit 1; } # --- Fechas ---------------------------------------------------------------------- # pubdateYmd: format compacte per localitzar l'arxiu descarregat (ex: 20250728) # pubdateY: any per a la metadada 'date' de l'arxiu d'àudio (ex: 2025) pubdateYmd=$(date -d "$rss_pubdate" +"%Y%m%d") pubdateY=$(date -d "$rss_pubdate" +"%Y") cover="$path/cover.jpg" destFolder="$path/$titol" mkdir -p "$destFolder" # --- Procesar audio -------------------------------------------------------------- # Incrusta metadades ID3 i portada a l'arxiu d'àudio mitjançant ffmpeg. # Si existeix cover.jpg al directori base, s'afegeix com a attached_pic. # L'arxiu original es elimina un cop processat correctament. processFile () { local input="$1" local ext="$2" local output="$destFolder/$titol.$ext" if [[ -f "$cover" ]]; then ffmpeg -y -loglevel quiet -i "$input" \ -i "$cover" \ -map 0:a -map 1:v \ -map_metadata -1 \ -c copy \ -metadata title="$titol" \ -metadata artist="$autor" \ -metadata album="$titol" \ -metadata genre="Podcast" \ -metadata track="1" \ -metadata date="$pubdateY" \ -disposition:v:0 attached_pic \ "$output" else ffmpeg -y -loglevel quiet -i "$input" \ -map 0:a \ -c copy \ -metadata title="$titol" \ -metadata artist="$autor" \ -metadata album="$titol" \ -metadata genre="Podcast" \ -metadata track="1" \ -metadata date="$pubdateY" \ "$output" fi rm -f "$input" } # Cerca l'arxiu descarregat pel nom de data. Si no existeix cap dels dos formats # suportats (mp3, m4a), el script finalitza sense error ni notificació. if [[ -f "$path/${pubdateYmd}.mp3" ]]; then processFile "$path/${pubdateYmd}.mp3" "mp3" elif [[ -f "$path/${pubdateYmd}.m4a" ]]; then processFile "$path/${pubdateYmd}.m4a" "m4a" else exit 0 fi # Copia la portada al directori de l'episodi per si el client RSS la necessita [[ -f "$cover" ]] && cp "$cover" "$destFolder/" # --- Generar feed RSS del podcast descargado ------------------------------------ # Regenera únicament el feed del podcast que acaba de rebre un episodi nou. # Recorre tots els arxius mp3/m4a del directori i els ordena per data (més recent primer). # La URL de cada arxiu s'escapa per reemplaçar espais per %20. DIR_NAME=$(basename "$path") OUTPUT_FILE="$OUTPUT_DIR/${DIR_NAME}.xml" TITLE="Podcast: ${DIR_NAME}" LINK="${LINK_BASE}/${DIR_NAME}.xml" IMAGE_URL="${LINK_BASE}/${DIR_NAME}/cover.jpg" NOW=$(date -R) { echo "" echo "" echo "" echo " $TITLE" echo " $LINK" echo " $NOW" echo " Podcast de ${DIR_NAME} generat automaticament" echo " " echo " $IMAGE_URL" echo " $TITLE" echo " $LINK" echo " " echo " " find "$path" -type f \( -name "*.mp3" -o -name "*.m4a" \) | sort -r | while read -r audio; do FILENAME=$(basename "$audio") RELATIVE_PATH=${audio#$BASE_DIR/} URL_ENCODED=$(echo "${LINK_BASE}/${RELATIVE_PATH}" | sed 's/ /%20/g; s|\([^:]\)//|\1/|g') PUBDATE=$(date -R -r "$audio") echo " " echo " ${FILENAME%.*}" echo " vctrsnts" echo " $URL_ENCODED" echo " ${FILENAME}" echo " " echo " $PUBDATE" echo " ${FILENAME%.*}" echo " " done echo "" echo "" } > "$OUTPUT_FILE" chown root:root "$OUTPUT_FILE" # --- Notificación única ---------------------------------------------------------- # Envia un unic missatge NTFY amb el resum complet de l'operacio: # episodi processat + feed regenerat. # S'usa text/plain per evitar problemes de format amb el body de curl. #NTFY_BODY="<200b>Nou episodi: #- ${titol} (${rss_pubdate}) # #Feed actualitzat: #- ${DIR_NAME}.xml" # NTFY_BODY="​ Nou episodi: - ${titol} (${rss_pubdate}) Feed actualitzat: - ${DIR_NAME}.xml" curl -s \ -o /dev/null \ 2>/dev/null \ -H "Authorization: Bearer ${NTFY_TOKEN}" \ -H "Title: Podcast Sync" \ -H "Tags: headphones" \ -H "Priority: default" \ -H "Content-Type: text/plain" \ -d "${NTFY_BODY}" \ "${NTFY_SERVER}/${NTFY_TOPIC}"