Merge branch 'master' of git.distorted.org.uk:~mdw/publish/public-git/dvdrip
[dvdrip] / dvdrip
diff --git a/dvdrip b/dvdrip
index 1226c41..9634fe0 100755 (executable)
--- a/dvdrip
+++ b/dvdrip
@@ -4,38 +4,33 @@ prog=${0##*/}
 dev=${DVDRIP_DEVICE-/dev/dvd}
 tmp=${DVDRIP_TMPDIR-${HOME?}/tmp/dvdrip}
 archive=${DVDRIP_ARCHIVE-jem.distorted.org.uk:/mnt/dvd/archive}
-here=$(realpath "$0"); here=${here%/*}
-: ${DVD_SECTOR_COPY=$here/dvd-sector-copy.$(uname -m)}
-: ${DVDRIP_UPLOAD=$here/dvdrip-upload}
-backup=nil eject=nil force=nil verbose=nil bogus=nil; unset dir sub n label
+: ${DVD_SECTOR_COPY=dvd-sector-copy}
+: ${DVD_ID=dvd-id}
+: ${DVDRIP_UPLOAD=dvdrip-upload}
+backup=nil ding=nil eject=nil force=nil retry=nil verbose=nil bogus=nil
+unset params
 usage () {
   cat <<EOF
-usage: $prog [-befv] [-D DEV] [-a ARCH] [-d DIR]
-       [-l LABEL] [-n N] [-s SUB] [-t TMP] TITLE
+usage: $prog [-defrv] [-D DEV] [-a ARCH] [-t TMP] TITLE
 EOF
 }
-while getopts "hD:a:bd:efl:n:s:t:v" opt; do
+while getopts "hB:D:a:defrt:v" opt; do
   case $opt in
     h) usage; exit 0 ;;
+    B) params=${params+$params,}$OPTARG ;;
     D) dev=$OPTARG ;;
     a) archive=$OPTARG ;;
-    b) backup=t ;;
-    d) dir=$OPTARG ;;
+    d) ding=t ;;
     e) eject=t ;;
     f) force=t ;;
-    l) label=$OPTARG ;;
-    n) n=$OPTARG ;;
-    s) sub=$OPTARG ;;
+    r) retry=t ;;
     t) tmp=$OPTARG ;;
     v) verbose=t ;;
     *) bogus=t ;;
   esac
 done
 shift $(( $OPTIND - 1 ))
-case $# in
-  1) title=$1 ;;
-  *) bogus=t ;;
-esac
+case $# in 1) title=$1 ;; *) bogus=t ;; esac
 case $bogus in t) usage >&2; exit 2 ;; esac
 case $verbose in t) set -x ;; esac
 case $archive in
@@ -73,84 +68,118 @@ archdo () {
 }
 archrun () { archdo run "$@"; }
 
-case ${dir+t},${n+t} in
-  t,t | ,)
-    n=$(printf "%02d" "$n")
-    ;;
-  *)
-    echo >&2 "$prog: must specify both directory and disc number, or neither"
-    exit 2
-    ;;
+tag=${title//\//_}
+
+archdo run_setrc test -f "$archpath/$title.iso"
+case $rc,$force in
+  0,nil) fail "output file already exists" ;;
+  0,t) warn "output file already exists; will overwrite" ;;
 esac
 
-hack_label () {
-  tr "[:lower:]" "[:upper:]" |
-    tr -Cs "[:alnum:]_\n" "[-*]" |
-    sed 's/^-//; s/-$//'
+mkdir -p "$tmp/$tag"
+
+discid=$("$DVD_ID" -I "$dev")
+if [ -f "$tmp/$tag/discid" ]; then
+  read oldid <"$tmp/$tag/discid"
+  case $force,$oldid in
+    t,"$discid" | nil,"$discid")
+      ;;
+    nil,*)
+      fail "discid mismatch: expected \`$oldid' but drive has \`$discid'"
+      ;;
+    t,*)
+      warn "discid mismatch: expected \`$oldid' but drive has \`$discid'; continuing anway"
+      ;;
+  esac
+fi
+info "copying \`$discid'"
+echo "$discid" >"$tmp/$tag/discid.new"
+mv "$tmp/$tag/discid.new" "$tmp/$tag/discid"
+
+if [ -b "$dev" ]; then msz=$(blockdev --getsize64 "$dev")
+else msz=nil; fi
+
+echo "$dev" >"$tmp/$tag/device.new"
+mv "$tmp/$tag/device.new" "$tmp/$tag/device"
+
+accumulate_badblocks () {
+  if [ -f "$tmp/$tag/badblocks.new" ]; then
+    if [ ! -f "$tmp/$tag/badblocks" ]; then
+      { echo "## bad-blocks region map"; echo; } >"$tmp/$tag/badblocks"
+    fi
+    sed -n "/^[^#]/p" "$tmp/$tag/badblocks.new" >>"$tmp/$tag/badblocks"
+    rm "$tmp/$tag/badblocks.new"
+  fi
 }
 
-case $backup in
-  t)
-    case ${label+t},${dir+t} in
-      t,*) ;;
-      ,) label=$(printf "%s" "$title" | hack_label) ;;
-      ,t) label=$(printf "%s_%s" "$dir" "$n" | hack_label) ;;
-    esac
-    len=$(printf "%s" "$label" | wc -c)
-    if [ $len -gt 32 ]; then echo >&2 "$prog: label too long"; exit 2; fi
-    ;;
-  nil)
-    case ${label+t} in
-      t) echo >&2 "$prog: label only meaningful to \`dvdbackup'"; exit 2 ;;
-    esac
-    ;;
+set --
+any=nil
+for i in "$tmp/$tag/dest.new" "$tmp/$tag/dest" "$tmp/$tag/dest.seen"; do
+  if [ -f "$tmp/$tag/dest.new" ]; then any=t; fi
+done
+case $any in
+  nil) printf "%s\n" "$title.iso" >"$tmp/$tag/dest.new" ;;
 esac
-
-case ${dir+t} in
-  t) tag="${dir}_${n}_${title}" out="$dir/$n. $title" ;;
-  *) tag=$title out=$title ;;
+case $eject in
+  t) touch "$tmp/$tag/eject" ;;
+  nil) rm -f "$tmp/$tag/eject" ;;
 esac
-tag=${tag//\//_}
-
-archdo run_setrc test -f "$archpath${sub+/$sub}/$out.iso"
-case $rc,$force in
-  0,nil) fail "output file already exists" ;;
-  0,t) warn "output file already exists; will overwrite" ;;
+case $ding in
+  t) touch "$tmp/$tag/ding" ;;
+  nil) rm -f "$tmp/$tag/ding" ;;
 esac
 
-mkdir -p "$tmp/$tag"
-case $backup in
+accumulate_badblocks
+case $retry in
   t)
-    if [ ! -d "$tmp/$tag/rip" ]; then
-      rm -rf "$tmp/$tag/rip.new"
-      run dvdbackup -Mp -i"$dev" -o"$tmp/$tag" -n"rip.new"
-      run mv "$tmp/$tag/rip.new" "$tmp/$tag/rip"
+    if [ -f "$tmp/$tag/badblocks.retry" ]; then
+      :
+    elif [ -f "$tmp/$tag/badblocks" ]; then
+      run mv "$tmp/$tag/badblocks" "$tmp/$tag/badblocks.retry"
+    else
+      fail "no blocks to retry"
     fi
-    if [ ! -f "$tmp/$tag/iso" ]; then
-      run genisoimage -quiet -dvd-video -udf -V "$label" \
-         -o "$tmp/$tag/iso.new" "$tmp/$tag/rip"
-      run mv "$tmp/$tag/iso.new" "$tmp/$tag/iso"
+    set -- "$@" -R"$tmp/$tag/badblocks.retry"
+    if [ -f "$tmp/$tag/iso" ]; then
+      mv "$tmp/$tag/iso" "$tmp/$tag/iso.new"
     fi
     ;;
-  nil)
-    if [ ! -f "$tmp/$tag/iso" ]; then
-      run_setrc "$DVD_SECTOR_COPY" -D"$dev" -c -b"$tmp/$tag/badblocks" -o"$tmp/$tag/iso.new"
-      case $rc in
-       0)
-         run mv "$tmp/$tag/iso.new" "$tmp/$tag/iso"
-         ;;
-       1)
-         run mv "$tmp/$tag/iso.new" "$tmp/$tag/iso"
-         fail "bad sectors found: check \`$tmp/$tag/iso', run again if ok"
-         ;;
-       *)
-         fail "$DVD_SECTOR_COPY: exit $rc"
-         ;;
+esac
+if [ ! -f "$tmp/$tag/iso" ]; then
+  run "$DVD_SECTOR_COPY" -cs ${params+"-B$params"} \
+      -b"$tmp/$tag/badblocks.new" "$@" "$dev" "$tmp/$tag/iso.new"
+  run mv "$tmp/$tag/iso.new" "$tmp/$tag/iso"
+  accumulate_badblocks
+  rm -f "$tmp/$tag/device"
+  case $retry in t) rm -f "$tmp/$tag/badblocks.retry" ;; esac
+  if [ -f "$tmp/$tag/badblocks" ]; then
+    fail "bad sectors found: check \`$tmp/$tag/iso', run again if ok"
+  fi
+  case $msz in
+    nil) ;;
+    *)
+      newmsz=$(blockdev --getsize64 "$dev")
+      case $newmsz in
+       $msz) ;;
+       *) fail "medium size changed ($msz -> $newmsz): try again" ;;
       esac
+      ;;
+  esac
+fi
+
+rm -f "$tmp/$tag/device"
+run mv "$tmp/$tag/dest.new" "$tmp/$tag/dest"
+if [ -f "$tmp/$tag/eject" ]; then eject=t; else eject=nil; fi
+if [ -f "$tmp/$tag/ding" ]; then ding=t; else ding=nil; fi
+run "$DVDRIP_UPLOAD"
+case $eject in t) run eject "$dev" ;; esac
+case $ding in
+  t)
+    if [ -t 1 ]; then exec 3>&1
+    elif [ -t 2 ]; then exec 3>&2
+    else exec 3>/dev/tty
     fi
+    printf "\a" >&3
+    exec 3>&-
     ;;
 esac
-printf "%s\n" "${sub+$sub/}$out.iso" >"$tmp/$tag/dest.new"
-mv "$tmp/$tag/dest.new" "$tmp/$tag/dest"
-run "$DVDRIP_UPLOAD"
-case $eject in t) run eject "$dev" ;; esac