
Я, как и любой другой выпускник, переживаю по поводу экзаменов. От баллов, полученных на ЕГЭ зависит слишком многое, поэтому сейчас трудно думать о чем то другом. Чтобы не обновлять сайт check.ege.edu.ru каждые две минуты, я решил написать расширение, которое будет делать это за меня, а заодно присылать уведомления, в случае, если какой-то из экзаменов проверили.
Задача не очень сложная, но есть один неприятный момент. Сайт, на котором публикуются результаты, требует, чтобы информация о участнике, при каждом закрытии браузера, заполнялась заново. Это очень не удобно, поэтому пришлось немного по-импровизировать. Было замечено, что вся необходимая информация хранится в файлах cookie, поэтому можно просто сохранять и обновлять их когда потребуется, без необходимости вводить данные заново. Таким образом, логика работы расширения такова:

Расширения для браузера пишутся на js, оформляются с помощью html и css. В целом, разработка расширения мало чем отличается от создания сайта. Обычно любое расширение имеет следующий «скелет»:

Manifest.json
В этом файле хранится основная информация: версия, название, описание, подключаемые файлы и тд.
manifest.json
{ "manifest_version": 2, "name": "Результаты ЕГЭ", "description": "Расширение следит за обновлениями на сайте check.ege.edu.ru и оповещает о новых результатах", "version": "1.0.0", "icons": {"128": "icon.png"}, "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "background": { "scripts": ["jquery.js","background.js"], //фоновые страницы "persistent": false // Эта строка включает режим Event Pages, который призван улучшить производительность за счет того, что расширение будет работать только тогда, когда это необходимо. Именно поэтому в дальнейшем будет использоваться alarms вместо setInterval. }, "permissions": [ //разрешения "cookies", "tabs", "alarms", "notifications", "storage", "http://check.ege.edu.ru/*", "https://check.ege.edu.ru/*" ], "web_accessible_resources": [ // Это необходимо для правильной работы оповещений "icon.png" ] }
Background.js
Код, находящийся в этом файле будет запущен сразу после открытия браузера. Именно здесь будет находится основная логика нашего расширения
background.js
chrome.alarms.create("1min", { // Повторяем код ниже каждую минуту delayInMinutes: 1, periodInMinutes: 1, }); chrome.alarms.onAlarm.addListener(function(alarm) { if (alarm.name === "1min") { chrome.cookies.getAll({"url": 'http://check.ege.edu.ru'}, function(cookie) { if (cookie.length){ chrome.storage.local.set({'sCookie': cookie}); // Если на сайте есть cookie файлы, то сохраняем их checkUpdates(); // и проверяем обновления }else{ chrome.storage.local.get(['sCookie'], function(result) { if (!jQuery.isEmptyObject(result)){ // Если нет, то загружаем сохраненные ранее chrome.cookies.set({ "url": 'http://check.ege.edu.ru', "name": result["sCookie"][0]["name"], "value": result["sCookie"][0]["value"] }, function(){ checkUpdates(); // и тоже проверяем обновления }); } }); } }); } }); function checkUpdates(){ var myInit = { method: 'GET', credentials: 'include'}; fetch('http://check.ege.edu.ru/api/exam', myInit).then(r => r.text()).then(result => { // Загружаем результаты ЕГЭ var examRes = {}; jQuery.parseJSON(result)['Result']['Exams'].forEach(function(element) { examRes[element['Subject']] = element['TestMark']; // Сохраняем их в массив examRes }); chrome.storage.local.get(['examRes'], function(result) { for (var element in result['examRes']){ if (result['examRes'][element] != examRes[element]){ showNotification(element, examRes[element]); chrome.storage.local.set({'examRes': examRes}); // Если они не совпадают, с прошлыми данными, то // показываем уведомление // и сохраняем новые данные } } }); }) } function showNotification(subName, mark){ // показываем уведомление, состоящее их названия предмета и баллов chrome.notifications.create('reminder', { type: 'basic', iconUrl: 'icon.png', title: 'Новые результаты!', message: subName + ' - ' + mark }); }
Popup.html
В этом файле хранится разметка popup окна, которое открывается при нажатии на иконку расширения. В нашем случае, в этом окне будет отображаться небольшая таблица с результатами ЕГЭ.

popup.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Результаты ЕГЭ</title> <script type="text/javascript" src="jquery.js"></script> <script src="popup.js"></script> <style> <!-- Здесь ничего интересного --> </style> </head> <body> <table border="1" id="mainTable"> <caption><b>Ваши результаты ЕГЭ</b></caption> <tr> <th>Предмет</th> <th>Тестовый балл</th> </tr> </table> </body> </html>
В заголовке мы подключили файл popup.js, который будет исполняться при каждом нажатии на иконку расширения. Вот его содержимое:
popup.js
chrome.cookies.getAll({"url": 'http://check.ege.edu.ru'}, function(cookie) { // Смотрим, установлены ли на сайте необходимые cookie if (cookie.length){ chrome.storage.local.set({'sCookie': cookie}); createTable(); // Если они есть, то сохраняем их и отрисовываем таблицу }else{ chrome.storage.local.get(['sCookie'], function(result) { // Если нет, то смотрим, нет ли у нас сохраненных ранее cookie файлов if (!jQuery.isEmptyObject(result)){ chrome.cookies.set({ "url": 'http://check.ege.edu.ru', "name": result["sCookie"][0]["name"], "value": result["sCookie"][0]["value"] }, function(){ // Если есть, то устанавливаем их и отрисовываем таблицу createTable(); }); }else{ // А если нет, то открываем сайт check.ege.edu.ru в новой вкладке chrome.tabs.create({url : "http://check.ege.edu.ru"}); } }); } }); function createTable(){ var myInit = { method: 'GET', credentials: 'include'}; fetch('http://check.ege.edu.ru/api/exam', myInit).then(r => r.text()).then(result => { // Получаем результаты и парсим их jQuery.parseJSON(result)['Result']['Exams'].forEach(function(element) { if (element['HasResult'] == false){ // Если результата еще нет, то выводим название предмета и надпись "не проверено" $("#mainTable").append('<tr><td>'+element['Subject']+'</td><td>Не проверено</td></tr>'); }else{ // Если есть, то выводим название предмета и баллы $("#mainTable").append('<tr><td>'+element['Subject']+'</td><td>'+element['TestMark']+'</td></tr>'); } }); }) }
Итого, весь код занимает менее 200 строк. Надеюсь, что это расширение пригодится не только мне. В любом случае, во время разработки я получил опыт, который поможет мне в дальнейшем.
Вот ссылка на страницу расширения в chrome store
