Всем привет!
Хотелось бы рассказать вам историю создания одного простенького развлекательного сервиса по записи gif’ок с веб-камеры при помощи HTML5 и JS. О том как решение на коленке на базе опенсорсных решений в одночасье произвело пусть хоть и маленький, но всплеск популярности волны от которого уже на протяжении полугода приносят небольшое количество посетителей которым полезен этот сервис.
А началось все просто
В конце лета обычным рабочим днем бороздя просторы GitHub я наткнулся на довольно интересный скрипт (facetogif) на нативном JS и HTML5 позволяющий записывать ролики с веб-камеры в gif-анимацию. Была приложена даже рабочая демка заливающая готовые ролики на сервис imgur или позволяющая сохранить их сразу на жестком диске.
Эта идея показалась мне очень интересной и я решил с небольшими переделками реализовать ее в виде самостоятельного сервиса.
Сказано — сделано. В тот же вечер я форкнул репозиторий, зарегистрировал домен «вгиф.рф», поднял
Для экономии ресурсов на сервер установил только Nginx и PHP-FPM.
первая версия сайта
На следующее утро я поделился ссылкой на новоявленный сервис друзьям на одном закрытом сообществе. И сервис встретили хорошо =) Постепенно в перерывах между работой я занялся небольшими доделками — добавил кнопки шаринга в VK и Twitter, а также подредактировал js чтобы можно было делать ролики только одного размера (для унификации). Ночью того же дня понял что домен в зоне рф это довольно плохая идея и зарегистрировал более красивый и интересный домен togif.me, на котором сервис и по сей день.
Наступила долгожданная суббота и я с самого утра решил заняться сайтом. Для начала сделал большой и красивый мануал с картинками и собой в главной роли, а затем выложил ее на развлекательном сайте Pikabu и стал ждать минусов (там рейтинговая система схожая с Reddit и Хабром). И тут стали появляться один за одним комментарии, с минусами вместе пошли и плюсы, а затем уже я заметил что свободное место на
Технические подробности
И тут я понял что допустил одну досадную ошибку. Ролик можно было скачать или загрузить, но при загрузке пользователю выдавалась только скучная прямая ссылка на gif-файл. Не хватало каталога загруженных роликов чтобы можно было не только записать свой, но и посмотреть на других посетителей сайта!
Настала пора переписывать “сервис” который состоял из 1 статичной html-страницы, 1 опенсорсного js и скрипта upload.php.
Вариант 1
Так как поток посетителей не прерывался, а каталог хотелось здесь и сейчас то я накидал простенькую схему БД MySQL, подключил Idiorm для запросов к БД в стиле ООП, написал простенькие роутинги для отображения страниц каталога и самих картинок и еще добавил Disqus для возможности комментирования каждого ролика.
Где то в тот же период я стал эксперементировать со сжатием роликов и оказалось что imagemagick сжимает каждый из них минимум на 30%, а то и на все 70% =)
Связано это с тем что ролики генерируютя посредством js в браузере когда каждый фрейм снимается отдельно и затем они складываются в ролик. При этом подходе одинаковые части кадров повторяются в каждом фрейме.
За это время количество посетителей плавно таяло (с 1000 уников до 300 в течение сентября), но меня это не сильно беспокоило т.к. сервис сделан чисто себе в удовольствие и я радовался каждому новому записанному ролику. Очень приятно осознавать что сделал пусть что-то очень простое и не совсем свое, но полезное.
Далее я решил переписать все на Yii Framework и получился:
Вариант 2
Новшества:
- галочка для “непубличных” роликов (не отображаются в каталоге)- хранение новых загруженных роликов в Selectel storage
- генерация превьюшек при помощи imagemagick
- нанесение на ролики ватермарки со ссылкой на сайт (прямо во время записи)
- отдельная страничка с FAQ
- подсчет количества просмотров каждого ролика
- генерация более безопасных ссылок с рандомным количеством символов и добавлением даты (вместо /image/4r32njfi3.gif стало /2014/04/5e7eaed8bd.gif)
- возможность «отзеркаливания» записи
Хранение роликов я перенес в selectel storage т.к. захотелось более быстрой отдачи файлов для конечных посетителей. Готовый php-класс я позаимствовал у Eugene Smith на GitHub.
Для узнаваемости сайта было решено добавлять к каждому записанному ролику ватермарку. Причем хотелось чтобы даже просто сохраненный с браузера ролик уже ее имел. Для этой задачи я решил нагрузить пользовательские ресурсы и вот что получилось:
function recorder_fn(ctx, gif, frames) {
var coords = facetogif.recorderFrame(),
drawW = facetogif.gifSettings.w,
drawH = facetogif.gifSettings.h;
if(facetogif.p_flag==0 && facetogif.scale==1) {
ctx.translate(coords.w, 0);
ctx.scale(-1, 1);
}
return function () {
if (facetogif.video.src) {
ctx.drawImage(facetogif.video, coords.x,coords.y, coords.w,coords.h);
if (facetogif.scale==1) {
//Грязный хак с переворотами =)
ctx.translate(coords.w, 0);
ctx.scale(-1, 1);
ctx.fillStyle = "white";
ctx.font = "normal 20px Arial";
ctx.textBaseline = 'top';
ctx.fillText("ToGIF.me", 220, 220);
ctx.translate(coords.w, 0);
ctx.scale(-1, 1);
}
else {
//наложение ватермарки begin
ctx.fillStyle = "white";
ctx.font = "normal 20px Arial";
ctx.textBaseline = 'top';
ctx.fillText("ToGIF.me", 220, 220);
//наложение ватермарки end
}
var frame = ctx.getImageData(0,0, drawW,drawH);
frames.push(frame);
gif.addFrame(frame, {delay: facetogif.gifSettings.ms});
} else {
clearInterval(recorder.interval);
facetogif.recIndicator.classList.remove('on');
recorder.state = recorder.states.IDLE;
}
}
}
Ну и отзеркаливание роликов я добавил по той причине что если записывать ролик в обычном режиме то на ролике ваша правая рука станет левой и наоброт. Поэтому для перфекционистов я добавил подобный режим.
Более безопасные ссылки я начал генерировать для защиты пользователей от полного скачивания архивов тупым перебором ссылок т.к. те кто доверился мне и загрузил на сервер приватные ролики должны заслуживать защиты. Алгоритм по понятным причинам раскрывать не буду.
За это время основной сайт успел переехать с
Затем при отсутствии существенных плюсов и более высокой стоимости решения (5$ + 300 руб. + 150 руб. каждый месяц) для сайта по фану было решено начать экономить.
Новая конфигурация включает в себя — мощный шаред-хостинг на сервере вскладчину и selectel storage для новых роликов. Для каждой порции в 10Gb гифок я решил создавать отдельный поддомен и по набору этого объема я стал их переносить на шаред-хостинг т.к. места там много, траффик не лимитируется и скорость отдачи не так важна ибо ролики уже не новые.
Облачное же хранилище с высокими скоростями остается только для новых роликов которые отдаются и сохраняются с высокими скоростями. Теперь затраты на сайт около 200 руб. в месяц что в принципе терпимо.
Текущий стек технологий:
Nginx, Imagemagick, HTML5, JS, PHP, Yii, MySQL
Нерешенные проблемы:
- не работает запись роликов в Safari
- не работает запись роликов в Iphone,Ipad
Немного статистики:
- Запуск сервиса — 22.08.13
- Трафик за данный период — ~1Tb
- Загружено роликов — ~15000
- Уникальных посетителей — ~80 000
Выводы:
- Для каких то тяжелых операций иногда можно нагружать клиентские компьютеры и клиентский JS в этом случае является спасительным кругом
- Для тяжелых операций на сервере целесообразно применять что-то более производительное чем php. Картинки например оптимизируются утилитой convert
- Yii показывает довольно выскокую скорость работы даже без встроенного кеширования, но нужно обязательно включать настройки для production mode
- Flash постепенно уходит, но есть еще куча устройств и программ которые не поддерживают новомодные фичи HTML5
Вот так используя опенсорс-решения можно сделать довольно интересный и полезный людям проект который пусть и без прибыли, но и без особых затрат продолжает кого-то радовать.
Автор: rhamdeew