Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bdav — Linux BDAV authoring tool.

English | 日本語

bdav is a Linux CLI that takes MPEG2-TS recordings (.ts / .m2t / .m2ts) — e.g. captured by a PT3 tuner card — and produces a BDAV file tree (CLIPINF/, PLAYLIST/, info.bdav, STREAM/) that consumer Blu-ray recorders / players recognize and play back.

  • No wine, no third-party binaries. Native implementation of the open BD-RE Part 3 (BDAV) format.
  • Automatic subtitle resolution from Syobocal (しょぼいカレンダー), the de-facto Japanese anime episode database, with 3 selectable title formats.
  • Parses foltia ANIME LOCKER filenames ({TID}-{EpNo}-...) to derive title ID and episode number automatically.
  • Per-directory or per-file input.
  • Two-stage flow (preview → confirm → build) for safety; one-shot mode available for CI / automation.
  • foltia ANIME LOCKER integration can create chapters automatically from CM-cut metadata.

For verified broadcast configurations and audio layouts, see docs/bdav-native-format.md.

License: MIT (LICENSE). See NOTICE.md for treatment of third-party tools, standards documents, and trademarks.


Quick start

Install

Zero third-party dependencies (Python standard library only), so any of the following works. The uv route is the easiest — you don't even need Python 3.11+ pre-installed; uv will fetch what it needs.

A) uv (recommended)

# One-time install of uv itself
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install bdav as a global CLI
uv tool install --from git+https://github.com/sorshi/bdav bdav

bdav --version

Upgrade with uv tool upgrade bdav, remove with uv tool uninstall bdav. The system Python is never touched.

B) pipx

# Debian/Ubuntu: sudo apt install pipx
# RHEL family:   sudo dnf install pipx  (or pip install --user pipx)
# macOS:         brew install pipx
pipx install git+https://github.com/sorshi/bdav

bdav --version

C) pip + venv (classic)

git clone https://github.com/sorshi/bdav.git
cd bdav
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
bdav --version

foltia ANIME LOCKER integration

Place the api directory from inside the foltia-api-server directory under foltia ANIME LOCKER's /home/foltia/php/. Do not contact the foltia ANIME LOCKER vendor about this integration. Only proceed if you understand and accept that you are solely responsible for any outcome regarding foltia ANIME LOCKER.

Tested OS versions (expected)

This project runs on glibc 2.17+ via uv and python-build-standalone, so the supported range is very broad. Development and playback verification were done on Ubuntu Server 24.04 LTS (x64), with discs burned on Windows 11 using ImgBurn and playback confirmed on a PS3.

OS Minimum version Notes
Debian 10 (buster, 2019) or later glibc 2.28+. Debian 12 (bookworm) / 13 (trixie) recommended
Ubuntu 18.04 LTS (bionic) or later glibc 2.27+. 22.04 / 24.04 LTS recommended
RHEL / AlmaLinux / Rocky 8+ (practical); 7 works for uv itself RHEL 8: glibc 2.28; RHEL 9/10 recommended
macOS 12 Monterey (Intel) / 11 Big Sur (Apple Silicon) or later
Windows WSL2 only (assumed) Native Windows unverified

Route (C) (pip + venv) requires system Python 3.11+; in that case:

  • Debian: 12 (bookworm, Python 3.11) or later; 11 and earlier need backports or pyenv
  • Ubuntu: 24.04 LTS (Python 3.12) recommended; 22.04 ships python3.11 in universe
  • RHEL / AlmaLinux: 9 (Python 3.11 in AppStream) or later; on 8 use dnf module install python3.11
  • macOS: Homebrew python@3.11 or later

Build a BDAV file tree in one shot (foltia-style recording directory)

bdav author \
  --input-dir /mnt/foltia/7749 \
  --output    /work/disc1 \
  --channel-name BS11 --channel-number 211

This scans each input file, derives TID / episode number from the foltia-style filename, fetches the program title + subtitle from Syobocal, formats them, prints a preview, then writes the BDAV tree.

Preview only

bdav author --input-dir /mnt/foltia/7749 --dry-run

Via plan JSON (recommended when you want to hand-edit before building)

# 1) Generate plan JSON + preview
bdav plan \
  --input-dir /mnt/foltia/7749 \
  --plan      /work/7749.plan.json

# 2) Optionally hand-edit /work/7749.plan.json
#    (e.g. fill in subtitles for episodes Syobocal didn't have)

# 3) Build
bdav build \
  --plan   /work/7749.plan.json \
  --output /work/disc1

Plan JSON format is documented in docs/workflow.md.


Subtitle formats (3 styles)

Selected with --subtitle-format (default: default).

ID Example output Use case
default #1 はじまりの章 Episode number + subtitle (default)
subtitle-only はじまりの章 Subtitle text only
title-episode-subtitle アニメA #1 はじまりの章 Includes program title
bdav author --input-dir /mnt/foltia/7749 --output /work/disc1 \
  --subtitle-format title-episode-subtitle

Combine with --episode-pad 2 to zero-pad to #01 (default 0 = no padding).

Details: docs/subtitle-formats.md.


Specifying inputs

A. Directory or glob (foltia naming)

# Directory: all .ts/.m2ts/.m2t/.mts inside
bdav author --input-dir /mnt/foltia/7749 --output /work/disc1

# Glob pattern: quote it so the shell doesn't expand it
bdav author --input-dir '/mnt/foltia/7749-*.m2t' --output /work/disc1

--input-dir accepts a directory, a glob pattern (* ? [ are detected), or a single file path. In all cases TID / episode number are extracted from the foltia filename and items are sorted by episode (so #1, #2, ... #10, #11 come out in numeric order, not alphabetical).

B. Per-file (title + recording channel per file)

bdav author --output /work/disc1 \
  --input /rec/00001.m2ts --title "#1 はじまりの章" \
    --channel-name "AT-X" --channel-number 333 \
  --input /rec/00002.m2ts --title "#2 出会いの章" \
    --channel-name "BS11" --channel-number 211

--title / --channel-name / --channel-number pair positionally with --input (the i-th value goes with the i-th input).

  • --title, if given, is used verbatim as formatted_title — Syobocal API lookup and --subtitle-format reformatting are both skipped (so you don't get a doubled #N prefix).
  • --channel-name / --channel-number are useful when burning a mixed disc with different recording stations per program. The BDAV spec stores the recording channel per-playlist (.rpls), so consumer BD recorders display the correct channel name per program on the disc menu.
  • If you give only one --channel-name (or --channel-number), it becomes the disc-wide default and applies to all items.
  • Specifying only one side (name or number) lets the other be auto-filled from the bundled channel definition (e.g. --channel-name "AT-X" → number 333 is filled in).
  • If you specify neither, bdav reads the input TS's SDT/PAT and resolves the station from the (ONID, TSID, SID) triplet via channels.toml, so even files that don't follow foltia naming get correct station info. Disable with --no-ts-probe. Inspect with bdav probe FILE. Regional terrestrial differences and additional stations can be overridden in ~/.config/bdav/channels.toml. Details: docs/channels.md.

C. List file (TSV / JSON)

bdav author --output /work/disc1 --list /work/titles.tsv

TSV columns: path<TAB>title<TAB>rec_time<TAB>ch_name<TAB>ch_num (columns after the first are optional).


Accepted input formats

Input Handling
.m2ts (192-byte TS) Placed in STREAM/ as-is (aligned to 6144-byte boundary)
.ts / .m2t (188-byte TS) Arrival times interpolated from PCR, then wrapped to 192-byte M2TS

No ffmpeg / tsMuxeR re-multiplexing is performed. PSI / PID / stream_type are preserved verbatim, so the original broadcast audio configuration (stereo / 5.1 surround / dual-mono bilingual) is correctly reflected in the BDAV metadata.


Main CLI options

Option Description
--input-dir PATH Directory / glob pattern ('/path/7784*.m2t') / single file (foltia naming recommended)
--input PATH (repeatable) Per-file input
--title TITLE (repeatable) Title paired positionally with --input
--list FILE TSV / JSON list file
--output DIR Output BDAV directory
--subtitle-format ID default / subtitle-only / title-episode-subtitle
--episode-pad N Zero-pad episode number (default 0)
--channel-name NAME (repeatable) Station name (e.g. BS11). Same count as --input → per-item; 1 value → disc-wide default. Number auto-filled from map if omitted
--channel-number N (repeatable) Station number (e.g. BS11=211, AT-X=333). Same rule; name auto-filled from map if omitted
--channel-map FILE (repeatable) Additional TOML overrides for the channel map (docs/channels.md)
--no-ts-probe Disable SDT/PAT auto-resolution from the input TS
--chapter-interval SEC Periodic chapter interval in seconds (default 300, 0 disables)
--chapters CSV (repeatable) Explicit per-clip chapter list (seconds, comma-separated; 1:23.4 form accepted). Pairs with --input
--chapters-file FILE (repeatable) Same but read from a text file (one timestamp per line, # for comments)
--no-marks Don't write PlayListMark
--copy-mode {copy,move,link} How to place files into STREAM/ (default copy). move consumes the input file; use copy or link for originals you want to preserve
--no-backup Skip the BACKUP/ mirror
--no-api Don't call the Syobocal API
--api-cache-dir DIR API response cache directory
--overwrite Overwrite existing output
--dry-run (author) Show preview and exit without building
--yes, -y (build / author) Don't prompt even if items are flagged review=true
--report PATH Write a build report JSON
-q, --quiet Suppress all non-error output (also implies --yes). For shell scripts.
-v, --verbose Print debug details (e.g. source paths, packet counts)
--foltia-url URL foltia host URL (e.g. http://foltia.local; /api/v1/ is auto-appended when missing). Imports CM-cut chapters per file
--foltia-user USER, --foltia-pass PASS Basic Auth credentials (env: FOLTIA_USER, FOLTIA_PASS)
--foltia-fields LIST foltia values that should force-override local values: chapters,subtitle,channel,all. Default (empty): foltia acts as a fallback — fills only fields the local sources couldn't resolve (e.g. an unknown regional terrestrial station name)

Run bdav <subcommand> --help for the full list.

Disc capacity summary

bdav plan / bdav author also estimates total disc usage and reports which Blu-ray media type would fit:

Total disc usage estimate: 22.47 GB across 11 clip(s)
  [OK]  BD-R SL     Single layer (25 GB)        89.8% full (25.03 GB capacity)
  [OK]  BD-R DL     Dual   layer (50 GB)        44.9% full (50.05 GB capacity)
  [OK]  BD-R XL TL  Triple layer (100 GB)       22.4% full (100.10 GB capacity)
  [OK]  BD-R XL QL  Quad   layer (128 GB)       17.6% full (128.00 GB capacity)
  → Recommended media: BD-R SL

.ts / .m2t inputs are sized as their post-wrap (* 192/188) byte count. UDF filesystem overhead (~10 MB) and BACKUP/ mirror size (~tens of KB) are not counted; they're negligible compared to the stream data. If the total exceeds all listed media types, a warning suggests splitting across multiple discs.

Build progress display

At default verbosity, bdav build (and the build phase of bdav author) prints a per-clip progress line, useful because each clip takes seconds-to-minutes to process:

Building 11 clip(s) -> /work/disc1/BDAV
  [ 1/11] 00001  7784-1-20260414-2300-333.m2t (1521 MB)... 12.3s  →  BS11 #1 まさかの上京 (1448s, 4827 EP)
  [ 2/11] 00002  7784-2-20260421-2300-333.m2t (1518 MB)... 12.1s  →  BS11 #2 ヘッジホッグ閉店 (1445s, 4820 EP)
  ...
BDAV written: /work/disc1/BDAV

-q suppresses everything for use in scripts; -v adds debug lines under each clip.


Output layout

/work/disc1/BDAV/
├── STREAM/
│   ├── 00001.m2ts        # input placed (copy/link, or explicit move) and aligned to 6144B
│   └── 00002.m2ts
├── CLIPINF/
│   ├── 00001.clpi
│   └── 00002.clpi
├── PLAYLIST/
│   ├── 00001.rpls
│   └── 00002.rpls
├── info.bdav
└── BACKUP/
    ├── CLIPINF/...
    ├── PLAYLIST/...
    └── info.bdav

Documentation


Auxiliary scripts / tools

scripts/ts_to_m2ts_packetwrap.py

Wraps 188-byte TS into 192-byte M2TS (a safe transform — no re-multiplexing). bdav author will auto-wrap on the fly, so this is only needed if you want to pre-convert.

python3 scripts/ts_to_m2ts_packetwrap.py \
  --source-glob "/recordings/*.ts" --out-dir /work/m2ts

tools/bdav_dump.py

Field-by-field dumper for *.clpi / *.rpls / info.bdav. Pass two files plus --diff for byte-level comparison.

PYTHONPATH=src python3 tools/bdav_dump.py /work/disc1/BDAV/CLIPINF/00001.clpi

tools/compare_bdav_dirs.py

Diff two BDAV directories (byte/field counts for CLIPINF / PLAYLIST / info.bdav).

tools/gen_test_corpus.py

Generates a synthetic M2TS test corpus via ffmpeg (development use).


Troubleshooting

  • error: no inputs (use --input-dir / --input / --list) — No input specified.
  • Syobocal API is unresponsive — pass --no-api to skip; on failure the tool falls back to filename-derived data and flags review=true. Edit the plan JSON by hand, then bdav build.
  • output not empty: ... (use --overwrite) — Add --overwrite.
  • Generated BDAV not recognized by a real player — If the input .m2ts was re-multiplexed by tsMuxeR / ffmpeg, the pmt_pid / pcr_pid / stream_type may have changed. Pre-convert with scripts/ts_to_m2ts_packetwrap.py (188 → 192 packet wrapping) instead.

Acknowledgements

  • During development we referenced many software projects, including chotBDAV. Our sincere thanks.

License and third-party rights

  • This project was developed by Sorshi(宗子) of DCC-JPL Japan.
  • This project's source code is MIT-licensed (LICENSE).
  • It is an independent implementation of BD-RE Part 3 (BDAV) and bundles no third-party binaries or code; nor does it depend on any at runtime.
  • For the treatment of standards documents, trademarks, and third-party tools, see NOTICE.md.

About

bdav is a Linux command that exports MPEG2-TS files (.ts, .m2t, .m2ts) recorded with devices such as the PT3 into a BDAV file tree (CLIPINF/, PLAYLIST/, info.bdav, STREAM/) compatible with home Blu-ray recorders and players.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors