Такой макет
71 subscribers
7 photos
16 links
Разработчик журнала «Нож»

Пишу о сервисах, технологиях и обо всем, что касается разработки изданий в интернете.

Связаться со мной можно здесь: @lukin
Download Telegram
to view and join the conversation
Channel created
С 80 версии в Chrome по умолчанию включена возможность, позволяющая пользователю или автору дать ссылку на текстовый фрагмент. Для примера, ссылка на конкретный абзац статьи Ножа:

https://knife.media/dopanomics/#:~:text=In%202001,%20Stanford

Выключить функцию можно в настройках:
chrome://flags/#enable-text-fragment-anchor


Ссылка на документацию: https://github.com/WICG/ScrollToTextFragment/
Не так давно команда Google Fonts обновила свой api, добавив возможность использования вариативных шрифтов.

Ссылка на докуменатцию: https://developers.google.com/fonts/docs/css2

Важно помнить, что шрифты – сравнительно тяжлый ресурс, а загрузка их должна быть моментальной, чтобы пользователь сразу видел текст.

Если на странице используется всего несколько статичных заголовков, набранных особенным шрифтом, то в запросе можно использовать параметр &text=. В таком случае cdn вернет клиенту скомпилированный шрифт с нужными буквами. Этот прием также работает и для первой версии api.
This media is not supported in your browser
VIEW IN TELEGRAM
Раз уж я начал вести канал, то наконец-то пришло время разобраться, как добавлять ссылку на слово в телеграм сообщениях. Оказывается, в нативном клиенте для macos есть встроенная функция преобразваний текста. Там можно заодно и прописные на строчные заменить, если забыли отключить caps.

Об этом я, кстати, узнал в одном из issue репозитория приложения. У проектов с открытыми исходниками очень часто можно найти ответы на свои вопросы в трекере. Либо задать там же.
Есть такая штука, которая называется SSI. Больше 10 лет назад я познакомился с этой технологией, когда на бесплатных тарифах хостингов не было поддержки php, но Server Side Includes были доступны. С их помощью можно было собрать простой сайт, динамически подключая разные части директивой include.
Поддержка SSI и сейчас включена в nginx из коробки, и может использоваться, например, для кэширования динамики в highload проектах.

На днях мне потребовалось сделать несколько статичных страниц с результатами теста для шаринга в социалки. К сожалению, фейсбук не позволяет подставлять параметры заголовка и описания на клиенте.
Весь проект был сделан на клиентском js, и использовать интерпретатор выглядело как оверинжиниринг. С помощью SSI это задачу можно решить средствами одного лишь вебсервера.

Нужно только прокинуть параметр запроса с результатом в шаблон и отобразить его в нужных тегах. Тут можно посмотреть, как это работает, а здесь полная документация к настройкам модуля для nginx.
В SSI шаблонах можно реализовать и гораздо более продвинутую функциональность, в том числе условное форматирование или даже рандом на основе регулярных выражений. И все это будет работать очень быстро и без дополнительных настроек окружения.
Не хочется превращать канал в обзор функциональности программ, но мимо такой штуки просто не могу пройти. Оказывается в Chrome можно без расширений сделать полный скриншот страницы. Это бывает очень полезно, когда нужно показать сайт по всей его высоте безо всяких подклеиваний.

Открываем консоль разработки (cmd+option+i / ctrl+shift+i), запускаем командное меню (cmd+shift+p / ctrl+shift+p) и выбираем Capture full size screenshot. После этого в папку загрузок автоматически сохранится скриншот в png.
This media is not supported in your browser
VIEW IN TELEGRAM
У нас на Ноже все слова в урле разделены дефисом. Заменять пробел подчеркиванием не рекомендуется. Дефис делит имя записи на слова, а подчекривание превращает два слова в единую сущность. Это касается не только адреса. Попробуйте в любом редакторе два раза щелкнуть на слово с дефисом – выделится только одна его часть. То же самое при перемещении по тексту при помощью клавиатуры (alt + →).

Это правило имеет значение и при индексации. Google напрямую об этом упоминает в своих рекомендациях для вебмастеров. Хотя хороший контрпример – Википедия, но не все могут себе позволить быть Википедией.
Где-то год назад Telegram пометил чат Тупого ножа как материалы для взрослых. Мы долго пытались убрать эту отметку, написав на все возможные адреса техподдержки, но все безуспешно – у пользователей iOS доступа к чату нет.

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

https://te.legra.ph/telegram-adult-06-18
Последний год с разной степенью успеха я борюсь с фейсбуком. Если быть точнее, то со счетчиком на кнопках шаринга. В определенный момент фб запретил получать эти данные без ключа авторизации, тогда я нашел недокументированный способ, который вскоре тоже перестал работать.

Мне удалось хитро обойти компрометацию токена на клиенте через проксирование запроса на nginx, но фейсбук и тут меня обошел, понизив лимит на количество запросов к API до 200 в час в расчете на количество пользователей приложения, которых у нас всего 1. В качестве временной альтернативы мне повезло найти такой же спроксированный API от крупного разработчика, у которого, видимо, эти лимиты сильно выше.

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

С помощью lua модуля от openresty, я написал правило, которое проксирует запрос к фб, получает содержимое этой кнопки, ищет там значение счетчика расшариваний и заворачивает в простой jsonp ответ. Все это должно работать очень быстро, а для надежности еще можно закешировать ответ с помощью proxy_cache минут на 20. Этот прекрасный модуль идет в пакете nginx-extras и для Debian совместимых систем ставится одной командой sudo apt install nginx-extras.

Код для nginx конфига: https://gist.github.com/antonlukin/69a19b2b0b9404e432b1edd9fddd14ff

Раунд, фейсбук.
3 сентября

Решил периодически писать о своих микропроектах. Начну с сайта к песне Шуфутинского про 3 сентября, тем более, что есть хороший повод – 4 годовщина со дня его запуска.

В 2016 году мы с дизайнером и разработчиком Лайфхакера на коленке за 2 вечера сделали первую версию сайта. На фоне играло видео с YouTube, а календарь переворачивался неестественно через центр. Тогда на сайт пришло чуть меньше 10 000 пользователей. С каждым годом эта цифра будет увеличиваться.

2017 год запомнился только тем, что сайт периодически падал с ошибкой Too many open files, которая решалась добавлением в конфиг nginx инструкции worker_rlimit_nofile 10240. В тот год календарь покрутило около 11 000 человек.

На 2018 год пришелся пик популярности. Про сайт написал Нож и упомянула Meduza. Всего пришло больше 52 000 пользователей. Большинство из соцсетей. Надо ли говорить, что об обновлении сайта я вспомнил вечером 2 сентября и прямо на живых пользователях пытался исправить проблему с автоматическим воспроизведением видео – YouTube зачем-то отключил такую возможность по умолчанию.

К сентябрю 2019-го я готовился заранее. Было понятно, что основной трафик теперь мобильный, а там видео на фоне совсем не работает. Поэтому я выкинул ролик, заменив на аудиодорожку. Починил переворот календаря и добавил вебсокеты – теперь число общих переворотов обновлялась в режиме реального времени. Все знакомые мне говорили, что тренд спал, и на сайт никто не придет, да и мне самому уже невероятно надоела эта тема. Однако, как это часто бывает, до мемеса спустя годы добрались крупные игроки. Свои календари сделали Pikabu и Лентач совместо с ВКонтакте, что вернуло интерес к теме, и транзитивно привело ко мне на сайт почти 50 000 человек.

В 2020 я все же решил вернуть на сайт видео, потому что без него выходило уж совсем скучно. Но от YouTube сразу было решено отказаться в пользу своего CDN. Благо теперь мобильные бразуеры дают возможность показывать видео на фоне сайта, если у него по умолчанию отключен звук. Также я добавил генератор обложек для шаринга. Теперь на них отображается число переворотов календаря.

Прогнозировать трафик не берусь, но кажется, что лавочку пора закрывать.
Интеграция AdFox и Premium-режим на Ноже

Как и почти любое медиа в рунете мы используем баннерокрутилку. Начинали со своих велосипедов, но быстро пришли к тому, что нужно ставить AdFox как стандарт индустрии. С первой попытки, конечно, сам черт ногу сломит в интерфейсе этой чудесной системы, но со временем начинаешь понимать что к чему.

Первая претензия у меня была к тому, как адфокс грузится на страницу – нужно добавить библиотеку и несколько блоков с кодом в тех местах, где должны крутиться баннеры. Проблема в том, что баннер может и не загрузиться, но блок останется. Это ломало нам залипание виджетов в сайдбаре. Второй неприятный момент – синхронная загрузка скрипта библиотеки. Если адфокс, который теперь Яндекс, не грузится или заблокирован (привет Украина), то мы подвесим загрузку всего сайта на неопредленный срок.

В итоге я написал скрипт, который реализует особую логику взаимодействия с адфокс:
- ищем на странице все виджеты с баннерами;
- подставляем в URL-запроса баннера специальные параметры, указывающие адфоксу, на какой странице мы сейчас находимся (шаблон, автор, категория, формат итд);
- добавляем callback – если баннер не загрузится, то удаляем его, иначе – отображаем;
- асинхронно загружаем основную библиотеку адфокс.

Помимо этого, скрипт может управлять видимостью загруженных баннеров. Например, один из форматов – кнопка внизу экрана. Так как она может перекрывать контент, мы решили рисовать на ней крестик, который убирает баннер со страницы на 8 часов. Для анализа данных клик по крестику вызывает событие, которое тоже передается в адфокс.

Теперь про Premium-режим. В рамках рекламного проекта необходимо было отображать специальный тумблер, который переключает дизайн сайта и при этом грузится и обсчитывается через адфокс. По своей сути сам переключатель – это просто баннер. Но что делать, если пользователь включил режим на одной странице, а на второй этот баннер по какой-то причине не загрузился? Пользователя выбросит из премиума без возможности вернуться. Решение – грузить отдельный скрипт независимо от адфокс, который будет проверять, был ли уже включен режим, и если да, то показывать сразу его.

В итоге баннер в адфоксе из себя представляет простую функцию передачи трекинговых ссылок и событий, которые при первой загрузке сохраняются в локальное хранилище. Всю остальную работу берет на себя отдельный скрипт, который грузится синхронно с нашего сервера.

На работу Premium-режима можно было посмотреть на https://knife.media без адблока.
Digitalocean выставил Ножу счет за декабрь, начислив почти $200 за перерасход трафика. При том, что сам сервер стоит всего $40.

Дело в том, что где-то месяц назад я решил отключить Cloudflare потому что он периодически преподносил неприятные сюрпризы – обрывал соединение или вообще падал с ошибкой при двойном проксировании.

В итоге я пока включил кэширование на Cloudflare только для папки с загрузками, буду следить за ситуацией. На графике выше кривая трафика до и после включения прокси. Результат, конечно, впечатляющий. Нагрузка на процессор, кстати, тоже существенно снизилась.
Комментарии на Ноже

В конце лета мы запустили собственные комментарии на Ноже. Они пришли на замену HyperComments. От последних пришлось отказаться в первую очередь из-за отсутствия внятной модерации и крайне печальной техподдержке даже на Enterprise тарифе. Например, нам так и не удалось добавить почту модератора на Google Apps.

С одной стороны, мне хотелось максимально упростить комментарии и сделать их автономными от основного сайта, с другой – нужно было сохранить возможность удалять спам и банить пользователей, залогинившись в админку WordPress. Поэтому я решил написать отдельный сервис на nodejs, который реализует интерфейс авторизации через соцсети, добавление комментариев и простейшую систему рейтингов. А модерация работает путем прямых запросов к удаленной базе данных для всех пользователей с ролью выше автора в WordPress.

На все я потратил примерно полтора месяца с перерывами на другие задачи. Около недели делал API, две недели писал импорт комментариев из HyperComments, остальное время писал фронтенд и связывал все части проекта.

Сейчас в базе около 25000 комментариев и 19000 пользователей, из них более 5000 новых. За спамом следит Telegram бот, который присылает в чат на проверку все ссылки, адреса электронной почты и прочие подозрительные вещи. В среднем на модерацию приходит около 15 комментариев в неделю. Из них 2-3 нужно удалять. Из интересной статистики: больше всего авторизовываются через Google и ВКонтакте, а вот Яндекс сильно отстает.

Еще из смешного. На Ноже есть пост, рассказывающий о сайте для криков. Далее цитата: «Идея сайта бесконечно проста: вы переходите по ссылке, вводите секретное слово TEETH и кричите». В общем ничего удивительного, что под самим постом на Ноже 500 комментариев со словом TEETH. Присоединяйтесь и вы.
Совсем недавно состоялся мажорный релиз WordPress. И мне очень радостно, что я стал частью этого большого проекта.

Несколько месяцев назад я заметил, что на Ноже ко всем тегам <aside> в статьях добавляется аттрибут target. Быстро стало понятно, что ошибка кроется в функции движка links_add_target, а точнее в неправильно сформированном регулярном выражении. Поискав по трекеру WordPress, и не найдя ничего на эту тему, я открыл новый тикет и пошел разбираться, как контрибутить в ядро. Все оказалось достаточно просто – у движка есть зеркало для разработки на Github. И туда можно отправить Pull Request. После проверки оставалось только ждать когда фикс уйдет в релиз.

Единственная моя заслуга, конечно, состояла в том, что мне посчастливилось наткнуться на этот баг. Но я очень доволен такому опыту и в будущем постарась найти время для исправления чего-то более серьезного.

Картинка себе на память.
Про пароли

Около 10 лет назад я ввел для себя систему генерации паролей, которую использовал по сегодняшний день при регистрации на большинстве сайтов. Не знаю ни одного случая компрометации моего алгоритма, но все же решил, что пора его поменять. А о старой технике как раз расскажу.

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

Для генерации статичной части пароля можно воспользоваться каким-то мнемоническим правилом. Частый пример – первые буквы слов какого-нибудь четверостишия. Например, MsNvViVs (муха села на варенье, вот и все стихотворение). К этому нужно добавить пару цифр для осложнения перебора. Например дату рождения бабушки наоборот (2-05 станет 50-2). В моем случае статичная строка пароля была случайной и я просто ее запомнил.

Теперь к динамической части. В общем случае каждый новый аккаунт регистрируется на каком-то отдельном сайте, из домена которого можно получить что-то с виду случайное, но по факту всегда одинаковое. Например, можно посчитать количество символов в домене, вычесть это из 100 и перевернуть число (для avito.ru это будет 100-8 = 92 => 29). Либо можно брать 5 букву доменного имени или следующую за ней. В этом месте, конечно, лучше придумать что-то свое. Достаточно простое, чтобы не приходилось каждый раз долго вычислять, при этом достаточно сложное, чтобы сходу было невозможно понять алгоритм.

Осталось поженить 2 части. Тут тоже есть хитрость. Можно добавлять динамическую порцию в какое-то определенное место статической части. Например, одну половину сначала, а другую – в конце, либо придумать что-то более изощренное. На чужих устройствах я использовал перенос каретки, чтобы обмануть кейлогеры. Т.е вводил часть пароля, затем мышкой тыкал в нужное место и вводил остальную часть. Но для большинства ситуаций это, конечно, лишнее.

Теперь посмотрим, что у нас получилось:

Сайт: avito.ru
Пароль: Ms50-2NvViVs29o

Сайт: vk.com
Пароль: Ms50-2NvViVs59m


Взгляните на результат и представьте, что кто-то узнал два ваших пароля. Основная задача системы – осложнить подбор третьего. Но тут нужно соблюдать баланс, чтобы самому во всем этом не запутаться.

По моему опыту лучший способ запомнить пароль или систему – это часто ее использовать. Потом все на себя возьмет мышечная память. Поэтому советую периодически разлогиниваться из аккаунтов и вообще не держать сессию авторизации слишком долго. Для часто посещаемых сайтов я использую отдельные пароли, которые стараюсь периодически менять.

Ну и пара слов о менеджере паролей. Да, это достаточно удобно, и да, это достаточно безопасно. Но есть и фатальные минусы – вся информация защищена единственным мастер-паролем, само приложение должно быть всегда под рукой, а облачному хранилищу нет окончательного доверия.

И напоследок. Для всех критичных аккаунтов типа мессенджеров, почты или банковских сервисов обязательно используйте двухфакторную аутентификацию и желательно через приложение (не SMS).
coronavirus

Многие из тех, кто знаком со мной лично, знают эту историю. Чуть меньше года назад я продал сайт с картой распространения коронавируса за $5000.
Началось все в конце января прошлого года. Мы в тот момент как раз жили в Азии и начало пандемии застали чуть раньше остальных. Я тогда залипал в игру Plague Inc, которая ожидаемо стало резко популярной, и Таня предложила мне сделать такую карту на реальных цифрах. Бегло погуглив, я не нашел единого источника данных и уже решил забить на идею, но вспомнил, что есть Википедия с ее многочисленными энтузиастами. В английской версии была актуальная табличка, в которую постоянно вносили данные. Написав простейший парсер, я получил обновляемые цифры с привязкой по странам. Почти сразу же всплыли первые проблемы с парсингом: пользователи Википедии постоянно ломали разметку таблицы, и мне приходилось писать костыли, которые игнорировали ошибки. Затем началась война правок от китайцев, которые делили и объединяли материковый Китай с Гонконгом и Макао. В один момент кто-то просто написал, что заболевших уже 100 000 (а власти скрывают). Я написал себе бота, который определял, что данные неадекватные и откатывался на старую версию. Этот же бот постил текстовую таблицу в канал.

Почти сразу ссылку на сайт опубликовал Нож в своем телеграм канале, а затем по просьбе нашего директора по развитию пост разместили в Лентаче. В пике количество активных пользователей на сайте доходило до 4000, а всего за 2 месяца посчиталось около 10 миллионов просмотров.

Через неделю после запуска я нашел более адекватный источник данных на одном из сайтов китайских СМИ и переписал парсер. Там названия стран не менялись, а ошибок в цифрах стало значительно меньше.

Надо сказать, что почти одновременно с запуском моей карты стал популярен сервис от университета Джонса Хопкинса.
И да, он был гораздо более точный и делил страны на регионы, но я решил ничего у себя не менять и позиционировать сайт скорее как развлекательный, нежели статистический.

В конце марта мне написали с вопросом, готов ли я продать сайт. Так как монетизировать я ничего не планировал, да и вообще вся эта тема мне порядком надоела, то я согласился при условии, что сервис не будет использоваться в мошеннических схемах. Так я отдал права на домен, перенес код и парсер и сменил владельца Телеграм канала, у которого к тому моменту уже было 20 000 подписчиков.

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

Скриншот сайта в первую неделю после запуска.
Мой любимый доменный регистратор очень ироничен. Если серьезно, то porkbun.com пока не дал ни одного повода думать о себе плохо. Я перенес практически все свои домены к ним, а от .ru зоны стараюсь отказаться совсем.
Вчера креативное бюро Золотые тигры России анонисировало гениальный проект – Музей ЖЭК-арта. По уши счастлив, что помогал в его разработке и вообще являюсь частью такой прекрасной команды.

Одной из задач было создание постеров для DIY-конструктора, и нам как нельзя кстати пригодилась библиотека, которую я делал для работы с постерами на Ноже. Это обертка над PHP-GD в основном для удобной генерации многострочного текста на изображении. Библиотека берет на себя все вычисления и позволяет гибко комбинировать надписи, добавлять ватермарки, применять фильтры итд.

Посмотрите как выглядит сгенерированный постер и обязательно соберите свой арт:
https://dvor.digital/share/1814cac7fc14b7052690ce05acf8afde8a41d0c0/
Remembrall

Я не люблю закладки в браузере – никогда не получается там организовать удобоное хранилище. Долгое время я скидывал ссылки себе в Saved Messages, но со временем там ожидаемо скопилась большая мусорка. Хотя идея отправлять находки самому себе в Telegram кажется мне очень простой и удобной, поэтому я решил просто завести для хороших ссылок отдельного бота. Для быстрого поиска нужной информации было решено помечать все ссылки тегами и кратким описанием. Получилась такая эталонная история сообщений с ботом, что пришлось делать для нее веб-интерфейс. Так и родился сервис Remembrall – напоминалка Невилла из Гарри Поттера.

Написан сервис на nodejs, база хранится в sqlite. Код доступен на Github. Профили могут быть как публичными, так и скрытыми под зашифрованным ключом. Еще из интересного – реализация удаления сообщений из базы на сервере. Telegram позволяет отслеживать редактирование, но ничего не сообщает боту об удалении из истории. Поэтому чтобы «забыть» ненужое сообщение, нужно отреплаить его с командой /forget.

Ну и напоследок ссылка на мой публичный профиль:
https://remembrall.app/lukin