Last active
May 14, 2020 12:56
-
-
Save mjtorn/00e5dbb1435c7dad7571a061b63dbb3d to your computer and use it in GitHub Desktop.
Python script to rip your DVDs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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