Меня всегда интересовали разнообразные «плюшки» для социальных сетей с точки зрения маркетинга. А именно то, как быстро войдет этот очередной бред в массовое пользование и то, сколько сил будет затрачено на достижение данного эффекта. Ниже я расскажу результат того, что я узнал на примере нашей последней работы vkomg.com
Уже несколько лет работаю фрилансом в американской компании, ориентирующейся на веб-разработках. Работа вполне стандартная для среднестатистической фриланс конторки: доработка кривого кода, доставшегося по наследству от прошлых разработчиков проекта, плюшки и плагины для CMS, иногда неплохие масштабные стартапы. Все это, конечно, хорошо. Но давно известно, что мелкие, на первый взгляд никому не нужные вещи приносят отдачи намного больше. Поэтому, в один прекрасный день, увидев на фейсбуке новые профили, мы разработали сервис по созданию очередного
Пару дней назад, увидев, что на родном ВКонтакте появился точно такой же блок с фотографиями около главного фото, мы загорелись идеей переделать имеющийся фейсбуковский проект под вконтакте в первый же день.
Добившись довольно интересных результатов в США, не выложив на продвижение никаких средств со своего кармана, начав всего с одной ссылки в собственном профиле, стало очень интересно какие результаты покажет Россия.
Конкретные цифры, история, результаты и куски кода в продолжении поста.
UPD: Хабраэффект в действии. Ругаемся с техподдержкой за несоответсвие обещаной максимальной нагрузки действительности.
UPD2: Хостер исправился. Сервер в полном здравии.
С чего начать?
В качестве языка для разработки первого варианта для фейсбука был выбран PHP. Уже имелся багаж готовых кусков кода, а запуск ранее других аналогов был одним из главных требований. Именно это стало главной причиной выбора этого языка.
Главными возможностями и требованиями были:
- Ajax загрузка файла фотографии с индикатором прогресса;
- Предзагрузка элементов интерфейса для большего удобства пользователей;
- Легкая возможность позиционировать маску на фотографии;
- Предпросмотр;
- Возможность скачать готовые фотографии одним архивом;
- Возможность отражения фотографии по горизонтали без перезагрузки страницы;
- Отсутствие каких либо материальных вложений на рекламу.
Маска и формат файла
Сердцем, конечно же, является далеко не скрипт кропа фотографий, а JS маска, позволяющая пользователю наглядно выбрать именно тот кусок картинки, который будет использоваться в качестве будущего юзерпика.
Разумеется, как и любые другие ленивые разработчики, мы кинулись искать готовые скрипты, которые можно было бы доработать именно до того функционала, который нам нужен. После просмотра нескольких десятков страниц, выданных различными поисковиками, стало ясно, что придется писать с нуля свою собственную маску. Все готовые решения были либо очень кривыми, либо требовали не меньше времени на их доработку, чем написание собственного скрипта с нуля. Все делалось в сумасшедшей спешке, поэтому про оформление маски в виде нормального, адекватного плагина для jQuery не могло идти и речи. После того как основной функционал будет доделан, я планирую переписать скрипт с нуля в виде нормального плагина под jQuery с возможностью легкого использования в последующих продуктах.
Следующей интересной, но довольно простой в решении задачей было отражение фотографии по горизонтали. Требовалось выполнить это без перезагрузки страницы и, без какой либо дополнительной предварительной обработки фото на сервере и с поддержкой всех браузеров. Решение пришло довольно быстро. Отражение делается простым добавлением этого css класса к контейнеру фотографии.
.flip-x {
-moz-transform: scaleX(-1);
-webkit-transform: scaleX(-1);
-o-transform: scaleX(-1); /* Поддержка Opera */
transform: scaleX(-1);
filter: fliph; /* Поддержка IE */
}
На практике я легко убедился, что данный метод работает отлично во всех браузерах, включая Opera и IE. Тем не менее, этот метод имеет один главный, но очень несущественный недостаток. Если применить этот класс к тегу img, то при попытке сохранить браузером картинку, сохранится неотраженный оригинал.
Все серверные преобразования изображения выполнены при помощи ImageMagick. Отражение по горизонтали, например, выполняется следующим образом:
system("convert -flop /path/to/file/original.jpg /path/to/file/tmp.jpg");
Также, благодаря ImageMagick, легко добиться поддержки огромного числа форматов. Не только стандартных jpg, gif и png. Так как в качестве результата пользователь получает jpg, имеет смысл воспользоваться конвертером еще на этапе загрузки фото.
system("convert /path/to/file/original.ext /path/to/file/out.jpg",$result);
if ($result===0) {
// Конвертация завершена успешно.
}
Загрузчик
Процесс загрузки фотографии — это также важный момент, которому стоит уделить достаточно внимания. Так как все создавалось в ужасной спешке, первая версия загрузчика представляла собой элементарную enctype=«multipart/form-data» форму, содержащую два элемента: поле выбора файла и кнопку отправки. Уже в первый день начали поступать сообщения от пользователей с жалобами на невозможность загрузить файл. После анализа сообщений выяснилось, что их можно разделить на 2 категории:
- «Я нажимаю загрузить файл, а оно мне пишет, что сначала надо выбрать файл, но как я его выберу, если я даже не могу ничего загрузить?» (Да-да… полнейший бред, но не стоит недооценивать глупость пользователей, эти люди нажимали кнопку отправки, не выбрав файл в первом поле. Они считали, что сначала надо нажать кнопку «Загрузить фотографию», что приводило к неминуемой ошибке, которую они не были в силах осмыслить)
- «Я выбираю файл, нажимаю „Загрузить фотографию“ и все зависает. Почему?». (Пользователь пытается загрузить слишком большой по размеру файл, либо скорость его подключения достаточно невысока)
Решение данной проблемы очевидно. То, что отсутствие нормального загрузчика подорвет юзабилити, также было очевидно изначально, но спешка, как всегда, все портит. Маловажные, на первый взгляд, моменты вызовут множество проблем в будущем.
Для исправления ситуации был использован плагин для jQuery под названием Uploadify.
Плагин позволяет легко реализовать загрузку файла с индикатором процесса загрузки. Метод довольно стандартен: использование элемента на flash для асинхронной передачи данных. Главным плюсом этого плагина является легкость в настройке (огромное число параметров и коллбеков) и возможность настройки внешнего вида при помощи CSS
Следует также предусмотреть вариант использования для ненавистников флеша. (использование все той же стандартной формы для пользователей без Flash). Первый же запрос к поисковику выдает интересные результат: библиотеку для определения версии Flash со всевозможными немыслимыми методами.
HTML содержит сразу две формы: обычную multipart и форму с флеш элементами. Флеш форма по умолчанию скрыта от глаз пользователя.
if(FlashDetect.installed) {
$('#plainform').hide();
$('#ajaxform').show();
}
Таким образом, обычная форма легко подменяется Uploadify формой при условии наличия у конечного пользователя Flash.
Предпросмотр
Предпросмотр — очередная вещь, которая облегчает жизнь простому пользователю. Идея проста: сгенерировать картинки, позиционировать картинки при помощи CSS на универсальной заготовке для фона. Углубляться в детали не буду. Единственное о чем здесь стоит рассказать — это popup скрипт. Совсем недавно я столкнулся с продуктом под названием TopUp, который показал себя довольно убедительно и за долгую историю использования не вызвал ни одной проблемы.
Предзагрузка
Чтобы улучшить user experience на странице с формой, было принято решение осуществить предзагрузку всех картинок, использующихся на странице с маской (например, все медиа ресурсы TopUp, чтобы всплывающее окно появлялось мгновенно, без загрузки на глазах у пользователя). Причем подгрузка этих элементов не должна влиять на скорость рендера страницы с загрузчиком. Первое, что пришло на ум — подгрузка картинок при помощи JS:
function preload(sources)
{
var images = [];
for (i = 0, length = sources.length; i < length; ++i) {
images[i] = new Image();
images[i].src = sources[i];
}
}
$(window).load(function() {
$("#preload").attr('src','preload-step2.php');
preload([
"res/images/preview.png",
"res/images/top_up/dashboard/sprite.png",
"res/images/top_up/dashboard/close_link.png",
"res/images/top_up/dashboard/bottom_left.png",
"res/images/top_up/dashboard/top_right.png",
"res/images/top_up/dashboard/bottom_right.png",
..........................
..........................
"res/images/btn-flip.gif"]
)
});
Водяной знак
Далее встал вопрос о создании полупрозрачного водяного знака. Вспомнив, сколько манипуляций требуется для реализации водяного знака при помощи GD, я решил привлечь для этой цели все тот же ImageMagick.
system("composite -gravity south -alpha on /path/to/file/watermark.png /path/to/file/profile.jpg /path/to/file/profile.jpg');
Удаление устаревших файлов
Так как пользователь будет забирать архив с результатом не сразу, а спустя какое-то время, необходимо предусмотреть сценарий удаления устаревших временных файлов. Для каждого пользователя создается временная директория, содержащая все файлы данной сессии. Задача: ежедневно удалять все директории, созданные более 24 часов назад.
#!/bin/bash
for i in `find /path/to/dirs/ -maxdepth 1 -type d -mtime +1 -print`; do rm -rf $i; done
Цифры
А теперь, самое интересное — результат.
На раскрутку фейсбуковского оригинала не было затрачено никаких усилий и средств. Все, что мы сделали — это изменили свои собственные юзерпики и опубликовали url в ленте новостей на обозрение своим друзьям. Тем не менее, фейсбуковский оригинал вчера достиг посещаемости в 4000 уникальных посетителей в день (очень нескромный результат, для проекта возрастом менее месяца).
VkOMG начинался аналогично. Смена собственного аватара и публикация статуса с URL + одна таргет реклама с бюджетом 25 рублей, которая принесла всего 50 реферралов на официальную страницу ВКонтакте (именно на страницу ВК, а не на внешний url).
Тем не менее, вот наши скромные результаты за 4 дня работы:
- 1й день — 24 уникальных посетителя, 56 аватар создано.
- 2й день — 246 пользователей, 542 аватары создано.
- 3й день — 440 уникальных пользователей, 1408 аватар создано
- 4й день — 890 пользователей — 2486 аватар создано.