Skip to content

Instantly share code, notes, and snippets.

@mjtorn
Last active May 14, 2020 12:56
Show Gist options
  • Save mjtorn/00e5dbb1435c7dad7571a061b63dbb3d to your computer and use it in GitHub Desktop.
Save mjtorn/00e5dbb1435c7dad7571a061b63dbb3d to your computer and use it in GitHub Desktop.
Python script to rip your DVDs
#!/usr/bin/env python3
"""
Mapfile format:
## More than meets the eye
@ -a2 -q19
1 1x09 - Fire on the Mountain
^ ^
| +- Output file name (sans .mp4)
+---- Title number
Argument lines starting with `@` contain extra
arguments passed to HandBrakeCLI. Each one
affects all the output lines until a new
such line is seen.
Actual comments starting with `#` and empty
lines are ignored.
Greetz and thankz to Con Kolivas for
the HandBrake options!
"""
import multiprocessing
import os
import subprocess
import sys
DVDW_DEVICE = os.environ.get('DVDW_DEVICE', '/dev/sr0')
DVDW_CPUCOUNT = os.environ.get('DVDW_CPUCOUNT', multiprocessing.cpu_count())
DVDW_MODE = os.environ.get('DVDW_MODE', 'pal_4_3')
OPT_720P = 'nombtree:keyint=1000:scenecut=10:ref=9:ip_factor=1:pb_factor=1:' \
'direct_pred=auto:weight_b:analyse=all:me=umh:mixed_refs:' \
'trellis=0:nofast_pskip:level_idc=41:threads={}:' \
'aq_mode=0:nodeterministic:psy-rd=0|0:b-adapt=2:level=4.1:' \
'direct=auto:fast-pskip=0:ipratio=1.00:pbratio=1.00:aq-mode=0' \
':mbtree=0:cabac=0:no-dct-decimate=1:aq-strength=0:bframes=16'.format(DVDW_CPUCOUNT)
BASE_MODES = {
'pal_4_3': {
'width': 720,
'height': 576,
'fps': 25,
},
'ntsc_4_3': {
'width': 720,
'height': 480,
'fps': 30,
}
}
BASE_ARGS = '-i {DVDW_DEVICE} -e x264 -x {OPT} ' \
'-w {width} -l {height} -r {fps} ' \
'--no-loose-crop --crop 0:0:0:0 ' \
'--comb-detect ' \
'-t {tracknum} ' \
'{extra_args}'
def find_handbrake():
"""Do a simple search in $PATH for HandBrakeCLI
"""
for path in os.environ['PATH'].split(':'):
candidate = os.path.join(path, 'HandBrakeCLI')
if os.path.exists(candidate):
return candidate
def get_arguments(mapfile, mode):
"""Parse `mapfile` and combine its arguments
with the ones in `mode`.
"""
fmt = mode.copy()
fmt['DVDW_DEVICE'] = DVDW_DEVICE
fmt['extra_args'] = ''
args = []
for line in open(mapfile, 'r'):
split_line = line.strip().split()
if not split_line:
continue
if line.startswith('#'):
continue
elif split_line[0] == '@':
fmt['extra_args'] = ' '.join(split_line[1:])
continue
fmt['tracknum'] = split_line[0]
trackname = ' '.join(split_line[1:])
args_list = BASE_ARGS.format(**fmt)
args.append((args_list, trackname))
return args
def main(mapfile):
"""Parse and rip
"""
hb = find_handbrake()
if not hb:
print('HandBrakeCLI not found')
return 1
mode = BASE_MODES.get(DVDW_MODE)
if mode['width'] <= 720:
mode['OPT'] = OPT_720P
else:
raise NotImplementedError('Not here yet')
args = get_arguments(mapfile, mode)
for arg, trackname in args:
cmd = '{} {}'.format(hb, arg)
cmd = cmd.split()
cmd.extend(('-o', '{}.mp4'.format(trackname)))
ret = subprocess.run(cmd)
return ret.returncode
if __name__ == '__main__':
if len(sys.argv) == 1:
print('USAGE: {} MAPFILE'.format(sys.argv[0]))
sys.exit(1)
sys.exit(main(sys.argv[1]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment