Расширение для Chrome показывает, когда кто-то набирает текст




Некоторые люди слишком много времени проводят в социальных сетях. Настолько много, что у них уже возникает зависимость. Один из таких — программист Александр Кирзенберг (Alexandre Kirszenberg), который к тому же любит копаться во внутренностях Facebook — в коде JavaScript, отвечающем за пользовательский интерфейс и коммуникации.

«Пару месяцев назад я задумался о маленьком статусном индикаторе, который показывает, когда один из ваших друзей набирает вам текст, — пишет Александр. — Такое маленькое расширение UI выдаёт много информации о собеседнике. Если индикатор несколько раз загорается и тухнет, это говорит о нерешительности. Если он загорелся надолго, кто-то пишет вам большое эссе. И нет ничего хуже того мучительного чувства, когда индикатор тухнет и больше не загорается».

Первым делом Александр решил найти, присылает ли Facebook уведомления о том, что кто-то набирает сообщения в Facebook Messenger, даже если у вас не запущен этот Facebook Messenger. Оказалось, что присылает.

Всем друзьям рассылается событие typ «длинного опроса» /pull (long polling). Небольшое исследование показало, что событие действительно рассылается для каждого чата, даже если получатель не открывал его и никогда не получал.

Так появилось расширение Facebook Sixth Sense для браузера Chrome. Оно показывает прямо в браузере, когда кто-то набирает сообщение в Facebook.



Для создания этого расширения программист использовал недокументированные Facebook API. Пришлось разбираться с кодом JavaScript, который Facebook безжалостно минифицирует, превращая в мешанину символов.

Сначала он выяснил, какие модули Facebook импортирует через программный интерфейс системы организации модулей Asynchronous Module Definition для асинхронной загрузки (у Facebook собственная реализация AMD). Модули и зависимости определяются стандартной функцией __d(name, dependencies, factory). Есть также require и requireLazy для импорта модулей.

Проще всего посмотреть, как это работает, в консоли браузера (хотя Facebook строго запрещает это делать). Похоже, там работают серьёзные ребята, с ними лучше не шутить.



Но мы всё-таки осмелимся.



Как видим, Facebook всегда загружает последнюю версию React — отличной библиотеки компонентов пользовательских интерфейсов. Facebook довольно интенсивно использует React по всему сайту. В коде Facebook более 15 000 компонентов React (по состоянию на октябрь 2015 года).

В исходном коде можно поискать __d( и посмотреть список модулей, доступных для импорта. Для главной страницы там всего-то 3000 модулей.

В чате Facebook Messenger, разумеется, тоже используются компоненты React. Нам нужно перехватить нотификации о наборе текста. Для более детального изучения кода Александр Кирзенберг рекомендует использовать инструмент React Developer Tools.





После установки этого расширения в инструментах разработчика Chrome появляется новая вкладка React. На ней выделяем чат.



Здесь среди различных компонентов Facebook Messenger ищем индикатор набора текста, он находится между <ChatTabComposerContainer /> и <MercuryLastMessageIndicator />.

Поиск __d('ChatTyping в кодовой базе React находит два модуля: ChatTypingIndicator.react.js и ChatTypingIndicators.react.js. Это именно то, что нам нужно, пишет Кирзенберг. Он замечает, что некоторые модули подгружаются по мере необходимости, так что ChatTypingIndicators.react.js можно обнаружить только со второго раза.

Вот его код.

function() {
  var k = c('MercuryThreadInformer').getForFBID(this.props.viewer)
    , l = c('MercuryTypingReceiver').getForFBID(this.props.viewer);
  this._subscriptions = new (c('SubscriptionsHandler'))();
  this._subscriptions.addSubscriptions(
    l.addRetroactiveListener(
      'state-changed',
      this.typingStateChanged
    ),
    k.subscribe(
      'messages-received',
      this.messagesReceived
    )
  );
},

А именно, нас интересует вызов c('MercuryTypingReceiver').

В консоли можно посмотреть, как он работает.

> MercuryTypingReceiver.getForFBID
// function (i){var j=this._getInstances();if(!j[i])j[i]=new this(i);return j[i];}
> MercuryTypingReceiver.get
// function (){return this.getForFBID(c('CurrentUser').getID());}

Для проверки, как работает статусный индикатор, Александр использовал приложение Messenger на собственном смартфоне, чтобы отправить себе на ПК соответствующие события и словить их в консоли.

Более подробно изучив код, он нашёл ещё два полезных модуля MercuryThreads и ShortProfiles. Первый получает всю информацию о треде Messenger по его идентификатору, второй делает то же самое по профилю.

В общем, после всех изысканий вот как выглядит окончательный код расширения для Chrome, всего 40 строчек.

function getUserId(fbid) {
  return fbid.split(':')[1];
}

requireLazy(
  ['MercuryTypingReceiver', 'MercuryThreads', 'ShortProfiles'],
  (MercuryTypingReceiver, MercuryThreads, ShortProfiles) => {

    MercuryTypingReceiver
      .get()
      .addRetroactiveListener('state-changed', onStateChanged);

    // Called every time a user starts or stops typing in a thread
    function onStateChanged(state) {

      // State is a dictionary that maps thread ids to the list of the
      // currently typing users ids'
      const threadIds = Object.keys(state);

      // Walk through all threads in order to retrieve a list of all
      // user ids
      const userIds = threadIds.reduce(
        (res, threadId) => res.concat(state[threadId].map(getUserId)),
        []
      );

      MercuryThreads.get().getMultiThreadMeta(threadIds, threads => {
        ShortProfiles.getMulti(userIds, users => {
          // Now that we've retrieved all the information we need
          // about the threads and the users, we send it to the
          // Chrome application to process and display it to the user.
          window.postMessage({
            type: 'update',
            threads,
            users,
            state,
          }, '*');
        });
      });

    }
  }

);

Неплохой такой хак, слегка раскрывающий внутренности Facebook.

Исходный код расширения опубликован на Github.

Кстати, по временным меткам из мессенджера Facebook можно даже отслеживать режим сна своих френдов (исходный код).

Поделиться с друзьями
-->

Комментарии (22)


  1. acupofspirt
    03.06.2016 02:14

    Для такой «слежки» и Большой брат не нужен


  1. Tel
    03.06.2016 10:07
    +2

    Очень круто, по моему.


  1. TimsTims
    03.06.2016 10:15
    +1

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

    Если это был какой-то близкий друг, то я успевал открыть это окно и написать ей(ему) первым: «Привет!»
    А она такая: «Ой, привет! ты не поверишь, я только-только хотела тебе написать!»


    1. dmitry_ch
      03.06.2016 16:32

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


  1. Amareis
    03.06.2016 10:39
    +3

    В Вилларибо только делают расширения, а в Вконтакте уже давно всё встроено )


  1. dmitry_dvm
    03.06.2016 10:43
    +3

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


    1. Extrapolator
      04.06.2016 14:32

      а как называется, где достать? Я бы затестил. :)



  1. Drim
    03.06.2016 10:52

    Интересное расширение. Может еще кто-то сделает под другие соц. сети (если это возможно конечно)


  1. rodgar
    03.06.2016 10:52
    +3

    Стилизация текста в консоли:
    console.log("%cExtra Large Yellow Text with Red Background", «background: red; color: yellow; font-size: x-large»);

    Chrome: developer.chrome.com/devtools/docs/console#styling-console-output-with-css
    Firefox: getfirebug.com/wiki/index.php/Console.log


  1. Orky
    03.06.2016 10:52
    +1

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


  1. GennPen
    03.06.2016 10:52
    +15

    пользователь набирает сообщение…
    пользователь набирает сообщение…
    пользователь набирает сообщение…
    пользователь набирает сообщение…
    пользователь набирает сообщение…
    «ПРИВЕТ!»


    1. Miraage
      03.06.2016 17:11
      +3

      пользователь набирает сообщение…
      пользователь набирает сообщение…
      пользователь набирает сообщение…
      пользователь набирает сообщение…
      пользователь набирает сообщение…
      )


  1. ivanbolhovitinov
    03.06.2016 11:37
    +4

    И нет ничего хуже того мучительного чувства, когда индикатор тухнет и больше не загорается

    Вот я и сам не знаю, что делать
    image


  1. Fen1kz
    03.06.2016 13:48
    +5

    Всем френдам рассылается событие typ длинного опроса /pull.

    Мне кажется, что "френдов" стоило перевести как "друзей", а вот "long polling" наоборот, переводить не стоило, потому что это термин.


    1. Klaster
      03.06.2016 14:05
      +4

      У меня стойкое ощущение что уже давно френды != друзья. Термин «контакты в социальной сети» был бы уместнее наверное.


      1. Fen1kz
        03.06.2016 18:16

        Или просто "всем контактам рассылается..."


  1. vitalets
    03.06.2016 14:41

    Ждем расширение, которое скрывает от друзей, что вы набираете текст :)


    1. Cheater
      03.06.2016 15:41

      Любой сторонний текстовый редактор плюс Ctrl+V…


      1. ilnuribat
        03.06.2016 22:28

        Особенно полезно, когда текст пишите длинный, и часто меняете содержание
        И при это случайно жмете Enter(CTRL+ENTER, у кого как) — половина мыслей отправилась, а вторая половина только в разработке)


  1. handymade
    03.06.2016 16:00
    +1

    Пришлось разбираться с кодом JavaScript, который Facebook безжалостно минифицирует, превращая в мешанину символов.

    годный пятничный пост на хабре


  1. parmactep
    03.06.2016 23:06
    +1

    Очевидно фейсбук не запрещает рыться в консоли. Фейсбук предупреждает. Думается это правильно с их стороны.