-
Notifications
You must be signed in to change notification settings - Fork 0
/
ios-backup
executable file
·124 lines (99 loc) · 4.94 KB
/
ios-backup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env bash
set -eo pipefail
shopt -s nullglob
source "${0%/*}/common.sh"
# constant variables - you should not change these unless you know what are you doing
readonly PHOTO_EXT="jpg|jpeg|png|heic"
readonly VIDEO_EXT="mov|mp4"
# fail if required variables are not set
# assign default values for optional variables if not set
setup_variables() {
fail_when_empty "${PHOTO_TARGET_DIR} ${VIDEO_TARGET_DIR}" "required variables are not set"
: "${NONINTERACTIVE:=false}"
: "${DATE_FORMAT:=%Y-%m-%d_%T}"
}
# print welcome/info message
usage() {
echo -e \
"${RED}${0##*/}\n" \
"${LGRN}-h|--help " "${NRM}Print this message\n" \
"${LGRN}--non-interactive " "${NRM}Skip interactive sanity check " "${GRN}[optional]" "${RED}${NONINTERACTIVE}\n" \
"${LGRN}--config=<file> " "${NRM}Use specific configuration file " "${GRN}[optional]" "${RED}${CFG_FILE}\n" \
"${LGRN}<config-file> " "${BLU}PHOTO_TARGET_DIR" "${NRM}Directory where processed photos will be moved " "${YLW}[required]" "${RED}${PHOTO_TARGET_DIR}\n" \
"${LGRN}<config-file> " "${BLU}VIDEO_TARGET_DIR" "${NRM}Directory where processed videos will be moved " "${YLW}[required]" "${RED}${VIDEO_TARGET_DIR}\n" \
"${LGRN}<config-file> " "${BLU}IDEVICE_ID " "${NRM}Backup specific idevice (if not set, use first found) " "${GRN}[optional]" "${RED}${IDEVICE_ID}\n" \
"${LGRN}<config-file> " "${BLU}DATE_FORMAT " "${NRM}Rename all media to specific format ('date' compliant)" "${GRN}[optional]" "${RED}${DATE_FORMAT}${NRM}"
}
# make sure that $1 list of directories exist
ensure_dirs() { for dir in ${1}; do mkdir -p "${dir}"; done; }
# when $IDEVICE_ID is not set, use id of first Apple device recognized
validate_idevice_id() {
local -r all_idevices="$(idevice_id -l 2>/dev/null || true)"
if [[ -z "${IDEVICE_ID// }" || ! "${all_idevices}" =~ "${IDEVICE_ID}" ]]; then
IDEVICE_ID="$(head -1 <<< "${all_idevices}")"
if [[ -z "${IDEVICE_ID// }" ]]; then
log "No Apple device could be found connected" "${RED}" >&2
exit 1
fi
fi
}
# mount $IDEVICE_ID with gvfs if it's not already mounted
mount_idevice() {
(gio mount -l | grep -q "^Mount.*afc://${IDEVICE_ID}") || gio mount "afc://${IDEVICE_ID}/"
}
# copy from DCIM dirs of $IDEVICE_ID all $1 types of files to $2 destination dir
copy_media_files() {
find "/run/user/${UID}/gvfs/afc:host=${IDEVICE_ID}/DCIM" -regextype posix-extended -iregex ".*\.("${1}")" | \
rsync -Pah --files-from - --no-relative / "${2}/"
}
# count files in $1 dir
count_files() { find "${1}" -maxdepth 1 -mindepth 1 -type f | wc -l; }
# rename all photos in $1 dir to $DATE_FORMAT standard
rename_photos() { (exiv2 -Fvr "${DATE_FORMAT}" rename "${1}/"*) || true; }
# get $1 video creation date in $DATE_FORMAT standard
get_video_creation_date() {
local -r all_params="$(mediainfo "${1}")"
local creation_date="$(awk '/^com.apple.quicktime.creationdate/ { print $3 }' <<< "${all_params}")"
[[ -z "${creation_date// }" ]] &&
creation_date="$(awk '/^Encoded date/ { print substr($0, index($0, $4)); exit }' <<< "${all_params}")"
date -d "${creation_date}" "+${DATE_FORMAT}"
}
# rename all videos in $1 dir to $DATE_FORMAT standard
rename_videos() {
for video in ${1}/*; do
mv -v --backup=numbered "${video}" "${1}/$(get_video_creation_date "${video}").${video##*.}"
done
}
# unmount $IDEVICE_ID with gvfs
unmount_idevice() { gio mount -u "afc://${IDEVICE_ID}/"; }
# main flow
parse_arguments "${@}"
load_config "${CFG_FILE}" "iphone-backup.cfg"
setup_variables
usage
ensure_deps "idevice_id gio rsync exiv2 mediainfo"
validate_idevice_id
sanity_check
ensure_dirs "${PHOTO_TARGET_DIR} ${VIDEO_TARGET_DIR}"
readonly timestamp="$(date +%s)"
readonly photo_tmp_dir="$(mktemp -d -t ios-backup-photo.XXXXXX)"
readonly video_tmp_dir="$(mktemp -d -t ios-backup-video.XXXXXX)"
trap "rm -rf "${photo_tmp_dir}" "${video_tmp_dir}"" EXIT
log "[phase 1] mount Apple device '${IDEVICE_ID}'" "${RED}"
mount_idevice
trap "unmount_idevice; $(trap -p EXIT | cut -f2 -d \')" EXIT
log "[phase 2] copy media files to temporary directories" "${RED}"
copy_media_files "${PHOTO_EXT}" "${photo_tmp_dir}"
copy_media_files "${VIDEO_EXT}" "${video_tmp_dir}"
readonly photo_counter="$(count_files "${photo_tmp_dir}")"
readonly video_counter="$(count_files "${video_tmp_dir}")"
log "[phase 3] rename media files to match '${DATE_FORMAT}' date format" "${RED}"
rename_photos "${photo_tmp_dir}"
rename_videos "${video_tmp_dir}"
log "[phase 4] move media files to target directories" "${RED}"
rsync -Pah --remove-source-files "${photo_tmp_dir}/" "${PHOTO_TARGET_DIR}/"
rsync -Pah --remove-source-files "${video_tmp_dir}/" "${VIDEO_TARGET_DIR}/"
sync
log "[success] backup finished" "${RED}"
log "took: $(print_elapsed_time "${timestamp}")" "${BLU}"
log "copied photos: ${photo_counter} | videos: ${video_counter} | total: $((photo_counter+video_counter))" "${BLU}"