SRS Project
The Series Ripper Script Project aims to automate the ripping of DVDs with an emphasis on accomodating multiple DVDs from a series. SRS is actually a handful of scripts each dedicated to a particular aspect of the process.
FUN – SRS function script, provides common functions
DVS – dump vob streams by disc, title, and chapter.
BEF – batch encode files
JAF – (optionally) join avi files
BRF – batch rename files
FUN
GOAL
Clean up code and get fancy with stuff that would otherwise make the code a PITA to wade through.
HOW
Relegate commonly-used groups of lines into functions. Provide C-like returns (strings) with echos, printfs, and other commands whose output goes through stdin/out.
CONSIDERATIONS
You have to be careful in BASH. The echo command will strip out existing newlines and insert a newline at the end without the -n option. Printf is more desirable.
I didn’t want people bitching about typos for invalid language codes, so I went and got all the codes from the official ISO 639-1 standard. There’s 184 of them, if you’re curious. It won’t help the user if they mis-type another valid language code (example: ka when the user meant ja), but mind-reading isn’t a job here.
CODE
X264ENCOPTS=bitrate=2500:frameref=5:bframes=5:b_pyramid:weight_b:direct_pred=auto:partitions=all:8x8dct:me=umh:subq=7:mixed_refs:trellis=2:threads=0
VALCODES="aa ab ae af ak am an ar as av ay az ba be bg bh bi bm bn bo br bs ca ce ch co cr cs cu cv cy da de dv dz ee el en eo es et eu fa ff fi fj fo fr fy ga gd gl gn gu gv ha he hi ho hr ht hu hy hz ia id ie ig ii ik io is it iu ja jv ka kg ki kj kk kl km kn ko kr ks ku kv kw ky la lb lg li ln lo lt lu lv mg mh mi mk ml mn mr ms mt my na nb nd ne ng nl nn no nr nv ny oc oj om or os pa pi pl ps pt qu rm rn ro ru rw sa sc sd se sg si sk sl sm sn so sq sr ss st su sv sw ta te tg th ti tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa wo xh yi yo za zh zu"
#==============================================================================
#=========================== FUNCTION DECLARATIONS ============================
#==============================================================================
function convert_stamphms_stampsec {
HOUR="`echo $1 | cut -d':' -f1`"
MINS="`echo $1 | cut -d':' -f2`"
SECS="`echo $1 | cut -d':' -f3`"
expr $HOUR \* 3600 + $MINS \* 60 + $SECS
}
function convert_stampsec_stamphms {
HOUR="`expr $1 / 3600`"
MINS="`expr $1 % 3600 / 60`"
SECS="`expr $1 % 3600 % 60`"
printf "%02d:%02d:%02d" $HOUR $MINS $SECS
}
function limited_key_verified_string {
# $1 = prompt
# $2 = number of keys to accept
# $3 = valid input
OKINPUT=0
while [ $OKINPUT -eq 0 ]; do
read -n $2 -p "$1" USRINPUT
for VALINPUT in $3 ; do
[ "$USRINPUT" == "$VALINPUT" ] && OKINPUT=1
done
[ $OKINPUT -eq 0 ] && printf "\a\r%79s\r" " " 1>&2
done
printf "$USRINPUT"
}
function limited_key_verified_number {
# $1 = prompt
# $2 = number of keys to accept
# $3 = input to be greater than or equal to
# $4 = input to be less than or equal to
OKINPUT=0
while [ $OKINPUT -eq 0 ]; do
read -n $2 -p "$1" USRINPUT
[ "$USRINPUT" -ge "$3" -a "$USRINPUT" -le "$4" ] && OKINPUT=1 || printf "\a\r%79s\r" " " 1>&2
done
printf "$USRINPUT"
}
function onelineinput {
OKINPUT=0
while [ $OKINPUT -eq 0 ]; do
read -e -p "$1" USERINPUT
for GOODKEYS in $2; do
[ "$GOODKEY" == "$USERINPUT" ] && GOODINPUT=1
done
[ $OKINPUT -eq 0 ] && printf "\a\r%79s\r" " " 1>&2
done
printf "$ONELINEINPUT"
}
function onenonblank {
ONENONBLANK=""
while [ "$ONENONBLANK" == "" ]; do
read -e -p "$1" ONENONBLANK
[ "$ONENONBLANK" == "" ] && printf "\a\r%79s\r" " " 1>&2
done
printf "$ONENONBLANK"
}
function pause {
read -n 1 -p "$1"
echo
}
function refresh_steps {
STEPPROMPT="STEP "
for (( LCV=1; $LCV<=4; LCV++ )); do
[ $LCV == $1 ] && STEPPROMPT="$STEPPROMPT[$LCV]" || STEPPROMPT="$STEPPROMPT $LCV "
done
printf "\e[7m%-50s%30s\e[m\n" "$STEPPROMPT " "$2"
echo
}
function program_header {
clear
printf "\e[7m%80s\r%*s\e[m\n" " " `expr \( 80 + ${#1} \) / 2` "$1"
}
DVS
GOAL
Ease the series-ripping process by dumping streams by discs, titles, chapters, and angles.
HOW
DVS provides an interface that will cycle through a user-specified number of discs. For each disc, DVS will provide an informative list of titles available, including run time, chapter count, angles available, audio track info, and subtitle info. DVS allows the user to preview titles before a selection is made. Once title selections are made, SRS will then provide an informative list of chapters and ask for a list of chapters to dump from. When DVS dumps the VOB stream, it will also write an info file for the angles, audio tracks, and subtitles it found.
CONSIDERATIONS
Chapter markers in VOB streams must appear on I-frames, so there's no need to worry about garbled pictures.
Using mencoder to dump video and audio into an avi (-ovc copy -oac copy) was considered to save disk space, but problems arose on VOB streams from poorly-mastered DVDs whose framerate switches constantly and non-sensically between 24fps and 30fps. (Vandread series, orginal Geneon release. This is probably the main reason Funimation is doing a re-release.) While the copy can be made 24fps or 30fps, the copy function sticks to one frame rate and either drops or duplicates frames if the input frame rate and output frame rate do not match. Going from 24fps to 30fps can leave the resulting output stream with a mix of hard-telecined and hard-duped content. Going from 30fps to 24fps leaves out frames needed to re-assemble clean 24fps progressive footage from telecined content.
The info file route was chosen to make both the batching and coding processes easier. On the coding side, the process can be more easily broken into chunks without having the chunks rely on one another. On the batching side, the user isn't constrained to use the utilities in one fell swoop. This was mostly a consideration for Red Vs. Blue Seasons 1 through 5. The series is 30fps pure interlaced and letter-boxed in Seasons 1 - 4. The crop settings are mostly the same in Seasons 1 - 3, except for a few episodes here and there. Season 4's crop settings are all over the place as the team switched between Halo 1 and Halo 2. Season 5 is encoded professionally with anamorphed 24fps progressive footage.
CODE
#!/bin/bash
source ./fun.sh
#==============================================================================
#================================ MAIN PROGRAM ================================
#==============================================================================
program_header "DVS - DUMP VOB SPLITS"
refresh_steps 1 "PROJECT INFO"
DVDDRIVE=`onenonblank "DVD device (ex: /media/cdrom): "`
PROJNAME=`onenonblank "Name of this project: "`
PROJPATH=`onenonblank "Place to put the folder for this project: "`
PROJDISC=`limited_key_verified_string "How many DVDs in this project (1-9): " 1 "1 2 3 4 5 6 7 8 9"`
# This could be made better by stepping through the path and making sure each
# folder in the path actually exists.
mkdir "$PROJPATH"
mkdir "$PROJPATH/$PROJNAME"
for (( CURRDISC=1; $CURRDISC>=$PROJDISC; $CURRDISC++ )); do
program_header "DVS - DUMP VOB SPLITS"
refresh_steps 2 "TITLE SELECTION"
pause "Insert DVD $CURRDISC and press any key to continue."
echo "Grabbing title information from this DVD..."
MPOUTPUT=`mplayer -dvd-device $DVDDRIVE dvd://1 -identify -frames 0 2> /dev/null | grep -E "^ID_DVD_TITLE_(.|..)"`
TITLELEN=( 0 `printf "$MPOUTPUT" | grep "_LENGTH" | cut -d'=' -f2 | cut -d'.' -f1 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
TITLECHP=( 0 `printf "$MPOUTPUT" | grep "_CHAPTERS" | cut -d'=' -f2 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
TITLEANG=( 0 `printf "$MPOUTPUT" | grep "_ANGLES" | cut -d'=' -f2 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
for (( CURTITLE=1; $CURTITLE<${#TITLELEN[@]}; CURTITLE++ )); do
MPOUTPUT=`mplayer -dvd-device $DVDDRIVE dvd://$CURTITLE -identify -frames 0 2> /dev/null | grep -E "^(audio|subtitle)"`
AUDIOFMT=( xxx `printf "$MPOUTPUT" | grep -E "^audio stream:" | cut -d: -f3 | cut -d' ' -f2 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
AUDIOCHN=( 0.0 `printf "$MPOUTPUT" | grep -E "^audio stream:" | cut -d: -f3 | cut -d' ' -f3 | cut -c2-4 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
AUDIOLNG=( xx `printf "$MPOUTPUT" | grep -E "^audio stream:" | cut -d: -f4 | cut -c2-3 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
AUDIOIDS=( 999 `printf "$MPOUTPUT" | grep -E "^audio stream:" | cut -d: -f5 | cut -c2-4 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
SBTTLIDS=( 99 `printf "$MPOUTPUT" | grep -E "^subtitle" | cut -d" " -f5 | printf "%02d" | sed -e :a -e '$!N; s/\n/ /g; ta'` )
SBTTLLNG=( xx `printf "$MPOUTPUT" | grep -E "^subtitle" | cut -d" " -f7 | sed -e :a -e '$!N; s/\n/ /g; ta'` )
VALAUDID[$CURTITLE]="${AUDIOIDS[@]}"
VALSUBID[$CURTITLE]="${SBTTLIDS[@]}"
for (( CURAUDIO=1; $CURAUDIO<${#AUDIOIDS[@]}; CURAUDIO++ )); do
AUDIOSTR[$CURTITLE]="${AUDIOSTR[$CURTITLE]} ${AUDIOIDS[$CURAUDIO]}:${AUDIOLNG[$CURAUDIO]}-${AUDIOFMT[$CURAUDIO]}-${AUDIOCHN[$CURAUDIO]}"
done
for (( CURSBTTL=1; $CURSBTTL<${#SBTTLIDS[@]}; CURSBTTL++ )) do
[ "${SBTTLLNG[$CURSBTTL]}" == "unknown" ] && SBTTLLNG[$CURSBTTL]='??'
SBTTLSTR[$CURTITLE]="${SBTTLSTR[$CURTITLE]} ${SBTTLIDS[$CURSBTTL]}:${SBTTLLNG[$CURSBTTL]}"
done
AUDIOSTR[$CURTITLE]=`printf "${AUDIOSTR[$CURTITLE]}" | cut -c1 --complement`
SBTTLSTR[$CURTITLE]=`printf "${SBTTLSTR[$CURTITLE]}" | cut -c1 --complement`
done
while [ "$VIEWSLCT" != "s" ]; do
program_header "DVS - DUMP VOB SPLITS"
refresh_steps 2 "TITLE SELECTION"
echo "TI RUN-TIME CH AN ----------------AUDIO TRACKS---------------- ----SUBTITLES----"
for (( CURTITLE=1; $CURTITLE<${#TITLELEN[@]}; CURTITLE++ )); do
printf "%02s %s %02s %02s %44s %17s\n" $CURTITLE "`convert_stampsec_stamphms ${TITLELEN[$CURTITLE]}`" ${TITLECHP[$CURTITLE]} ${TITLEANG[$CURTITLE]} "${AUDIOSTR[$CURTITLE]}" "${SBTTLSTR[$CURTITLE]}"
done
echo
VIEWSLCT=`limited_key_verified_string "Do you want to (v)iew or (s)elect titles? " 1 "v s"`
if [ $VIEWSLCT == v ]; then
MAXTITLE=`expr ${#TITLELEN[@]} - 1`
echo; VIEWTITL=`limited_key_verified_number "Title (nn)? " 2 1 $MAXTITLE`
[ "$VIEWTITL" == "08" ] && VIEWTITL=8
[ "$VIEWTITL" == "09" ] && VIEWTITL=9
VIEWANGL=`limited_key_verified_number " Angle (n)? " 1 1 ${TITLEANG[$VIEWTITL]}`
VIEWAUD=`limited_key_verified_string " Audio (nnn)? " 3 "${VALAUDID[$VIEWTITL]}"`
VIEWSUB=`limited_key_verified_string " Subtitle (nn)? " 2 "${VALSUBID[$VIEWTITL]} 99"`
[ "$VIEWSUB" == "08" ] && VIEWSUB=8
[ "$VIEWSUB" == "09" ] && VIEWSUB=9
echo; echo "Playing selection..."
mplayer -dvd-device $DVDDRIVE dvd://$VIEWTITL -dvdangle $VIEWANGL -aid $VIEWAUD -sid $VIEWSUB -msglevel all=-1 &> /dev/null
fi
done
echo
echo "You can specify multiple titles in a space-separated list (ex: 1 2 3)"
read -e -p "Which titles do you want to rip? " CHOSTITL
for CURRTITL in $CHOSTITL; do
program_header "DVS - DUMP VOB SPLITS"
refresh_steps 3 "CHAPTER SELECTION"
TOTLCHAP="`mplayer -dvd-device $DVDDRIVE dvd://$CURRTITL -identify -frames 0 2> /dev/null | grep 'chapters in this DVD title.' | cut -d' ' -f3`"
CHPLINES=`expr $TOTLCHAP / 5 + 1`
CHPLSTHMS="`mplayer -dvd-device $DVDDRIVE dvd://$CURRTITL -identify -frames 0 2> /dev/null | grep '^CHAPTERS:' | cut -d' ' -f2`"
for (( CURRCHAP=1; $CURRCHAP<=$TOTLCHAP; CURRCHAP++ )); do
ONECHPHMS="`echo $CHPLSTHMS | cut -d',' -f$CURRCHAP`"
ONECHPSEC="`convert_stamphms_stampsec $ONECHPHMS`"
CHPLSTSEC="${CHPLSTSEC}${ONECHPSEC},"
done
CHPLSTSEC="${CHPLSTSEC}${TITLELEN[$CURRTITL]}"
echo "CH -LENGTH- || CH -LENGTH- || CH -LENGTH- || CH -LENGTH- || -CH -LENGTH-"
for (( CHP_YPOS=1; $CHP_YPOS<=$CHPLINES; CHP_YPOS++ )); do
for (( CHP_XPOS=0; $CHP_XPOS<5; CHP_XPOS++ )); do
CURRCHAP=`expr $CHP_XPOS \* $CHPLINES + $CHP_YPOS`
if [ $CURRCHAP -le $TOTLCHAP ]; then
NEXTCHAP="`expr $CURRCHAP + 1`"
BEGSTAMP="`echo $CHPLSTSEC | cut -d',' -f$CURRCHAP`"
ENDSTAMP="`echo $CHPLSTSEC | cut -d',' -f$NEXTCHAP`"
CHAPLEN="`expr $ENDSTAMP - $BEGSTAMP`"
printf "%2s %8s" $CURRCHAP `convert_stampsec_stamphms $CHAPLEN`
[ $CHP_XPOS -ne 4 ] && printf " || "
fi
done
printf "\n"
done
echo
STEPCHAPS="`limited_key_verified_string "Would you like to step through the chapters to see what you need (y/n)? " "1" "y n"`"
echo
if [ $STEPCHAPS == y ]; then
echo "MPlayer will spawn in its own window for each chapter."
echo "Press Q to stop the video and go on to the next one."
pause "Press any key to continue..."
for (( CURSTEPCHAP=1; $CURSTEPCHAP<=$TOTLCHAP; CURSTEPCHAP++ )); do
echo "Playing chapter $CURSTEPCHAP"
mplayer -dvd-device $DVDDRIVE dvd://$CURRTITL -chapter $CURSTEPCHAP-$CURSTEPCHAP -msglevel all=0 &> /dev/null
done
fi
echo "You must specify a range of chapters, even if it is only one chapter. (ex: 1-1)"
echo "You can specify a list of ranges in a space-separated list. (ex: 1-1 2-3 4-4)"
read -e -p "Which chapters do you want to rip for title $CURRTITL? " CHOSCHAP
program_header "DVS - DUMP VOB SPLITS"
refresh_steps 4 "RIP SELECTIONS TO HARD DRIVE"
for CURRCHAP in $CHOSCHAP; do
BEGCHAP=`echo $CURRCHAP | cut -d"-" -f1`
ENDCHAP=`echo $CURRCHAP | cut -d"-" -f2`
FILEPATH="$PROJPATH/$PROJNAME/D`printf "%02d" $CURRDISC`T`printf "%02d" $CURRTITL`C`printf "%02d" $BEGCHAP`-`printf "%02d" $ENDCHAP`"
echo "DVD TITLE `printf "%02d" $CURRTITL` CHAPTERS `printf "%02d" $BEGCHAP` - `printf "%02d" $ENDCHAP`: WRITING INFO FILE"
echo "ANGS=${TITLEANG[$CURRTITL]}" > $FILEPATH.info
echo "AUDS=${AUDIOSTR[$CURRTITL]}" >> $FILEPATH.info
echo "SUBS=${SBTTLSTR[$CURRTITL]}" >> $FILEPATH.info
echo "DVD TITLE `printf "%02d" $CURRTITL` CHAPTERS `printf "%02d" $BEGCHAP` - `printf "%02d" $ENDCHAP`: DUMPING VOB STREAM"
mplayer -dvd-device $DVDDRIVE dvd://$CURRTITL -chapter $CURRCHAP -dumpstream -dumpfile "$FILEPATH.vob" -msglevel all=0 &> /dev/null
done
done
done
echo "All titles and chapters of all discs have been ripped to the hard drive."
pause "Press any key to continue."
BEF
GOAL
Provide an informative and intuitive batch interface for angle selection, audio selection, subtitle ripping, crop settings, and common video filters. Allow the user to get on with their daily lives while BEF encodes over the next two days.
HOW
Not there yet.
CONSIDERATIONS
The console sucks for this job.
JAF
GOAL
Provide an interface to join the resulting AVI files.
HOW
Not there yet
CONSIDERATIONS
Episodic content sometimes use hooks — a brief period of content that appears before the opening credits or after the ending credits. While the content is usually chaptered accordingly, this will make for a pretty strange file division if you leave out the credits. This script will help you bring the pieces back together.
BRF
GOAL
Provide an interface to rename files in a directory.
HOW
Not there yet.
CONSIDERATIONS
To keep things short and simple, DVS uses really terse file names. This helps users make the file names mean something.
No Comments Yet »
RSS feed for comments on this post. TrackBack URI
Leave a comment
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.

