#!/bin/sh# ---------------------------------------------------------------------# DESCRIPTION:# Maintains an OGG Vorbis mirrors from a filetree of FLAC audio files## AUTHOR:# Simon Kinsella, November 2009## LICENSE: BSD license# WARRANTY: NONE. Not rigorously tested, but it works for me!# Use at your own risk.## ---------------------------------------------------------------------## IMPORTANT - paths to master and slave trees MUST be absolute!## Syntax:# ------# ogg-sync.sh -q quality <master-tree> <slave-tree># where <master-tree> is an absolute path to the base of the FLAC audio# tree# The OGG mirrors will be created under a directory 'q<n>' under# absolute path <slave-tree># e.g.:# ogg-sync.sh -q2 /music/flac-audio /music/ogg-mirrors# will create an OGG mirror of '/music/flac-audio' under# '/music/ogg-mirrors/q2/'## FINAL WARNING: Please back-up your files and test the operation# of this script before using day-to-day.## TODO:# 1) Make the syntax more forgiving, possibly# 2) Better error handling / recovery, the usual stuff.# 3) Find a way to dispatch encoding jobs concurrently for SMP systems.# Tried xjobs but was unsuccessful.OGGENC="/usr/local/bin/oggenc"SCRIPT="`basename $0`"SCRIPT_DIR="`pwd`"while getopts ":q:" Optiondo case $Option in q ) QUALITY="${OPTARG}" if [ ${QUALITY} -lt 0 -o ${QUALITY} -gt 9 ] then echo "${SCRIPT}: Invalid Quality value '${QUALITY}'" exit 1 fi esacdoneshift $(($OPTIND - 1))if [ "$1" ]then if [ ! -d "$1" ] then echo "${SCRIPT}: Invalid master directory '$1'" exit 1 fi MASTER_DIR="$1"else echo "${SCRIPT}: Master directory not specified" exit 1fiif [ "$2" ]then SLAVE_DIR="$2"else echo "${SCRIPT}: Slave directory not specified" exit 1fi#=============================================================================#1) For each ogg file in the slave tree:# 1.1) Look for flac file of the same path and name in the master tree:# 1.1.1) If not found, delete the ogg#echo "Removing stale ogg files..."mkdir -p "${SLAVE_DIR}/q${QUALITY}"cd "${SLAVE_DIR}/q${QUALITY}"SLAVE_DIR="`pwd`"find . -type f -name "*.ogg" | sed 's/^[.\/]*\(.*\).ogg$/\1/' \| while read FILE do if [ ! -f "${MASTER_DIR}/${FILE}.flac" ] then #echo "Master file ${MASTER_DIR}/${FILE}.flac not found - deleting ${SLAVE_DIR}/${FILE}.ogg" rm -f "${SLAVE_DIR}/${FILE}.ogg" fi done# 2) Look for existing manifest file in MASTER_DIR/manifest.logcd "${MASTER_DIR}"#echo "Preparing manifests..."MANIFEST="${MASTER_DIR}/q${QUALITY}-ogg-sync.manifest"touch "${MANIFEST}"rm -f "${MANIFEST}.new"touch "${MANIFEST}.new"#3) For each entry in the manifest:# 3.1) If no matching flac file exists, remove the manifest entry#echo "Cleaning manifest..."sed -E '/^[0-9a-f]{32}:.*.flac$/!d' "${MANIFEST}" \| while IFS=: read OLD_MD5 FILE do if [ -f "${FILE}" ] then #not pretty... NEW_MD5="`md5 -qs "\`ls -l "${FILE}" | sed 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *\(.*\)$/\1/'\`"`" if [ "${OLD_MD5}" = "${NEW_MD5}" ] then echo "${NEW_MD5}:${FILE}" >> "${MANIFEST}.new" fi fi donerm "${MANIFEST}"mv "${MANIFEST}.new" "${MANIFEST}"#4) For each flac file in the master tree:# 4.1) If no identical entry exists in the manifest (same path, filename, size and date):# 4.1.1) Create a new ogg# 4.1.2) Add a manifest entry#echo "Generating OGG files..."rm -f "${SCRIPT_DIR}/process_flac.todo"find . -type f -name "*.flac" | sed 's/^[.\/]*\(.*\).flac$/\1/' \| while read FILE do NEW_MD5="`md5 -qs "\`ls -l "${FILE}.flac" | sed 's/^[^ ]* *[^ ]* *[^ ]* *[^ ]* *\(.*\)$/\1/'\`"`" # is the flac file already in the manifest? grep -qF "${NEW_MD5}:${FILE}.flac" "${MANIFEST}" # no - need to process the flac if [ $? -ne 0 ] then# echo "${SCRIPT_DIR}/process_flac.sh ${QUALITY} '${MASTER_DIR}' '${SLAVE_DIR}' '${FILE}' ${NEW_MD5} '`basename ${MANIFEST}`'" >> "${SCRIPT_DIR}/process_flac.todo" mkdir -p "`dirname "${SLAVE_DIR}/${FILE}.ogg"`" \ && "${OGGENC}" -Qq"${QUALITY}" -o "${SLAVE_DIR}/${FILE}.ogg" "${FILE}.flac" \ && echo "${NEW_MD5}:${FILE}.flac" >> "${MANIFEST}" fi doneexit 0