Files
2026-01-07 19:14:21 +01:00

349 lines
10 KiB
Makefile

# PDF to Scroll Video Converter - Justfile
# Run `just --list` to see all available commands
# Default recipe (shows help)
default:
@just --list
# Setup: Install dependencies and create required folders
setup:
@echo "📦 Setting up project..."
@mkdir -p inputs tmp
@echo "✅ Folders created: inputs/, tmp/"
@echo ""
@echo "📋 Checking dependencies..."
@command -v ffmpeg >/dev/null 2>&1 || echo "❌ ffmpeg not found - install it!"
@command -v pdftoppm >/dev/null 2>&1 || echo "❌ pdftoppm not found - install poppler-utils!"
@command -v python3 >/dev/null 2>&1 || echo "❌ python3 not found!"
@python3 -c "import PIL" 2>/dev/null || echo "❌ PIL/Pillow not found - run: pip install Pillow"
@python3 -c "import yaml" 2>/dev/null || echo "❌ PyYAML not found - run: pip install pyyaml"
@echo ""
@echo "✅ Setup complete! Place your PDFs in the 'inputs/' folder"
# Install Python dependencies
install-deps:
@echo "📦 Installing Python dependencies..."
pip install --break-system-packages Pillow pyyaml
@echo "✅ Dependencies installed!"
# Run the converter
run:
@echo "🚀 Starting PDF to Scroll Video Converter..."
python3 scroll.py
# Run with custom config
run-config CONFIG:
@echo "🚀 Running with config: {{CONFIG}}"
python3 scroll.py --config {{CONFIG}}
# Quick run: setup + convert
convert: setup run
# Clean temporary files
clean:
@echo "🧹 Cleaning temporary files..."
rm -rf tmp/
@echo "✅ Cleaned tmp/ folder"
# Clean everything (including output)
clean-all:
@echo "🧹 Cleaning all generated files..."
rm -rf tmp/
rm -f output_scroll.mp4
@echo "✅ Cleaned tmp/ and output files"
# Check if inputs folder has PDFs
check:
@echo "📂 Checking inputs folder..."
@if [ -z "$(ls -A inputs/*.pdf 2>/dev/null)" ]; then \
echo "⚠️ No PDF files found in inputs/"; \
echo " Place your PDF files in the inputs/ folder"; \
exit 1; \
else \
echo "✅ Found PDFs:"; \
ls -lh inputs/*.pdf | awk '{print " - " $$9 " (" $$5 ")"}'; \
fi
# Show project status
status:
@echo "📊 Project Status"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo ""
@echo "📁 Input PDFs:"
@if [ -z "$(ls -A inputs/*.pdf 2>/dev/null)" ]; then \
echo " ⚠️ No PDFs found"; \
else \
ls -lh inputs/*.pdf | awk '{print " ✓ " $$9 " (" $$5 ")"}'; \
fi
@echo ""
@echo "📹 Output Video:"
@if [ -f "output_scroll.mp4" ]; then \
ls -lh output_scroll.mp4 | awk '{print " ✓ " $$9 " (" $$5 ")"}'; \
else \
echo " ⚠️ No output video found"; \
fi
@echo ""
@echo "💾 Temporary Files:"
@if [ -d "tmp" ] && [ -n "$(ls -A tmp 2>/dev/null)" ]; then \
du -sh tmp 2>/dev/null | awk '{print " ⚠️ Using " $$1 " in tmp/"}'; \
else \
echo " ✓ No temp files"; \
fi
@echo ""
# Watch output video with mpv (if installed)
watch:
@if [ ! -f "output_scroll.mp4" ]; then \
echo "❌ No output video found. Run 'just run' first."; \
exit 1; \
fi
@if command -v mpv >/dev/null 2>&1; then \
echo "🎬 Playing output_scroll.mp4..."; \
mpv output_scroll.mp4; \
elif command -v vlc >/dev/null 2>&1; then \
echo "🎬 Playing output_scroll.mp4..."; \
vlc output_scroll.mp4; \
else \
echo "❌ No video player found (mpv or vlc)"; \
echo " Video is at: output_scroll.mp4"; \
fi
# Show video info
info:
@if [ ! -f "output_scroll.mp4" ]; then \
echo "❌ No output video found."; \
exit 1; \
fi
@echo "📊 Video Information:"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@ffprobe -v quiet -print_format json -show_format -show_streams output_scroll.mp4 | \
python3 -c "import sys, json; d=json.load(sys.stdin); \
s=d['streams'][0]; f=d['format']; \
print(f'Resolution: {s[\"width\"]}x{s[\"height\"]}'); \
print(f'Duration: {float(f[\"duration\"]):.1f}s'); \
print(f'FPS: {eval(s[\"r_frame_rate\"])}'); \
print(f'Codec: {s[\"codec_name\"]}'); \
print(f'Size: {int(f[\"size\"])/1024/1024:.1f} MB')"
# Create example config with different settings
config-portrait:
@echo "📝 Creating portrait config (1080x1920)..."
@cat > config_portrait.yml << 'EOF'
# Portrait/Mobile format
input_folder: "inputs"
output_filename: "output_portrait.mp4"
cache_folder: "./tmp"
resolution:
width: 1080
height: 1920
timing:
seconds_per_slide: 15
fps: 30
EOF
@echo "✅ Created config_portrait.yml"
config-landscape:
@echo "📝 Creating landscape config (1920x1080)..."
@cat > config_landscape.yml << 'EOF'
# Landscape/Desktop format
input_folder: "inputs"
output_filename: "output_landscape.mp4"
cache_folder: "./tmp"
resolution:
width: 1920
height: 1080
timing:
seconds_per_slide: 15
fps: 30
EOF
@echo "✅ Created config_landscape.yml"
config-fast:
@echo "📝 Creating fast scroll config..."
@cat > config_fast.yml << 'EOF'
# Fast scrolling (5 seconds per slide)
input_folder: "inputs"
output_filename: "output_fast.mp4"
cache_folder: "./tmp"
resolution:
width: 1080
height: 1920
timing:
seconds_per_slide: 5
fps: 30
EOF
@echo "✅ Created config_fast.yml"
config-slow:
@echo "📝 Creating slow scroll config..."
@cat > config_slow.yml << 'EOF'
# Slow scrolling (30 seconds per slide)
input_folder: "inputs"
output_filename: "output_slow.mp4"
cache_folder: "./tmp"
resolution:
width: 1080
height: 1920
timing:
seconds_per_slide: 30
fps: 60
EOF
@echo "✅ Created config_slow.yml"
config-hq:
@echo "📝 Creating high quality config..."
@cat > config_hq.yml << 'EOF'
# High quality (60fps, slow scroll)
input_folder: "inputs"
output_filename: "output_hq.mp4"
cache_folder: "./tmp"
resolution:
width: 1080
height: 1920
timing:
seconds_per_slide: 20
fps: 60
EOF
@echo "✅ Created config_hq.yml"
# Create all preset configs
configs: config-portrait config-landscape config-fast config-slow config-hq
@echo ""
@echo "✅ All preset configs created!"
@echo " Use with: just run-config config_<name>.yml"
# Run tests with a sample PDF (if test.pdf exists)
test:
@if [ ! -f "test.pdf" ]; then \
echo "⚠️ No test.pdf found"; \
echo " Create a test.pdf or copy a PDF to test with"; \
exit 1; \
fi
@echo "🧪 Running test with test.pdf..."
@mkdir -p inputs_test
@cp test.pdf inputs_test/
@cat > config_test.yml << 'EOF'
input_folder: "inputs_test"
output_filename: "output_test.mp4"
cache_folder: "./tmp_test"
resolution:
width: 1080
height: 1920
timing:
seconds_per_slide: 5
fps: 30
EOF
@python3 scroll.py
@echo "✅ Test complete! Check output_test.mp4"
# Benchmark: measure processing time
bench:
@echo "⏱️ Starting benchmark..."
@time just run
# Show disk usage
disk:
@echo "💾 Disk Usage:"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@du -sh inputs 2>/dev/null | awk '{print "Inputs: " $$1}'
@du -sh tmp 2>/dev/null | awk '{print "Temp: " $$1}' || echo "Temp: 0 B"
@ls -lh output_*.mp4 2>/dev/null | awk '{print "Output: " $$5 " (" $$9 ")"}' || echo "Output: none"
@echo ""
@df -h . | tail -1 | awk '{print "Free: " $$4 " available on disk"}'
# Help: show detailed usage instructions
help:
@echo "🎬 PDF to Scroll Video Converter"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@echo ""
@echo "📋 Quick Start:"
@echo " 1. just setup # Setup project"
@echo " 2. Copy PDFs to inputs/"
@echo " 3. just run # Convert to video"
@echo " 4. just watch # Play the result"
@echo ""
@echo "🎨 Presets:"
@echo " just configs # Create all config presets"
@echo " just run-config config_portrait.yml"
@echo " just run-config config_fast.yml"
@echo ""
@echo "🔧 Common Commands:"
@echo " just convert # Setup + run in one command"
@echo " just status # Show project status"
@echo " just clean # Remove temp files"
@echo " just info # Show video details"
@echo ""
@echo "📚 More Commands:"
@echo " just --list # List all commands"
@echo ""
# Development: format Python code (requires black)
fmt:
@if command -v black >/dev/null 2>&1; then \
echo "🎨 Formatting code..."; \
black scroll.py; \
else \
echo "⚠️ black not installed: pip install black"; \
fi
# Development: lint Python code (requires pylint)
lint:
@if command -v pylint >/dev/null 2>&1; then \
echo "🔍 Linting code..."; \
pylint scroll.py; \
else \
echo "⚠️ pylint not installed: pip install pylint"; \
fi
# Create a backup of current output
backup:
@if [ ! -f "output_scroll.mp4" ]; then \
echo "❌ No output video to backup"; \
exit 1; \
fi
@mkdir -p backups
@cp output_scroll.mp4 "backups/output_$(date +%Y%m%d_%H%M%S).mp4"
@echo "✅ Backup created in backups/"
# Archive project (create tar.gz)
archive:
@echo "📦 Creating project archive..."
@tar -czf pdf-scroll-converter_$(date +%Y%m%d).tar.gz \
scroll.py config.yml Justfile README.md \
--exclude='tmp/*' --exclude='*.mp4' --exclude='inputs/*'
@echo "✅ Archive created: pdf-scroll-converter_$(date +%Y%m%d).tar.gz"
# Upload output to transfer.sh (temporary file sharing)
share:
@if [ ! -f "output_scroll.mp4" ]; then \
echo "❌ No output video to share"; \
exit 1; \
fi
@echo "📤 Uploading to transfer.sh..."
@curl --upload-file output_scroll.mp4 https://transfer.sh/output_scroll.mp4
@echo ""
@echo "✅ Upload complete! Link valid for 14 days."
# Open project in editor
edit:
@${EDITOR:-nano} scroll.py
# Show ffmpeg version and codecs
ffmpeg-info:
@echo "📹 FFmpeg Information:"
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
@ffmpeg -version | head -1
@echo ""
@echo "Available encoders:"
@ffmpeg -hide_banner -encoders 2>/dev/null | grep "^ V" | head -5