Skip to content

Prod/dev split, dev site on dev relative path, prod on root #11

Prod/dev split, dev site on dev relative path, prod on root

Prod/dev split, dev site on dev relative path, prod on root #11

name: Build Videos and Deploy Site
on:
push:
branches: [main]
paths:
- '.github/workflows/**'
- 'Chapter*/**'
- 'scene_utils/**'
- 'imgs/**'
- 'docs/**/*.md'
- 'mkdocs.yml'
- 'manim.cfg'
- 'requirements.txt'
workflow_dispatch:
inputs:
chapters:
description: 'Chapters to rebuild (comma-separated, e.g. "0,3,5" or "all")'
required: false
default: 'all'
prod:
description: 'Use ElevenLabs TTS for production quality narration'
required: false
type: boolean
default: false
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y ffmpeg sox libcairo2-dev libpango1.0-dev \
texlive texlive-latex-extra texlive-fonts-extra
- name: Install Python dependencies
run: |
pip install 'setuptools<82'
pip install manim manim-voiceover[gtts] invoke python-graphblas \
networkx matplotlib python-dotenv \
mkdocs mkdocs-material pymdown-extensions
if [ "${{ inputs.prod }}" = "true" ]; then
pip install 'elevenlabs>=0.2.27,<0.3.0'
fi
- name: Restore dev video cache
uses: actions/cache@v4
with:
path: .video-cache/dev
key: dev-videos-${{ hashFiles('Chapter**/Scene*.py', 'Chapter**/Thumb.py', 'scene_utils/**/*.py', 'imgs/**', 'manim.cfg') }}
restore-keys: dev-videos-
- name: Restore prod video cache
uses: actions/cache@v4
with:
path: .video-cache/prod
key: prod-videos-${{ hashFiles('Chapter**/Scene*.py', 'Chapter**/Thumb.py', 'scene_utils/**/*.py', 'imgs/**', 'manim.cfg') }}
restore-keys: prod-videos-
- name: Restore voiceover cache
uses: actions/cache@v4
with:
path: |
Chapter0/media/voiceovers
Chapter1/media/voiceovers
Chapter2/media/voiceovers
Chapter3/media/voiceovers
Chapter4/media/voiceovers
Chapter5/media/voiceovers
Chapter6/media/voiceovers
Chapter7/media/voiceovers
Chapter8/media/voiceovers
Chapter9/media/voiceovers
key: voiceovers-${{ hashFiles('Chapter**/Scene*.py') }}
restore-keys: voiceovers-
- name: Determine chapters to build
id: chapters
run: |
mkdir -p .video-cache/dev .video-cache/prod
# Determine build mode
if [ "${{ inputs.prod }}" = "true" ]; then
CACHE_DIR=".video-cache/prod"
else
CACHE_DIR=".video-cache/dev"
fi
# On workflow_dispatch, use the input
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ "${{ inputs.chapters }}" = "all" ]; then
echo "rebuild=0,1,2,3,4,5,6,7,8,9" >> "$GITHUB_OUTPUT"
else
echo "rebuild=${{ inputs.chapters }}" >> "$GITHUB_OUTPUT"
fi
else
# On push, rebuild dev chapters that have cache misses
REBUILD=""
for N in 0 1 2 3 4 5 6 7 8 9; do
CHAPTER="Chapter${N}"
if [ ! -f "${CACHE_DIR}/${CHAPTER}_480p15.mp4" ] || [ ! -f "${CACHE_DIR}/${CHAPTER}.png" ]; then
if [ -d "$CHAPTER" ]; then
REBUILD="${REBUILD:+${REBUILD},}${N}"
fi
fi
done
echo "rebuild=${REBUILD}" >> "$GITHUB_OUTPUT"
fi
- name: Build chapters
env:
ELEVEN_API_KEY: ${{ secrets.ELEVEN_API_KEY }}
run: |
# Determine target cache directory
if [ "${{ inputs.prod }}" = "true" ]; then
CACHE_DIR=".video-cache/prod"
else
CACHE_DIR=".video-cache/dev"
fi
REBUILD="${{ steps.chapters.outputs.rebuild }}"
echo "Build mode: $([ "${{ inputs.prod }}" = "true" ] && echo "PROD" || echo "DEV")"
echo "Chapters to rebuild: ${REBUILD:-none}"
# Build chapters that need rebuilding
if [ -n "$REBUILD" ]; then
IFS=',' read -ra CHAPTERS <<< "$REBUILD"
for N in "${CHAPTERS[@]}"; do
N=$(echo "$N" | tr -d ' ')
CHAPTER="Chapter${N}"
if [ ! -d "$CHAPTER" ]; then
echo "Skipping ${CHAPTER} (directory not found)"
continue
fi
echo "=========================================="
echo "Building ${CHAPTER}"
echo "=========================================="
# Build and stitch the chapter
if [ "${{ inputs.prod }}" = "true" ]; then
invoke build-chapter --chapter "$CHAPTER" --quality l --pause-time 0 --prod
else
invoke build-chapter --chapter "$CHAPTER" --quality l --pause-time 0
fi
# Render thumbnail
cd "$CHAPTER"
manim -ql -s Thumb.py Thumb -o "../../../../docs/${CHAPTER}.png"
cd ..
# Cache the results
cp "docs/${CHAPTER}_480p15.mp4" "${CACHE_DIR}/${CHAPTER}_480p15.mp4"
cp "docs/${CHAPTER}.png" "${CACHE_DIR}/${CHAPTER}.png"
echo "${CHAPTER} complete"
done
fi
- name: Assemble and build site
run: |
# Step 1: Build prod site at root (if prod videos exist)
PROD_VIDEOS_EXIST=false
for N in 0 1 2 3 4 5 6 7 8 9; do
CHAPTER="Chapter${N}"
if [ -f ".video-cache/prod/${CHAPTER}_480p15.mp4" ]; then
cp ".video-cache/prod/${CHAPTER}_480p15.mp4" "docs/${CHAPTER}_480p15.mp4"
cp ".video-cache/prod/${CHAPTER}.png" "docs/${CHAPTER}.png"
PROD_VIDEOS_EXIST=true
fi
done
if [ "$PROD_VIDEOS_EXIST" = "true" ]; then
echo "Building prod site at root..."
mkdocs build -d site
else
echo "No prod videos cached yet. Building placeholder prod site..."
mkdocs build -d site
fi
# Step 2: Build dev site at /dev/
for N in 0 1 2 3 4 5 6 7 8 9; do
CHAPTER="Chapter${N}"
if [ -f ".video-cache/dev/${CHAPTER}_480p15.mp4" ]; then
cp ".video-cache/dev/${CHAPTER}_480p15.mp4" "docs/${CHAPTER}_480p15.mp4"
cp ".video-cache/dev/${CHAPTER}.png" "docs/${CHAPTER}.png"
fi
done
echo "Building dev site at /dev/..."
mkdocs build -d site/dev
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: site
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4