Skip to content

Instantly share code, notes, and snippets.

@mx-moth
Last active December 26, 2015 06:59
Show Gist options
  • Save mx-moth/7112049 to your computer and use it in GitHub Desktop.
Save mx-moth/7112049 to your computer and use it in GitHub Desktop.
A bash script to copy music to my phone. The phone/mtpfs has issues staying connected, and file transfer speed is not great, so I did not want to overwrite existing files. MTP does not support renaming files, so `rsync` did not work. Finally, FAT does not support some characters in filenames (sorry, GY!BE, "Motherfucker=redeemer" does not work),…
#!/bin/bash
# A dodgy ripoff of rsync for my music files
#
# Usage: To copy the contents of "Zechs Marquise/Getting Paid/" and "Grails/"
# from your music library to your mounted phone:
#
# syncdir --source $HOME/Music \
# --destination /mnt/phone/Music \
# "Zechs Marquise/Getting Paid/" \
# "Grails/"
#
# The source defaults to `pwd`. This script works best when you are in the
# source directory, as you can leave off the source and tab-complete files to
# copy:
#
# cd $HOME/Music
# syncdir --destination /mnt/phone/Music \
# "Zechs<TAB>..." \
# "Gr<TAB>"
#
# To send your whole music library across, use it like so:
#
# cd $HOME/Music
# syncdir --destination /mnt/phone/Music
#
# or:
#
# syncdir --source $HOME/Music --destination /mnt/phone/Music
#
# This never deletes files, and should not be used for transferring back to
# your music library. It is designed specifically for transferring to
# intermittent FAT devices.
args=$( getopt \
--options t:f:vqs \
--longoptions destination:,source:,silent \
--name 'sync-music' \
-- "$@" )
if [ $? -ne 0 ] ; then
exit 1
fi
eval set -- "$args"
dst_base=
src_base=$( pwd )
log_level=2
while true ; do case "$1" in
-f|--source)
src_base="$2"
shift 2
;;
-t|--destination)
dst_base="$2"
shift 2
;;
-v) # Increase verbosity
log_level=$(( $log_level + 1 ))
shift
;;
-q) # Decrease verbosity
log_level=$(( $log_level - 1 ))
shift
;;
--silent) # Turn off output
log_level=0
shift
;;
--)
shift
break
esac ; done
munge_for_fat() {
echo "$1" \
| sed -e 's![[:cntrl:]*/:<>?\\|+,.\;\=\[\]]\+!*!g' \
-e 's!\([/ ]\|^\)[*.]\+!\1!g' \
-e 's![*.]\+\($\|[/ ]\)!\1!g' \
-e 's![*]!-!g' \
| iconv -cs -f UTF-8 -t ASCII
}
skip_file() {
# Check if a source file needs copying to the destination
src="$1"
dst="$2"
if ! [ -e "$dst" ] ; then
# The destination file does not exist
return 1
fi
src_size=$( stat -Lc %s "$src" )
dst_size=$( stat -Lc %s "$dst" )
if [ "$src_size" -ne "$dst_size" ] ; then
# The files differ in size
return 2
fi
# Modification times are not to be trusted, as FAT does not have good
# modification timestamp support, so we can not use them as a final test
# ala rsync. See the discussion of `--modify-window` in `man rsync` for
# more information.
return 0
}
error() {
# Print an error to stderr
log error "$@" >&2
}
log() {
# Usage: `log (info|success|warning|error) message`
level="$1"
shift
case "$level" in
info)
[ "$log_level" -lt 3 ] && return
echo -en '\e[36m' ;;
success)
[ "$log_level" -lt 2 ] && return
echo -en '\e[32m' ;;
warning)
[ "$log_level" -lt 2 ] && return
echo -en '\e[33m' ;;
error)
[ "$log_level" -lt 1 ] && return
echo -en '\e[31m' ;;
*)
return
esac
echo -en "$@"
echo -e '\e[0m'
}
while IFS= read -d $'\0' -r src_file ; do
dst_file=$( munge_for_fat "$src_file" )
src="$src_base/$src_file"
dst="$dst_base/$dst_file"
if [ -d "$src" ] ; then
# source is a directory
if ! [ -e "$dst" ] ; then
mkdir -p "$dst" \
&& log "success" "A $dst_file"
elif ! [ -d "$dst" ] ; then
error "$dst exists and is not a directory"
fi
else
# source is a file
skip_file "$src" "$dst"
exit_code=$?
if [ $exit_code -eq 0 ] ; then
# Nothing to do
log info " $dst_file"
else
# Copy the file over, and log if it is an update or modification
case $exit_code in
1) char="A" ;;
2) char="U" ;;
esac
cp --no-preserve="mode,ownership" --remove-destination "$src" "$dst" \
&& log success "$char $dst_file"
fi
fi
done < <( cd "$src_base" ; find "$@" -print0 )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment