**TL;DR** vibe-coded blog thing with HLS video transcoding on push (using git-lfs for the video files)
Everything except these words were created by claude (including the code / CI / docker crap / whatever - this blog was ressurected from when I used to be better at things)
- vivi_
Magnetic Ribbon
Front cover (left) and back cover (right) of the VHS tape
HILARIOUS! (not really)
The Pre-commit Hook
Here's the git pre-commit hook that manages video hashes:
#!/bin/bash
# Pre-commit hook to update video transcoding hashes
# This ensures .transcoded-videos.txt is always current
echo "🔍 Checking video files for changes..."
# Create/update .transcoded-videos.txt with current video hashes
if [ -d "content/videos" ]; then
# Create temporary file
temp_file=$(mktemp)
# Calculate hashes for all video files
for video in content/videos/*.mp4 content/videos/*.mov content/videos/*.avi content/videos/*.mkv; do
if [ -f "$video" ]; then
basename=$(basename "$video")
file_hash=$(sha256sum "$video" | cut -d' ' -f1)
echo "$file_hash $basename" >> "$temp_file"
fi
done
# Sort the file for consistency
sort "$temp_file" > .transcoded-videos.txt
rm "$temp_file"
# Add to staging area if it changed
if ! git diff --quiet --cached .transcoded-videos.txt 2>/dev/null; then
echo "📝 Updated .transcoded-videos.txt with current video hashes"
git add .transcoded-videos.txt
fi
else
# No videos directory, ensure file is empty
if [ -f .transcoded-videos.txt ] && [ -s .transcoded-videos.txt ]; then
echo "🗑️ No videos found, clearing .transcoded-videos.txt"
> .transcoded-videos.txt
git add .transcoded-videos.txt
fi
fi
echo "✅ Video hash check complete"
The Pipeline
Here's the GitLab CI configuration that makes this whole thing work:
stages:
- build
- deploy
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
cache:
paths:
- .cache/pip/
build_site:
stage: build
image:
name: linuxserver/ffmpeg
entrypoint: [""]
variables:
GIT_SSL_NO_VERIFY: "1"
before_script:
- apt-get update && apt-get install -y git git-lfs python3 python3-pip
- git lfs install
- git lfs pull
- pip3 install pelican markdown typogrify --break-system-packages
script:
- echo "=== TRANSCODING VIDEOS ==="
- mkdir -p temp_videos
- echo "Video file info:"
- ls -la content/videos/ || echo "No videos directory"
- |
# Load hash-based tracking file (format: hash filename)
touch .transcoded-videos.txt
echo "📋 Already transcoded videos:"
cat .transcoded-videos.txt || echo " (none)"
echo
if [ -d "content/videos" ]; then
for video in content/videos/*.mp4 content/videos/*.mov content/videos/*.avi content/videos/*.mkv; do
if [ -f "$video" ]; then
basename=$(basename "$video")
name_only="${basename%.*}"
# Calculate file hash
file_hash=$(sha256sum "$video" | cut -d' ' -f1)
echo "🔍 $basename -> $file_hash"
# Check if this hash is already transcoded
if grep -q "^$file_hash " .transcoded-videos.txt; then
echo "⏭️ Skipping $basename (hash matches - video unchanged)"
continue
fi
# Remove any old entries for this filename (in case video was updated)
sed -i "/ $basename$/d" .transcoded-videos.txt
echo "🎬 Transcoding: $video -> $name_only (this will take ~10 minutes)"
mkdir -p "temp_videos/$name_only"
# CPU transcoding
ffmpeg -i "$video" \
-c:v libx264 -preset ultrafast -crf 30 \
-c:a aac -b:a 96k \
-threads 0 \
-hls_time 6 -hls_playlist_type vod \
-hls_segment_filename "temp_videos/$name_only/segment_%03d.ts" \
"temp_videos/$name_only/playlist.m3u8"
# Record the hash for this file
echo "$file_hash $basename" >> .transcoded-videos.txt
echo "✅ Completed: $name_only (hash: $file_hash)"
echo "💾 Added to .transcoded-videos.txt - commit this file to skip future re-encoding"
fi
done
else
echo "No videos found in content/videos/"
fi
- echo "=== TRANSCODING COMPLETE ==="
- |
# Note: .transcoded-videos.txt is managed by the pre-commit hook
# No need to commit from CI as it would create a build loop
if ! git diff --quiet .transcoded-videos.txt; then
echo "📝 .transcoded-videos.txt was updated during transcoding"
echo "💡 Make sure to commit this file locally to skip re-encoding in future runs"
else
echo "📋 No hash changes - all videos were already transcoded"
fi
- echo "=== BUILDING PELICAN SITE ==="
- python3 -m pelican content -s publishconf.py
- echo "=== COPYING NEW VIDEOS TO FINAL OUTPUT ==="
- |
if [ -d "temp_videos" ] && [ "$(ls -A temp_videos 2>/dev/null)" ]; then
echo "Moving newly transcoded videos to output/videos/..."
mkdir -p output/videos
cp -r temp_videos/* output/videos/
echo "✅ New videos copied to output"
else
echo "📭 No new videos to copy"
fi
- echo "=== RSYNC TO SERVER ==="
- apt-get install -y openssh-client rsync sshpass
- |
if [ -n "$SSH_PRIVATE_KEY" ]; then
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H [SERVER_IP] >> ~/.ssh/known_hosts
# Sync site content (excluding videos to preserve existing ones)
echo "🌐 Syncing site content (excluding videos)..."
rsync -avz --delete --exclude='.git*' --exclude='/videos/' output/ root@[SERVER_IP]:/var/www/gmalloc.com/
# Sync only new videos (no --delete to preserve existing videos)
if [ -d "output/videos" ] && [ "$(ls -A output/videos 2>/dev/null)" ]; then
echo "🎬 Syncing new videos (preserving existing)..."
rsync -avz --exclude='.git*' output/videos/ root@[SERVER_IP]:/var/www/gmalloc.com/videos/
fi
elif [ -n "$SSH_PASSWORD" ]; then
# Sync site content (excluding videos to preserve existing ones)
echo "🌐 Syncing site content (excluding videos)..."
sshpass -p "$SSH_PASSWORD" rsync -avz --delete --exclude='.git*' --exclude='/videos/' -e "ssh -o StrictHostKeyChecking=no" output/ root@[SERVER_IP]:/var/www/gmalloc.com/
# Sync only new videos (no --delete to preserve existing videos)
if [ -d "output/videos" ] && [ "$(ls -A output/videos 2>/dev/null)" ]; then
echo "🎬 Syncing new videos (preserving existing)..."
sshpass -p "$SSH_PASSWORD" rsync -avz --exclude='.git*' -e "ssh -o StrictHostKeyChecking=no" output/videos/ root@[SERVER_IP]:/var/www/gmalloc.com/videos/
fi
else
echo "No SSH credentials available!"
exit 1
fi
- echo "Deployment complete!"
only:
- main