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

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

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

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



первая версия сайта

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



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

И тут я понял что допустил одну досадную ошибку. Ролик можно было скачать или загрузить, но при загрузке пользователю выдавалась только скучная прямая ссылка на 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;
      }
    }
  }


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

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

За это время основной сайт успел переехать с 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


Вот так используя опенсорс-решения можно сделать довольно интересный и полезный людям проект который пусть и без прибыли, но и без особых затрат продолжает кого-то радовать.
Поделиться публикацией
Комментарии 37
    +4
    Не сразу понял, где же ссылка на сам сайт. Подумал-подумал, и понял: togif.me/
      +15
      Я внимательно читал правила Хабра. Там пишут что ссылки на свои ресурсы вне «Я пиарюсь» нельзя. Потому и не запостил =)
      image
        +7
        image
          +1
          А чо там девок так много? И да, обнаружена картинка очень похожая на ЦП
            +3
            Скиньте id в личку — обязательно удалю.
              +1
              Было бы круто и удобно, если бы на сайте была кнопка «пожаловаться» для подобных ситуаций. И вам было бы удобнее видеть все жалобы в одном месте на сайте, и тут же удалять картинки, если жалоба — легитимная. Это работает быстрее, чем чтение писем.

              Так же, вы себе очень облегчите работу (и освободите кучу времени, которую можно потратить более продуктивно), если дадите зарегистрированным пользователям самостоятельно удалять свои картинки.
        +5
        Была не плохая статья habrahabr.ru/company/flysoft/blog/191892/ где автор делится опытом оптимизации анимированных gif, путём конвертирования их в WebM-видео формат. Хотя ситуация несколько специфичная, но позволила сэкономить на объёме исходящего трафика.
          +4
          Я ее читал и даже очень хотел заморочиться перекодированием в WebM. Уж очень сильно трафик экономится. Но для большей совместимости решил оставить старый добрый gif.
            +2
            fallback в gif никто не отменял. А так как процент пользователей, которые смогут вкусить все радости html5 видео уже довольно велик, экономия на трафике так же будет не маленькой.
              0
              Ну если проект будет жить то заморочусь наверное — сама тема также очень интересна.
          +4
          Знаете, это очень интересная идея, а особенно если ее встроить в систему комментариев. Вместо вставки смайлов и меммов, вставлять в комментарии снятые гифки, мне кажется многим понравилось бы.
            +6
            Ага комментарии наполненные гифками весом по 1,5-2 Мб каждая. Пожалейте мой gprs'ез ))
              +1
              Да, gprs это тяжёлый случай, но ведь можно оптимизировать эти самые гифки, да и у большинства скорость интернета 1мб/с и выше.
              +5
              Могу скинуть ссылку на страничку с ~700 комментариев где через один коммент идут гифки =)
              На ноуте сразу начинает сильно шуметь кулер и скроллится оно довольно небыстро.
              +5
              Хорошо если сделать как на большинстве популярных ресурсов когда у анимаций отобпажается только превью с 1 кадром, а остальное подгружается при клике. Кстати можно будет заморочиться с виджетом для реализации подобного эффекта на сторонних сайтах. Спасибо!
                0
                И ещё, что бы отображалась уменьшенная картинка, а не полноразмерная ;)
                  0
                  320x240 это много? )
                    0
                    Не много, но поскольку

                    >>можно будет заморочиться с виджетом

                    думаю будет разумным в короткой форме указывать и класс разрешения, кому нибудь да пригодится :)
              +2
              Спасибо за сервис! Постил пару картинок оттуда на developerslife… =)
                +3
                Вам спасибо! Один из первых бета-тестеров как-никак =)
                +2
                Каким-то чудом ваш сайт обошли стороной извращенцы-эксгибиционисты ))))
                  0
                  Если вставить ссылку на сайт в фейсбуке — он выдаст в качестве картинок порнуху.
                  UPD. А, уже «полилось»…
                    0
                    Ну это петросяны-юмористы у которых еще 1 апреля до сих пор. Гордые махальцы писюном также были — но они оперативно удаляются =)
                    +1
                    Ну это пока :)
                    +28
                    image

                    полезный сервис ))
                      +8
                      А главное интересный!
                      image
                      +1
                      Собирали ли статистику с nginx'а? Сколько и с каких ресурсов запрашивалось? На каких мощностях крутился nginx и какую нагрузку выдерживал, поделитесь цифрами, если таковые имеются. Спасибо!
                        0
                        Долгое время сервис жил на VPS 1 ядро, 512MB RAM и 20Gb SSD. LA в пик поднимался максимум до 1. Максимум было за сутки около 9к уников и 12 тысяч просмотров. Вообще на самом деле это очень небольшая нагрузка. Самый узкий момент это оптимизация gif'ок и заливка их в облако — тут просто процессы долго висели пока ждали выполнения этих процедур. Nginx падать даже и не собирался =)

                        Сегодня днем сайт испытывал небольшие трудности, но все из-за тяжелых воркеров Apache который то и дело ложился (на том сервере традиционно Nginx+Apache+mod_php+MySQL).
                        Дабы не подставлять соседей по серверу оперативно перенес сайт на конфигурацию с 2 ядрами, 2Gb RAM и 40Gb SSD. Оставил Nginx+PHP-FPM+MySQL и дополнительно установил APC — LA на уровне 0.01-0.10, RAM всего 160Mb занято. В принципе мог бы и на самой минимальной конфигурации все это дело крутить без проблем. За сегодня вчера около 2к уников и ~35к просмотров.
                          0
                          Спасибо! А что по поводу статистики?
                            0
                            Вы конкретно про статистику Nginx? Собрать точную статистику не представляется возможным по нескольким причинам:
                            1) Ролики раздаются с 4 различых хостов которые в различное время были на разных серверах
                            2) Вчера чтобы не мешать соседям по серверу переехал на отдельный сервер. Там включил только логи ошибок.

                            С посещаемостью около 100 уников в день выходило около 80-100 гигабайт трафика в месяц. Есть только статистика Яндекс.Метрики общие данные по которой мне не жаль показать и статистика с selectel storage где за 5 месяцев набежало 550Gb трафика только на раздаче роликов.

                            Но все же еще раз скажу — такая нагрузка даже для слабеньких конфигураций вообще не нагрузка.
                        0
                        generated by togif.me
                          0
                          Герой DOOM!
                          0
                          Почему-то ссылку не хочет отдавать. При нажатии на «получить ссылку». «загрузка» уже минут 10 висит, а ссылку не отдаёт. Хабраэффект? На всякий случай вот айди сгенерённой гифки: blob:d1bc766b-ae36-48e5-8fc5-ca6e6db3d59d
                            0
                            Не думаю что в 7 утра по МСК он имеет место быть =)
                            Могу лишь посоветовать сохранить ролик на диск если он очень долго висит в загрузке в облако. К сожалению есть такие проблемы, случается нечасто, но бывает.
                            0
                            При перелистывании страниц все прыгает. Может сделать фиксированной высоту картинок?
                              0
                              Да, этим займусь в ближайшее свободное время. Там еще есть проблема с адаптивностью. А все потому что проект делается в свободное от работы время которое довольно ограничено.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                            Самое читаемое