Bash automation script for converting videos to HEVC (x265) or AV1 in batch (series/movies), with "smart" logic (skip/passthrough) and a persistent queue.
Prerequisites:
- bash 4+ (Git Bash/WSL on Windows OK)
- ffmpeg with
libx265(AV1 vialibsvtav1optional, VMAF vialibvmafoptional)
Installation:
git clone <repo_url> NAScode
cd NAScode
chmod +x nascodeMinimal usage:
# Convert a folder (serie mode by default)
bash nascode -s "/path/to/series"
# Film mode (more quality-oriented)
bash nascode -m film -s "/path/to/movies"
# Dry-run (simulation)
bash nascode -d -s "/path/source"
# Off-peak hours (default range 22:00-06:00)
bash nascode -p -s "/path/to/series"
# Filter index/queue: ignore small files (useful for movies)
bash nascode -m film --min-size 700M -s "/path/to/movies"Important defaults (from config):
- Mode:
serie - Video codec:
hevc - Audio codec:
aac - Output:
Converted/
- Converts to HEVC (x265) or AV1 depending on
--codec. - Manages a queue (persistent index) and can skip files already "good".
- Supports video passthrough mode (video copied, audio optimized if relevant).
- Adds a suffix (dynamic or custom) to reflect video codec, output resolution and (optionally) audio codec.
- Optional: VMAF and sample for quick testing.
- Limitation: portrait mode videos (vertical / rotation metadata) are not effectively supported; resolution/bitrate estimation logic is primarily designed for "landscape" sources and may produce unsuitable parameters.
NAScode supports English and French:
# English output
bash nascode --lang en -s "/path/source"
# French output (default)
bash nascode --lang fr -s "/path/source"
bash nascode -s "/path/source"
# Set language via environment variable
export NASCODE_LANG=en
bash nascode -s "/path/source"Documentation is available in both languages:
These tables summarize the most frequent decisions (skip / copy / convert / downscale). For the complete logic and details, see docs/SMART_CODEC.md.
Reminders:
--audio copy: copies audio without modification.--force-audio: forces conversion to target codec (bypass smart).--no-lossless: forces conversion of premium codecs (DTS/DTS-HD/TrueHD/FLAC).--equiv-quality/--no-equiv-quality: enables/disables "equivalent quality" mode (audio + video cap). (Ignored inadaptatifmode: stays enabled.)--limit-fps/--no-limit-fps: limits FPS to 29.97 for HFR content (>30 fps).seriemode: enabled by default (size optimization).film/adaptatifmodes: disabled by default (max quality, increased bitrate if HFR).- Note: VMAF is ignored if FPS is modified (frame-by-frame comparison impossible).
Channel management (multichannel):
seriemode: forced stereo (systematic downmix if 5.1/7.1+).film/adaptatifmodes: target layout stereo (2ch) or 5.1 (automatic downmix if 7.1).- Default multichannel codec (film/adaptatif): EAC3 384k (TV/receiver compatible).
- Multichannel AAC: only with
-a aac --force-audio(320k cap). - Multichannel Opus:
-a opus(224k cap). - Anti-upscale: no conversion if source < 256k (unless downmix required).
Premium codecs (DTS/DTS-HD/TrueHD/FLAC):
- Without
--no-lossless: passthrough (preserved if already 5.1, otherwise downmix β EAC3 384k). - With
--no-lossless: forced conversion (stereo β target codec, multichannel β EAC3 384k).
Note: in serie mode, forced stereo may convert cases otherwise in copy (including premium) to guarantee 2.0 output.
| Source codec | Status | Channels | Source bitrate | Action | Result |
|---|---|---|---|---|---|
| DTS / DTS-HD / TrueHD | Premium | 5.1 | * | copy |
Preserved (passthrough) |
| DTS / DTS-HD / TrueHD | Premium | 7.1 | * | convert |
β EAC3 384k 5.1 (downmix) |
| FLAC | Lossless | * | * | copy |
Preserved (max quality) |
| Opus | Efficient | stereo |
|
copy |
Preserved as-is |
| Opus | Efficient | 5.1+ |
|
copy |
Preserved as-is |
| AAC | Efficient | stereo |
|
copy |
Preserved as-is |
| AAC | Efficient | 5.1 |
|
copy |
Preserved as-is |
| EAC3 | Standard | 5.1 |
|
copy |
Preserved as-is |
| EAC3 | Standard | 5.1 |
|
downscale |
EAC3 β 384k |
| AC3 | Inefficient | 5.1 | * | convert |
β EAC3 384k |
| MP3 / PCM / others | Inefficient | * | * | convert |
β target codec |
Reminders:
- Hierarchy (efficiency): AV1 > HEVC > VP9 > H.264 > MPEG4
- "Skip" depends on a threshold derived from
MAXRATE_KBPSand tolerance:$\text{threshold} = \mathrm{MAXRATE}_{\mathrm{KBPS}} \times (1 + \text{tolerance})$ - Default: 10% tolerance
- If the source is in a more efficient codec than the target (e.g., AV1 when target is HEVC), the threshold is translated into the source codec space via codec efficiency.
- Example (
seriemode, target HEVC): HEVC threshold 2772k β AV1 threshold β $2772 \times 50/70 \approx 1980$k
-
--force-video: forces video re-encoding (bypass smart). -
--equiv-quality/--no-equiv-quality: enables/disables "equivalent quality" mode (audio + video cap). (Ignored inadaptatifmode: stays enabled.)
| Source codec | vs target | Bitrate (vs threshold) | Action | Result |
|---|---|---|---|---|
| AV1 | > HEVC |
|
skip |
Preserved (better codec, OK bitrate) |
| AV1 | > HEVC |
|
encode |
Re-encoding in AV1 (no downgrade) |
| HEVC | = HEVC |
|
skip |
Preserved (already optimized) |
| HEVC | = HEVC |
|
encode |
Re-encoding (bitrate too high) |
| VP9 / H.264 / MPEG4 | < HEVC | * | encode |
Conversion β HEVC |
| Source > 1080p (e.g., 4K) | * | * | encode + scale |
Downscale β 1080p + target codec |
| Video OK but audio improvable | * | * | passthrough |
Video copied + audio processed |
Command:
bash nascode [options]For the complete list of options:
bash nascode --helpDetailed guides:
Code reference (audio):
- "Smart codec" decision: lib/audio_decision.sh
- FFmpeg/layout construction: lib/audio_params.sh
- Default output:
Converted/(in script folder) - Logs:
logs/(in script folder) - If a conversion produces a heavier file (or gain < threshold), the output is redirected to
Converted_Heavier/(configurable) to avoid reprocessing loops.
Details: docs/TROUBLESHOOTING.md
- No files to process: your filters/exclusions probably eliminated everything (e.g.,
--min-size,EXCLUDES, wrong-s). Retry without filter, or force regeneration:bash nascode -R -s "...". - Invalid queue (NUL separator): if you provide a custom queue, it must be null-separated. Otherwise, delete
logs/Queueand rerun with-R. - Source excluded by config: if you see an error indicating
SOURCEis inEXCLUDES, change-sor remove the exclusion (in config).
NAScode can send notifications via a Discord webhook (Markdown format):
- at startup: active parameters + queue preview (up to 20 items, with truncation)
- during run: start/end of each file (
[i/N]prefix, duration, sizesbefore β after) - during run: file skip (ignored + reason)
- transfers: pending then completed (if applicable)
- VMAF (if enabled): start + result per file (score/quality) + global end
- entering/exiting peak hours when
--off-peakis active - at the end: summary (if available) then an end message with timestamp
Configuration (via environment variables):
NASCODE_DISCORD_WEBHOOK_URL(required): webhook URL (secret)NASCODE_DISCORD_NOTIFY(optional):true/false(defaulttrueif URL is defined)
Recommended (local, not versioned):
cp .env.example .env.local
# then edit .env.local (DO NOT commit)
bash nascode -s "/path/to/series"By default, nascode automatically loads ./.env.local (if present) at startup.
- Disable:
NASCODE_ENV_AUTOLOAD=false - Use another file:
NASCODE_ENV_FILE=/path/to/my.env
Security: never commit the webhook. If you posted it in a chat/log/issue, consider it compromised and regenerate it on Discord's side.
- Docs index: docs/DOCS.md
- Advanced configuration & constants: docs/CONFIG.md
- Adding a new codec: docs/ADDING_NEW_CODEC.md
- macOS instructions: docs/fr/Instructions-Mac.txt
- Conversion criteria: docs/SMART_CODEC.md
The repo uses Bats:
bash run_tests.sh
# Verbose
bash run_tests.sh -v
# Filter
bash run_tests.sh -f "queue" # exampleOn Git Bash / Windows, run_tests.sh also tries ${HOME}/.local/bin/bats if bats is not in PATH.
- Work rules: agent.md
- Copilot (repo-level): .github/copilot-instructions.md
See: docs/CHANGELOG.md
MIT License - Free to use and modify.