Тысяча и одна gif

в 11:47, , рубрики: Без рубрики

Всем привет!
Хотелось бы рассказать вам историю создания одного простенького развлекательного сервиса по записи gif’ок с веб-камеры при помощи HTML5 и JS. О том как решение на коленке на базе опенсорсных решений в одночасье произвело пусть хоть и маленький, но всплеск популярности волны от которого уже на протяжении полугода приносят небольшое количество посетителей которым полезен этот сервис.

А началось все просто

В конце лета обычным рабочим днем бороздя просторы GitHub я наткнулся на довольно интересный скрипт (facetogif) на нативном JS и HTML5 позволяющий записывать ролики с веб-камеры в gif-анимацию. Была приложена даже рабочая демка заливающая готовые ролики на сервис imgur или позволяющая сохранить их сразу на жестком диске.
Эта идея показалась мне очень интересной и я решил с небольшими переделками реализовать ее в виде самостоятельного сервиса.
Сказано — сделано. В тот же вечер я форкнул репозиторий, зарегистрировал домен «вгиф.рф», поднял VPS (самый дешевый тариф за 5$) на DigitalOcean и написал простейший скрипт на php складирующий ролики прямо там на сервере.
Для экономии ресурсов на сервер установил только Nginx и PHP-FPM.

Тысяча и одна gif
первая версия сайта

На следующее утро я поделился ссылкой на новоявленный сервис друзьям на одном закрытом сообществе. И сервис встретили хорошо =) Постепенно в перерывах между работой я занялся небольшими доделками — добавил кнопки шаринга в VK и Twitter, а также подредактировал js чтобы можно было делать ролики только одного размера (для унификации). Ночью того же дня понял что домен в зоне рф это довольно плохая идея и зарегистрировал более красивый и интересный домен togif.me, на котором сервис и по сей день.
Наступила долгожданная суббота и я с самого утра решил заняться сайтом. Для начала сделал большой и красивый мануал с картинками и собой в главной роли, а затем выложил ее на развлекательном сайте Pikabu и стал ждать минусов (там рейтинговая система схожая с Reddit и Хабром). И тут стали появляться один за одним комментарии, с минусами вместе пошли и плюсы, а затем уже я заметил что свободное место на VPS стало постепенно уменьшаться. Поздно спохватился с прикручиванием Яндекс.Метрики. Прикрученная поздно вечером она показала около 700 уникальных посетителей. В то время к посту на Пикабу было уже около 500 комментариев. Ну а затем кто-то добрый выложил ссылку на сервис в посте на Joyreactor и посещаемость увеличилась вновь! В воскресенье счетчик метрики застыл на отметке в 8 с лишним тысяч посетителей и 12 тысяч просмотров!

Тысяча и одна gif

Технические подробности

И тут я понял что допустил одну досадную ошибку. Ролик можно было скачать или загрузить, но при загрузке пользователю выдавалась только скучная прямая ссылка на gif-файл. Не хватало каталога загруженных роликов чтобы можно было не только записать свой, но и посмотреть на других посетителей сайта!
Настала пора переписывать “сервис” который состоял из 1 статичной html-страницы, 1 опенсорсного js и скрипта upload.php.

Вариант 1

Так как поток посетителей не прерывался, а каталог хотелось здесь и сейчас то я накидал простенькую схему БД MySQL, подключил Idiorm для запросов к БД в стиле ООП, написал простенькие роутинги для отображения страниц каталога и самих картинок и еще добавил Disqus для возможности комментирования каждого ролика.
Где то в тот же период я стал эксперементировать со сжатием роликов и оказалось что imagemagick сжимает каждый из них минимум на 30%, а то и на все 70% =)
Связано это с тем что ролики генерируютя посредством js в браузере когда каждый фрейм снимается отдельно и затем они складываются в ролик. При этом подходе одинаковые части кадров повторяются в каждом фрейме.

За это время количество посетителей плавно таяло (с 1000 уников до 300 в течение сентября), но меня это не сильно беспокоило т.к. сервис сделан чисто себе в удовольствие и я радовался каждому новому записанному ролику. Очень приятно осознавать что сделал пусть что-то очень простое и не совсем свое, но полезное.

Далее я решил переписать все на Yii Framework и получился:

Вариант 2

Тысяча и одна gif

Новшества:

  • галочка для “непубличных” роликов (не отображаются в каталоге)- хранение новых загруженных роликов в 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;
      }
    }
  }

Ну и отзеркаливание роликов я добавил по той причине что если записывать ролик в обычном режиме то на ролике ваша правая рука станет левой и наоброт. Поэтому для перфекционистов я добавил подобный режим.

Более безопасные ссылки я начал генерировать для защиты пользователей от полного скачивания архивов тупым перебором ссылок т.к. те кто доверился мне и загрузил на сервер приватные ролики должны заслуживать защиты. Алгоритм по понятным причинам раскрывать не буду.

За это время основной сайт успел переехать с VPS на DigitalOcean на облачную виртуалку в Selectel, а старые ролики остались на месте и для ссылок вида togif.me/image/xxx.gif стали работать автоматические редиректы на old.togif.me/image/xxx.gif

Затем при отсутствии существенных плюсов и более высокой стоимости решения (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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js