Skip to content

🤖 AI-Powered Daily News Digest & Website #439

🤖 AI-Powered Daily News Digest & Website

🤖 AI-Powered Daily News Digest & Website #439

name: 🤖 AI-Powered Daily News Digest & Website
on:
schedule:
# Run daily at 5:00 AM UTC (6:00 AM BST / 5:00 AM GMT)
# This ensures 6 AM UK time during British Summer Time
- cron: '0 5 * * *'
workflow_dispatch: # Allow manual triggering
inputs:
debug_mode:
description: 'Enable debug output'
required: false
default: false
type: boolean
force_ai_regeneration:
description: 'Force regeneration (use current TTS config e.g. ElevenLabs); ignores existing today content'
required: false
default: false
type: boolean
concurrency:
group: daily-digest-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'workflow_dispatch' }}
permissions:
contents: write
pages: write
id-token: write
jobs:
# --- Check if today's content already exists (skip generation when possible) ---
check-content:
runs-on: ubuntu-latest
container: dynamicdevices/audionews-digest:latest
defaults:
run:
shell: bash
working-directory: ${{ github.workspace }}
outputs:
content_exists: ${{ steps.check_content.outputs.content_exists }}
today_date: ${{ steps.check_content.outputs.today_date }}
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
lfs: true
- name: 🔍 Check if today's content exists
id: check_content
run: |
cd "$GITHUB_WORKSPACE" || exit 1
TODAY=$(date +%Y_%m_%d)
LANGUAGES=("en_GB" "pl_PL" "bella")
ALL_EXIST=true
for LANG in "${LANGUAGES[@]}"; do
AUDIO_FILE="docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"
TEXT_FILE="docs/${LANG}/news_digest_ai_${TODAY}.txt"
if [[ -f "$AUDIO_FILE" && -f "$TEXT_FILE" ]]; then
AUDIO_SIZE=$(stat -c%s "$AUDIO_FILE" 2>/dev/null || echo "0")
[[ $AUDIO_SIZE -le 50000 ]] && ALL_EXIST=false
else
ALL_EXIST=false
fi
done
# When force_ai_regeneration is set, always run generation
if [[ "${{ inputs.force_ai_regeneration }}" == "true" ]]; then
echo "content_exists=false" >> $GITHUB_OUTPUT
echo "🔄 Force regeneration: will generate all languages"
elif [[ "$ALL_EXIST" == "true" ]]; then
echo "content_exists=true" >> $GITHUB_OUTPUT
echo "🌍 All language content exists for today"
else
echo "content_exists=false" >> $GITHUB_OUTPUT
echo "🌍 Some language content missing - will generate"
fi
echo "today_date=$TODAY" >> $GITHUB_OUTPUT
# --- No-op when content exists so merge can depend on skip OR generate ---
skip-generation:
runs-on: ubuntu-latest
needs: check-content
if: needs.check-content.outputs.content_exists == 'true'
steps:
- run: echo "💰 Skipping AI generation - today's content already exists"
# --- Generate one language per matrix cell (runs in parallel) ---
generate-one-language:
runs-on: ubuntu-latest
container: dynamicdevices/audionews-digest:latest
defaults:
run:
shell: bash
working-directory: ${{ github.workspace }}
needs: check-content
if: needs.check-content.outputs.content_exists != 'true'
strategy:
fail-fast: false
matrix: { language: [en_GB, pl_PL, bella] }
permissions:
contents: read
actions: read
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ELEVENLABS_API_KEY: ${{ secrets.ELEVENLABS_API_KEY }}
DEBUG_MODE: ${{ github.event.inputs.debug_mode }}
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
lfs: true
- name: 🤖 Generate digest for ${{ matrix.language }}
run: |
cd "$GITHUB_WORKSPACE" || exit 1
LANG="${{ matrix.language }}"
FORCE_ARG=""
[[ "${{ inputs.force_ai_regeneration }}" == "true" ]] && FORCE_ARG="--force-regenerate"
TTS_ARG=""
[[ "$LANG" == "en_GB" ]] && TTS_ARG="--tts-provider elevenlabs"
[[ "$LANG" == "bella" ]] && TTS_ARG="--tts-provider elevenlabs"
echo "▶ Generating $LANG..."
timeout 300 python scripts/github_ai_news_digest.py --language "$LANG" $TTS_ARG $FORCE_ARG
TODAY=$(date +%Y_%m_%d)
AUDIO="docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"
TEXT="docs/${LANG}/news_digest_ai_${TODAY}.txt"
if [[ ! -f "$AUDIO" || ! -f "$TEXT" ]]; then
echo "❌ $LANG: expected files missing"
exit 1
fi
echo "✅ $LANG generated"
- name: 📤 Upload digest artifact
uses: actions/upload-artifact@v4
with:
name: digest-${{ matrix.language }}
path: docs/${{ matrix.language }}/
# --- Merge artifacts, update HTML/RSS, commit and push ---
merge:
runs-on: ubuntu-latest
needs: [check-content, skip-generation, generate-one-language]
if: always() && (needs.skip-generation.result == 'success' || needs.generate-one-language.result == 'success')
permissions:
contents: write
actions: read
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}
lfs: true
- name: 🐍 Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: 📦 Install dependencies
run: pip install -r requirements.txt
- name: 📥 Download generated artifacts (when generation ran)
if: needs.generate-one-language.result == 'success'
uses: actions/download-artifact@v4
with:
pattern: digest-*
path: artifacts
merge-multiple: false
- name: 📂 Merge artifacts into docs/
if: needs.generate-one-language.result == 'success'
run: |
for dir in artifacts/digest-*; do
[ -d "$dir" ] || continue
LANG=$(basename "$dir" | sed 's/^digest-//')
mkdir -p "docs/${LANG}/audio"
cp -a "$dir"/* "docs/${LANG}/" 2>/dev/null || true
[ -d "$dir/audio" ] && cp -a "$dir/audio"/* "docs/${LANG}/audio/" 2>/dev/null || true
echo "✅ Merged $LANG"
done
- name: 🔄 Ensure Git LFS files
run: git lfs pull || echo "⚠️ Git LFS pull failed (may continue)"
- name: 📊 Verify content
run: |
TODAY=$(date +%Y_%m_%d)
for LANG in en_GB pl_PL bella; do
AUDIO="docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"
TEXT="docs/${LANG}/news_digest_ai_${TODAY}.txt"
if [ -f "$AUDIO" ] && [ -f "$TEXT" ]; then
echo "✅ ${LANG}: $(stat -c%s "$AUDIO") bytes audio"
else
echo "❌ ${LANG}: missing files"; exit 1
fi
done
- name: 🌐 Update language HTML pages
run: |
TODAY=$(date +%Y_%m_%d)
for LANG in en_GB pl_PL bella; do
AUDIO="docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"
TEXT="docs/${LANG}/news_digest_ai_${TODAY}.txt"
[ "$(stat -c%s "$AUDIO" 2>/dev/null || echo 0)" -gt 1000 ] || { git lfs pull --include="docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3" || true; }
python3 scripts/update_language_website.py --language "$LANG" || exit 1
done
- name: 📱 Verify file locations
run: |
for LANG in en_GB pl_PL bella; do
ls docs/${LANG}/audio/news_digest_ai_*.mp3 docs/${LANG}/news_digest_ai_*.txt 2>/dev/null || true
done
- name: 🎙️ Generate Podcast RSS
run: |
git lfs pull || true
python scripts/generate_podcast_rss.py || exit 0
- name: 🔍 Quality check
run: |
TOTAL=0
for LANG in en_GB pl_PL bella; do
f=$(ls docs/${LANG}/audio/news_digest_ai_*.mp3 2>/dev/null | head -1)
[ -n "$f" ] && TOTAL=$((TOTAL + $(stat -c%s "$f")))
done
[ $TOTAL -gt 0 ] || { echo "❌ No audio"; exit 1; }
echo "✅ Total audio: $(numfmt --to=iec $TOTAL)"
- name: 📝 Commit generated files
run: |
git config --local user.email "ai-digest@github.com"
git config --local user.name "AI News Digest Bot"
# CRITICAL: Check if HTML/RSS need updating BEFORE pulling (to avoid overwriting local updates)
# This check must happen on the locally updated files, not after pulling remote
TODAY=$(date +%Y_%m_%d)
TODAY_FORMATTED=$(date +%Y-%m-%d)
TODAY_ALT_FORMAT=$(date +"%B %d, %Y")
HTML_NEEDS_UPDATE=false
for LANG in en_GB pl_PL bella; do
if [ -f "docs/${LANG}/index.html" ]; then
# Check if HTML contains today's date in various formats
if grep -q "$TODAY_FORMATTED\|$TODAY_ALT_FORMAT" "docs/${LANG}/index.html" 2>/dev/null; then
echo "✅ ${LANG} HTML page already contains today's date (local check)"
else
HTML_NEEDS_UPDATE=true
echo "📝 ${LANG} HTML page needs updating for today ($TODAY_FORMATTED) - was updated locally"
fi
else
HTML_NEEDS_UPDATE=true
echo "📝 ${LANG} HTML page missing - needs creation"
fi
done
# RSS feeds are ALWAYS regenerated in the previous step, so they may have changed
# even if they already contain today's date (new episode added, content updated, etc.)
# We need to check if the RSS file content actually changed, not just the date
RSS_NEEDS_UPDATE=false
for LANG in en_GB pl_PL bella; do
if [ -f "docs/${LANG}/podcast.rss" ]; then
# Check if RSS feed contains today's date - if not, definitely needs update
if ! grep -q "<lastBuildDate>.*$(date +%d.*%b.*%Y)" "docs/${LANG}/podcast.rss" 2>/dev/null && \
! grep -q "<pubDate>.*$(date +%d.*%b.*%Y)" "docs/${LANG}/podcast.rss" 2>/dev/null; then
RSS_NEEDS_UPDATE=true
echo "📻 ${LANG} RSS feed missing today's date - needs update"
else
# RSS contains today's date, but it was just regenerated so it might have changed
# We'll check if it actually changed after staging (using git diff --staged)
echo "✅ ${LANG} RSS feed contains today's date (was regenerated, will check for changes)"
fi
else
RSS_NEEDS_UPDATE=true
echo "📻 ${LANG} RSS feed missing - needs creation"
fi
done
# CRITICAL: Always stage RSS feeds because they're always regenerated and may have changed
# (new episode added, content updated, etc.) even if date is already today
# Stage HTML and RSS files BEFORE pulling to preserve updates
echo "📝 Staging HTML and RSS files before pull (RSS always regenerated, HTML may be updated)..."
git add docs/en_GB/index.html docs/pl_PL/index.html docs/bella/index.html 2>/dev/null || true
git add docs/en_GB/podcast.rss docs/pl_PL/podcast.rss docs/bella/podcast.rss 2>/dev/null || true
# CRITICAL: Backup newly generated audio/text BEFORE pull - pull overwrites working tree with
# origin/main and would replace our new ElevenLabs (or regenerated) audio with old content.
GENERATED_BACKUP="${RUNNER_TEMP:-/tmp}/generated_backup_$$"
mkdir -p "$GENERATED_BACKUP"
for LANG in en_GB pl_PL bella; do
if [ -f "docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3" ]; then
mkdir -p "$GENERATED_BACKUP/${LANG}/audio"
cp -a "docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3" "$GENERATED_BACKUP/${LANG}/audio/"
echo "💾 Backed up ${LANG} audio"
fi
if [ -f "docs/${LANG}/news_digest_ai_${TODAY}.txt" ]; then
mkdir -p "$GENERATED_BACKUP/${LANG}"
cp -a "docs/${LANG}/news_digest_ai_${TODAY}.txt" "$GENERATED_BACKUP/${LANG}/"
echo "💾 Backed up ${LANG} text"
fi
done
# Sync with remote: fetch then reset to origin/main (we've backed up generated files, so this is safe).
# Using fetch+reset avoids "cannot pull with rebase: Your index contains uncommitted changes".
echo "🔄 Syncing with origin/main (fetch + reset, generated content already backed up)..."
git fetch origin main
git reset --hard origin/main
# Restore generated audio/text so we don't lose newly created content (e.g. ElevenLabs regeneration)
if [ -d "$GENERATED_BACKUP" ]; then
echo "🔄 Restoring generated audio and text after pull..."
for LANG in en_GB pl_PL bella; do
if [ -f "$GENERATED_BACKUP/${LANG}/audio/news_digest_ai_${TODAY}.mp3" ]; then
mkdir -p "docs/${LANG}/audio"
cp -a "$GENERATED_BACKUP/${LANG}/audio/news_digest_ai_${TODAY}.mp3" "docs/${LANG}/audio/"
echo "✅ Restored ${LANG} audio"
fi
if [ -f "$GENERATED_BACKUP/${LANG}/news_digest_ai_${TODAY}.txt" ]; then
cp -a "$GENERATED_BACKUP/${LANG}/news_digest_ai_${TODAY}.txt" "docs/${LANG}/"
echo "✅ Restored ${LANG} text"
fi
done
rm -rf "$GENERATED_BACKUP"
fi
# CRITICAL: After pull, we need to re-apply HTML and RSS updates because:
# 1. HTML update step ran earlier and updated files locally
# 2. RSS generation step ran earlier and regenerated feeds
# 3. git pull --rebase may have overwritten those updates with remote versions
# 4. We need to re-apply the updates to ensure we commit the latest versions
# CRITICAL: Always re-apply HTML updates after pull (not just if HTML_NEEDS_UPDATE was true)
# Reason: The HTML update step ran earlier and updated files, but git pull --rebase may have
# overwritten them. We need to ensure HTML is always up-to-date with today's content.
# Re-check if HTML needs updating AFTER pull (pull may have overwritten our updates)
echo "🔄 Re-checking and re-applying HTML updates after pull..."
TODAY=$(date +%Y_%m_%d)
TODAY_FORMATTED=$(date +%Y-%m-%d)
TODAY_ALT_FORMAT=$(date +"%B %d, %Y")
HTML_NEEDS_UPDATE_AFTER_PULL=false
for LANG in en_GB pl_PL bella; do
if [ -f "docs/${LANG}/index.html" ]; then
# Check if HTML contains today's date AFTER pull
if ! grep -q "$TODAY_FORMATTED\|$TODAY_ALT_FORMAT" "docs/${LANG}/index.html" 2>/dev/null; then
HTML_NEEDS_UPDATE_AFTER_PULL=true
echo "📝 ${LANG} HTML page missing today's date after pull - will update"
fi
else
HTML_NEEDS_UPDATE_AFTER_PULL=true
echo "📝 ${LANG} HTML page missing after pull - will create"
fi
done
# Re-apply HTML updates if needed (after pull check)
if [ "$HTML_NEEDS_UPDATE_AFTER_PULL" = "true" ]; then
echo "🔄 Re-applying HTML updates after pull..."
git lfs pull || echo "⚠️ Git LFS pull failed (may continue if files already available)"
for LANG in en_GB pl_PL bella; do
if [ -f "docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3" ] && [ -f "docs/${LANG}/news_digest_ai_${TODAY}.txt" ]; then
if python3 scripts/update_language_website.py --language ${LANG}; then
echo "✅ ${LANG} HTML page updated successfully after pull"
else
echo "❌ ${LANG} HTML update failed after pull"
exit 1
fi
else
echo "⚠️ ${LANG} content files not found - cannot update HTML"
fi
done
else
echo "✅ All HTML pages already contain today's date after pull"
fi
# Always re-generate RSS feeds after pull (they're always regenerated anyway)
# This ensures we have the latest RSS with today's episode, even if pull overwrote them
echo "🔄 Re-generating RSS feeds after pull to ensure latest episodes..."
git lfs pull || echo "⚠️ Git LFS pull failed (may continue if files already available)"
python scripts/generate_podcast_rss.py || echo "⚠️ RSS regeneration failed after pull"
# CRITICAL: git pull --rebase can UNSTAGE files, so we MUST re-stage everything after pull
# Even if we staged before pull and re-applied after pull, the rebase operation can reset staging
# We ALWAYS stage HTML and RSS files after pull to ensure they're committed
echo "📝 Re-staging HTML and RSS files after pull (rebase may have unstaged them)..."
git add docs/en_GB/index.html docs/pl_PL/index.html docs/bella/index.html 2>/dev/null || true
git add docs/en_GB/podcast.rss docs/pl_PL/podcast.rss docs/bella/podcast.rss 2>/dev/null || true
# Verify files are actually staged (debug output)
echo "🔍 Verifying staged files..."
for LANG in en_GB pl_PL bella; do
if git diff --staged --name-only | grep -q "docs/${LANG}/index.html"; then
echo "✅ ${LANG}/index.html is staged"
else
echo "⚠️ ${LANG}/index.html is NOT staged - attempting to stage again..."
git add "docs/${LANG}/index.html" 2>/dev/null || echo "❌ Failed to stage ${LANG}/index.html"
fi
if git diff --staged --name-only | grep -q "docs/${LANG}/podcast.rss"; then
echo "✅ ${LANG}/podcast.rss is staged"
else
echo "⚠️ ${LANG}/podcast.rss is NOT staged - attempting to stage again..."
git add "docs/${LANG}/podcast.rss" 2>/dev/null || echo "❌ Failed to stage ${LANG}/podcast.rss"
fi
done
# Check if today's content already exists in remote (another workflow may have already committed)
# Only skip if ALL languages already exist (not just some)
ALL_LANGUAGES_EXIST=true
for LANG in en_GB pl_PL bella; do
if git ls-tree -r origin/main --name-only | grep -q "docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"; then
echo "✅ Remote already has ${LANG} content for ${TODAY}"
else
ALL_LANGUAGES_EXIST=false
echo "📝 Remote missing ${LANG} content for ${TODAY} - will commit"
fi
done
# NOTE: HTML_NEEDS_UPDATE was set BEFORE the pull, but we've now re-applied HTML updates.
# RSS feeds have been re-generated after pull, so we need to check if they actually changed.
# Check if RSS feeds actually changed (they're always regenerated, but might be identical)
RSS_ACTUALLY_CHANGED=false
for LANG in en_GB pl_PL bella; do
if git diff --staged docs/${LANG}/podcast.rss 2>/dev/null | grep -q .; then
RSS_ACTUALLY_CHANGED=true
echo "📻 ${LANG} RSS feed has changes to commit"
fi
done
# CRITICAL: Always check if HTML actually changed after re-application
# We must check regardless of the pre-pull HTML_NEEDS_UPDATE value because:
# 1. HTML update step ran earlier and updated files
# 2. git pull --rebase may have overwritten them
# 3. We re-applied updates based on HTML_NEEDS_UPDATE_AFTER_PULL
# 4. We need to check if the re-applied files actually changed
HTML_ACTUALLY_CHANGED=false
for LANG in en_GB pl_PL bella; do
if git diff --staged docs/${LANG}/index.html 2>/dev/null | grep -q .; then
HTML_ACTUALLY_CHANGED=true
echo "🌐 ${LANG} HTML page has changes to commit"
else
# Check if HTML was re-applied but shows no diff (might mean it's identical to remote)
if [ "$HTML_NEEDS_UPDATE_AFTER_PULL" = "true" ]; then
echo "⚠️ ${LANG} HTML was re-applied but shows no staged changes - may be identical to remote"
fi
fi
done
# Only skip commit if ALL of the following are true:
# 1. All audio files exist
# 2. HTML pages didn't actually change (even if they were updated)
# 3. RSS feeds didn't actually change (even though they were regenerated)
if [ "$ALL_LANGUAGES_EXIST" = "true" ] && [ "$HTML_ACTUALLY_CHANGED" = "false" ] && [ "$RSS_ACTUALLY_CHANGED" = "false" ]; then
echo "💰 COST OPTIMIZATION: All content already exists and is up to date"
echo "📊 Another workflow may have already committed - skipping commit"
echo "✅ This is expected behavior for concurrent runs"
exit 0
fi
if [ "$ALL_LANGUAGES_EXIST" = "true" ]; then
if [ "$HTML_ACTUALLY_CHANGED" = "true" ] || [ "$RSS_ACTUALLY_CHANGED" = "true" ]; then
echo "📝 Audio files exist but HTML/RSS have changes - will commit updates"
fi
fi
# Add ONLY language-specific files to avoid conflicts
# This prevents touching the root index.html and other development files
git add docs/en_GB/ docs/fr_FR/ docs/de_DE/ docs/es_ES/ docs/it_IT/ docs/nl_NL/ docs/pl_PL/ docs/bella/ docs/en_GB_LON/ docs/en_GB_LIV/ || true
# Explicitly add RSS feeds to ensure they're always committed when updated
git add docs/en_GB/podcast.rss docs/pl_PL/podcast.rss docs/bella/podcast.rss 2>/dev/null || true
# Explicitly add HTML pages to ensure they're always committed when updated
git add docs/en_GB/index.html docs/pl_PL/index.html docs/bella/index.html 2>/dev/null || true
# Also add any files that might be in wrong location (for backward compatibility)
git add news_digest_ai_*.mp3 news_digest_ai_*.txt 2>/dev/null || true
# Always check if RSS feeds or HTML pages were staged for commit
RSS_UPDATED=false
HTML_UPDATED=false
for LANG in en_GB pl_PL bella; do
if git diff --staged docs/${LANG}/podcast.rss 2>/dev/null | grep -q .; then
RSS_UPDATED=true
echo "📻 ${LANG} RSS feed has been updated and staged"
fi
if git diff --staged docs/${LANG}/index.html 2>/dev/null | grep -q .; then
HTML_UPDATED=true
echo "🌐 ${LANG} HTML page has been updated and staged"
fi
done
# Create commit with date and stats
if git diff --staged --quiet; then
echo "💰 COST OPTIMIZATION: No new files to commit - content already exists"
echo "📊 Estimated API cost savings: \$0.50-\$2.00"
exit 0
fi
# Build COMMIT_MSG (one block for both RSS/HTML-only and new-audio cases)
COMMIT_MSG="🤖 Daily AI news digest & website update $(date +%Y-%m-%d)
📊 Generated: $(date '+%Y-%m-%d %H:%M UTC')"
if [ "$RSS_UPDATED" = "true" ]; then
COMMIT_MSG="${COMMIT_MSG}
📻 Podcast: RSS feeds updated"
fi
if [ "$HTML_UPDATED" = "true" ]; then
COMMIT_MSG="${COMMIT_MSG}
🌐 Website: HTML pages updated"
fi
# Add audio stats when we have new audio or when remote was missing some
TOTAL_SIZE=0
LANG_STATS=""
for LANG in en_GB pl_PL bella; do
if ls docs/${LANG}/audio/news_digest_ai_*.mp3 1> /dev/null 2>&1; then
audio_file=$(ls docs/${LANG}/audio/news_digest_ai_*.mp3 | head -1)
size_bytes=$(stat -c%s "$audio_file")
size_human=$(numfmt --to=iec $size_bytes)
TOTAL_SIZE=$((TOTAL_SIZE + size_bytes))
LANG_STATS="${LANG_STATS}${LANG}: ${size_human} "
fi
done
if [ $TOTAL_SIZE -gt 0 ]; then
total_size_human=$(numfmt --to=iec $TOTAL_SIZE)
COMMIT_MSG="${COMMIT_MSG}
🎧 Audio: ${total_size_human} total (${LANG_STATS})"
fi
COMMIT_MSG="${COMMIT_MSG}
🤖 AI: Enhanced analysis"
if [ $TOTAL_SIZE -gt 0 ]; then
COMMIT_MSG="${COMMIT_MSG}
🌐 Website: Updated with accessible newspaper layout"
fi
COMMIT_MSG="${COMMIT_MSG}
♿ Accessibility: Optimized for visually impaired users"
git commit -m "$COMMIT_MSG"
# Single push-with-retry block (avoids duplicate commits when another run already pushed)
MAX_PUSH_RETRIES=3
PUSH_RETRY=0
while [ $PUSH_RETRY -lt $MAX_PUSH_RETRIES ]; do
if git push; then
echo "✅ Files committed and pushed successfully"
break
fi
PUSH_RETRY=$((PUSH_RETRY + 1))
if [ $PUSH_RETRY -lt $MAX_PUSH_RETRIES ]; then
echo "⚠️ Push attempt $PUSH_RETRY failed, pulling latest and retrying..."
git fetch origin main
REMOTE_HAS_SAME=false
for LANG in en_GB pl_PL bella; do
if git ls-tree -r origin/main --name-only | grep -q "docs/${LANG}/audio/news_digest_ai_${TODAY}.mp3"; then
REMOTE_HAS_SAME=true
fi
done
if [ "$REMOTE_HAS_SAME" = "true" ]; then
echo "✅ Remote already has today's content - another workflow succeeded"
echo "💰 Skipping push to avoid duplicate commits"
exit 0
fi
git reset --hard HEAD~1
git pull --rebase origin main || git reset --hard origin/main
git add docs/en_GB/ docs/fr_FR/ docs/de_DE/ docs/es_ES/ docs/it_IT/ docs/nl_NL/ docs/pl_PL/ docs/bella/ docs/en_GB_LON/ docs/en_GB_LIV/ || true
git add docs/en_GB/podcast.rss docs/pl_PL/podcast.rss docs/bella/podcast.rss 2>/dev/null || true
git add docs/en_GB/index.html docs/pl_PL/index.html docs/bella/index.html 2>/dev/null || true
git add news_digest_ai_*.mp3 news_digest_ai_*.txt 2>/dev/null || true
git commit -m "$COMMIT_MSG" || echo "⚠️ No changes to commit after rebase"
else
echo "⚠️ Push failed after $MAX_PUSH_RETRIES attempts - another workflow may have already pushed"
echo "✅ This is acceptable for concurrent runs"
fi
done
- name: 📤 Upload artifacts for download
uses: actions/upload-artifact@v4
with:
name: ai-news-digest-${{ needs.check-content.outputs.today_date }}-${{ github.run_number }}
path: |
docs/en_GB/audio/news_digest_ai_${{ needs.check-content.outputs.today_date }}.mp3
docs/en_GB/news_digest_ai_${{ needs.check-content.outputs.today_date }}.txt
docs/pl_PL/audio/news_digest_ai_${{ needs.check-content.outputs.today_date }}.mp3
docs/pl_PL/news_digest_ai_${{ needs.check-content.outputs.today_date }}.txt
docs/bella/audio/news_digest_ai_${{ needs.check-content.outputs.today_date }}.mp3
docs/bella/news_digest_ai_${{ needs.check-content.outputs.today_date }}.txt
if-no-files-found: warn
retention-days: 90
create-issue-on-failure:
runs-on: ubuntu-latest
needs: [check-content, skip-generation, generate-one-language, merge]
if: always() && (needs.merge.result == 'failure' || needs.generate-one-language.result == 'failure')
permissions:
issues: write
steps:
- name: ❌ Create issue on failure
uses: actions/github-script@v7
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🚨 Daily AI Digest Failed - ${new Date().toISOString().split('T')[0]}`,
body: `### ❌ AI News Digest Generation Failed
**Run**: ${context.runId}
**Date**: ${new Date().toISOString()}
**Workflow**: ${context.workflow}
Please check the [workflow logs](${context.payload.repository.html_url}/actions/runs/${context.runId}) for details.
### Possible Issues:
- API key expired or missing
- Network connectivity issues
- News source changes
- Audio generation failure
- Website update failure
This needs immediate attention for accessibility service continuity.`,
labels: ['bug', 'ai-digest', 'urgent']
})
deploy-website:
needs: merge
runs-on: ubuntu-latest
if: always() && needs.merge.result == 'success'
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
ref: main # Deploy from main branch
lfs: true # Enable Git LFS checkout
- name: 📦 Pull LFS files
run: |
echo "🔍 Checking LFS files before pull..."
echo "Checking language-specific audio directories..."
find docs -name "*.mp3" -type f -exec ls -lh {} \; | head -10 || echo "No audio files found"
echo "🔄 Pulling LFS files..."
git lfs pull
echo "✅ LFS files after pull:"
echo "Sample audio files (should be >500KB each):"
find docs -name "news_digest_ai_*.mp3" -type f -exec ls -lh {} \; | head -10
- name: 🔧 Setup Pages
uses: actions/configure-pages@v5
- name: 📦 Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./docs
- name: 🚀 Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
notify-completion:
needs: [merge, deploy-website]
runs-on: ubuntu-latest
if: always() && needs.merge.result == 'success' && needs.deploy-website.result == 'success'
steps:
- name: 🎉 Success notification
run: |
if [ "${{ github.event_name }}" = "schedule" ]; then
echo "⏰ Scheduled daily digest completed successfully!"
echo "📅 Date: $(date)"
echo "🎧 Audio ready for visually impaired users"
echo "🤖 AI analysis completed"
echo "🌐 Accessible website deployed"
echo "♿ Accessibility service operational"
else
echo "🔧 Manual workflow completed successfully!"
echo "📅 Date: $(date)"
echo "🎧 Audio ready for visually impaired users"
echo "🤖 AI analysis completed"
echo "🌐 Accessible website deployed"
echo "♿ Accessibility service operational"
fi
echo ""
echo "🔗 Website: https://audionews.uk"