Pick of the Week - Nov 10 [Show all picks]
Path Finder 5 - A feature-laden Finder replacement
Submit Hint Search The Forums LinksStatsPollsFAQHeadlinesRSS
12,000 hints and counting!

A Python script to back up DVDs to MP4 files Apps
This is a script that came from my desire to easily back up dvds that I don't have the time to watch now.

HandBrake is an awesome program, but it requires user intervention. If I want to use it on a headless Mac, I want to automate it. This script is a wrapper around HandBrakeCLI, the command-line version of Handbrake.. First it locates the DVD, by scanning /Volumes. Next, it scans the titles for the longest feature on the disc (the movie). Finally, it rips the DVD to an mp4 file. I have hard-coded all the options (2048 kbps, 192kbps AAC, pixel aspect ratio). If these settings don't work for you, look in the code and change them.

To use:
./rip.py [destination dir]
Dependencies:
  • python 2.4+ (Mac OS X ships with 2.3): go to python.org
  • HandBrakeCLI (place in /usr/local/bin, and make sure your path includes this directory, or change the HANDBRAKE variable in the rip.py source file): go to HandBrake
  • chmod +x rip.py
    (to make the script executable)
I think that's it. This method won't appeal to everyone, but it's simple to run, once you get it set up. Here's the script:



#!/usr/bin/python

import os
import sys
import re
from subprocess import Popen
import time

HANDBRAKE = '/usr/local/bin/HandBrakeCLI'

def usage():
    print 'rip.py [dvd_name output_dir]'

def get_dvd_file():
    vols = os.listdir('/Volumes')
    candidates = list()
    for vol in vols:
        if vol.startswith('.'):
            continue
        candidates.append(vol)
    if len(candidates) > 0:
        for vol in candidates:
            dirs = os.listdir('/Volumes/' + vol)
            if 'VIDEO_TS' in dirs:
                return vol
    else:
        sys.exit()

def prettify_filename(filename):
    """
    LITTLE_MISS_SUNSHINE => Little Miss Sunshine
    """
    pretty = ''
    l = None
    for i in xrange(len(filename)):
        c = filename[i]
        if not l or l == '_':
            pretty += c.upper()
        else:
            pretty += c.lower()
        l = c
    return pretty

start = time.time()
dvd_file = None
out_dir = None

#really ugly comand line parsing, should you opt
if len(sys.argv) > 3:
    print sys.argv
    usage()
    sys.exit()
if len(sys.argv) == 3:
    dvd_file, out_dir = sys.argv[1:]
elif len(sys.argv) == 2:
    dvd_file = get_dvd_file()
    out_dir = sys.argv[1]
else:
    dvd_file = get_dvd_file()
    out_dir = '.'
if out_dir.endswith('/'):
    out_dir = out_dir[:-1]

#input and output options for handbrake
infile = '/Volumes/%s' % (dvd_file)
dvd_file = prettify_filename(dvd_file)
outfile = '%s/%s.m4v' % (out_dir, dvd_file)

#lets verify the paths
if not os.path.exists(infile) or not os.path.exists(out_dir):
    print 'bad paths: input file (%s) output directory (%s)' % (infile, out_dir)
    sys.exit()

#scan the dvd for the titles
tmp = os.tmpfile()
po = Popen((HANDBRAKE, '-i%s' % (infile), '-t0'), stderr=tmp) 
while po.poll() == None:
    time.sleep(1)
    sys.stdout.write('.')
    sys.stdout.flush()
tmp.seek(0)
sys.stdout.write('n')

#read the output from the scan to get all the titles and their length
title = re.compile('title (d+):')
duration = re.compile('duration: (d+):(d+):(d+)')
chapters = list()
t = d = None
for line in tmp.readlines():
    tm = title.search(line)
    dm = duration.search(line)
    if tm != None:
        t = tm.groups()[0]
    elif dm != None:
        d = dm.groups()
        d = [ int(x) for x in d ]
        h, m, s = d
        secs = h * 3600 + m * 60 + s
        chapters.append((t, secs))
        t = d = None

#determine the longest title
max_secs = title = 0
for chapter in chapters:
    if chapter[1] > max_secs:
        title = chapter[0]
        max_secs = chapter[1]

print 'ripping: chapter %s (%ds)' % (title, max_secs)

#start the ripping process, redirect stderr to tmp
tmp = os.tmpfile()
po = Popen((HANDBRAKE, '-i%s' % (infile), '-t%s' % (title), '-o%s' % (outfile), 
            '-effmpeg', '-m', '-b2048', '-p',         #video options
            '-B256', '-R48', '-66ch') , stderr=tmp)   #audio options
while po.poll() == None:
    time.sleep(60)
    sys.stdout.write('.')
    sys.stdout.flush()
sys.stdout.write('n')

#get total time
secs = time.time() - start
hrs = int(secs) / 3600
min = int(secs) % 3600 / 60
sec = int(secs) % 60

print 'you totally ripped! (%d:%d:%d total time)' % (hrs, min, sec)

# notify via growl
os.popen('growlnotify -m "Completed encoding %s" -p 2' % (dvd_file))



kirkmc adds: I haven't tested this.
    •    
  • Currently 0.00 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (0 votes cast)
 
[15,624 views]  

A Python script to back up DVDs to MP4 files | 15 comments | Create New Account
Click here to return to the 'A Python script to back up DVDs to MP4 files' hint
The following comments are owned by whomever posted them. This site is not responsible for what they say.
A Python script to back up DVDs to MP4 files
Authored by: enoch111 on Wed, May 30 2007 at 10:39AM PDT
Does this run automatically when the DVD is inserted?

Also, would it be possible to have it eject the DVD once the rip is finished? I have no idea about programming anything, so if that's a stupid question as to the capabilities of python, I apologize. :)

jason

[ Reply to This | # ]
A Python script to back up DVDs to MP4 files
Authored by: berndtj on Wed, May 30 2007 at 7:00PM PDT
There is a way to eject afterward using diskutil, but I'm not sure what the command is.

I have the script hooked up to sofa control to run, but you could install a folder action to have it run everytime you insert a DVD. If you figure it out, add it as a comment.

[ Reply to This | # ]
Script Problem
Authored by: amaloney on Wed, May 30 2007 at 11:03AM PDT
When I tried to run the script I got

Traceback (most recent call last):
File "./rip.py", line 6, in ?
from subprocess import Popen
ImportError: No module named subprocess

I am a newbie with scripting.

I am running Mac OS X 10.4.9
I placed HandBrakeCLI in /usr/local/bin

I ran the OS X installer for Python 2.5.1.
It created /Applications/MacPython 2.5 which contains Python Launcher.app

I copied the script to TextWrangler 2.2.1 and saved it as rip.py in a directory /Applications/A_Rip_Stoff

In Terminal I ran chmod +x rip.py

I then ran ./rip.py and got the above msg.

What am I doing wrong?

Al Maloney

[ Reply to This | # ]
Script Problem
Authored by: simonpie on Wed, May 30 2007 at 11:32AM PDT
Well you need to install the subprocess module, it is not installed by default.



[ Reply to This | # ]
Script Problem
Authored by: amaloney on Wed, May 30 2007 at 12:12PM PDT
Install subprocess module ???

I guess I am out of my league here.
I'll put myself on hold for a while.
I'm afraid I might screw up things in my ignorance.

Thanks anyway
Al

[ Reply to This | # ]
Script Problem
Authored by: simonpie on Wed, May 30 2007 at 6:46PM PDT
Script Problem
Authored by: berndtj on Wed, May 30 2007 at 6:54PM PDT
The issue is that the script is still running python 2.3. The subprocess module is part of python 2.4+, hence the dependence.

After you install python 2.4 or 2.5, you will need to change the link to python in /usr/bin

from the terminal type "ls -la | grep python", you will see what I mean.

To fix this just do the following:

sudo mv python python.old

sudo ln -s /Library/Frameworks/Python.framework/Versions/Current/bin/python python

sudo rm python.old

Once you do this, the script should work. If you don't want to muck with the links in /usr/bin, you can replace the first line of the script from:
#!/usr/bin/python
to:
#!/Library/Frameworks/Python.framework/Versions/Current/bin/python

Hope that helps.

[ Reply to This | # ]
Script Problem
Authored by: robgmann on Wed, May 30 2007 at 10:13PM PDT
I was able to get the script to start by making sure #!/usr/bin/python was on the first line of the script. (When I pasted it from the hint, it wasn't the first line).

Then it reads the DVD for a minute and outputs:
........................................nripping: chapter 0 (0s)
.nyou totally ripped! (0:1:40 total time)

No output file is created, i.e. nothing appears to have happened.
Is there a simple way to see diagnostics of this script?
So far, it seems no one has had success making it run.




[ Reply to This | # ]
Script Problem
Authored by: berndtj on Wed, May 30 2007 at 10:30PM PDT
Hmmm.

Well you can run HandBrakeCLI stand alone, and see if it works. From the output you show, it appears that the scanning did not return anything.

Try:

HandBrakeCLI /Volumes/your_dvd -t 0

You should see a bunch of output. The script parses this output to return the longest title.

[ Reply to This | # ]
Script Problem
Authored by: robgmann on Fri, Jun 1 2007 at 8:13AM PDT
Still not getting it... here is my command and output:
HandBrakeCLI -i /Volumes/WW_S3_D4/ -t0

HandBrake 0.8.5b1 (2007042001) - http://handbrake.m0k.org/
1 CPU detected
Opening /Volumes/WW_S3_D4/...
Scanning title 1 of 13...
Scanning title 2 of 13...
Scanning title 3 of 13...
Scanning title 7 of 13...
Scanning title 8 of 13...
Scanning title 9 of 13...
Scanning title 10 of 13...
Scanning title 13 of 13...
No title found.
HandBrake has exited.

And when I run the script, I still just get
./scripts/rip.py /Volumes/SHARED/shared/Ripped/
.........nripping: chapter 0 (0s)
.nyou totally ripped! (0:1:9 total time)
sh: line 1: growlnotify: command not found



[ Reply to This | # ]
Script Problem
Authored by: berndtj on Fri, Jun 1 2007 at 8:18AM PDT
"No title found" sounds like HandBrake is having trouble reading the DVD properly. Try it with a different DVD.

[ Reply to This | # ]
subprocess module
Authored by: tatilsever on Wed, May 30 2007 at 3:53PM PDT
I gotta say "subprocess module" sounds like it came straight out of StarTrek. :)

[ Reply to This | # ]
A Python script to back up DVDs to MP4 files
Authored by: bhammond on Tue, Jun 5 2007 at 7:40AM PDT
just add this to the end of the file:

os.popen("diskutil eject '%s'" % (infile))


[ Reply to This | # ]
A Python script to back up DVDs to MP4 files
Authored by: bhammond on Tue, Jun 5 2007 at 7:44AM PDT
oops, that was supposed to be in response to the user that wanted the disk ejected after ripping successfully finished.

[ Reply to This | # ]
A Python script to back up DVDs to MP4 files
Authored by: trpeterson1984 on Sat, Jun 30 2007 at 9:22PM PDT
I'm having a problem with the script. After I run it, I get:
Traceback (most recent call last):
  File "/library/scripts/rip.py", line 66, in <module>
    dvd_file = prettify_filename(dvd_file)
  File "/library/scripts/rip.py", line 35, in prettify_filename
    for i in xrange(len(filename)):
TypeError: object of type 'NoneType' has no len()
I don't know Python so I don't know what len() means. Any help in the right direction would be appreciated.

[ Reply to This | # ]