Handy tools designed for voice actors and audio engineers.
π Live Demo: voiceover-tools.com
- Real-time word and character count
- Adjustable reading speed calculation
- Pricing calculator with custom rates
- Script comparison and diff visualization
- Pronunciation lookup - Click a word to see ARPABET phonetic notation (North American English)
- Professional fullscreen teleprompter for studio recording
- Auto-scroll with adjustable speed control
- Elapsed and remaining time display
- Keyboard-first operation (Space, arrows, Esc, Home)
- Remote control via smartphone (scan QR code)
- Convert audio files to telephony-compatible formats
- Batch file conversion with progress tracking
- Volume normalization
- Phone-optimized audio filtering (300-3400Hz)
- Automated ACX audiobook technical requirements validation
- MP3 format and bitrate verification (192+ kbps CBR)
- Sample rate checking (44.1 kHz)
- RMS loudness measurement (-23dB to -18dB)
- Peak amplitude analysis (β€ -3dB)
- Leading/trailing silence measurement
- Detailed compliance report with actionable guidance
The fastest way to get started - no cloning required:
docker run -d -p 3000:3000 -p 5000:5000 --name vo-tools tro2789/vo-tools:latestAccess at http://localhost:3000
Download just the compose file for easy deployment:
curl -O https://raw.githubusercontent.com/tro2789/vo-tools/main/docker-compose.yml
docker compose up -dOr clone the full repo:
git clone https://github.com/tro2789/vo-tools.git
cd vo-tools
docker compose up -dAccess at http://localhost:3010
Useful commands:
docker compose down # Stop
docker compose logs -f # View logs
docker compose pull # Update to latest imagePrerequisites: Node.js 20+, Python 3.11+
git clone https://github.com/tro2789/vo-tools.git
cd vo-tools
npm install
npm run devAccess at http://localhost:3000
Note: The ACX Checker and Telephony Converter require the Python backend. See Development Guide for full setup.
When deploying behind a reverse proxy (Nginx, Nginx Proxy Manager, Caddy, etc.), you need to configure proper routing for the API endpoints.
Add these location blocks to your proxy configuration:
# Main application (Next.js)
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket for teleprompter remote (Flask)
location /socket.io/ {
proxy_pass http://127.0.0.1:5000/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Flask API endpoints
location /api/convert {
proxy_pass http://127.0.0.1:3000/api/convert;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /api/acx-check {
proxy_pass http://127.0.0.1:3000/api/acx-check;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /health {
proxy_pass http://127.0.0.1:5000/health;
proxy_http_version 1.1;
proxy_set_header Host $host;
}voiceover-tools.com {
reverse_proxy / localhost:3000
reverse_proxy /socket.io/* localhost:5000
reverse_proxy /api/convert localhost:3000
reverse_proxy /api/acx-check localhost:3000
reverse_proxy /health localhost:5000
}- Port 3000 serves the Next.js frontend and API routes (
/api/convert,/api/acx-check) - Port 5000 serves the Flask backend (WebSocket
/socket.io/, health check/health) - Only expose your reverse proxy (port 80/443) to the internet
- Keep ports 3000 and 5000 internal (localhost only)
For active development with hot-reload:
# Start development container (ports 3011/5001)
docker compose -f docker-compose.dev.yml up -d --build
# View logs
docker logs -f vo-tools-devπ See docs/DEVELOPMENT.md for:
- Complete development workflow
- Git branching strategy (dev β main)
- Testing procedures
- Troubleshooting guide
vo-tools/
βββ app/ # Next.js app router pages
β βββ page.tsx # Landing page
β βββ acx-check/ # ACX compliance checker
β βββ script-analysis/ # Script analysis tool
β βββ teleprompter/ # Teleprompter tool
β βββ telephony-converter/ # Audio converter tool
β βββ remote/ # Mobile remote control
β βββ api/ # API routes
βββ components/ # React components
βββ hooks/ # Custom React hooks
βββ lib/ # Utilities and API clients
βββ app.py # Flask API backend
βββ acx_analyzer.py # ACX audio analysis
βββ Dockerfile # Production container
βββ docs/ # Documentation
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, TypeScript, Tailwind CSS |
| Backend | Python Flask, Gunicorn |
| Audio Processing | FFmpeg, pydub, scipy |
| Container | Docker, Supervisord |
Copy .env.example to .env and configure:
cp .env.example .env| Variable | Description | Default |
|---|---|---|
API_KEY |
Authentication key for Flask API - required! | your-secure-api-key-change-this |
AUTH_ENABLED |
Enable API authentication | true |
ALLOWED_ORIGINS |
CORS origins (comma-separated) | https://voiceover-tools.com,... |
π‘ Generate a secure API key:
openssl rand -hex 32
Important: The API_KEY protects your Flask API from external abuse. Your Next.js frontend uses this key internally to authenticate to Flask. Users access your site through Next.js (port 3000) and never see the API key. Only expose port 3000 publicly - keep port 5000 internal.
Production Setup:
# Create .env file with your API key
echo "API_KEY=$(openssl rand -hex 32)" > .env
# Deploy with docker-compose (reads .env automatically)
docker-compose up -dSecurity Best Practices:
- β
Set a strong random
API_KEY - β Only expose port 3000 to the internet (Next.js)
- β Keep port 5000 internal (Flask API)
- β Use HTTPS in production with reverse proxy (Nginx/Cloudflare)
- β Never commit
.envto git
| Variable | Description | Default |
|---|---|---|
FLASK_API_URL |
Internal Flask URL | http://localhost:5000 |
NEXT_PUBLIC_API_URL |
Public API URL (leave empty for same-origin) | `` |
| Variable | Description | Default |
|---|---|---|
MAX_CONTENT_LENGTH |
Max upload size in bytes | 52428800 (50MB) |
UPLOAD_FOLDER |
Upload directory path | /tmp/uploads |
ALLOWED_EXTENSIONS |
Allowed file types | wav,mp3,ogg,flac,m4a,aiff,wma,aac |
FFMPEG_TIMEOUT |
Processing timeout (seconds) | 60 |
| Variable | Description | Default |
|---|---|---|
RATE_LIMIT_ENABLED |
Enable rate limiting | true |
RATE_LIMIT_PER_MINUTE |
Requests per minute per IP | 10 |
RATE_LIMIT_PER_HOUR |
Requests per hour per IP | 100 |
WS_RATE_LIMIT_PER_MINUTE |
WebSocket requests per minute | 30 |
| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Node environment | production |
FLASK_HOST |
Flask bind address | 0.0.0.0 |
FLASK_PORT |
Flask port | 5000 |
FLASK_DEBUG |
Debug mode (never in prod) | false |
LOG_LEVEL |
Logging level | INFO |
- π¬ Discord Community
- β Buy Me A Coffee
- π Report Issues
Built with β€οΈ for the voiceover community