Chrome Extension Programming: Illustrating a Basic Survival Skill with a Twitter Case Study
Andrej Karpathy рассказывает о навыке быстрого создания расширений для Chrome, позволяющих модифицировать любые веб-сайты по своему вкусу. На примере Twitter он демонстрирует, как за ~100 строк JavaScript и 10 минут работы можно убрать раздражающие элементы интерфейса, скрыть рекламные твиты, настроить автоматическую подгрузку новых записей и добавить подсветку твитов от редко пишущих авторов. Анализ ленты за неделю показал, что всего 30 аккаунтов из 384 подписок формируют 50% всего контента. Расширение использует локальное хранилище Chrome для накопления статистики частоты публикаций и подсвечивает жёлтым редких авторов, а зелёным — избранных VIP-аккаунтов. Кarpathy подчёркивает, что умение инспектировать DOM и писать JavaScript открывает мощные возможности для персонализации любого сайта.
Хакинг расширений
Я хотел поделиться несколькими примерами мощного навыка, который постепенно осваивал в течение последнего года. Это просто умение быстро собирать собственные расширения для браузера Chrome и с их помощью настраивать любимые сайты под себя. Писать расширения очень быстро: нужен короткий файл манифеста с некоторой скучной мета-информацией, несколько js/html-файлов с кодом в папке, а затем вы просто активируете эту папку как расширение из меню «Расширения» парой кликов. В целом с расширениями можно делать массу интересного:
добавлять кнопки, пункты контекстного меню модифицировать функциональность адресной строки (Omnibox) создавать специальные веб-страницы расширения для отображения различных данных/настроек расширению доступно локальное (или синхронизируемое) постоянное хранилище данных можно выполнять практически произвольный Javascript над DOM любой веб-страницы
Невозможно переоценить, насколько мощным является последний пункт. Вы можете запускать Javascript. Поверх любой веб-страницы. Вы можете читать DOM страницы. Вы можете писать в него — автоматически, при загрузке страницы или даже периодически! Это даёт полную свободу в модификации любой веб-страницы на свой вкус: убирать раздражающий контент, добавлять новые функции, логировать/парсить данные сайта, менять вёрстку и так далее. Это абсолютно невероятно!
Я проведу вас через несколько примеров возможных модификаций Twitter, чтобы дать представление о том, насколько это просто и мощно. Twitter — это весело, и я пользуюсь им часто, но их сайт раздражает, содержит уродливые элементы и порой лишён функциональности, которую я хотел бы видеть. Обычный человек запросил бы фичи и ждал, но с тёмными искусствами хакинга расширений мы можем сделать гораздо лучше. Давайте приступим.
Исправляем уродливое
Недавнее изменение в Twitter добавило этот уродливый текст, видимый по умолчанию и постоянно, под каждым твитом:
Я понимаю, что это заставляет людей случайно кликать по этим элементам и накручивает метрики вовлечённости Twitter, но это бесполезно, уродливо и просто занимает слишком много места. Давайте кликнем правой кнопкой по одному из таких элементов и выберем «Просмотреть код». Откроется HTML страницы, и здесь мы видим виновные элементы DOM:
Итак, у нас есть список с элементами — по одному для Reply, Retweet, Favorite и More. Внутри каждого из них находится (ссылка, обрабатывающая клик), глубже — , который становится иконкой, и наконец уродливый текст, обёрнутый в . Выглядит достаточно просто: мы найдём все эти элементы по атрибуту class, спустимся до текста и избавимся от него. Создаём новую папку для расширения TwitterClean, копируем шаблонный код манифеста и настраиваем его на загрузку JavaScript-файла при каждом открытии Twitter. Например, сразу после загрузки страницы twitter.com выполним:
var clean_twitter = function(){ var ugly = []; ugly.push('.action-reply-container'); ugly.push('.action-rt-container'); ugly.push('.action-del-container'); ugly.push('.action-fav-container'); ugly.push('.more-tweet-actions'); for(var i=0;i<ugly.length;i++) { var u = $(ugly[i]).find('b'); u.text(''); } }
Загружаем расширение, обновляем Twitter — и вуаля! Весь текст исчез, остались только иконки. Их вполне достаточно. О, и раз уж мы пишем код, который автоматически выполняется при загрузке twitter.com, давайте подкинем ещё вот это:
$('.promoted-tweet').hide(); // упс!
Предоставлю вам самим догадаться, что делает эта одна шаловливая строчка кода :)
Автоматическая загрузка новых твитов
Вот ещё одна раздражающая вещь: у вас открыт Twitter на втором мониторе, приходят новые твиты, но Twitter не загружает их автоматически! Он просто показывает вот это:
Это пассивно-агрессивное поведение Twitter: он сообщает, что есть ещё два новых твита, но при этом отказывается их показывать. Это было бы слишком полезно для пользователей. Вместо этого они хотят, чтобы вы бросили свои дела и нажали кнопку для загрузки новых твитов. К счастью, вы владеете искусством хакинга расширений, поэтому можно просто кликнуть правой кнопкой по надписи, выбрать «Просмотреть код» и увидеть, что элемент
var periodic = function() { L = document.getElementsByClassName('js-new-tweets-bar'); if(L.length > 0){ L[0].click(); } } setInterval(periodic, 1000);
Когда этот код запускается при загрузке twitter.com, он настраивает проверку раздражающей плашки каждую секунду (1000 миллисекунд) и вызывает её обработчик клика, который подгружает новые твиты. Вот и всё — теперь ваши твиты автоматически подгружаются, как только появляются, без необходимости постоянно обновлять страницу вручную. Мы писали код всего 5 минут, и за это время подправили внешний вид Twitter, убрали кое-какой «функционал» и добавили новый! Мы на ходу! Давайте теперь сделаем что-нибудь поинтереснее.
Подсветка твитов от редко пишущих авторов (или, подождите, твиперов?)
Однажды я решил собрать твиты из своей ленты за неделю через REST API Twitter и обнаружил, что 30 аккаунтов формируют 50% всего, что я вижу в Twitter. Учитывая, что я подписан на 384 аккаунта, это всего 7%! К сожалению, для Twitter все твиты равны, а это значит, что какой-нибудь навязчивый гуру соцсетей, который твитит 100 раз в день, полностью заглушает твиты от ваших друзей, которые считают, что перед публикацией неплохо бы иметь что-то стоящее. Ладно, не совсем так, но мне хотелось иметь механизм для подсветки очень редких авторов и возможность видеть их контент. Twitter никогда не реализует это, потому что для их модели монетизации это не имеет никакого смысла, но, к счастью, мы можем легко собрать это сами! Вот функция, которая проходит по всем твитам в вашей ленте, смотрит, кто написал твит, и «начисляет» каждый уникальный твит соответствующему пользователю:
var charge_tweets = function() { // получаем все твиты в ленте Twitter var items = $('.tweet'); for(var i=0;i<items.length;i++) { var it = items[i]; // извлекаем информацию из HTML твита var original_user = $(it).attr('data-screen-name'); var retweeter = $(it).attr('data-retweeter'); var tweet_id = $(it).attr('data-tweet-id'); // немного логики var charged_user = original_user; if(typeof retweeter !== 'undefined') { charged_user = retweeter; } // начисляем твит пользователю if(charge.hasOwnProperty(charged_user)) { var L = charge[charged_user]; if($.inArray(tweet_id, L) === -1) { L.push(tweet_id); } } else { charge[charged_user] = [tweet_id]; } } };
По сути, оказывается, что каждый твит имеет класс «tweet», поэтому перебирать их тривиально, как показано выше. Аналогично, изучив структуру HTML, оказывается, что мы можем просто извлечь имя пользователя и (уникальный) id твита и использовать их для построения словаря user_string -> [tweet id, ...]. Конечно, нужно подождать несколько дней, чтобы накопить хорошее распределение частоты публикаций для всех, на кого мы подписаны, — ведь мы заходим в Twitter снова и снова, каждый раз видя новые твиты от разных людей. Но это также означает, что нам нужно сохранять и загружать словарь charge из локального хранилища расширения Chrome, иначе мы потеряем всю накопленную статистику при закрытии вкладки! Это несложно:
var save_charge = function() { chrome.storage.local.set({'charge': charge}); } var load_charge = function() { chrome.storage.local.get('charge', function (result) { if(result.charge) { charge = result.charge; console.log('loaded tweet frequency stats:'); console.log(charge); } else { console.log('no tweet frequency to load'); } }); }
Теперь нужно просто убедиться, что load_charge() вызывается при запуске, а save_charge() — каждый раз, когда появляются новые твиты и наш словарь charge обновляется. На основе этого словаря charge мы можем легко найти, скажем, 50-й перцентиль частоты и подсветить любой твит от пользователя, который публикует реже, чем 50% людей, на которых мы подписаны:
var display_charges = function() { var items = $('.tweet'); for(var i=0;i<items.length;i++) { var it = items[i]; // ... как выше, а затем: var charged_tweets = charge[charged_user]; var charge_count = charged_tweets.length; // подстраиваем цвет подсветки твита в зависимости от редкости if(charge_percentile > 0) { var ratio = charge_count / charge_percentile; var x = Math.floor(Math.min(ratio,1)*255); $(it).css('background-color', 'rgb(255,255,' + x + ')'); } } }
Это лишь одна из множества возможностей. Здесь ratio будет низким для пользователей, которые редко твитят, и мы окрашиваем их твиты в жёлтый цвет в зависимости от редкости. Такое очень трудно не заметить в ленте! :) А раз уж мы тут, почему бы не добавить ещё:
var VIP = ['elonmusk']; if($.inArray(charged_user, VIP) !== -1) { $(it).css('background-color', 'rgb(150,255,150)'); }
Таким образом, твиты Elon Musk (или других ваших фаворитов в Twitter) будут всегда светиться ярким зелёным цветом, который трудно не заметить! Отлично. Вот что получается:
Только посмотрите на это! Mashable и некто, кому нужно было донести до каждого подписчика своё «Ааааррргх», выглядят обычно; твиты Elon невозможно пропустить благодаря зелёному цвету, а кто-то, кто публикует относительно редко, подсвечен жёлтым.
Итоги
Нам понадобилось ~100 строк и 10 минут JavaScript (с небольшой практикой), и мы подправили внешний вид Twitter, убрали э-э… нежелательный контент, сделали автообновление Twitter и добавили совершенно новую функцию — подсветку редко пишущих твиперов!
И всё же мы лишь едва коснулись поверхности. Если вам комфортно ориентироваться в HTML страниц с помощью отличного инспектора Chrome и писать HTML/Javascript/CSS, эти быстрые хаки способны значительно улучшить ваш онлайн-опыт, давая мощные инструменты для кастомизации любимых сайтов. А если вам пока некомфортно, возможно, пора заглянуть в руководство Chrome Extensions «Getting Started» и написать пару хаков :)