349 lines
10 KiB
Makefile
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
|