Skip to content

Instantly share code, notes, and snippets.

@akomakom
Last active April 16, 2021 22:31
Show Gist options
  • Save akomakom/03db32a22441e7c467614bb397425768 to your computer and use it in GitHub Desktop.
Save akomakom/03db32a22441e7c467614bb397425768 to your computer and use it in GitHub Desktop.
Automated DVD Rip (then encode) using dvdbackup and ffmpeg, on insert. udev->systemd->dvdrip(script here)->dvdbackup (automatic rip to VOB). Then, when all are ripped, run dvdencode(script here) to compress all VOBS into a new cleanly named hierarchy

What this is

A collection of files to set up the following automation:

  • Activate on insert
  • Rip the DVD to a temporary path (eg /opt/dvd/tmp.XXXXX/NAME-FROM-DVD-ITSELF/VIDEO_TS)
  • Eject

Then a manual step:

  • Review directory names and rename as needed (a lot of DVD disk identifiers are useless)
  • run dvdencode, it will process all of the above to a new hierarchy, example filename: /opt/dvd/encoded/NAME-FROM-DVD-ITSELF/NAME-FROM-DVD-ITSELF-1-of-7.mp4

dvdencode can be re-run, it will only encode files it hasn't already encoded. If encoding fails, the partial file is deleted. A log file is written, and encoding stops on any error.

Notes

  • By default, dvdrip is run as root, and output directories will be root-owned. To change this, uncomment the User= line in the systemd unit file.
  • Default ffmpeg options are low quality, small size (good for ripping instructional DVDs). Change by editing the top of dvdencode

Installation

Each file has its intended location at the top, shell scripts need to be made executable.
You may need to do this once to apply changes without restart:

  • systemctl daemon-reload
  • systemctl restart udev
  • Also, install dvdbackup, ffmpeg
#!/bin/bash -e
# goes anywhere you like, eg /usr/local/bin/dvdencode
#
# Script to find directories of DVD rips created by "dvdbackup"
# and automatically encode the individual files found, giving them proper names.
# Uses the directory name (parent of "VIDEO_TS") as the name base.
# Creates a new hierarchy. Does not overwrite, so can be re-run to resume
################# CONFIG #########################
# dir with VIDEO_TS directories anywhere under, eg
# <INPUT_DIR>/[tmp.XXXX]/Some Name/VIDEO_TS/
# "Some Name" becomes the name for output dir/files
INPUT_DIR=/opt/dvd/
# output hierarchy root:
OUTPUT_DIR=/opt/dvd/encoded
LOG_FILE="${OUTPUT_DIR}/log-$(date -Iminutes).txt"
DRY_RUN=${DRY_RUN:-false} # set to enable, ie DRY_RUN=true dvdencode
FFMPEG_PARAMS="-c:v libx265 -crf 28 -preset fast -x265-params log-level=error -max_muxing_queue_size 4096"
VOB_FIND_OPTS="-size +3M" # a param to the find command, eg skip VOBs smaller than 3MB
##################################################
mkdir -p $OUTPUT_DIR
log() {
echo "$@" | tee -a $LOG_FILE
}
do_encode() {
log "Encoding '${1}' to '${2}'"
if [ "$DRY_RUN" == "true" ] ; then
log "DRY RUN, skipping"
return
fi
if [ -s "$2" ] ; then
log "File already exists: ${2}"
else
#ffmpeg -i "$1" -crf 30 "$2"
if ffmpeg -loglevel error -i "$1" $FFMPEG_PARAMS "$2" ; then
log "Encoding succeeded"
else
log "Encoding failed with code $?, deleting output file"
rm -f "$2"
fi
fi
OLD_SIZE=$(stat -c %s "$1")
NEW_SIZE=$(stat -c %s "$2")
log "Old size: $OLD_SIZE, new size: $NEW_SIZE, $(($OLD_SIZE/$NEW_SIZE))x smaller"
}
# store them all in an array so bash while read doesn't get messed up while the directory changes
readarray -t dirs < <(find "${INPUT_DIR}" -type d -name VIDEO_TS)
DIRCOUNT=${#dirs[@]}
log "Discovered ${DIRCOUNT} directories: ${dirs[@]}"
for dir in "${dirs[@]}" ; do
NAME=$(cd "$dir" ; cd .. ; basename "`pwd`")
log "Processing DIR $dir, NAME: ${NAME}"
mkdir -p "${OUTPUT_DIR}/${NAME}"
# store them all in an array so bash while read doesn't get messed up while the directory changes
# skip small interlude files
readarray -t files < <(find "$dir" -name '*.VOB' $VOB_FIND_OPTS | sort)
COUNT=${#files[@]}
log "COUNT: ${COUNT}"
INDEX=0
for file in "${files[@]}" ; do
INDEX=$(($INDEX+1))
log "INDEX ${INDEX}/${COUNT}: '${file}'"
ENCODED_NAME=$(echo "${NAME}-${INDEX}-of-${COUNT}.mp4" | sed 's/ /_/g')
do_encode "$file" "${OUTPUT_DIR}/${NAME}/${ENCODED_NAME}"
done
done
#!/bin/bash
# goes into /usr/local/bin/dvdrip
# launched by udev/systemd (as root or change user in systemd)
SAVE_DIR=/opt/dvd
mkdir -p $SAVE_DIR
DIR=$(mktemp -d -p $SAVE_DIR)
killall dvdbackup # in case of prior manual eject while ripping
log() {
logger -t dvdrip $@
echo $(date "+%x %X :") $@ >> $SAVE_DIR/log-rip.txt
}
cd $DIR
log "Saving DVD to $DIR (Running as $(id))"
dvdbackup -M 2>&1 | tee -a $SAVE_DIR/log-rip.txt
eject
log "Completed: Saving DVD to $DIR: $(ls $SAVE_DIR)"
# /etc/udev/rules.d/dvdrip.rules
# Triggers a systemd service (dvdrip.service) every time a DVD is inserted
# For use in a systemd device unit (eg /lib/systemd/system/dvdrip.service)
ACTION=="change", ENV{ID_CDROM_DVD}=="1", ENV{ID_CDROM_MEDIA_STATE}=="complete", ENV{ID_FS_TYPE}=="udf", TAG+="systemd", ENV{SYSTEMD_WANTS}="dvdrip.service"
ACTION=="change", ENV{ID_CDROM_DVD}=="1", ENV{ID_CDROM_MEDIA_STATE}=="complete", ENV{ID_FS_TYPE}=="iso9660", TAG+="systemd", ENV{SYSTEMD_WANTS}="dvdrip.service"
# you can do something similar for audio CDs:
#ACTION=="change", ENV{ID_CDROM_MEDIA_CD}=="1", TAG+="systemd", ENV{SYSTEMD_WANTS}="cdrip.service"
# /lib/systemd/system/dvdrip.service (then systemctl daemon-reload)
[Unit]
Description=Rip inserted DVD
DefaultDependencies=false
StopWhenUnneeded=true
[Install]
WantedBy=dev-dvd.device
[Service]
Type=oneshot
ExecStart='/usr/local/bin/dvdrip'
# Optional, to write VOB files/dirs as user
#User=<YOUR USERNAME>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment