Привет. Сегодня заметка о том, как я настроил бекапинг мобильных фоток. Механизм прост, обкатан и проверен месяцами работы, так что описываю как есть.
Всё базируется на нескольких простых вещах:
- Syncthing;
inotify-tools
;- демонизированный shell-скрипт.
На десктопе — Ubuntu, на смартфоне — Android. Базовые хотелки:
- логирование;
- конфигурирование;
- копирование фоток из директории Syncthing в безопасное место;
- обработка нескопированных вовремя фоток.
В итоге все фотки и видосики с мобилы будут сами лететь на комп, мы сможем смело чистить память смартфона от лишнего, а потом спокойно сортировать слитые фотки по своему фотоархиву на компе.
План понятен, погнали делать.
Оглавление
Syncthing
Если мы говорим о бекапинге, то важно понимать как работает эта прога.
Syncthing синхронизирует содержимое какой-то директории между девайсами. Это значит, что на всех задействованных девайсах будет находиться эта директория. Это не «персональное облако».
В общем случае, когда по умолчанию настроена двунаправленная синхронизация, все изменения директории на одном девайсе отражаются и на остальных.
Да, можно настроить однонаправленную. Но это не означает чего-то волшебного: всё будет почти также, и на каком-то (принимающем, но не отдающем) устройстве можно будет вертеть синхронизируемую директорию с её контентом как угодно. Только распространить её изменения остальным девайсам не выйдет: ST любезно сообщит о твоём косяке и предложит вернуть её взад, тогда весь контент вернётся обратно. Либо ты отказываешься от синхры.
В конечном итоге, не получится штатно настроить синхронизацию так, чтобы смартфон просто скидывал фотки на комп, а на компе эти фотки можно было бы переместить куда-то. Смотря как настроена синхронизация, либо они тогда удалятся на смартфоне, либо тебе придётся вернуть их обратно в папку.
Так вот, наша задача — просто скопировать фотки из синхронизируемой директории и оставить её жить своей жизнью (удаляешь тяжёлый видос из «Галереи» смартфона -> Syncthing замечает удаление -> видос трётся на других девайсах). Копировать можно либо вручную периодически, либо автоматизировано в реальном времени. Второй вариант вполне подходит.
Так что давай пошагово:
- ставь Syncthing на все свои устройства:
https://syncthing.net/downloads/- готовый скрипт для ubuntu
- открывай приложение на смартфоне
- открывай страницу на десктопе: http://127.0.0.1:8384/
Для начала нам надо связать два девайса. Для этого на десктопе в правом верхнем углу надо выбрать Действия — Показать ID. Будет отображено вот такое:
На главном экране приложения переходи на вкладку Устройства и жми +
в правом верхнем углу. На следующем экране справа от поля ввода ID устройства есть кнопка сканера QR-кода. Жми и сканируй QR с монитора. Задавай Имя и сохраняй.
Папка с фотками в приложении уже должна быть добавлена сразу при первом запуске. Разработчики понимают, что засинхронить фотки — первое, что придёт в голову пользователю смартфона.
Если её внезапно нет, то на вкладке Папки главного экрана надо нажать тот же +
в углу. Ниже скриншоты того, как могут выглядеть дальнейшие шаги:
Главное там — задать ярлык (видимое название в рамках Syncthing), путь до папки с фотками (в моём случае это /storage/emulated/0/DCIM
) и включить крыжик у девайса, который ты только что добавил. Остальное по желанию.
Сохраняем и переключаемся на десктоп. Смартфон должен пригласить комп к синхронизации выбранной на смарте папки. Там должно выпрыгнуть примерно такое приглашение:
Жмём Добавить и видим ноую форму добавления удалённой папки на свой комп. Самое важное здесь — указать Путь к папке (локальное расположение), остальное можно оставить по дефолту или настроить по желанию.
Сохраняем и оставляем синхрониться, а пока переходим к
inotify-tools
Он не поставляется с убунтой из коробки, надо лапками:
$ sudo apt install inotify-tools
В этом пакете находятся несколько утилит, нас интересует только inotifywait
. Она может в реальном времени следить за состоянием файловой системы и выдавать отчёты о событиях в stdout
или куда пожелаешь.
Чтобы с ней поразбираться, можешь почитать inotifywait -h
. Нас интересуют следующие аргументы:
--quiet
выводит только информацию о возникших событиях--monitor
программа не завершится и продолжит работу после первого возникшего события--event moved_to
нам нужно ловить только события перемещения файлов--format %f
выводить только имя файла, вызвавшего событие; это конечное имя файла (не путь), который был перемещён (другие форматы указаны вman inotifywait
)--include "$regexp"
следить только за файлами, конечное имя коих удовлетворяет некоему регулярному выражению- и последнее — абсолютный путь до директории наблюдения
А теперь подробнее о паре аргументов.
Когда файл прилетает и пишется на комп, возникает целая туча событий: создание (create
), изменение (modify
), то, сё. Прилетает он с префиксом .syncthing-
в имени. Когда запись файла завершена, возникает событие moved_to
— это переименование (перемещение) файла в его должное имя, т. е. удаление префикса.
Поэтому мы ограничиваем список событий --event
только переименованием файла в конечное имя и фильтруем таковые по регулярке --include
. Оная для моего случая такова:
regexp="[0-9]{8}_[0-9]{6}.*\.(jpg|mp4|gif)"
Это дата в формате %Y%m%d_%H%M%S
+ расширение файла.
Команда, с которой можно поиграться в итоге, выглядит так:
inotifywait \
--quiet \
--monitor \
--event moved_to \
--format %f \
--include "[0-9]{8}_[0-9]{6}.*\.(jpg|mp4|gif)" \
"/home/user/example"
Пишем скрипт
Еееее! Башизм!
В принципе, команду выше уже можно вставить в скрипт, добавить шибенг, скорректировать мелочи и использовать. Но мы же не звери какие-то. Надо реализовать задуманное.
Для логирования придумаем функцию, которая пишет что-нибудь одновременно в stdout
и в файл с именем по текущей дате (для простоты отслеживания и, при желании, ротации):
#!/bin/bash
# директория расположения логов
dir_logs="$HOME/inotifywait-cp-logs"
# функция логирования
print() {
echo -e "[`date '+%H:%M:%S'`] $*" \
| tee -a "$dir_logs/`date '+%Y%m%d'`.log"
}
Конфигурирование я заложу на переменных: это даст переиспользуемость скрипта без изменений логики, при этом я смогу его однажды настроить любым текстовым редактором и не любиться в голову.
Помимо dir_logs
ещё понадобятся такие вещи:
#!/bin/bash
# директория с прилетевшими фотками
dir_src="$HOME/Syncthing/Mobile/Camera"
# директория, в которую их надо копировать
dir_dest="$HOME/some/safe/place"
# директория расположения логов
dir_logs="$HOME/inotifywait-cp-logs"
# регулярка для фильтрации файлов по именам
regexp="[0-9]{8}_[0-9]{6}.*\.(jpg|mp4|gif)"
#...
Это всё, на что я заложу несложную логику.
Вот теперь можно приступать к копированию фоток. Берём команду inotifywait
выше и корректируем аргументы. Поскольку она выводит имена перемещённых файлов, а мы заранее знаем их путь, то просто пайпим этот вывод в цикл:
# ...
inotifywait \
--quiet \
--monitor \
--event moved_to \
--format %f \
--include "$regexp" \
"$dir_src" \
| while read filename; do
cp "$dir_src/$filename" "$dir_dest/$filename"
print "COPIED:\t$dir_src/$filename => $dir_dest/$filename"
done
Скопировали — отчитались.
А что, если синхра работает давно, а скрипт мы запустили только сейчас? Нам надо скопировать те файлы, которые уже прилетели на комп пока скрипт не работал, да не все, а согласно той же регулярке, по которой фильтруется inotifywait
.
Решаем просто: грепаем ls
директории с фотками. Это должно произойти перед тем, как мы начнём следить за новыми файлами.
#!/bin/bash
# ...
# обработка нескопированных вовремя файлов
ls -1 "$dir_src" \
| grep -E "^${regexp}$" \
| while read filename; do
cp "$dir_src/$filename" "$dir_dest/$filename"
print "COPIED:\t$dir_src/$filename => $dir_dest/$filename"
done
# ...
Отсюда другой вопрос: что если в директории назначения уже есть копия, появившаяся ранее? Можно было бы форсить перезапись через cp -f
, но я не хочу тупо их перезаписывать, потому что это тупо. А если их тысяча? А если каждый видос по полтора гига?
Я лучше сэкономлю дисковых операций и просто скипну файл-копию. К тому же, мы можем вынести повторяющийся кусок кода в функцию.
# ...
# функция копирования файла
# пропускает существующие в папке назначения
copy () {
if [ -f "$dir_dest/$1" ]; then
print "SKIPPED:\t$dir_dest/$1"
else
cp "$dir_src/$1" "$dir_dest/$1"
print "COPIED:\t$dir_src/$1 => $dir_dest/$1"
fi
}
# обработка нескопированных вовремя файлов
ls -1 "$dir_src" \
| grep -E "^${regexp}$" \
| while read filename; do copy "$filename"; done
# наблюдение за перемещениями файлов по папке
inotifywait \
--quiet \
--monitor \
--event moved_to \
--format %f \
--include "$regexp" \
"$dir_src" \
| while read filename; do copy "$filename"; done
А что, если во время работы скрипта директория бекапов/логов была удалена, куда копировать? А что, если скрипт уже работает, но Syncthing ещё не настроен или не запущен?
Надо вовремя создавать все директории. Вот такая строчка:
mkdir -p "$dir_src" "$dir_dest" "$dir_logs"
встанет в самое начало функции copy()
и перед вызовом ls -1
. Так директории будут создаваться в нужный момент, если их нет.
Так, файл скрипта сохранили, sudo chmod
нули его на +x
и позапускали, пофоткали клаву, понаблюдали за логами и перемещениями файлов.
Теперь демонизируем всё это. Создадим файлик, например, /home/user/.local/bin/photosync.service
(рядом покладём сам скрипт, чтоб долго не искать) и напишем в нём следующее:
[Unit]
Description=Photosync from android
[Service]
Type=simple
Restart=always
# перепроверь эти три параметра и скорректируй, если что:
User=user
WorkingDirectory=/home/user
ExecStart=bash /home/user/.local/bin/photosync.sh
[Install]
WantedBy=network.target
Одной командой делаю симлинк на файл демона, включаю автозапуск и запускаю:
$ sudo ln -sf \
/home/user/.local/bin/photosync.service \
/etc/systemd/system/photosync.service && \
sudo systemctl enable --now photosync && \
sudo systemctl status photosync
На этом всё. Совсем несложно использовать лёгкие инструменты, которые лежат под рукой, не так ли? Можно ещё задействовать logrotate
, чтобы логи архивировались/удалялись по времени и не занимали много места. Можно удалять из синхронизируемой директории скопированные файлы. Можно прикрутить копирование файлов, например, по ssh на домашний сервер или свой s3-сторадж в облаке.
По копированию бекапов в удалённые хранилища я когда-то уже написал пару статей. Там есть вещи, которые можно переиспользовать в данном случае:
Я же ограничился резервированием на другой локальный диск.
Ниже полный готовый гист. Бери, юзай.