- PVSM.RU - https://www.pvsm.ru -

EazyPhoto: уютный фотохостинг для своего сервера

В недалекие времена, когда flickr ещё не предлагал терабайт [1] под хранение фотографий, а BitTorrent Sync только вышел на экраны интернета в своей небезопасной альфа-версии, была у меня потребность: делиться фотографиями с друзьями и не только. Но как обычно у программистов это бывает, под словом «делиться» стоит гораздо больше, чем выложить фоточки во ВКонтактик. А именно:

  • Выложить куда-нибудь фотографии на свой сервер с красивым и простым web-интерфейсом.
  • Просто и массово заливать и скачивать оригиналы изображений.
  • Иметь возможность разграничить доступ к определенным альбомам.
  • Попытаться связать это с локальным сетевым хранилищем, чтобы не дублировать фотографии.
  • По возможности удалять оригиналы фотографий с сервера через какое-то время и оставлять только фотографии с измененным размером.
  • По-максимуму бесплатно! :)

После таких мыслей в голове начинает зарождаться идея: «Надо накреативить...» — и ты уже не можешь остановиться.

Что сейчас предлагают фотохостинги?

Гугл нашел очень много облачных сервисов для выкладывания фотографий, предназначенных в основном для фотографов (и не только). Суть всех сервисов сводится к тому, что начиная с определенного объема надо платить фиксированную сумму в месяц. Если за полгода сумма не выглядит большой, то спустя два года она будет неприятным напоминанием. Аналогию можно провести с оплатой ru-доменов по 600 рублей в год в nic.ru и с постоянным напоминанием себе, что надо бы перевести уже эти домены к другим регистраторам :).

С другой стороны, если у вас уже есть какой-нибудь сервер, то надо использовать его по максимуму. Я нашел два проекта, которые в принципе бы смогли подойти под мои задачи. Это Piwigo [2] (бывший phpWebGallery) и Koken [3]. Последний проект вообще очень сильно порадовал. Но познакомившись с ними поближе, понял, что это мне тоже не подходит.

Dropbox, Skydrive, Google+ (Picasa), Яндекс.Фотки — вот эти ребята отлично выполняли свои функции до тех пор, пока места хватало.

Поделиться с друзьями

Хочу подробнее рассказать о том, что значит для меня термин «поделиться». После какого-то события (будь то поездка на природу или прогулки по городу), в котором принимают участие несколько человек, появляется много фоток. После обработки фотки (300-700 МБ) отправляются на местный NAS (Synology DS210j). И вот эту папку с NAS надо бы выложить в Интернет, чтобы её скачали те самые друзья, которые есть на фотках.
Загружать/скачивать через браузер такой объем — не для меня.

Но в конечном итоге хочется иметь ссылку на альбом, которую можно скинуть ещё кому-нибудь. Ну и список альбомов тоже неплохо было бы получить. Простой обычный процесс.

Самое главное, должны быть оригиналы фотографий и нормальный ресайз без фильтров (не то, что сейчас предлагают VK и остальные). Потом, когда у каждого будет 4К телевизор (как сейчас FullHD), будет очень здорово полистать свой фотоархив и ещё раз порадоваться.

BitTorrent Sync

После того, как я прочитал новости о выходе первой версии BTSyncа под все платформы — я все осознал. В моей голове четко выстроился алгоритм работы:

  1. Первоначальная заливка фотографий происходит через BitTorrent Sync.
  2. Пользователь неважно где расшаривает папку и получает readonly secret key, при этом он может сделать это на NAS или у себя локально.
  3. Далее пользователь идет в веб-интерфейс управления и добавляет альбом через readonly secret key.
  4. Веб-интерфейс посылает команду BTSync скачать вот эту папку на сервере. Постепенно начинается скачивание на сервер.
  5. В это время в кроне или ещё где идет проверка, скачалось ли все или нет (а-ля индексация файлов). Все файлы, например, добавляются в БД, и к ним создается уменьшенная копия (т.е. вся мета-информация попадает из оригинальных файлов в базу данных).
  6. Через какое-то время мы удаляем оригиналы с сервера (но! они сохраняются у пользователей, которые успели скачать).

У BTSync под Linux консольного API до сих пор нет. Но есть веб-интерфейс, который может выступать в качестве API-сервера. Вооружившись Go, я написал консольную утилиту [4] для работы с BTSync. Ну а потом сделал класс [5] для PHP. А дальше дело за малым: написать все остальное ;)

EazyPhoto

По основной своей специальности я php-программист. Верстка — это самое страшное для меня, что может быть:). Поэтому, взяв Foundation, я попытался что-нибудь на нем изобразить.
EazyPhoto: уютный фотохостинг для своего сервера
На главной странице мы видим список альбомов с названиями и датами. А на странице альбома — квадратные фотки с предпросмотром, как в дропбоксе. Если добавить к каждой фотке описание и задать её порядковый номер, то получится что-то типа блога. Размер больших фотографий для web-интерфейса я выбрал прямо как маркетолог — FullHD :)

Управление альбомами и фотографиями происходит внутри административной панели. Вот таким вражеским образом выглядит добавление нового альбома: достаточно заполнить название, дату начала и ReadOnly Secret.
EazyPhoto: уютный фотохостинг для своего сервера

На чем это все написано?

Проект написан на внутреннем движке Eaze [6]. Он далек от совершенства, но позволяет быстро решать определенные задачи в известный короткий промежуток времени. У него нет нормальной документации, но он же написан на PHP, поэтому чтобы что-то понять, достаточно заглянуть внутрь (прямо как в идеологии go-lang :).

База данных: выбрал mysql, потому что оно у всех есть. В основном тут интересны эти две таблички: albums и photos
EazyPhoto: уютный фотохостинг для своего сервера

Индексация файлов

Сначала я написал индексатор на PHP: он пробегал по новым альбомам, добавлял их в очередь на загрузку в BTSync, и потом пробегал по существующим и добавлял новые найденные файлы. Достаточно повесить скрипт в cron раз в 5 минут: и этого бы хватило. Но не мне.
Было бы круто, если бы фотки добавлялись в базу по мере их скачивания. И тут на помощь приходит Go.

eazyphotod

Небольшой демон, который висит и проверяет директории на наличие новых файлов. Создает превью для фотографий и сохраняет в базу. Общается с BTSync'ом. Вот его основные задачи.
Для реализации данных задач я воспользовался следующими пакетами:

Проверив в демо-проекте все необходимые функции, я начал собирать это все в рабочую версию. Потребовалось примерно два дня, чтобы получить готовый результат [13].

Как это работает?

eazyphotod запускается через upstart (в дальнейшем планирую переделать под supervisord). После запуска он загружает все альбомы в память и начинает сканирование директорий на наличие новых фотографий. Параллельно с этим запускается гоурутина на остлеживание изменений в файловой системе и на обработку HTTP запросов (обновить мета-информацию альбома и добавить новый альбом в очередь на скачку).
Все запросы (resize, обновление мета-информации, событие о новом файле) ставятся в одну очередь [14]:

var  SyncQueue  = make(chan *SyncItem) 
type SyncItem struct {
	Album    *model.Album
	FsPhotos model.PhotoList
	FullSync bool
	Filename string
}

Поэтому нет необходимости отслеживать одновременный доступ к map'ам и другим важным переменным. Все идет в одной общей очереди.
Работа с базой данных тоже получилась довольно простой [15].
Вообще, если вы думали писать на go, но все не решались — мой вам совет: возьмите и напишите уже что-нибудь на нем :)

И ещё одно: мои go-проекты на github по идеологии [16] размещены неправильно, т.к. в репозитории должна быть корневой только одна папка src. А у меня — целиком проект. Мне как-то не комфортно, когда рядом с исходным кодом в одной папке лежат примеры конфигов, README.md и прочие вспомогательные материалы.

Итог

Со своими задачами сервис вполне справляется: хранилище все время в сети, на нем установлен BTSync. После того, как фотографии отправлены на хранилище, папка добавлена в BTSync и веб-интерфейсе создан альбом — можно лечь спать. Сервер с eazyphoto сам скачает фотографии и добавит их в текущий альбом. Утром можно зайти, проверить, и отправить ссылку друзьям. А друзья уже при необходимости скачают оригиналы к себе через BitTorrent Sync.

Попробуй собери

Для тех, кто решил попробовать поднять это все у себя — вот ссылки:

  1. github.com/sergeyfast/eazyphoto-web [17] — php-часть
  2. github.com/sergeyfast/eazyphotod [13] — сам демон

Для тех, кто хочет потыкать и посмотреть пример

Ссылку на демо сознательно не публикую. Но Яндекс поможет найти по словам на черной плашке.

Все инструкции (или их подобие) находятся внутри проектов (open source такой open source :).

Установка вспомогательного софта на примере Ubuntu

1. Установим btsync:

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 [18]
Минимальная версия 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

Источник [19]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/php-2/40298

Ссылки в тексте:

[1] терабайт: http://habrahabr.ru/post/180383/

[2] Piwigo: http://piwigo.org/

[3] Koken: http://koken.me/

[4] консольную утилиту: https://github.com/sergeyfast/btsync-cli

[5] класс: https://github.com/sergeyfast/bittorrent-sync-client

[6] Eaze: http://wiki.eaze.ru

[7] code.google.com/p/gcfg/: http://code.google.com/p/gcfg/

[8] github.com/disintegration/imaging: https://github.com/disintegration/imaging

[9] github.com/go-sql-driver/mysql: https://github.com/go-sql-driver/mysql

[10] github.com/howeyc/fsnotify: https://github.com/howeyc/fsnotify

[11] github.com/rwcarlsen/goexif/exif: https://github.com/rwcarlsen/goexif/exif

[12] github.com/sergeyfast/btsync-cli/: https://github.com/sergeyfast/btsync-cli/

[13] готовый результат: https://github.com/sergeyfast/eazyphotod

[14] очередь: https://github.com/sergeyfast/eazyphotod/blob/master/src/sync.go#L215

[15] довольно простой: https://github.com/sergeyfast/eazyphotod/blob/master/src/model/queries.go

[16] по идеологии: http://golang.org/doc/code.html#Organization

[17] github.com/sergeyfast/eazyphoto-web: https://github.com/sergeyfast/eazyphoto-web

[18] blog.labix.org/2013/06/15/in-flight-deb-packages-of-go: http://blog.labix.org/2013/06/15/in-flight-deb-packages-of-go

[19] Источник: http://habrahabr.ru/post/188968/