В недалекие времена, когда flickr ещё не предлагал терабайт под хранение фотографий, а BitTorrent Sync только вышел на экраны интернета в своей небезопасной альфа-версии, была у меня потребность: делиться фотографиями с друзьями и не только. Но как обычно у программистов это бывает, под словом «делиться» стоит гораздо больше, чем выложить фоточки во ВКонтактик. А именно:
- Выложить куда-нибудь фотографии на свой сервер с красивым и простым web-интерфейсом.
- Просто и массово заливать и скачивать оригиналы изображений.
- Иметь возможность разграничить доступ к определенным альбомам.
- Попытаться связать это с локальным сетевым хранилищем, чтобы не дублировать фотографии.
- По возможности удалять оригиналы фотографий с сервера через какое-то время и оставлять только фотографии с измененным размером.
- По-максимуму бесплатно! :)
После таких мыслей в голове начинает зарождаться идея: «Надо накреативить...» — и ты уже не можешь остановиться.
Что сейчас предлагают фотохостинги?
Гугл нашел очень много облачных сервисов для выкладывания фотографий, предназначенных в основном для фотографов (и не только). Суть всех сервисов сводится к тому, что начиная с определенного объема надо платить фиксированную сумму в месяц. Если за полгода сумма не выглядит большой, то спустя два года она будет неприятным напоминанием. Аналогию можно провести с оплатой ru-доменов по 600 рублей в год в nic.ru и с постоянным напоминанием себе, что надо бы перевести уже эти домены к другим регистраторам :).
С другой стороны, если у вас уже есть какой-нибудь сервер, то надо использовать его по максимуму. Я нашел два проекта, которые в принципе бы смогли подойти под мои задачи. Это Piwigo (бывший phpWebGallery) и Koken. Последний проект вообще очень сильно порадовал. Но познакомившись с ними поближе, понял, что это мне тоже не подходит.
Dropbox, Skydrive, Google+ (Picasa), Яндекс.Фотки — вот эти ребята отлично выполняли свои функции до тех пор, пока места хватало.
Поделиться с друзьями
Хочу подробнее рассказать о том, что значит для меня термин «поделиться». После какого-то события (будь то поездка на природу или прогулки по городу), в котором принимают участие несколько человек, появляется много фоток. После обработки фотки (300-700 МБ) отправляются на местный NAS (Synology DS210j). И вот эту папку с NAS надо бы выложить в Интернет, чтобы её скачали те самые друзья, которые есть на фотках.
Загружать/скачивать через браузер такой объем — не для меня.
Но в конечном итоге хочется иметь ссылку на альбом, которую можно скинуть ещё кому-нибудь. Ну и список альбомов тоже неплохо было бы получить. Простой обычный процесс.
Самое главное, должны быть оригиналы фотографий и нормальный ресайз без фильтров (не то, что сейчас предлагают VK и остальные). Потом, когда у каждого будет 4К телевизор (как сейчас FullHD), будет очень здорово полистать свой фотоархив и ещё раз порадоваться.
BitTorrent Sync
После того, как я прочитал новости о выходе первой версии BTSyncа под все платформы — я все осознал. В моей голове четко выстроился алгоритм работы:
- Первоначальная заливка фотографий происходит через BitTorrent Sync.
- Пользователь неважно где расшаривает папку и получает readonly secret key, при этом он может сделать это на NAS или у себя локально.
- Далее пользователь идет в веб-интерфейс управления и добавляет альбом через readonly secret key.
- Веб-интерфейс посылает команду BTSync скачать вот эту папку на сервере. Постепенно начинается скачивание на сервер.
- В это время в кроне или ещё где идет проверка, скачалось ли все или нет (а-ля индексация файлов). Все файлы, например, добавляются в БД, и к ним создается уменьшенная копия (т.е. вся мета-информация попадает из оригинальных файлов в базу данных).
- Через какое-то время мы удаляем оригиналы с сервера (но! они сохраняются у пользователей, которые успели скачать).
У BTSync под Linux консольного API до сих пор нет. Но есть веб-интерфейс, который может выступать в качестве API-сервера. Вооружившись Go, я написал консольную утилиту для работы с BTSync. Ну а потом сделал класс для PHP. А дальше дело за малым: написать все остальное ;)
EazyPhoto
По основной своей специальности я php-программист. Верстка — это самое страшное для меня, что может быть:). Поэтому, взяв Foundation, я попытался что-нибудь на нем изобразить.
На главной странице мы видим список альбомов с названиями и датами. А на странице альбома — квадратные фотки с предпросмотром, как в дропбоксе. Если добавить к каждой фотке описание и задать её порядковый номер, то получится что-то типа блога. Размер больших фотографий для web-интерфейса я выбрал прямо как маркетолог — FullHD :)
Управление альбомами и фотографиями происходит внутри административной панели. Вот таким вражеским образом выглядит добавление нового альбома: достаточно заполнить название, дату начала и ReadOnly Secret.
База данных: выбрал mysql, потому что оно у всех есть. В основном тут интересны эти две таблички: albums и photos
Индексация файлов
Сначала я написал индексатор на PHP: он пробегал по новым альбомам, добавлял их в очередь на загрузку в BTSync, и потом пробегал по существующим и добавлял новые найденные файлы. Достаточно повесить скрипт в cron раз в 5 минут: и этого бы хватило. Но не мне.
Было бы круто, если бы фотки добавлялись в базу по мере их скачивания. И тут на помощь приходит Go.
eazyphotod
Небольшой демон, который висит и проверяет директории на наличие новых файлов. Создает превью для фотографий и сохраняет в базу. Общается с BTSync'ом. Вот его основные задачи.
Для реализации данных задач я воспользовался следующими пакетами:
- code.google.com/p/gcfg/ — работа с конфигурационными ini-файлами в стиле gitconfig. На выходе — заполненная структура.
- github.com/disintegration/imaging — работа с изображениями (resize, crop, fit, etc..). Без использования gd, чистый go.
- github.com/go-sql-driver/mysql — драйвер для mysql.
- github.com/howeyc/fsnotify — кроссплатформенный пакет для отслеживания изменений в файловой системе.
- github.com/rwcarlsen/goexif/exif — пакет для чтения EXIF-данных.
- github.com/sergeyfast/btsync-cli/ — мой пакет для работы с API BTSync.
Проверив в демо-проекте все необходимые функции, я начал собирать это все в рабочую версию. Потребовалось примерно два дня, чтобы получить готовый результат.
Все запросы (resize, обновление мета-информации, событие о новом файле) ставятся в одну очередь:
var SyncQueue = make(chan *SyncItem)
type SyncItem struct {
Album *model.Album
FsPhotos model.PhotoList
FullSync bool
Filename string
}
Поэтому нет необходимости отслеживать одновременный доступ к map'ам и другим важным переменным. Все идет в одной общей очереди.
Работа с базой данных тоже получилась довольно простой.
Вообще, если вы думали писать на go, но все не решались — мой вам совет: возьмите и напишите уже что-нибудь на нем :)
И ещё одно: мои go-проекты на github по идеологии размещены неправильно, т.к. в репозитории должна быть корневой только одна папка src. А у меня — целиком проект. Мне как-то не комфортно, когда рядом с исходным кодом в одной папке лежат примеры конфигов, README.md и прочие вспомогательные материалы.
Итог
Со своими задачами сервис вполне справляется: хранилище все время в сети, на нем установлен BTSync. После того, как фотографии отправлены на хранилище, папка добавлена в BTSync и веб-интерфейсе создан альбом — можно лечь спать. Сервер с eazyphoto сам скачает фотографии и добавит их в текущий альбом. Утром можно зайти, проверить, и отправить ссылку друзьям. А друзья уже при необходимости скачают оригиналы к себе через BitTorrent Sync.
Попробуй собери
Для тех, кто решил попробовать поднять это все у себя — вот ссылки:
- github.com/sergeyfast/eazyphoto-web — php-часть
- github.com/sergeyfast/eazyphotod — сам демон
Все инструкции (или их подобие) находятся внутри проектов (open source такой open source :).
sudo add-apt-repository ppa:tuxpoldo/btsync
sudo apt-get update
sudo apt-get install btsync
Порт с данными = 0. Порт для веб-интерфейса: 8888. IP: 127.0.0.1
2. Установим go
Рекомендую через godeb blog.labix.org/2013/06/15/in-flight-deb-packages-of-go
Минимальная версия go: 1.1
3. Установим eazyphotod
git clone git://github.com/sergeyfast/eazyphotod.git
cd eazyphotod
export GOPATH=`pwd`
go get code.google.com/p/gcfg github.com/disintegration/imaging github.com/go-sql-driver/mysql github.com/howeyc/fsnotify github.com/rwcarlsen/goexif/exif github.com/sergeyfast/btsync-cli/src/btsync
go build -o eazyphotod src/*.go
После этого у нас появился бинарник.
Рекомендую создать /usr/local/eazyphotod/ (user www-data), туда скопировать eazyphotod + config.gcfg
Закинуть eazyphotod.conf в /etc/init/ и запустить (предварительно настроив config.gcfg):
service eazyphotod start
(deb-way: засунть конфиг в /etc/eazyphotod.conf, бинарник в /usr/bin/eazyphotod, и указать ссылку на конфиг через -config параметр).
Дальнейшее развитие
Хотелось бы не пугать потенциальных пользователей админкой, а сделать им нормальный веб-интерфейс для управления и простой скрипт/пакет для установки. Но все это актуально только с eazyphotod, потому что cron и php-процесс для гиков — явно не выход ;)
Если у кого-нибудь есть мысли по функциональности или тому, как должно это все выглядеть (или вдруг кто-нибудь хочет помочь ;) — велком.
Напоследок: лирическое отступление. Фотографируйте, делитесь с друзьями и родителями. Жизнь быстро проходит, а фотоархив остаётся (желательно в RAID1 и дополнительной копией на случай апокалипсиса :)…
Автор: sergeyfast