#!/bin/bash################################################ redfist.sh 0.1 # This little script extracts chapter times # from HandBrake-encoded movies and translates # them into a format readable by mkvmerge. ################################################ It accepts two command-line arguments, the # path to the HandBrake-encoded .mp4 to read,# and the path to a copy of MP4Box. ################################################ For this to work, you obviously have to use# chapter markers in HandBrake, and for this# process to be useful, it should be done with# HandBrake 0.8.5b2 or later, which has precise# chapter times, instead of following what the# DVD says.INPUTFILE="$1"MP4BOX_PATH="$2"############## SED STUFF ############## First, extract the chapter index to stdout with mp4box. Then, display only# the lines with the timecodes and chapters on them (starts with "<TextSample").# Cut away everything before the time, the double quotes that confuse sed, and# then the rest of the line until the end bracket (">") of the line. Strip# control characters like ^M, too.# Store what's left in the TIMECODE array for later use.TIMECODE=($($MP4BOX_PATH -ttxt 3 $INPUTFILE -std | grep '<TextSample ' | sed -e 's/TTXT.*)//g' -e 's/<TextSample sampleTime="//g' -e 's/"//g' -e 's/text=.*>//g' -e 's/[[:cntrl:]]//g'))# First, extract the chapter index to stdout with mp4box. Then, display only# the lines with the timecodes and chapters on them (starts with "<TextSample").# Cut away everything before the time, the double quotes that confuse sed, # everything before the chapter name (through "text="), the single quotes# which confuse sed, and the bracket (">") at the end of the line.# Store what's left in the TITLE array for later use. For now, this only works# when you use the default names ("Chapter XX") because of limitations in how# bash handles strings in arrays (it delimits on spaces and so I'm assuming# there will be two spots used in the array per title before the next Chapter).# Oh yeah, it'd also help if bash arrays were multidimensional.TITLE=($($MP4BOX_PATH -ttxt 3 $INPUTFILE -std | grep '<TextSample ' | sed -e 's/TTXT.*)//g' -e 's/<TextSample sampleTime="//g' -e 's/"//g' -e 's/.*text=//g' -e "s/'//g" -e 's/>//g'))############## LOOP PREP ############## For the timecode index and the loop.ITERATOR1=0# For the chapter title index.ITERATOR2=0# We want to iterate through based on the number of timecodes stored# in the TIMECODE array.CHAPTERNUM=$(echo ${#TIMECODE[*]})# And yet, we don't want the last chapter marker from HandBrake,# because it's just the last frame of the video. So decrement.CHAPTERNUM=$((CHAPTERNUM-1))# This xml header text only needs to be at the top, so# throw it in before the loop starts.echo -e "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"echo -e "<!DOCTYPE Chapters SYSTEM \"matroskachapters.dtd\">"echo -e "<Chapters>"echo -e "<EditionEntry>"######################################## LOOPING, WHERE THE REAL WORK'S DONE ######################################## Loop through all the chapters.while [ $ITERATOR1 -lt $CHAPTERNUM ]do echo -e "<ChapterAtom>" echo -e "<ChapterTimeStart> \c" echo -e ${TIMECODE[$ITERATOR1]} "\c" echo -e "</ChapterTimeStart>" echo -e "<ChapterDisplay>" # Timecode written, it's on to the title. echo -e "<ChapterString> \c" # Then, two words from the title array. echo -e ${TITLE[$ITERATOR2]} ${TITLE[$ITERATOR2+1]} "\c" echo -e "</ChapterString>" echo -e "<ChapterLanguage>eng</ChapterLanguage>" echo -e "</ChapterDisplay>" echo -e "</ChapterAtom>" # Iterate the timecodes and the loop by one. ITERATOR1=$((ITERATOR1+1)) # Because HandBrake uses two-word title names, # and each word is stored separately in the array, # iterate it by two to jump past both words used # this time through the loop. ITERATOR2=$((ITERATOR2+2))done############## POST LOOP ############## This is just to close out the xml divs.echo -e "</EditionEntry>"echo -e "</Chapters>"