Но одну вещь механизм content script не позволяет делать — получать доступ к javascript-окружению веб-страницы.
Когда я делал расширение для скробблинга прослушиваемой музыки из vk.com на last.fm, для мониторинга состояния плеера я сначала использовал парсинг DOM элементов плеера) Это было ужасно, и после первого же изменения в верстке всё сломалось. Поэтому пришлось придумать что-то понадёжнее. Поиски в интернете привели к простому и, казалось бы, очевидному механизму внедрения своего кода в веб-страницу:
1. Из контент скрипта создаём в DOM дереве страницы элемент «script» со своим кодом.
//исполнить скрипт vk_inner в контексте vk.com var script=document.createElement('script'); script.type='text/javascript'; script.src=chrome.extension.getURL("js/vk_inner.js");
2. Код производит патчинг функций, работа с которыми необходима. Для патчинга используем метод addCallListener, найденный где-то на просторах интернета. Он заменяет собой целевую функцию, и вызывает обработчики перед и после её запуска:
Function.addCallListener = function(func, callbacks) { var successNumber = 0, errorNumber = 0, name = func.name; return function() { var args = [].slice.call(arguments); var result, error; var props = { args: args, self: this, name: name } callbacks.before && callbacks.before(props); try { result = func.apply(this, arguments); props.successNumber = ++successNumber; props.result = result; props.status = 'success'; callbacks.success && callbacks.success(props); } catch (e) { props.errorNumber = ++errorNumber; props.error = e; props.status = 'error'; callbacks.error && callbacks.error(props); } callbacks.after && callbacks.after(props); return result; } }
3. Производим патчинг нужных функций. В случае vk.com это функция audioPlayer.onPlayProgress, она вызывается каждую секунду во время проигрывания:
var ARTIST_NUM = 5; var TITLE_NUM = 6; var artistElem = document.getElementById('vkScrobblerArtist'); var titleElem = document.getElementById('vkScrobblerTrackTitle'); //вешаем слушатель прогресса песни audioPlayer.onPlayProgress = Function.addCallListener(audioPlayer.onPlayProgress, { after: function(props) { //сохраняем исполнителя и песню artistElem.innerHTML = audioPlayer.lastSong[ ARTIST_NUM ]; titleElem.innerHTML = audioPlayer.lastSong[ TITLE_NUM ]; } });
Теперь при работе плеера в элементах artistElem и titleElem будут находиться актуальные название песни и её исполнитель. Остаётся только периодически проверять их содержимое и делать с ним что угодно. Можно избавиться от периодической проверки содержимого элементов, если использовать механизм событий jQuery. Таким образом можно устроить обмен любыми сериализуемыми данными между js веб-страницы и расширением.
ссылка на оригинал статьи http://habrahabr.ru/post/186762/
Добавить комментарий