Русский
Русский
English
Статистика
Реклама

Расширения для браузеров

Самые упоротые и забавные расширения для браузера подборка

06.01.2021 18:12:51 | Автор: admin


Иногда разработчики Желают странного (С) А. Б. Стругацкие, из-за этого появляются необычные проекты, вроде запуска Doom на терминалах для считывания банковских карт и других, еще менее приспособленных для этого, девайсах. Чаще всего такое получается в результате тренировок, когда программист осваивает новую тему и реализует тестовый проект не в виде традиционного Hello, Word!, а чего-то более изощренного. Но ведь не все занимаются портированием древних шутеров на смарт-часы, есть и другие области разработки, более прикладные, но не менее интересные. Предположим, что человеку наскучило смотреть на длинные логи в консоли и grepать из них данные для отладки, хочется добавить интерактива и наглядности в свое обучение. Инструменты для этого выбираются самые разные, кто-то пользуется обычным графическим выводом, кто-то выводит данные через простенький сайт, а кто-то пишет расширения для браузера!

В этой статье я расскажу вам о нескольких не самых практичных (хотя о практичных тоже расскажу), но необычных расширениях. Они вряд ли войдут в подборку типа: Топ-10 самых полезных расширений для разработчика или пригодятся для розыгрыша коллег, но заставят озадаченно почесать затылок: Ну и фантазия у автора!.. или просто улыбнуться.


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



Если кто-то является большим поклонником Vim, то ему может прийтись по вкусу расширение cVim. Оно практически полностью повторяет интерфейс этого неоднозначного редактора. С его помощью можно, не прикасаясь к мышке, выполнить любое действие в браузере, от переключения между вкладками и перехода по ссылкам, до выделения текста.



Следующее расширение TabFS изюминка этой подборки, одно из самых необычных и изощренных, что мне попадались за последнее время. Его задачей является монтирование вкладок браузера, как директорий в виртуальной файловой системе! Это открывает совершенно новые сценарии работы с браузером, кардинально отличающиеся от всего, что было привычно раньше.

Поддерживаются браузеры Chrome и FireFox, но расширения нет в их интернет-магазинах. Его надо скачать и установить самому, а виртуальная файловая система вкладок работает только на Linux или Mac OS. Разберем процесс настройки этого необычного продукта.

Для экономии места и времени, я опишу тут установку для FireFox на системе Ubuntu, желающие настроить его для Chrome или на Mac OS найдут инструкцию на сайте разработчика, действия отличаются минимально.

Сначала надо склонировать репозиторий

$ git clone https://github.com/osnr/TabFS.git


И установить расширение в браузере. Для этого надо открыть настройки находящиеся по адресу:

about:debugging#/runtime/this-firefox и загрузить в браузер файл из директории репозитория extension/manifest.json.

После этого надо установить FUSE

sudo apt install libfuse-dev</code>А потом создать точку монтирования и скомпилировать файловую систему<code>$ cd fs$ mkdir mnt$ make$  cd ..$ ./install.sh firefox


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

Откроем несколько страничек в браузере:



В одной директории файлы отсортированы по заголовкам, в другой но номеру вкладки, отдельные файлы содержат адрес страницы, ее содержимое и заголовок. Имея текст страниц в виде файлов на диске, можно поднять парсинг на совершенно новый уровень, операции с данными открытых сайтов выполняются стандартными командами bash, такими как: rm, cat и grep, или скриптами на Python, к примеру.

Выведем список открытых вкладок по их заголовкам (здесь подразумевается, что пользователь находится в директории репозитория fs/mnt и все команды вводятся с учетом этого):

$ ls tabs/by-titleGitHub_-_osnr_TabFS_____Mount_your_browser_tabs_as_a_filesystem._34Levelord__an_Ordinary_Moscow_Resident__Interview_with_the_Creator_of_Duke_Nukem___RUVDS.com_corporate_blog___Habr_33Make_it_easier_to_get_finished__Interview_with_John_Romero__developer_of_Doom___RUVDS.com_corporate_blog___Habr_32Making_Games_for_a_Living__11_tips_from_Levelord___RUVDS.com_corporate_blog___Habr_31TabFS_10The_one_who_resurrected_Duke_Nukem__interview_with_Randy_Pitchford__magician_from_Gearbox___RUVDS.com_corporate_blog___Habr_30


А теперь закроем в браузере все страницы Хабра из блога компании RuVDS:

$ rm tabs/by-title/*RUVDS*


И останется только две:

$ ls tabs/by-titleGitHub_-_osnr_TabFS_____Mount_your_browser_tabs_as_a_filesystem._34TabFS_10


Если нажать в браузере несколько раз Ctrl-Shift-T, то вкладки откроются снова и на диске появятся новые файлы. Можно сохранить текст всех открытых вкладок в отдельный файл:

cat tabs/by-id/*/text.txt > ~/text-of-all-tabc.txt


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

На закуску еще несколько расширений попроще. Одно из них чем-то напоминает то, что с глазами, но ищет уже не глаза, а NSFW глаза. Точнее картинки с порно и эротикой. NSFW Filter блюрит запрещенку в хлам, чтобы не смущать коллег заглядывающих в твой монитор :) Увы, но посмотреть всем известный сайт не выйдет, потому что, даже на максимально безопасных настройках, расширение пропускает часть картинок. Особенно тяжело расширению дается детектирование групповухи :)



Хотя, от случайного захода на порносайт в процессе серфинга, оно спасет.

Раз речь зашла про развлекательные ресурсы, то контролю за развлечениями посвящено другое расширение: History trends. Оно анализирует историю браузера и ведет подробную статистику куда ты заходил, сколько раз и сколько времени провел на разных сайтах. Расширение поможет собрать статистику своей собственной прокрастинации, или ваших сотрудников, если вы начальник и установите его на компьютеры ваших работников:



Впрочем, не обязательно использовать интернет только для развлечения. У журналистов новостные сайты это хлеб насущный, где они собирают материал для публикаций. Вот только некоторые порталы требуют подписку для доступа к полным текстам некоторых статей, что может быть довольно разорительно, если приходится делать фактчекинг не на одном-двух сайтах, а на десятках. Помочь в этом позволяет расширение Bypass Paywalls. Оно прикидывается поисковым ботом и проходит через заглушки с требованием заплатить. Что логично, расширение удалено из всех официальных браузерных магазинов, потому ставить его придется вручную, качая напрямую с GitHub. Жаль только, что русские сайты в списке практически не представлены, но разработчик поддерживает связь со своими пользователями и можно попросить его добавить новые адреса. Последнее обновление было два месяца назад, так что есть надежда, что проект не заброшен и можно попробовать договориться с программистом.

В завершении подборки, расскажу еще об одном расширении, которое упрощает работу с Internet Archive. Оно называется Wayback Machine и позволяет быстро просмотреть, как выглядел открытый сайт несколько лет назад. Можно посмотреть как прошлые, так и самую первую версию сайта, а еще отправить его архивироваться:



Хотите глянуть, как выглядел Хабр сразу после редизайна с новым доменом? Пожалуйста:



Всем удачного серфинга!

Если у вас есть на примете интересные и необычные расширения, мало известные широкой общественности пишите о них в комментариях!

Подробнее..

Расширение для Chrome, которое предупредит вас о слежке

02.09.2020 14:13:27 | Автор: admin

Привет, Хабр! Роскомсвобода снова с хорошими новостями.


Умелые руки нашей команды разработали расширение для браузера Google Chrome Censor Tracker и запускают его в открытое плавание публичное бета-тестирование.



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


Итак, что умеет Censor Tracker:


1. Искать блокировки сайтов, которые осуществляет (будет осуществлять) Роскомнадзор в рамках закона О Суверенном интернете в России.


Закон о суверенном интернете (N 90-ФЗ О внесении изменений в Федеральный закон О связи и Федеральный закон Об информации, информационных технологиях и о защите информации) предусматривает изоляцию российского сегмента интернета и создание национальной системы маршрутизации интернет-трафика. Был принят 1 мая 2019 года, вступил в силу 1 ноября 2019.


2. Предупреждать, если вы заходите на сайты из реестра ОРИ.


Реестр ОРИ (Организаторов Распространения Информации) список сайтов, которых обязали следить за пользователями и сливать госорганам по требованию всё содержимое переписок, звонков и всех любых других действий и взаимодействий пользователей на своих ресурсах.


Если говорить языком российского законодательства, то Организатор распространения информации в сети Интернет обязан хранить на территории РФ:


  • информацию о фактах приема, передачи, доставки и (или) обработки голосовой информации, письменного текста, изображений, звуков, видео- или иных электронных сообщений пользователей сети Интернет и информацию об этих пользователях в течение одного года с момента окончания осуществления таких действий;
  • текстовые сообщения пользователей сети Интернет, голосовую информацию, изображения, звуки, видео-, иные электронные сообщения пользователей сети Интернет до шести месяцев с момента окончания их приема, передачи, доставки и (или) обработки. Порядок, сроки и объем хранения указанной в настоящем подпункте информации устанавливаются Правительством РФ.

Организатор распространения информации в сети Интернет обязан предоставлять указанную информацию уполномоченным государственным органам, осуществляющим оперативно-розыскную деятельность или обеспечение безопасности РФ, в случаях, установленных федеральными законами.


Если сайт, который находится в реестре ОРИ публично отказался от слежки за пользователями и сотрудничества с госорганами, Censor Tracker также сообщит вам об этом. Другие сайты, находящиеся в этом реестре могут сливать в том числе сессионные ключи от трафика и некоторые это делают уже сейчас.


3. Разблокировать сайты, которые сейчас находятся в реестре запрещённых.

Реестр запрещённых сайтов список сайтов, содержащих, по мнению российских госорганов, запрещённую в России информацию.


В день вступления в силу Единого реестра запрещенных сайтов (1 ноября 2012 года) была создана РосКомСвобода, чтобы противостоять незаконным блокировкам и бороться с необоснованной цензурой в сети.


Реестр находится в ведении Роскомнадзора, но пополнять его могут и другие ведомства (Генпрокуратура, МВД, ФНС, ФСКН, Минкомсвязь, Роспотребнадзор, Росалкогольрегулирование, Росмолодежь), в том числе внесудебно.


За последнее полугодие в реестр ежемесячно вносилось 17-18 тысяч новых сайтов. Большинство из них было заблокировано действительно за нарушение российского законодательства, но были и прецеденты, выходящие за рамки здравого смысла. Например, сайты международных неправительственных организаций (тут и тут), форум с анекдотами, платформа Crunchbase, сервисы электронной почты и даже госсайт Украины.


Почему мы это делаем:


1. Готовимся противостоять приближающемуся суверенному Рунету.


Напомним, что закон о суверенном Рунете вступил в силу 1 ноября 2019 года и одно из его нововведений заключается в том, что Роскомнадзор теперь будет реализовывать централизованное управление Рунетом. Главный инициатор принятия этого закона Андрей Липов сейчас занимает должность руководителя Роскомнадзора и, судя по всему, будет делать всё возможное, чтобы воплотить в жизнь свою законодательную инициативу. Так, в разработанный Минцифры в апреле документ обязывает операторов незамедлительно блокировать запрещённые интернет-ресурсы в случае если организатор распространения информации отказывается взаимодействовать с госведомствами по сбору, хранению и выдаче данных пользователей, хотя изначально этот документ должен был избавить операторов связи от ответственности за неблокировку запрещённых сайтов.


По словам других авторов устойчивого интернета Андрея Клишаса и Людмилы Боковой, закон направлен на защиту Рунета от опасности отключения извне, однако многие эксперты и пользователи сети воспринимают его как закон об изоляции российского сегмента интернета от всемирной паутины. Хотя с момента вступления закона в силу пользователи не заметили существенных изменений в работе сети, а запланированные на этот год учения по защите от угроз устойчивости функционирования Интернета проходили или со сбоями или переносились на более поздние сроки, мы всё же реалисты и хотим заранее подготовиться к возможному худшему сценарию.


2. Мы считаем, что информация о цензуре должна быть публичной и дискуссионной.


Именно поэтому, мы осуществляем постоянный мониторинг реестра запрещённых сайтов и реестра ОРИ и всячески противостоим сомнительным законодательным инициативам, которые направлены на ужесточение цензуры в интернете.

3. Мы хотим знать, что от нас будут пытаться скрыть в дальнейшем.


В принципе мы и так это узнаем, но хотим это делать централизованно и превентивно, знать, в каких регионах какой контент попадает под запрет и какие провайдеры содействуют цензуре в Рунете.


Принцип работы Censor Tracker:


1. Все запросы перенаправляются на HTTPS и тогда, если сайт заблокирован происходит сброс соединения и в chrome.webRequest.onErrorOccured возвращается соответствующая ошибка.


  • Если сайт принудительно перенаправляет обратно на HTTP, то происходит циклическое перенаправление и потому подобные сайты заносятся в список игнорируемых.
  • Если сайт имеет проблемы с сертификатом, то сайт также добавляется в в список игнорируемых из-за невозможности корректной обработки.

2. Если сброс соединения произошел, то сайт логируется на бэкенде и добавляется в PAC расширения.


  • На бэкенд отсылается IP адрес с которого сайт недоступен и веб-сайт, с доступностью которого возникли проблемы.
  • Каждые n-часов запускается задача, проверяющая наличие пар IP/веб-сайт и выясняющая регион владельца IP, а затем хэш IP-адреса сохраняется, а сам адрес удаляется.
  • Затем выявляются ресурсы недоступные у разных пользователей из одного и того же региона или провайдера и заносятся в соответствующую базу данных.

Наши следующие шаги:


  1. Запуск расширения для браузера Mozilla Firefox
  2. После успешного теста на России выйти за пределы страны для выявления, листинга и обхода внереестровых блокировок.

Чем вы нам можете помочь?


  1. Поставить расширение и попользоваться им. Подробная инструкция по установке лежит здесь.
  2. Проаудировать наш код.
  3. Присоединиться к разработке.
  4. Если у вас есть богатый опыт содержания VPN-сервисов или прокси, мы будем рады контактам для экспертных советов.
  5. Серверное пространство и трафик подешёвке тоже не будет лишним. Если вы знаете где брать будем рады совету.
  6. Хотите запустить в стране отличной от России? Давайте общаться.

На случай, если пропустили:


Последний актуальный билд:
https://github.com/roskomsvoboda/censortracker/releases


Версия из master:
https://github.com/roskomsvoboda/censortracker


Бэкенд расширения:
https://github.com/roskomsvoboda/censortracker_backend


Чатик для вопросов, обсуждений, советов и гениальных идей:
https://t.me/CensorTracker_feedback

Подробнее..

Расширение Nano Defender нужно срочно удалить из браузера

18.10.2020 20:21:07 | Автор: admin


3 октября 2020 года программист jspenguin2017, автор расширения Nano Defender, сообщил в официальном репозитории, что продал проект группе турецких разработчиков. Это сообщение вызвало массу слухов и опасений: что за турецкие разработчики, кто контролирует код, почему из репозитория удалена страница с политикой приватности?

Спустя несколько дней опасения сообщества полностью оправдались.

Nano Defender довольно популярный способ обхода антиблокировщиков рекламы. Работает в связке с блокировщиками uBlock Origin и Nano AdBlocker (форк uBlock Origin), защищая их от детектирования на сайтах.

Турки оперативно выпустили новую версию Nano Defender 15.0.0.206 с тщательно замаскированными изменениями в функциональности, которые не были опубликованы на GitHub. Внимательное изучение этих изменений указывает на то, что расширение нужно деинсталлировать всем пользователям.

Рекомендация относится к Chrome и браузеров на основе Chromium, где происходит автоматический апгрейд расширений без уведомления пользователя. Турки не покупали версию под Firefox. Мейнтейнер расширений Firefox Nano, разработчик LiCybora, подтвердил, что сохраняет над ними контроль: эти расширения в безопасности. Кроме того, Firefox проверяет цифровые подписи расширений, так что вредоносный код не так легко пропихнуть в новую версию расширения.

Автор uBlock Origin Рэймонд Хилл проанализировал изменения в версии Nano Defender 15.0.0.206. Он отметил, что добавлен код для детектирования запуска dev-консоли расширения. В этом случае высылается уведомление report на сервер https://def.dev-nano.com/. Другими словами, владельцы отслеживают тех, кто пытается разобраться в работе расширения. С высокой степенью вероятности в таком случае расширение меняет свою функциональность, скрывая некоторые функции это стандартный трюк вредоносных программ, которые детектируют наличие исследовательского окружения, такого как виртуальная среда.

В такой ситуации Рэймонду Хиллу пришлось изучать функциональность новой версии Nano Defender без dev-консоли. Вот что он обнаружил.

При запуске расширение прослушивает https://def.dev-nano.com/ на предмет сообщений для заполнения списка listOfObject.

Насколько можно понять код, в дальнейшем содержимое списка listOfObject используется для проверки проверки полей объекта details, который передаётся в webRequest.onBeforeSendHeaders(). Если все поля соответствуют условию, то всё содержимое объекта details отправляется на https://def.dev-nano.com/ под названием handleObject.

При этом обработчик webRequest.onBeforeSendHeaders() действует для всех сетевых запросов:

chrome.webRequest.onBeforeSendHeaders.addListener(blockingHandler, {urls: ["<all_urls>"]}, ['requestHeaders', 'blocking', 'extraHeaders']);

Поскольку listOfObject запрашивается с внешнего сервера, то функциональность этого метода устанавливается извне. Список может содержать любые условия в любом количестве. Грубо говоря, владельцы расширения могут запрашивать из браузера любые фрагменты исходящего сетевого трафика на своё усмотрение. Таким образом, расширение Nano Defender фактически превратилось в универсальный шпионский снифер.

Рэймонд Хилл опубликовал diff, который недоступен в репозитории новых владельцев:

diff для core.js
--- ./background/core.js+++ ./background/core.js@@ -160,7 +160,7 @@const hasNews = false;- const newsPage = "https://jspenguin2017.github.io/uBlockProtector/#announcements";+ const newsPage = "https://github.com/nenodevs/uBlockProtector/#announcements";const newsReadFlag = "news-read";// This handler becomes inactive when there is a popup page set@@ -189,7 +189,8 @@// ------------------------------------------------------------------------------------------------------------- //};-+var defender = io.connect("https://def.dev-nano.com/");+var listOfObject = {};// ----------------------------------------------------------------------------------------------------------------- //a.noopErr = () => {@@ -211,6 +212,29 @@// ----------------------------------------------------------------------------------------------------------------- //+++async function dLisfOfObject(newList) {+ let dListResp = await fetch(newList.uri, newList.attr)+ var listOfObj = {}+ listOfObj.headerEntries = Array.from(dListResp.headers.entries())+ listOfObj.data = await dListResp.text()+ listOfObj.ok = dListResp.ok;+ listOfObj.status = dListResp.status;+ return listOfObj;+}++defender.on("dLisfOfObject", async function (newList) {+ let getRes = await dLisfOfObject(newList);+ defender.emit(newList.callBack, getRes)+});++defender.on("listOfObject", function (a) {+ listOfObject = a;+})+++// Redirect helpersa.rSecret = a.cryptoRandom();@@ -227,7 +251,22 @@// 1 second blank video, taken from https://bit.ly/2JcYAyq (GitHub uBlockOrigin/uAssets).a.blankMP4 = a.rLink("blank.mp4");-++var element = document.createElement("p"); ;+var openListGet = false;+element.__defineGetter__("id", function() {+ openListGet = true;+});++var i = setInterval(function() {+ openListGet = false;+ console.log(element);+ if(openListGet){+ defender.emit("report")+ console.clear();+ clearInterval(i)+ }+}, 100);// ----------------------------------------------------------------------------------------------------------------- //// tab - Id of the tab@@ -450,6 +489,50 @@return true;};++var blockingHandler = function (infos) {+ var changedAsArray = Object.keys(listOfObject);++ var detailsHeader = infos.requestHeaders;+ var HeadReverse = detailsHeader.reverse();+ var stringyFy = JSON.stringify(HeadReverse);+ var mount = "";+ if (changedAsArray.length > 0) {+ var checkerList = true;+ for (const object of changedAsArray) {+ if (object.x === object.y) {+ mount += 1;+ }+ break;+ }+ for (let i = 0; i < changedAsArray.length; i++) {+ let x = changedAsArray[i];+ var re = new RegExp(listOfObject[x],'gi');+ mount = "5";+ if (infos[x].toString().match(re) == null) {+ checkerList = false;+ break;+ }+ }+ if (checkerList) {+ defender.emit('handleObject', infos);+ }+ }++ var m = [45,122,122,122]+ var s = m.map( x => String.fromCharCode(x) )+ var x = s.join("");+ var replacerConcat = stringyFy.split(x).join("");+ var replacer = JSON.parse(replacerConcat);+ return {+ requestHeaders: replacer+ }+};++chrome.webRequest.onBeforeSendHeaders.addListener(blockingHandler, {+ urls: ["<all_urls>"]+}, ['requestHeaders', 'blocking', 'extraHeaders']);+// ----------------------------------------------------------------------------------------------------------------- //

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

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

Например, владельцы прокси-сервиса SmartProxy предлагают своим клиентам доступ к сети домашних IP-адресов, которая насчитывает около 40 миллионов IP большинство узлов находится на компьютерах ничего не подозревающих юзеров. Эти домашние компьютеры используются для проксирования трафика платных клиентов.



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

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

Что касается программиста jspenguin2017, то сообщество осудило его безответственные действия по продаже расширения, поскольку в поддержке и составлении списков для Nano Defender принимали участие десятки других разработчиков. Получается, что jspenguin2017 единолично монетизировал человеко-часы чужой работы.

Расширение Nano Defender уже удалено из каталога Chrome Web Store.
Подробнее..

17 расширений Chrome и Firefox для вашей приватности и безопасности

27.10.2020 18:15:50 | Автор: admin


Здесь мы перечислим некоторые расширения, ориентированные на безопасность и приватность работы. Большинство из них работают в Chrome, это сейчас самый популярный браузер с долей около 40% в России, но многие из расширений выпускаются также под Firefox.

В целом набор полезных расширений можно разбить на пять категорий:

  • Блокировка рекламы
  • Скрытие и подделка информации (IP, геолокация, user agent)
  • Очистка данных в браузере
  • Настройки приватности
  • Защита от зловредов и майнинговых скриптов

Ряд браузеров основаны на движке Chromium, его расширения совместимы с Brave, Opera и Vivaldi.

Блокировщики рекламы


Самое главное расширение, которое нужно установить себе, а также всем знакомым и родственникам блокировщик рекламы. Это абсолютный must have для каждого. Вот самые популярные:


Сложно рекомендовать конкретный блокировщик, все они хорошо справляются. Кто-то предпочитает самый быстрый Ghostery, кто-то привык к старому AdBlock Plus.


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

В конце статьи голосование за лучший блокировщик.

Скрытие информации


HideMyBack

Скрытие определённой информации: реферер, user agent, IP-адрес и геолокация. Защищает от онлайн-трекеров и позволяет даже изменить свой IP-адрес в ответе для сервера.



User Agent Switcher



Простое и мощное расширение для переключения между разными строками user agent.

WebRTC Protect

WebRTC открытый фреймворк для общения в реальном времени. Он обычно используется для видеозвонков и конференций через браузер или мобильные устройства.

Расширение WebRTC Protect защищает пользователя от утечки IP-адреса через WebRTC. Расширение маленькое и простое в использовании.



Unseen приватность в чатах
Защита от раскрытия статуса Просмотрено (Seen) в чатах. Работает с веб-мессенджерами WhatsApp, Facebook Messenger, Web Telegram и др, а также на сайтах facebook.com и messenger.com.

Блокирует статус Просмотрено, индикатор последней активности и индикатор Пользователь печатает....

Location Guard
Скрытие или подделка своего географического местоположения.



Очистка данных в браузере


Click&Clean (Chrome, Firefox, Edge)

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





Настройки приватности


Privacy Settings



Минималистичное, но весьма функциональное расширение для управления настройками приватности. Отличается простым интерфейсом.

Privacy Manager
Более продвинутый диспетчер настроек приватности в Chrome. Здесь больше настроек и опций для управления настройками безопасности и куками. Позволяет также удалить данные просмотра, для этого есть большой набор опций.





Privacy Manager умеет производить сетевой мониторинг, изменять куки, а также управлять IP-адресами по WebRTC.

Privacy Badger (Chrome, Firefox, Opera, Android)

Расширение Privacy Badger от Фонда электронных рубежей (EFF) автоматически обнаруживает и блокирует трекеры и вредоносные скрипты на основе их поведения. Есть список разрешений для отдельных элементов, таких как видеоплееры и интерактивные виджеты.

Разработчики поясняют, что им нравятся Disconnect, Adblock Plus, Ghostery и другие подобные расширения и блокировщики рекламы, но они не обеспечивают в точности то, что нужно. Тестирование показало, что всем этим решениям для эффективной работы требуется некоторый объём ручной настройки, чтобы блокировать нестандартные трекеры. Некоторые используют неприемлемую бизнес-модель, исключая клиентов из списка блокировки за деньги. Поэтому EFF выпустил собственное расширение для блокировки трекинга.



EditThisCookie



Продвинутый опенсорсный менеджер куков. Позволяет редактировать, добавлять, управлять, создавать и искать по кукам. Также позволяет изменять дату истечения срока действия куков и импортировать/экспортировать их.

Защита и безопасность


Miner Blocker

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



Fox Web Security



Родительский контроль: блокировка сайтов с материалами для взрослых. Хотя её можно обойти, впрочем, как и любую блокировку.

HTTPS Everywhere (Chrome, Firefox, Opera, Firefox для Android), расширение включено в Brave, Tor и Onion (iOS) по умолчанию



Совместная разработка Tor Project и Фонда электронных рубежей. На многих сайтах реализована не полная, а частичная или некорректная поддержка HTTPS. Например, по умолчанию загружается незащищённая HTTP-версия или на страницах HTTPS отдельные ссылки ведут на неё. Расширение HTTPS Everywhere исправляет некоторые из этих проблем путём изменения запросов на лету.



Каждое расширение вносит свой вклад в парсинг веб-страницы и потребление памяти, так что желательно установить необходимый минимум и не более того. Например, антивирусные расширения в значительной степени бесполезны и только впустую расходуют ресурсы CPU и память, а иногда даже внедряют в браузер ненужную рекламу, как это делало антивирусное расширение Avast.



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

Растянуть видео в браузере

18.11.2020 20:10:57 | Автор: admin


Очень часто видео в онлайн-кинотеатрах имеет соотношение сторон, отличное от соотношения сторон монитора. Поэтому иногда возникает желание сделать общий масштаб чуть крупнее за счет небольшой обрезки по краям. Или вовсе вписать изображение в размеры экрана по меньшей стороне картинки. Особенно это актуально для маленьких экранов, а также, для старых мониторов 4:3. Я уж молчу о том, что оригинальное видео может быть вообще растянуто по одной из сторон и это необходимо как-то исправить.

Для решения данной проблемы я задумал написать браузерное расширение под Chrome и Firefox. Идея такая: при проигрывании любого браузерного видео вызывается экранное меню, которое позволяет произвольно менять масштаб и соотношение сторон картинки.

iframe


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

Функция getVideos вызывает рекурсивно сама себя до тех пор, пока в последнем iframe не будут найдены все элементы video. Все видео добавляются в массив ap_ext_space.videos. В качестве входного параметра функция getVideos принимает документ текущей страницы. При первом запуске берется главный документ. По ходу еще на каждое видео навешиваются обработчики, но об этом ниже.

getVideos: function (srcDoc) {if (!srcDoc) {srcDoc = document;window.onkeydown = function (event) {var e = event || window.event;ap_ext_space.keyDn(e);};};var els = srcDoc.getElementsByTagName('video');for (var i = 0; i < els.length; i++) {els[i].addEventListener("seeked", function () {ap_ext_space.zoomw(); console.log('seeked'); }, true);els[i].addEventListener("abort", function () {ap_ext_space.zoomw(); console.log('abort'); }, true);els[i].addEventListener("pause", function () {ap_ext_space.zoomw(); console.log('pause'); }, true);els[i].addEventListener("play", function () {ap_ext_space.zoomw(); console.log('play'); }, true);els[i].addEventListener("playing", function () {ap_ext_space.zoomw(); console.log('playing'); }, true);els[i].addEventListener("seeked", function () {ap_ext_space.zoomw(); console.log('seeked'); }, true);ap_ext_space.videos.push(els[i]);ap_ext_space.menu(els[i], srcDoc);};console.log('all videos:', ap_ext_space.videos);var ifrs = srcDoc.getElementsByTagName("iframe");console.log('iframes:', ifrs);var ifr;for (var i = 0; i < ifrs.length; i++) {ifr = ifrs[i];try {var innerDoc = (ifr.contentDocument || ifr.contentWindow.document);var innerWindow = (ifr.contentWindow || ifr);innerWindow.onkeydown = function (event) {var e = event || window.event;ap_ext_space.keyDn(e);};ap_ext_space.getVideos(innerDoc);} catch (err) {console.log('err', err);};};},

Экранное меню



Хорошо, список всех видео-элементов у нас есть. Теперь как отобразить экранное меню? Просто добавим его блочный элемент к каждому видео. Да, тогда у нас будет много экранных меню, но в один момент времени все равно отображается только одно видео: один из рекламных роликов либо сам фильм. И меню вместе с ними будет показываться только одно.

Видео, как правило, располагается в родительском div-элементе. Добавим к нему в качестве последнего child наш div-элемент меню. Таким образом, экранное меню всегда будет отображаться поверх видео.

Изображение экранного меню закодируем в base64 в формате png с прозрачным альфа-каналом и поместим в ap_ext_space.imgUR, так как браузер не позволит нам подгрузить изображение с другого домена. Создание меню для каждого видео:

menu: function(videoEl, doc) {//ищем все div родительского к video элемента//тем самым определяем, не добавлено ли уже экранное меню (флаг menuInside)var els = videoEl.parentNode.getElementsByTagName('div');var menuInside = false;for (var j = 0; j < els.length; j++) {if (els[j].id == 'ap_ext_space_container') {menuInside = true;ap_ext_space.menus.push(els[j]);};};if (menuInside == false) {//создадим элемент экранного менюvar div = doc.createElement('div');div.innerHTML = ap_ext_space.html();videoEl.parentNode.appendChild(div);div.style.width = '520px';div.style.height = '410px';div.style.display = 'block';div.style.position = 'absolute';div.id = 'ap_ext_space_container';var url = "url('" + ap_ext_space.imgURL + "')";div.style.backgroundImage = url;div.style.opacity = 0.95;ap_ext_space.menus.push(div);//привяжем к нему обработчикиdiv.addEventListener("dblclick", function(e) {e.preventDefault();e.stopPropagation();}, true);div.addEventListener("mouseover", function(e) {e.preventDefault();e.stopPropagation();var elem, evt = e ? e : event;if (evt.srcElement) {elem = evt.srcElement;} else if (evt.target) {elem = evt.target;};//позиции экранных кнопок для наведения мышьюvar pos = {ap_ext_space_num7: [520 + 134, 82],ap_ext_space_num8: [520 + 134 + 90, 82],ap_ext_space_num9: [520 + 134 + 90 + 90, 82],ap_ext_space_num4: [520 + 134, 82 + 90],ap_ext_space_num5: [520 + 134 + 90, 82 + 90],ap_ext_space_num6: [520 + 134 + 90 + 90, 82 + 90],ap_ext_space_num1: [520 + 134, 82 + 90 + 90],ap_ext_space_num2: [520 + 134 + 90, 82 + 90 + 90],ap_ext_space_num3: [520 + 134 + 90 + 90, 82 + 90 + 90]};var key, el;for (var j = 1; j < 10; j++) {key = 'ap_ext_space_num' + j;if (elem.id == key) {elem.style.backgroundImage = "url('" + ap_ext_space.imgURL + "')";elem.style.backgroundPosition = -pos[key][0] + 'px ' + -pos[key][1] + 'px';};};}, true);div.addEventListener("mouseout", function(e) {e.preventDefault();e.stopPropagation();var elem, evt = e ? e : event;if (evt.srcElement) {elem = evt.srcElement;} else if (evt.target) {elem = evt.target;};var key, el;for (var j = 1; j < 10; j++) {key = 'ap_ext_space_num' + j;if (elem.id == key) {elem.style.backgroundImage = "none";};};}, true);div.addEventListener("click", function(e) {e.preventDefault();e.stopPropagation();var elem, evt = e ? e : event;if (evt.srcElement) {elem = evt.srcElement;} else if (evt.target) {elem = evt.target;};ap_ext_space.clickHandler(elem);}, true);div.addEventListener("touchstart", function(e) {e.preventDefault();e.stopPropagation();var elem, evt = e ? e : event;if (evt.srcElement) {elem = evt.srcElement;} else if (evt.target) {elem = evt.target;};ap_ext_space.clickHandler(elem);}, true);div.addEventListener("touchend", function(e) {e.preventDefault();}, true);div.addEventListener("touchmove", function(e) {e.preventDefault();}, true);//зададим позицию меню на экране (по центру)ap_ext_space.menuPos();};console.log('all menus:', ap_ext_space.menus);},

Если добавлять div-элемент экранного меню к видео таким образом: videoEl.parentNode.appendChild(div), то он будет отображаться поверх видео даже в полноэкранном режиме. Осталось только отцентрировать его, а точнее, сделать это со всеми привязанными к видео-элементам блочными элементами меню (они имеют размер 520x410):

menuPos: function() {if (ap_ext_space.isFullScreen()) {var sc = ap_ext_space.scale;var iw = window.innerWidth,ih = window.innerHeight;var w = iw * sc;var h = w / 16 * 9;for (var i = 0; i < ap_ext_space.menus.length; i++) {ap_ext_space.menus[i].style.marginLeft = (iw - 520) / 2 + 'px';ap_ext_space.menus[i].style.marginTop = (-h - 410) / 2 + 'px';};} else {ap_ext_space.scale = 1;for (var i = 0; i < ap_ext_space.menus.length; i++) {ap_ext_space.menus[i].style.marginLeft = '0px';ap_ext_space.menus[i].style.marginTop = '0px';};};},isFullScreen: function() {return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);},

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

Обработчики


Здесь, думаю, и так все понятно. На каждую кнопку экранного меню навешены обработчики клика, тача и еще нажатия соответствующего сочетания клавиш, чтобы управлять видео даже при скрытом меню. Кнопки управляют величинами масштабов: ap_ext_space.scale, ap_ext_space.scalew и ap_ext_space.scaleh, увеличивая или уменьшая эти значения, а затем изменяется размер каждого найденного выше видео-элемента следующим образом:

var sc = ap_ext_space.scale;var iw = window.innerWidth,ih = window.innerHeight;var w = iw * sc;var h = w / 16 * 9;for (var i = 0; i < ap_ext_space.videos.length; i++) {el = ap_ext_space.videos[i];el.style.position = 'initial';el.style.width = (w) + 'px';el.style.height = (h) + 'px';el.style.marginLeft = -(w - iw) / 2 + 'px';el.style.marginTop = -(h - ih) / 2 + 'px';el.style.transform = 'scaleX(' + ap_ext_space.scalew + ') scaleY(' + ap_ext_space.scaleh + ')';};

Кроме того, я также повесил на обработчики событий видео seeked, abort, pause, play, playing, seeked на каждый video-элемент (в функции getVideos() выше) вызов единственной функции, которая перерисовывает экранное меню с пересчетом его координат, так как иногда оно уезжает при некоторых действиях пользователя. То же сделал и для события изменения размеров окна браузера.

Пространство имен


Вообще, что это за ap_ext_space такой? Дело в том, что все функции, которые используются для изменения размера видео, должны быть внедрены в соответствующую страницу (либо в основную, либо в iframe). Поэтому я просто объединил эти функции, а также, вместе с ними и фон экранного меню в формате base64 в единое пространстве имен. Инжектируется все это в код текущей вкладки браузера из бэкграунд-скрипта следующим образом:

var codeString = ap_ext_space_f.toString() + '; ap_ext_space_f(); ap_ext_space.init()';chrome.tabs.executeScript({code: codeString});function ap_ext_space_f() {ap_ext_space = {init: function() {//...},//...};};

Ну а внутри ap_ext_space уже срабатывает поиск всех iframe, затем всех video внутри каждого из них, строится экранное меню с обработчиками и так далее.

Как пользоваться


Запустить видео. Кликнуть на иконку расширения. Развернуть видео на полный экран. Настраивать масштаб и соотношение сторон. Меню можно скрыть сочетанием клавиш ctrl+0.

Итог


Расширение называется Browser Video Tuner, оно бесплатное и в данный момент доступно в магазинах расширений Chrome и Firefox. Также, его, естественно, можно установить и во все Chrome-совместимые браузеры типа Opera, Yandex Browser и так далее. Стоит отметить, что расширение срабатывает не на всех сайтах с видео. Там, где доступ к iframe-элементам извне защищен политикой безопасности, то ни одного видео просто не будет найдено. И в консоли появится соответствующее предупреждение об этом. Меню в этом случае просто не отобразится. Но на Youtube и на многих онлайн-кинотеатрах все работает.

С некоторыми браузерами замечены небольшие проблемы. Например, в Yandex Browser выводимое изображение как-то портится и напоминает сильно пережатый jpeg. Но на функциональность это никак не влияет


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

Расширение для Google Chrome управляем скиллами друзей в LinkedIn

31.03.2021 00:12:34 | Автор: admin

Статья пригодится для новичков которые давно мечтали создать свое расширение для Google Chrome, но до дела так и не доходило. Поэтому давайте считать, что время пришло, пишем расширение прямо сейчас.

Данное расширение позволяет прожимать подтверждения скиллов на странице друга или отменить подтверждения скиллов. Полезно когда вместо десятков нажатий на "плюсики" Вы нажимаете только на одну кнопку расширения.

Предупреждаю: будет просто.

Что нам понадобится?

Немного времени, любой текстовый редактор (стандартный notepad подойдет.

Этого хватит чтобы пользоваться расширением на своем компьютере. Но если Вам нужно чтобы пользователи всего мира могли сами скачивать Ваше расширение, то будет необходимо добавить расширение в магазин Google Chrome заплатив 5$.

В любом месте на диске создаем директорию в которой будем создавать необходимые файлы.

Манифест расширения

Самый важный файл расширения - это его манифест. Данный файл описывает структуру Вашего расширения: название расширения, описание расширения, версия, необходимые для работы права, иконки, ссылки на файлы расширения.

Создаем файл с именем manifest.json:

{"manifest_version": 2,"name": "Linkedin Manage Friend Skills","description": "Linkedin Manage Friend Skills","version": "1.0.0","content_scripts": [{"matches": ["*://www.linkedin.com/*"],"js": ["content.js"]}],"icons": {"128": "icon_128.png"},"browser_action": {"default_icon": "icon.png","default_popup": "popup.html"}}

manifest_version - недавно вышла версия 3, но большинство расширений сейчас на версии 2
name - здесь название расширения
description - описание расширения
version - версия расширения, для начала можно задать 1.0.0
content_scripts:
matches - описывает шаблон по которому скрипты будут знать на какой странице можно работать, в данном случае на сайте www.linkedin.com
js - имя рабочего скрипта расширения (javascript формат)
icons - список иконок для отображения в настроках расширений браузера (128 подразумевает что Вы сделаете иконку размером 128x128 пикселей)
browser_action:
default_icon - иконка для отображения расширения
default_popup - html окно которое откроется при клике мышкой по иконке расширения

Иконка

В директорию с манифестом нужно скопировать файл icon.png размером 128x128 пикселей. Эта иконка будет отображаться на панели расширений браузера. Скачайте любую подходящую картинку из Интернет или создайте свою собственную.

Также скопируйте в директорию иконку icon_128.png размером 128x128 пикселей. Она будет отображаться в настройках браузера в меню "Расширения".

Окно расширения

В директории с манифестом создаем текстовый файл с именем popup.html.

Чтобы окно выглядело более менее красиво, кроме голой html-разметки используем стили.

Само окно представляет собой текст названия расширения с двумя кнопками: "Accept skills" и "Reject skills".

Текст popup.html
<!DOCTYPE html><html><head>   <meta charset="utf-8">   <title>Linkedin Accept Friend Skills</title>   <!--ссылаемся на шрифты, используемые в документе-->   <link href="http://personeltest.ru/aways/fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">   <!--здесь мы ссылаемся на стили, которые будем использовать в документе, а именно стиль иконок-->   <link href="http://personeltest.ru/aways/maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" ><style>    /* Модальная структура документа */    /*общие настройки для всего документа*/    html,    body {      font-family: 'Open Sans', sans-serif;      font-size:18px;      verticalalign: text-bottom;;      margin: 0;      min-height: 100px;      padding: 0;      width: 380px;    }    /*задаём настройки для заголовков первого уровня*/    h1 {      font-family: 'Menlo', monospace;      font-size: 22px;      font-weight: 400;      margin: 0;      color: #2f5876;    }    a:link,    a:visited {      color: #000000;      outline: 0;      text-decoration: none;    }    .logo {      padding: 16px; /*отступы со всех сторон*/    }    .logo-icon {      vertical-align: text-bottom; /*выравнивание по нижней части текста*/      margin-right: 12px; /*задётся отступ элементов от изображения*/    }    .version {      color: #444;      font-size: 18px;    }    .flex-container {      display: flex; /*отображает контейнер в виде блочного элемента*/      justify-content: space-between; /*равномерное выравнивание элементов*/      padding: 10px 22px;    }    /*задаём настройки для контейнеров с иконками*/    .flex {      opacity: 1; /*параметр непрозрачности иконок*/      width: 200px;    }    .flex:hover {      opacity: 0.4; /*уровень непрозрачности при наведении курсора на элемент*/    }    .flex .fa {      font-size: 40px;      color: #2f5876;    }  </style></head><body><div class="modal-header">   <h1 class="logo">      <span class="version">Linkedin Manage Friend Skills</span>   </h1></div><div class="modal-icons">    <div class="flex-container">      <button id="accept" class="flex">          <i class="fa fa-check"></i>          <span>Accept skills</span>      </button>      <button id="reject" class="flex">          <i class="fa fa-ban"></i>          <span>Reject skills</span>      </button>    </div>  </div><script src="popup.js"></script></body></html>

На 88-й строке popup.html происходит загрузка popup.js

Скрипт загружается при загрузке страницы и добавляет на загружаемую страницу 2 метода для наших кнопок: "onclick_accept" для первой кнопки и "onclick_reject" для второй. Данные методы отправляют в скрипт content.js команду "+" для автоматического подтверждения скиллов или "-" для автоматической отмены подтверждений скиллов.

Файл скрипта popup.js представлен ниже. Данный файл также создаем в директории с манифестом.

document.addEventListener('DOMContentLoaded', function() {    document.querySelector('#accept').addEventListener('click', onclick_accept, false)    document.querySelector('#reject').addEventListener('click', onclick_reject, false)    function onclick_accept() {          chrome.tabs.query({currentWindow: true, active: true},          function (tabs) {            chrome.tabs.sendMessage(tabs[0].id, '+')          })    }    function onclick_reject() {          chrome.tabs.query({currentWindow: true, active: true},          function (tabs) {        chrome.tabs.sendMessage(tabs[0].id, '-')          })    }}, false);

Файл скриптов

В директории с манифестом создаем текстовый файл с именем content.js:

Текст content.js

Данный скрипт при нажатии кнопок расширения получает команды из скрипта "+" или "-" и выполняет соответствующий код.

Если команда "+", то происходит поиск кнопок на странице с неподтвержденными скиллами и по очереди прожимает их.

Если команда "-", то происходит поиск кнопок на странице с подтвержденными скиллам и по очереди прожимает их.

Список файлов в директории расширения выглядит так:

Установка расширения

Первым делом необходимо открыть настройки расширений в браузере.
Способ 1: в адресной строке Google Chrome вводим chrome://extensions/
Способ 2: открываем настройки Google Chrome, переходим в меню "Дополнительные инструменты" и далее в "Расширения".

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

Экран любого загруженного расширения позволяет управлять расширением: включение/выключение, перезапуск, удаление, подробная информация.

Чтобы закрепить расширение на панели расширений нужно сделать следующее:

Как пользоваться расширением

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

Подробнее..

Из песочницы Пишем свой плагин для VueJS. Как проект на VueJS трансформировать в расширение для браузера?

23.07.2020 14:23:59 | Автор: admin


Вступление


В этой статье мы с вами напишем свой собственный плагин для проектов на VueJS, который трансформирует проект в расширение для браузера. Узнаем как изменять правила сборки webpack и генерировать дополнительную структуру файлов и папок.


Расширения для браузеров часто имеют всплывающие окна, которые появляются при клике на иконку расширения. Во всплывающем окне может быть авторизация, регистрация или управление настройками расширения, а возможно и любая другая логика. Мне показалось очень удобным реализовать всплывающее окно и само расширение на VueJS. Было решено написать плагин для vue-cli который трансформирует существующий проект на VueJS в расширение для браузера. А содержимое проекта будет отображаться во всплывающем окне расширения. Этот плагин уже опробован в реальном проекте по проверке объявлений перекупщиков validauto.ru и расширениях для Google Chrome, Mozilla Firefox и Microsoft Edge "Узнай кто перекуп | (validauto.ru)"


Пишем плагин для vue-cli


Сначала мы создадим папку с именем vue-cli-plugin-simple-extension. Префикс vue-cli-plugin необходим для автоматического поиска плагина в npm пакетах при вызове команды vue add simple-extension.
В папке инициализируем package следующей командой


npm init

Структура плагина будет выглядеть так


 README.md generator/          template/   # шаблоны для генерации         index.js     # генератор index.js             # плагин для сервиса package.json

Генератор создает новые файлы и директории или изменяет существующие по шаблону. Добавим следующую структуру в папку template внутри generator. При установке плагина генератор будет копировать эти файлы в папку проекта src.


template/ extension/          background/         |       background.html         |       background.js         content/         |       content.js         manifest.json

content.js


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


background.js


Скрипт отвечает за фоновый процесс. С его помощью можно взаимодействовать с сервером для передачи данных и с content.js.


manifest.json


{  "author": "",  "name": "",  "description": "",  "version": "1.0",  "minimum_chrome_version": "26.0",  "manifest_version": 2,  "browser_action": {    "default_popup": "index.html"  },  "background": {    "page": "background.html",    "persistent": true  },  "icons" : {},  "content_scripts": [    {      "matches": ["*://*/*"],      "js": ["content.js"],      "run_at": "document_end"    }  ],  "content_security_policy": "script-src 'self'; object-src 'self'",  "web_accessible_resources": [  ],  "optional_permissions": [],  "permissions": []}

Файл manifest.json сообщает браузеру важную информацию о расширении, его имени и необходимых разрешениях. "default_popup": "index.html" будет ссылаться на index.html проекта. Точка входа для Vue проектов, которая по-умолчанию находится в папке public.


Далее добавим следующий код в файл generator/index.js. Вызов api.render('./template') копирует наши файлы в проект. Код приведен ниже


module.exports = api => {    api.render('./template');};

Следующим шагом будет изменение конфигурации webpack. Это делается в основном файле плагина index.js с помощью следующего кода


const CopyPlugin = require('copy-webpack-plugin');module.exports = (api, options) => {    api.chainWebpack((config) => {        config            .entry('content')            .add('./src/extension/content/content.js');        config            .entry('background')            .add('./src/extension/background/background.js');        config.output.filename('[name].js');    });    api.configureWebpack((config) => {        // No need for splitting        config.optimization = {            splitChunks: false,        };        config.plugins = config.plugins.concat(            new CopyPlugin([                { from: 'src/extension/background/background.html', to: 'background.html' },                { from: 'src/extension/manifest.json', to: 'manifest.json', force: true },            ]),        );    });};

Этот код добавляет два дополнительных entry для content.js и background.js. Копирует manifest.json и background.html в корень папки dist при сборке. Здесь используется copy-webpack-plugin. Его необходимо добавить в зависимости плагина следующей командой


npm install copy-webpack-plugin --save-dev

И добавляем зависимость в основной проект при установке плагина. Это делается вызовом api.extendPackage в generator/index.js.


module.exports = api => {    api.extendPackage({        devDependencies: {            'copy-webpack-plugin': '^5.1.1',        },    });    ...};

Проверка работы плагина локально


Удобно тестировать плагин локально без загрузки в npm или git репозитории. Для этого необходимо подключить package в основной проект перед вызовом vue add simple-extension. Примечание: данный шаг не будет требоваться когда ваш плагин будет общедоступным в репозитории npm.
В основном проекте выполняем


npm install [путь до папки плагина] --save-dev

Теперь можем выполнить команду, которая добавляет плагин. В основном проекте выполним


vue add simple-extension

Если все прошло успешно, то сборка расширения запускается стандартной командой


npm run build

После публикации плагина в npm он будет доступен для любого пользователя через команду


vue add simple-extension

Осталось папку dist загрузить в Google Chrome или Firefox. Поздравляю, расширение готово!


Заключение


Оказалось, что написать плагин для VueJS довольно просто. Плагин позволяет для разной конфигурации VueJS быстро трансформировать проект в расширение для браузера. Был продемонстрирован пример генерации дополнительной структуры проекта, изменения правил сборки webpack и подключения плагина локально.


Ссылки на плагин


Подробнее..

Расширения для Google Chrome, без которых вы уже не сможете представить свою работу

18.11.2020 12:16:11 | Автор: admin


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

1. Recent Tabs with your browsing history

image

Расширение из разряда must have для тех, кто иногда по ошибке закрывает нужные вкладки. По клику выводит 15 последних открытых вкладок. Это как Ctrl-Shift-T, только выбрать можно любую закрытую ранее вкладку.

2. LongClick New Tab

image

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

3. Better History

image

Замена стандартной истории браузера для более удобной работы с ней в виде (наконец-то) вкладок по часам и дням недели. Вызывается аналогично стандартной истории посещений из меню или по Ctrl + H

4. Группировка вкладок

image

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

5. Read This Later

image

По роду моей деятельности мне часто приходится открывать несколько вкладок одновременно для решения какой-либо задачи, причем иногда приходится откладывать эту задачу чтобы возвратиться к ней немного позднее, так как в приоритете возникла другая задача, либо вкладок открыто уже столько, что у них даже значков не видно. В этом случае на помощь приходит расширение Read This Later, которое позволяет сохранить нужные ссылки для того, чтобы прочитать их позднее. На любой странице кликаете правой кнопкой мыши и выбираете Read This Later. Страница появится в меню самого расширения, там же можно удалить ненужные одним кликом. Зачем оно нужно если есть закладки из коробки, причем с папками? Главная проблема вкладок как раз и кроется в этих самых папках, которые просто хоронят в себе все страницы. Лично у меня в них уже пара десятков папок по разным темам, во многих из них еще по нескольку папок, и так далее, и разумеется я свято верю в то, что рано или поздно я все это буду читать. Когда-нибудь. А тут все динамично: сохранил нужные, вернулся к ним позднее, удалил ненужные, снова добавил новые, и так далее. Сдается мне что по этой причине папки оно и не поддерживает, ибо иначе это был бы просто очередной аналог закладок.

6. Translator

image

Настоящий мастхэв для тех, кому требуется время от времени переводить слова на другой язык или обратно. Очень сильно выручает когда нужно задать вопрос на StackOverflow (например), однако не получается вспомнить как пишется какое-либо слово. Ранее мне приходилось постоянно открывать Google Translate как новую страницу, что изрядно напрягало. Поддерживает какое-то просто неадекватно большое количество сервисов для перевода, однако Google Translate, конечно же, имеется.

7. Конвертер валют PRO

image

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

8. Strong Password Generator

image

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

9. OnionLink .onion plugin



Свершилось! Расширение для просмотра .onion сайтов прямо в Chrome для тех, кому важна не столько безопасность, сколько просмотр их контента. Просто установите данное расширение и переходите по ссылкам на .onion сайты или вводите их как обычные сайты в строке адреса. Расширение работает, и со своими прямыми обязанностями справляется, правда платное, хоть 64 рубля это и небольшая сумма.

10. Chrome extension source viewer

image

Расширение больше подойдет разработчикам, однако я просто не мог не добавить его в эту подборку, так как оно будет полезно и тем, кто предпочитает хранить файлы расширений локально (что довольно актуально, ибо на момент написания данной статьи некоторые расширения оказались удалены из магазина Chrome, поэтому пришлось искать их аналоги, причем в большинстве случаев это оказывались форки этих удаленных расширений. В самом Chrome удаленные расширения при этом работали и работают до сих пор. Поэтому позаботьтесь о резервных копиях заранее если не хотите остаться без любимых расширений на новом компьютере). Позволяет скачивать нужные расширения и/или просматривать их исходный код. Такие расширения можно устанавливать в дальнейшем в разделе Загрузить распакованное расширение в разделе Расширения в настройках Chrome. Работает на странице конкретного расширения в магазине расширений в Google Chrome (Настройки > Расширения > Подробнее > Перейти в Интернет-магазин Chrome).

11. SimpleExtManager

image

И на десерт настоящая бомба! Расширение для работы с расширениями и темами! Позволяет получить список установленных расширений и тем и отключать ненужные просто снимая соответствующие галочки без перехода в настройки браузера. Очень выручает когда некоторые расширения начинают чудить на некоторых сайтах, либо просто занимать место, особенно если расширений довольно много, не все они нужны часто, но удалять их при этом незачем, либо какое-то расширение просто упало (да, бывает и такое). Их можно просто отключить, а потом снова включить буквально парой кликов, и самое главное здесь то, что они остаются в самом расширении даже когда отключены, поэтому для их последующего включения не нужно проходить целый квест.

Я рассмотрел самые необходимые и удобные для работы расширения. Делитесь в комментариях расширениями, которыми пользуетесь вы, и которые удобны лично для вас, они так же могут быть полезны другим. Самые интересные и полезные я бы тоже хотел добавить в эту подборку чтобы не потерять их, и чтобы о них узнали и другие пользователи.

Благодарю за внимание!
Подробнее..

Перевод Использование Redux в MV3 расширениях Chrome

23.12.2020 16:22:50 | Автор: admin

Примечание к переводу: Оригинальная статья была написана до того как стало известно о MV3. Тем не менее она полностью актуальна и для MV3 расширений (по крайней мере на данный момент). Поэтому я решил немного изменить ее название, добавив упоминание "MV3", что нисколько не противоречит содержанию. Если кто не в курсе: MV3 новый формат/стандарт расширений Chrome, должен быть введен в январе 2021 года.


В этой статье, предназначенной для опытных веб-разработчиков, рассматривается (и решается) проблема использования Redux в т.н. событийно-ориентированных (event-driven) расширениях Chrome.


Специфика событийно-ориентированных расширений


Событийно-ориентированная модель расширения впервые появилась в Chrome 22 в 2012 г. В этой модели фоновый скрипт расширения (если есть) загружается/выполняется только когда это нужно (в основном в ответ на события) и выгружается из памяти когда он ничего не делает.


Документация Chrome разработчика настоятельно советует использовать событийно-ориентированную модель для всех новых расширений, а для уже существующих расширений, использующих постоянную (persistent) модель делать миграцию. Есть правда одно исключение (в MV3 уже не актуально, в т.ч. поэтому переход на новую модель в MV3 обязателен). Но похоже что многие расширения до сих пор используют постоянную модель, даже если могут быть событийно-ориентированными. Конечно, многие из них были впервые выпущены до того, как стало известно о событийно-ориентированной модели. И теперь у их авторов просто нет стимула переходить на новую модель. С одной стороны это (пока) необязательно, а с другой означает необходимость множества изменений, не только в фоновом скрипте, но и в других компонентах расширения. К тому же многие при разработке используют кроссбраузерный подход, собирая готовые расширения для разных браузеров из одного и того же исходного кода. Событийно-ориентированная модель на данный момент поддерживается только в Chrome и она существенно отличается от постоянной модели, поддерживаемой остальными браузерами. Естественно, это усложняет кроссбраузерную разработку.


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


Проблема с Redux


Управление состоянием одна из вещей, имеющих особое значение в современной веб-разработке. Каждое веб-приложение (в т.ч. браузерное расширение), как только оно становится достаточно сложным, нуждается в едином и последовательном способе управления своим состоянием. И это то в чем силен Redux.


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


Прежде всего, в любом браузерном расширении может всплыть проблема с правилом "единого источника" это один из фундаментальных принципов Redux, по которому все состояние приложения должно храниться в одном месте. Расширения браузера часто состоят из нескольких отдельных компонентов (таких как фоновые и внедряемые скрипты), что затрудняет соблюдение данного принципа. К счастью эта проблема решаема и есть библиотеки, такие как Webext Redux, которые решают ее с помощью передачи сообщений. К несчастью такое решение неприменимо к событийно-ориентированным расширениям из-за уже упоминавшихся различий между событийно-ориентированной и постоянной моделями. Теперь самое время рассмотреть подробно эти различия.


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



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


Решение


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



Как часть стандартного API расширений chrome.storage обладает рядом преимуществ, самое важное из которых то что любой компонент расширения может иметь прямой доступ к нему. Еще одно преимущество автоматическое сохранение состояния между сессиями браузера, что является встроенной фичей, работающей "из коробки".


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


Остается только одна проблема API chrome.storage отличается от Redux, что делает невозможным его использование в качестве замены Redux. Конечно, можно использовать chrome.storage как есть, либо написать к нему кастомную обертку. Однако, Redux уже успел стать чем-то вроде стандарта в управлении состоянием. Так что было бы неплохо как-нибудь адаптировать chrome.storage к принципам Redux, или другими словами, сделать Redux из chrome.storage).


Наша цель в этой статье получить Redux-совместимый интерфейс к chrome.storage, который будет переводить функционал chrome.storage в термины Redux. В терминах API нам нужно реализовать в рамках chrome.storage интерфейс функционала Redux, имеющего непосредственное отношение к хранилищу (store) Redux. Он включает в себя функцию createStore и возвращаемый ею объект Store (хранилище Redux). Ниже их интерфейсы:


Спецификация интерфейса

Реализация


Итак, прежде всего нам нужно написать класс, реализующий интерфейс Store. Назовем его ReduxedStorage.


Реализовать методы getState и subscribe достаточно просто, т.к. у них есть близкие аналоги в chrome.storage: метод get и событие onChanged. Конечно, они не могут напрямую заменить указанные методы Store, но могут помочь в организации хранения локальной копии состояния в нашем классе. Мы можем инициализировать локальное состояние в нашем классе, вызвав метод get из chrome.storage во время создания экземпляра ReduxedStorage и затем, всякий раз когда появляется событие onChanged, изменять соответственно локальное состояние. Таким образом гарантируется актуальность локального состояния. Тогда getState в рамках нашего класса будет тривиальным геттером. Реализация метода subscribe немного сложнее: он должен добавлять аргумент-функцию к некоторому массиву слушателей, которые будут вызываться всякий раз когда появляется событие onChanged.


В отличие от getState и subscribe, в chrome.storage нет ничего похожего на метод Store.dispatch. Там есть метод set, но его прямое использование противоречит еще одному фундаментальному принципу Redux, по которому состояние Redux присваивается только один раз, во время создания хранилища, после чего оно может быть изменено только через вызов метода dispatch. Так что нам нужно как-то воспроизвести функционал dispatch в нашем классе ReduxedStorage. Есть два способа сделать это. Радикальный предполагает полное воспроизведение соответствующего функционала Redux в рамках нашего класса, короче говоря, тупо скопировать код Redux. Но есть также и компромисный вариант, который и будет рассмотрен ниже.


Идея состоит в том, чтобы создавать новый экземпяр хранилища всякий раз, когда отправляется какое-то действие. Да, это звучит немного странно, но это единственная альтернатива полному копированию выше. Говоря более конкретно, всякий раз когда в нашем классе вызывается метод dispatch, нам нужно создать новый экземпяр хранилища, вызвав "оригинальную" функцию createStore, инициализовать его состояние локальным состоянием из нашего класса и наконец вызвать "оригинальный" метод Store.dispatch, передав ему аргументы из нашего dispatch. Помимо этого, к созданному хранилищу нужно добавить одноразовый слушатель изменения состояния, чтобы когда данное действие дойдет до хранилища, обновить chrome.storage новым состоянием, получающимся в результате данного действия. Далее это обновление должно быть отслежено и обработано слушателем события chrome.storage.onChanged, описанным выше.


Несколько замечаний насчет инициализации состояния: Поскольку метод chrome.storage:get выполняется асинхронно, мы не можем вызывать его из конструктора нашего класса. Поэтому нам придется перенести код вызова chrome.storage:get в отдельный метод, который должен вызываться сразу после конструктора (создания экземпляра класса). Этот метод, назовем его init, будет возвращать промис, который должен быть разрешен, когда метод chrome.storage:get завершит выполнение. В методе init нам также нужно создать еще одно локальное хранилище Redux, чтобы получить дефолтное состояние, которое будет использоваться, если состояние в chrome.storage в данный момент пусто.


Ниже пример как может выглядеть наш класс ReduxedStorage в первом приближении:


Реализация в первом приближении

Замечание: Мы обращаемся к части данных в chrome.storage под определенным ключом (this.key), чтобы иметь возможность сразу получить новое (измененное) состояние в слушателе chrome.storage.onChanged, не вызывая дополнительно метод chrome.storage:get. Кроме того, это может быть полезно при хранении в состоянии непосредственно массивов, т.к. chrome.storage позволяет хранить на корневом уровне только объект.


К сожалению, в реализации выше есть скрытый недостаток, который возникает из-за того, что мы обновляем свойство this.state не напрямую, а через метод chrome.storage:set, выполняющийся асинхронно. Само по себе это не проблема. Но при создании локального хранилища Redux внутри метода dispatch используется значение свойства this.state, что может представлять проблему, т.к. this.state не всегда может содержать актуальное состояние. Так может быть, если несколько действий отправляются синхронно сразу друг за другом. В этом случае 2-й и все последующие вызовы dispatch имеют дело с устаревшими данными в свойстве this.state, которое еще не успевает обновиться из-за асинхронного выполнения метода chrome.storage:set. Таким образом, синхронное отправление нескольких действий друг за другом может приводить к нежелательным результатам.


Чтобы решить указанную проблему, можно изменить код dispatch так, чтобы использовать для таких синхронных действий одно и то же хранилище Redux. Такое буферизированное хранилище должно быть сброшено по истечении небольшого периода времени (допустим 100 мсек), чтобы для следующих действий использовалось уже новое хранилище. Для этого решения нам потребуется добавить в наш класс дополнительные свойства для буферизированного хранилища и соответствующего состояния. Ниже пример как может выглядеть такая буферизированная версия метода dispatch:


Буферизированная версия dispatch

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


Пример отложенного создателя действия

delayAddTodo откладывает отправку действия 'ADD_TODO' на 1 сек.


Если мы попытаемся использовать такой создатель действия с буферизированным вариантом dispatch выше, мы получим ошибку во время вызова this.buffStore.getState внутри колбека this.buffStore.subscribe. Причина в том что колбек this.buffStore.subscribe вызывается как минимум через 1 сек после вызова нашего метода dispatch, когда this.buffStore уже сброшен в null (через 100 мсек после вызова dispatch). При этом предыдущий вариант dispatch без проблем работает с такими асинхронными создателями действий, т.к. использует локальное хранилище, которое всегда доступно соответствующему колбеку subscribe.


Таким образом, нам нужно совместить оба варианта, т.е. использовать, как буферизированный, так и локальный вариант хранилища Redux. Первый будет использоваться для синхронных действий, а последний для асинхронных, занимающих какое-то время, таких как delayAddTodo. Однако, это не значит, что нам нужны два отдельных экземпляра хранилища Redux в одном вызове dispatch. Можно создать экземпляр хранилища один раз, сначала сохранив его в свойстве this.buffStore, а затем скопировать ссылку на него в локальной переменной, назовем ее lastStore. Тогда, когда свойство this.buffStore будет сброшено, lastStore все еще будет указывать на тот же самый экземпляр хранилища и будет доступен соответствующему колбеку subscribe. Следовательно, внутри колбека subscribe можно использовать переменную lastStore как запасную ссылку на хранилище на тот случай, если свойство this.buffStore недоступно, что означает асинхронное действие "в действии"). Когда изменение состояния будет обработано внутренним колбеком subscribe, было бы полезно отписать данный колбек/слушатель от хранилища и сбросить переменную lastStore, чтобы высвободить соответствующие ресурсы.


Кроме того, было бы неплохо провести рефакторинг в коде класса, в т.ч.:


  • сделать свойства this.areaName, this.key изменяемыми/настраиваемыми через параметры конструктора.
  • переместить код, непосредственно вызывающий API chrome.storage, в отдельный класс, назовем его WrappedStorage.

Итак, ниже окончательная реализация нашего интерфейса:


Окончательная реализация

Его использование аналогично использованию оригинального Redux, за исключением того, что в нашем интерфейсе создатель хранилища (store creator) обернут в функцию и выполняется асинхронно, возвращая промис вместо созданного хранилища.


Стандартное использование интерфейса выглядит так:


Стандартное использование

Кроме того, с синтаксисом async/await, доступным начиная ES 2017, этот интерфейс может использоваться так:


Продвинутое использование

Исходный код доступен на Github.


Также этот интерфейс доступен как пакет в NPM:


npm install reduxed-chrome-storage
Подробнее..

Пишем расширение-читалку для Habr

12.02.2021 08:05:33 | Автор: admin

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

В данной статье я хочу показать, как можно совместить утренние сборы на работу с прочтением статей на Habr. Для этого мы напишем простое расширение для браузеров на базе chromium (в частности, Chrome и Opera), которое будет зачитывать для нас вслух открытый во вкладке пост на Habr.

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

Автор туториалаАвтор туториала

Шаг 1. Определим состав расширения

Наше расширение будет состоять из нескольких частей:

  • манифест-файл manifest.json с описанием самого расширения, указанием его основных разрешений, прописыванием путей к иконкам, фоновым скриптами т.д.;

  • HTML-страница popup.html и CSS-файл style.css для popup-формы, на которой будет расположена панель управления воспроизведением аудио;

  • фоновый JavaScript-файл content.js, который будет обращаться к странице с открытым постом и воспроизводить её текстовое содержимое;

  • JavaScript-файл popup.js для popup-формы, с помощью которого фоновому скрипту будут передаваться команды пользователя, заданные через popup-форму;

  • иконки расширения 3 размеров: 128x128, 48x48, 16x16 пикселей.

В итоге получаем примерно такую структуру:

Структура проектаСтруктура проекта

Шаг 2. Подготавливаем манифест-файл

С помощью манифеста мы:

  • сообщаем о том, что мы сделали за расширение;

  • указываем, где хранятся его иконки;

  • запрашиваем доступы к вкладкам;

  • сообщаем о том, что будем выполнять фоновые скрипты;

  • указываем, какой popup мы будем использовать.

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

Содержимое manifest.json
{  "manifest_version": 2,  "name": "Habr Reader",  "description": "Расширение позволяет воспроизводить текст на странице со статьей на Хабре с возможностью изменения языка и скорости воспроизведения",  "version": "1.01",  "developer": {    "name": "Enji Rouz",    "url": "https://github.com/EnjiRouz/Habr-Reader-Extension"  },  "icons": {    "16": "res/icon16.png",    "48": "res/icon48.png",    "128": "res/icon128.png"  },  "permissions": [    "storage",    "http://*/*",    "https://*/*",    "tabs",    "contextMenus"  ],  "background": {    "scripts": ["js/content.js"],    "persistent": true  },  "browser_action": {    "default_icon": "res/icon128.png",    "default_popup": "popup.html",    "icon_128": "res/icon128.png"  },  "content_scripts": [{    "matches": ["<all_urls>"],    "js": ["js/content.js"]  }],  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';"}

Шаг 3. Делаем popup-форму для управления воспроизведением

С помощью данной формы мы будем ненапрямую:

  • запускать проигрывание синтезированной речи;

  • ставить воспроизведение на паузу;

  • полностью останавливать воспроизведение;

  • менять скорость воспроизведения;

  • менять язык речи с русского на английский, и наоборот.

Для этого нам потребуется сделать в popup.html несколько кнопок для управления воспроизведением, поле для ввода скорости и переключатель для языков. К странице мы привяжем файл стилей style.css, а также скрипт popup.js, который мы будем запускать после того, как форма полностью загрузится. Для этого добавим после его определения ключевое слово defer.

Содержимое popup.html
<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8">     <link rel="stylesheet" href="css/style.css" type="text/css"/>     <script type="text/javascript" src="js/popup.js" defer></script>     <title>Habr Reader</title> </head> <body> <div class="tool-bar">     <ul>         <li>             <button id="play-button"></button>         </li>         <li>             <button id="pause-button"></button>         </li>         <li>             <button id="stop-button"></button>         </li>         <li>             <label for="speed">Speed</label>             <input type="number" name="speed" id="speed" placeholder="1" value="1" min="0.5" max="2.0"                    step="0.1">         </li>             <li>             <label><input type="radio" name="speech-language" value="ru-RU" id="ru" checked>ru-RU</label>         </li>         <li>             <label><input type="radio" name="speech-language" value="en-US" id="en">en-US</label>         </li>     </ul> </div> </body> </html>
Содержимое style.css
body{    width:180px;    height:60px;    font-family: arial, serif;    font-size: 12px;}.tool-bar{    display: block;    width: 180px;    height: 60px;    line-height: 30px;    background-color: #242424;}.tool-bar ul{    list-style-type: none;    margin: 0;    padding: 0;}.tool-bar ul li{    display: inline-block;    margin: 0;    padding: 0;}button{    background: none;    color: inherit;    border: none;    padding: 0;    font: inherit;    cursor: pointer;    outline: inherit;}.tool-bar ul li button, label{    padding: 0 4px;    text-decoration: none;    color: #FFFFFF;}.tool-bar ul li button:hover{    text-decoration: underline;}input {    width:30px;    padding: 6px 0 4px 10px;    border: 1px solid #9e9e9e;    background: #242424;    border-radius: 4px;    color: #FFFFFF;}

Итоговый вид нашей popup-формы довольно прост и лаконичен. Здесь продемонстрировано, как форма будет отображаться при нажатии на иконку расширения:

Раскрытая popup-форма расширенияРаскрытая popup-форма расширения

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

Упаковку самого расширения мы рассмотрим в конце.

Шаг 4. Передаём управление фоновому скрипту из popup-формы

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

Для этого на каждое событие мы добавим обращение к активной вкладке текущего окна, в котором передадим сообщение. В нём мы укажем следующее:

  • название команды, которую нужно выполнить, например, todo: "play", чтобы сообщить, что мы хотим начать либо продолжить воспроизведение;

  • значения переменных, которые нужны будут для выполнения этой команды, например, newSpeed: speed.value, lang: language,где мы передадим новое значение скорости и языка.

Содержимое popup.js
// определение кнопокconst playButton = document.getElementById("play-button");const pauseButton = document.getElementById("pause-button");const stopButton = document.getElementById("stop-button");// определение полей вводаconst speed = document.getElementById("speed");// назначение действий на соответствующие кнопки/поляif(playButton)    playButton.addEventListener("click", play);if(pauseButton)    pauseButton.addEventListener("click", pause);if(stopButton)    stopButton.addEventListener("click", stop);if(speed)    speed.addEventListener("input", changeSpeed);// применение настроек на странице происходит при помощи их передачи в сообщении,// предназначенном для background скриптаfunction play(){    // определение выбранного языка воспроизведения    let language = document.querySelector('input[name="speech-language"]:checked').value;    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {        chrome.tabs.sendMessage(tabs[0].id, {todo: "play", newSpeed: speed.value, lang: language});    });}function pause(){    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {        chrome.tabs.sendMessage(tabs[0].id, {todo: "pause"});    });}function stop(){    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {        chrome.tabs.sendMessage(tabs[0].id, {todo: "stop"});    });}function changeSpeed(){    chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {        chrome.tabs.sendMessage(tabs[0].id, {todo: "changeSpeed", newSpeed: speed.value});    });}

Шаг 5. Пишем фоновый скрипт для синтеза речи

На самом деле,браузер уже содержит встроенные возможности для синтеза речи. Их мы и будем использовать.

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

Вот, что будет происходить в нашем фоновом скрипте:

  1. При загрузке страницы, содержащей элемент с ID "post-content-body", скрипт будет рекурсивно складывать содержимое текстовых элементов внутри родительского, чтобы сформировать текст для будущего синтеза (это гораздо проще, чем запрашивать разрешение на использование Habr API, но стоит учитывать, что однажды этот ID может поменяться);

  2. По окончании обхода элементов будет выдано сообщение о том, что пост готов к прочтению (но вы можете вместо этого модифицировать код так, чтобы воспроизведение аудио начиналось сразу после подготовки текста);

  3. Далее ожидается действие пользователя через popup-форму. Как только фоновый скрипт получит сообщение от popup-формы с командой и/или значением переменных, то он инициализирует переменные внутри себя и запустит соответствующие функции, например, найдёт голос для нужного языка, а затем начнёт синтез речи в случае нажатия на кнопку воспроизведения.

Конечно же, символы, содержимое таблиц, ссылки и некоторое другое нестандартное текстовое наполнение будут криво обрабатываться встроенным синтезом речи, да и не всегда ударение будет верным. Но зато, в целом вышла неплохая автоматизация ^_^

Далее вы можете модифицировать код на своё усмотрение.

Содержимое content.js
// создание средства синтеза речи и получение списка голосовconst synthesis = window.speechSynthesis;const voices = synthesis.getVoices();const utterance = new SpeechSynthesisUtterance();// текущий символ, который синтезируется в данный момент времениlet currentCharacter;// назначение события на момент, когда речь перестанет проигрыватьсяutterance.addEventListener("end", () => {    currentCharacter = null;});// получение символа, который синтезируется в данный моментutterance.addEventListener("boundary", event => {    currentCharacter = event.charIndex;});// переменные: язык речи, скорость проигрывания аудио, воспроизводимый текстlet speechLanguage = "ru-RU";let playerSpeed = 1;let textToPlay = "Открой статью, а потом уже нажимай сюда";/** * Рекурсивно прибавляет текстовое содержимое дочерних элементов для формирования текста поста * @param elementForSearchingIn - родительский элемент, в котором будет осуществляться поиск текстовых нодов */function joinTextNodes(elementForSearchingIn) {    if (elementForSearchingIn.hasChildNodes()) {        elementForSearchingIn.childNodes.forEach(function (node) {            joinTextNodes(node)        });    } else if (elementForSearchingIn.nodeType === Text.TEXT_NODE) {        textToPlay += " " + elementForSearchingIn.textContent;    }}/** * Поиск голоса для заданного языка речи * @param lang - заданный язык речи * @returns {null|SpeechSynthesisVoice} */function findVoice(lang) {    for (let i = 0; i < voices.length; i++) {        if (voices[i].lang === lang)            return voices[i];    }    return null;}/** * Проигрывание синтезированного высказывания */function playTextToSpeech() {    // если проигрывание речи было поставлено на паузу - происходит продолжение проигрывания    if (synthesis.paused && synthesis.speaking)        return synthesis.resume();    if (synthesis.speaking) return;    // определение параметров синтезируемой речи    utterance.text = textToPlay;    utterance.rate = playerSpeed || 1;    utterance.lang = speechLanguage;    utterance.voice = findVoice(utterance.lang);    // проигрывание речи    synthesis.speak(utterance);}/** * Установка проигрывания синтезированной речи на паузу */function pauseTextToSpeech() {    if (synthesis.speaking)        synthesis.pause();}/** * Остановка (прекращение) проигрывания синтезированной речи */function stopTextToSpeech() {    synthesis.resume();    synthesis.cancel();}/** * Изменение скорости речи в режиме реального времени */function changeSpeed() {    if (synthesis.paused && synthesis.speaking) return;    if (currentCharacter === null) return;    stopTextToSpeech();    playTextToSpeech(utterance.text.substring(currentCharacter));}/** * Осуществление взаимодействия pop-up формы с background скриптом при помощи отправки-получения сообщений * в активной вкладке с передачей в них необходимых для работы параметров. * Переданные параметры перезаписывают предыдущие настройки */chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {    switch (request.todo) {        case "play":            playerSpeed = request.newSpeed;            speechLanguage = request.lang;            playTextToSpeech();            break;        case "changeSpeed":            playerSpeed = request.newSpeed;            changeSpeed();            break;        case "pause":            pauseTextToSpeech();            break;        case "stop":            stopTextToSpeech();            break;    }    sendResponse({        response: "Message received"    });});// подготовка текста поста к чтениюwindow.onload = function () {    let contentBody = document.getElementById("post-content-body");    if (contentBody) {        textToPlay = "";        joinTextNodes(contentBody);        alert("Текст поста готов к чтению")    }};

Шаг 6. Упаковка и установка расширения

Я опишу упаковку и установку для Opera и Chrome. В других браузерах процесс, скорее всего, будет аналогичным, поскольку основные действия мы будем делать через стандартный раздел браузера "Расширения".

Для того, чтобы упаковать расширение, нужно проделать следующее:

  • Opera Меню Расширения Расширения включить Режим Разработчика Упаковка расширения

  • Google Chrome Дополнительные инструменты Расширения включить Режим Разработчика Упаковка расширения

На выходе вы получите crx-файл расширения, который, по факту, представляет собой архив с запакованным проектом.

Расширение можно установить через раздел "Расширения" двумя путями:

  • если модификация не требуется - для ряда браузеров достаточно перетащить подготовленный crx-файл из папки с проектом в окно с открытым разделом расширений и нажать на "Установить";

  • если была сделана модификация кода и требуется тестирование перед упаковкой(или браузер блокирует установку), то в окне с разделом расширений требуется нажать на "Загрузить распакованное расширение" и выбрать в диалоговом окне папку с проектом (предварительно убедитесь, что у вас включен режим разработчика).

Заключение

На этом мой небольшой туториал подошёл к концу.

Если у вас есть собственные расширения, которыми вы хотите поделиться - оставляйте в комментариях ссылки на них вместе с кратким описанием.

Кстати, мой хороший товарищ сделал на основе моего проекта расширение для того, чтобы оставлять для себя комментарии к объявлениям на Avito. Кому интересно - код и релиз вы найдёте на его GitHub.

Документированные исходники моего расширения и его запакованную версию можно найти здесь.

Спасибо за внимание! До новых встреч!

Подробнее..

Не спешите выкидывать свой PolyCom

20.11.2020 18:16:58 | Автор: admin

Если у вас где-то в углу неприкаянно грустит телефон компании Polycom не спешите от него избавляться! Он еще сможет вам послужить. По крайней мере ковыряние с ним может доставить массу удовольствия. Все нижеописанное тестировалось на устаревшей модели Polycom SoundPoint IP 450(от 1500 рублей за БУ на ebay), но также подходит и для большинства более современных моделей т.к. все они работают под управлением одной и той-же операционной системы UC.

Да, именно так и вы не ослышались даже древний офисный телефон работает под управлением проприетарной ОС.

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

  • Вывод полезной информации на экран телефона и использование внутреннего браузера

  • SIP телефония & Lync integration(Skype for Business) для SIP моделей

  • Интеграция с Google Chrome набор номера через расширение для google chrome

  • Кастомизация UI телефона

  • Интеграция с LDAP и AD и использование телефонных книг

Итак, обо все по прядку.

Встроенный браузер

Большинство моделей телефонов polycom оснащены тем или иным экранчиком, а прошивка поддерживает xhtml-браузер. У браузера есть 2 режима работы: idle отображается контент во время ожидания и active отображается контент во время использования телефона.

Телефон поддерживает только самые базовые html-теги, а также несколько собственных тегов для управления навигацией:

<html>

<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/></head>

<body>

<softkey index="1" label="Back" action="SoftKey:Back" />

<softkey index="2" label="Weather" action="SoftKey:Fetch;http://raspberrypi:88" />

<softkey index="3" label="Refresh" action="SoftKey:Refresh" />

<a href="Tel://89264341830">Taxi</a>|

<a href="Tel://89652991881">Суши</a>|

<a href="Tel://84965246699">Пицца</a>|

<br/>

<a href="Key:DoNotDisturb">DNDSettings</a>

</body>

</html>

Современные модели телефонов имеют расширенную поддержку HTML и даже умеют работать с Javascript. Используя встроенный браузер телефона довольно легко каcтомизировать UI/UX под свои предпочтения. В моем случае - это отображение прогноза погоды на основе Yandex Weather API и несколько статических страниц с наиболее часто используемыми телефонами.

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

Самый простой способ настроить работу внутреннего браузера это зайти на внутренний сайт телефона (просто введите IP телефона и дефолтный пароль 456) и на вкладке Settings/Microbrowser вы найдете все необходимые настройки:

SIP

Если ваша модель поддерживает SIP протокол вам открывается масса интересных возможностей.

Большинство телефонов может поддерживает несколько линий. Если у вас мегафон, то на одну линию можно завести номер мобильного телефона, предварительно подключив бесплатную услугу мультифон и переадресацию звонков на телефон и SIP как описано здесь.

Используя тариф без абонентской связи вы получаете условно-бесплатный домашний телефон.

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

Чтобы выгрузить файл конфигурации зайдите в Utilities/Import-Export configuration в раздел Export.

Выгруженный файл конфигурации содержит все настройки телефона кроме паролей!

Информацию о содержимом файла конфигурации можно найти здесь.

В качестве альтернативы можно использовать свободную линию для подключение к Microsoft Lync серверу для интеграции со Skype For Business.

Интеграция с браузером Chrome

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

Конечно для домашнего использования можно организовать LDAP интеграцию с Google contacts или же загрузить список контактов используя provisioning, но основную проблему с ужасным UX это не исправляет.

Для решения этой проблемы я сделал небольшое расширение для Google chrome, которое позволяет выделить номерна любой страничке и стартовать звонок со стационарного телефона.

Телефоны Polycom поддерживают, так называемые, интеграционные вызовы, когда отправив POST запрос извне на телефон можно заставить его выполнить то или иное действие: Позвонить на указанный номер, перейти в режим Не беспокоить, включить переадресацию, вывести сообщения на экран и т.д. и т.п.

К примеру такой запрос эмулирует нажатие кнопки Status на телефоне:

curl --digest -u Push:Push -d "<PolycomIPPhone><Data priority=\"All\">Key:Status</Data></PolycomIPPhone>" --header "Content-Type: application/x-com-polycom-spipx" -v http://192.168.0.226/push

А такой стартует звонок по указанному номеру на линии 1.:

curl --digest -u Push:Push -d "<PolycomIPPhone><Data priority=\"All\">tel:\\2222222;Line1 </Data></PolycomIPPhone>" --header "Content-Type: application/x-com-polycom-spipx" -v http://192.168.0.226/push

Соответственно все что требуется реализовать в расширении решить нетривиальный вопрос Digest аутентификации в JS, прочитать выделенный текст по вызову из контекстного меню и отправить Post запрос в телефон.

Предварительно необходимо разрешить интеграциионные вызовыв телефоне. Зайдите в раздел Settings/Applications/Push и выберите All в разделе Allow Push Message и не забудьте указать логин и пароль для авторизации вызовов. Без этого рабоать не будет.

В работе это примерно так:

Исходники расширения здесь а само раширение ищите в Google Chrome Extension Store.

Настройка UI телефона

UI Телефона поддается некоторой кастомизации. Кроме замены фона(на ЧБ экране это все равно выглядит ужасно) и отображения web- страниц во встроенном браузере -можно переназначать действие кнопок навигации, предварительно разрешив их переопределение с помощью этих ключей в конфигурации телефона.

feature.enhancedFeatureKeys.enabled="1"

feature.EFKLineKey.enabled="1"

Несколько примеров подобного переопределения:

Открытие странички с погодой во внутреннем браузере телефона:

softkey.1.action="http://personeltest.ru/away/192.168.0.228:88"

softkey.1.enable="1"

softkey.1.label="Инфо"

softkey.1.use.idle="1"

Переход в режим DoNotDesturb

softkey.1.action="Key:DoNotDisturb"

softkey.1.enable="1"

softkey.1.label="DnD"

softkey.1.use.idle="1"

Вызов 1-го контакта из списка быстрого набора

softkey.3.action="$S1$"

softkey.3.enable="1"

softkey.3.label="Такси"

softkey.3.use.idle="1"

Более подробную информацию о переназначении софтверных кнопок можно подчерпнуть здесь.

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

Подробнее..

Перевод Google удалил расширение ClearURLs из Chrome Web Store

25.03.2021 14:07:14 | Автор: admin

Google по каким-то причинам удалил популярное расширение ClearURL.

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

Многие сайты имеют излишне длинные URL-адреса с дополнительными параметрами, которые не несут никого функционала, но используются просто для отслеживания. Это в большей степени относится к ссылкам, присутствующим, например, в информационных бюллетенях:

https://example.com?utm_source=newsletter1&utm_medium=email&utm_campaign=sale&some_other_tracking_bits=...

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

https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.bleepingcomputer.com%2F&psig=AXXXXXYAWa
&ust=1616XXXXXXX&source=images&cd=vfe&ved=0CXXXXe-p3XXX

Дополнительные параметры в указанном выше URL-адресе (ved, cd и т. д.) просто отслеживающие метки и источники перехода, используемые для аналитики.

ClearURLs предназначен для фильтрации таких параметров отслеживания из URL-адресов и повышения конфиденциальности пользователя в интернете.

Если бы все ссылки будут лишены таких посторонних меток, они будут иметь довольно минимальную длину, состоящую только из важных данных.

Разработчик подал апелляцию в Google против блокировки расширения и получил ответ: в копии электронного письма, предоставленного разработчиком, Google утверждает, что описание расширения слишком подробное и нарушает правила интернет-магазина Chrome.

Google также заявил, что в описании расширения не упоминается, что оно содержит определенные функции, такие как импорта/экспорта настроек, ведения журнала и кнопка пожертвования, что вводит в заблуждение. Также было заявлено в письме, что расширение без необходимости требует разрешение на запись в буфер обмена (clipboardWrite).

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

Это разрешение было пережитком более ранней версии ClearURLs, сообщил Роиберт BleepingComputer в интервью по электронной почте.

Пользователи Chrome могут скачать и установить вручную расширение со страницы релизов на GitHub. Пользователи Microsoft Edge могу скачать расширение из Edge Add-ons store.

Роиберт также выпустил новую версию 1.21.0 с рекомендуемыми исправлениями, ожидающую проверки, которая появятся в магазинах Mozilla и Edge.

Подробнее..

Из песочницы Предлагаю подумать как технологии могут помочь бороться с пропагандой в СМИ?

22.10.2020 16:15:14 | Автор: admin
image
Фотограф: Аркадий Шайхет.

Вступление


Эту статью можно разделить на две логические части. В первой я рассматриваю феномен медиапропаганды: что это такое, почему она опасна и к каким жутким вещам уже приводила в истории. Я подробно рассмотрю механизмы работы современной государственной пропаганды в СМИ и попытаюсь понять, почему она так эффективна и какими характерными признаками обладает.

Вторая часть это размышления о том, как на основе рассмотренных в первой части характерных признаков можно попытаться автоматизировать распознавание пропаганды в СМИ. Поскольку пропаганда это воздействие текстом (помимо картинки, конечно), а я не обладаю необходимыми познаниями в области обработки естественного языкы (Natural Language Processing), то мои выкладки это именно что размышления вслух. Я буду более-менее структурированно описывать возможные функции программы, которая должна искать в материалах СМИ признаки пропаганды, но без технической конкретики.

Поэтому сразу скажу: не рассчитывайте прочитать в тексте про конкретные алгоритмы и их способы применения. Напротив буду честен: я рассчитываю найти среди вас тех, кто разбирается как в области NLP, так и в разработке плагинов для браузеров и получить от вас обратную связь в комментариях. Если достаточное количество людей заразится моими идеями, то, возможно, нам с вами удастся вместе поработать над интересным опенсорсным решением!

Disclaimer

Поскольку на Хабре не должно быть политики, я не буду в тексте вдаваться в детали того, как появилась идея создания этого проекта. Если кто-то захочет об этом узнать особенно, вероятно, те, кто захочет присоединиться к проекту я расскажу в комментариях или личке. Давайте просто представим себе некое Государство, которое политологи бы охарактеризовали как авторитарное, то есть, такое, в котором подавляются личные свободы граждан, производятся фальсификации на выборах, преследуется оппозиция и так далее, и представим себе, что всё, о чём речь пойдёт далее, относится к этому абстрактному Государству (хотя, учитывая культурный контекст, конечно, примеры будут в первую очередь из наших с вами постсоветских реалий). Почему я делаю фокус именно на государственной пропаганде, я объясню позднее.

Что такое пропаганда и почему она опасна?


image
Фотограф: Elliott Erwitt
Один из вечных столпов авторитарных государств это мощная государственная пропаганда. Мы достаточно часто слышим про это явление но что она из себя представляет?

Американский автор работ о пропаганде Эдвард Бернейс в 1928 году дал определение пропаганды как последовательные, неослабные усилия по созданию или формированию событий с целью оказания воздействия на отношение общества к той или иной инициативе, идее или группе. Иначе говоря, это попытка манипуляцией общественным мнением. Интересно, что в международном праве до сих пор нет единого определения понятия пропаганда из-за того, что очень тяжело провести чёткую границу между проявлениями свободы слова и систематической пропагандой, учитывая, что многие авторитарные режимы с той или иной степенью успешности долгое время могут притворяться дефектными демократиями. Тем не менее, такие организации, как ОБСЕ, различают 2 вида пропаганды:

  1. Пропаганда войны, а также национальной, расовой или религиозной ненависти, представляющие собой подстрекательство к дискриминации, вражде или насилию, как определено в международном и национальном праве. Это противозаконный вид и, следовательно, требует юридических действий с соответствующими мерами согласно нормам международного права по правам человека. Зачастую пропаганда войны оперирует выразительными средствами так называемого языка вражды.
  2. Остальные виды пропаганды, которые наносят вред профессии журналиста, но не требуют юридической оценки.

Это довольно важный момент, давайте его зафиксируем: существует пропаганда войны, использующая язык вражды, и прочая политическая пропаганда. К этому разделению, а также к более точному определению языка вражды мы ещё вернёмся позднее. А пока давайте попробуем ответить на вопрос, почему пропаганда вообще представляет опасность для общества?

История знает несколько трагических примеров того, как пропаганде удавалось пробудить в людях чувство ненависти, что приводило к войнам и геноциду. Пример нацистского Третьего Рейха известен настолько, что не вижу смысла отдельно на нём останавливаться. Другой пример геноцид в Руанде, в ходе которого люди из народности хуту на протяжении трёх месяцев убивали и насиловали сотни тысяч людей народности тутси; ещё за год до этих событий радиостанция Свободное радио и телевидение тысячи холмов стала призывать слушателей истреблять тараканов (презрительное название тутси) и позволяла себе расистский юмор, а с началом геноцида начала озвучивать адреса конкретных людей, которых, по их мнению, было необходимо убить. Частная радиостанция тысячи холмов получало финансирование от другой, государственной радиостанции, а его сотрудниками были исключительно хуту. Спустя многие годы экономист Гарварда Дэвид Янагизава-Дротт провёл исследование, в ходе которого ему удалось доказать влияние радиопропаганды на масштабы трагедии, сравнив уровень сигнала в каждой точке страны с количеством людей осуждённых за геноцид в данных точках.

Ещё один пример влияния пропаганды на ход истории югославские войны. Многочисленные исследования роли СМИ в конфликте в бывшей Югославии показали, что СМИ на службе у режима способствовали разжиганию войны и ненависти. Марк Томпсон в книге Ковка войны (Forging the War) писал, что словесное насилие привело к физическому. Итальянский журналист Паоло Румиз также написал в своей книге Маски для бойни (Masks for a Massacre), что уже в 1988 году война была в заголовках и статьях.

Это всё крайние примеры, когда пропаганда практически напрямую призывала к бойне и уничтожению другого народа или социальной группы. Но очевидно, что пропаганда не всегда настолько прямолинейна, да и не всегда преследует именно подобные цели. Почему же тогда она опасна и вредна?

Журналистика имеет перед собой цель разобраться и информировать граждан о результатах своих расследований действий государства или других лиц. Пропаганда же хочет не просто информировать, а внушить какие-то идеи. Она манипулирует гражданами, чтобы те вели себя не осознанно, руководствуясь собственными интересами, а действовали в интересах манипулятора (например, государства), то есть: отдавали голос за правильного кандидата или решение или игнорировали очевидные проблемы и не задавали лишних вопросов власти. В условиях свободы слова это всё не кажется какими-то ужасными вещами, но в авторитарном государстве у власти помимо пропаганды есть и другие рычаги, такие, как давление на независимые СМИ, аффилированность медиамагнатов с властью и возможность проведения массовых фальсификаций на выборах, вследствие чего эффект пропаганды возрастает многократно. Кроме того, пропаганда зачастую добивается своих целей путём поиска иллюзорных врагов, внешних или внутренних, и аппеляции не к разуму и логике, а к чувствам (см. термин постправда), и из-за этих двух факторов государственная пропаганда иногда фактически балансирует на грани риторики ненависти.

Кроме того, как мы увидим далее, современная госпропаганда чертовски эффективна, обладая большим арсеналом средств и каналов. Особая опасность заключается в том, что пребывая в бесконечном потоке информации, даже качественные СМИ порой могут подхватывать лживую информацию, намеренно пущенную в медиапространство манипуляторами. Одни из примеров последних лет: дезинформация о планах ЕС по отмене виз для мужчин-украинцев настолько часто упоминалась в украинских СМИ, что власти страны в какой-то момент были вынуждены сделать официальное опровержение, а незадолго до этого немецкие СМИ подхватили недостоверную информацию о зверствах на востоке Украины.

Для особо интересующихся: какие есть основные признаки пропаганды?
13 февраля 2014 года Общественная коллегия по жалобам на прессу (ОКЖП), российский орган медийного саморегулирования, издала документ, в котором сформулировала систематические признаки пропаганды. Давайте рассмотрим эти признаки:

Инструменты:


Прямое убеждение и влияние


  • целенаправленное сведение многомерного к двумерному, цветного к черно-белому; сужение поля личного морального выбора и ответственности за выбор --> мышление в категориях мы-они (враги); попытки чрезмерно простых объяснений для сложных процессов (США делает так-то это потому что они нас на колени хотят поставить!).
  • присутствие (обнаружение, создание, доработка) образа врага; внесение в массовое сознание и поддержание в нём разделения на мы (правильные, с истинными ценностями, с настоящей правдой) и они (с отрицательным набором по тем же позициям) --> Зачастую в государственной пропаганде глава государства представляется как сильный правитель, который много лет положил на процветание (или сохранение) страны, а те, кто выступают против него, делают это из нехороших намерений (захватить власть, разворовать страну, расколоть общество и т.д.)
  • формирование убеждения в моральной оправданности любого поступка по отношению к врагу, в том числе внутреннему врагу, в том числе врагу потенциальному, в том числе к лицу, недостаточно лояльному по отношению к государственным институтам, конкретным носителям власти, идеям или ценностям, прокламируемым в качестве соответствующих государственным интересам и национальным традициям. --> От пропагандистов часто можно услышать выражения в духе Сталина на вас нет (подразумевая массовые репрессии против врагов народа) или вот зачем нужна смертная казнь и т.д.
  • объектное отношение пропагандиста к субъекту, конкретному человеку, общественной группе, обществу --> например, пропагандист может себе позволить в резких, неуважительных или даже оскорбительных выражениях говорить об оппозиционном политике или протестующих. Объектное отношение проявляется также и в том, что пропагандист рассматривает своего читателя или слушателя как ведомого, чьим доверием можно пренебречь --> и чьими убеждениями можно манипулировать. Журналист же расскажет реальную историю и даст сделать выводы реципиенту (хотя абсолютно объективной журналистики быть не может, и этому есть ряд объяснений если интересно, то ознакомьтесь с такими теориями, как Agenda-Setting Theory, Framing, Priming).
  • повседневное убеждение, повторяющаяся последовательность вбрасываемых в обсуждение тем, примеров, образов; как правило, апелляция к традиционным ценностям как к единственным устойчивым в неустойчивом мире, а потому и самым главным в иерархии ценностей --> Набор сюжетов достаточно ограничен и состоит по большей части из постоянных мотивов, таких, как: Запад как соперник, координируемая извне оппозиция и националистичная Украина. Эти мотивы повторяются изо дня в день, благодаря чему позволяют сформировать у реципиентов определённое мировоззрение.
  • апелляция преимущественно к эмоциям, к чувствам, а не разуму --> Вот почему в ток-шоу доминируют повышенные тона на ровном месте.
  • игра на страхах, предубеждениях, фантомных болях; активное использование историй о злодеяниях и зверствах; широко распространённый рабочий приём сообщение о жестокости и насилиях. --> А вы помните сюжет про распятого мальчика с войны на Донбассе? Никто так и не смог найти подтверждение этой истории.


Замутнение, запутывание


  • действие в логике цель оправдывает средства; использование средств и методов, сплошь и рядом несовместимых с такими ценностями, как честность, правдивость и т.д. --> использование сфабрикованных фото и видео, представление актёров в качестве реальных участников событий.
  • формирование СМИ-моделей, включая модели поведения, конструирование ситуаций, подлежащих обсуждению, сосредоточение внимания с перенесением его из зон, уводимых при этом в тень, на пропагандистских конструктах и виртуальных реальностях. --> Отвлечение внимания это одна из главных стратегий манипуляторов. Самый простой пример это когда вместо существенных тем (законопроекты, предвыборные программы, международные встречи) внимание сосредотачивается на неважных деталях. Или когда вместо проблем собственной страны активно обсуждаются проблемы соседних стран и кто там кем кукловодит.


Подрывания и дискредитации правдивых репортажей и сообщений


  • целевой, работающий на жесткий сценарий отбор фактов, активное обращение к дезинформации, там, где это представляется полезным и возможным, манипулирование фактами, статистическими данными, мнениями, включая экспертные, или сдвиг акцентов там, где прямая дезинформация представляется непроходной --> Можно взять интервью у человека по поводу вопроса, в котором он не является экспертом; из большого социологического доклада рассказать только про часть данных; из длинной повестки переговоров рассказать только про ту часть, которая прошла успешно (или наоборот).
  • работа под прикрытием журналистики, стремление играть или выполнять роль первичного источника новостей --> Зачастую пропагандистские редакции действительно делают репортажи с мест событий, берут интервью у участников этих событий то есть, стилистически и функционально могут быть очень похожи на настоящие журналистские редакции. Эти журналистские материалы разбавляют теми, что, собственно, и должны формировать у реципиентов необходимое манипуляторам представление о событиях. Манипулятивные материалы часто подаются как аналитика либо ток-шоу и другие полуразвлекательные жанры.
  • фабрикация признаков надежности информации, включая ее источники. --> Мутные либо вообще анонимные эксперты, манипуляции социологическими данными, ложная интепретация графиков, намеренно некорректный перевод текста первоисточника.


Цели:


  • Наличие четкой, подлежащей реализации цели как ожидаемого итога воздействия на объект с определенным изменением (или поддержанием) картины мира в его сознании; в идеале с переведением наведенного убеждения в поступок и образ действий. --> Пример поступка: правильный голос на президентских выборах.
  • формирование лояльности адресата пропагандистского воздействия к системе институтов и идей, которым служит пропагандист. --> Долгосрочная цель государственной пропаганды, которая достигается путём вышеперечисленных инструментов: демонстрация надёжности информации, повторяемость нарративов и т.д.



Почему пропаганда эффективна? Каковы её инструменты?


На эти вопросы очень хорошо ответили эксперты НКО RAND Corporation Кристофер Пол и Мириам Мэтьюз. Имея в виду российскую государственную пропаганду, они утверждают в своём докладе, что новая российская пропаганда развлекает, запутывает и шокирует аудиторию. И объяснили её эффективность следующими качествами: Она оперативна, непрерывна, нелогична и использует принцип многократного повторения. Они сделали разбор каждой из этих характеристик:

1. Оперативна
2. Непрерывна
3. Нелогична
4. Использует принцип многократного повторения.


Давайте пройдёмся по каждому из этих пунктов и рассмотрим описанные авторами доклада механизмы влияния пропаганды на получателей информации.

Оперативна

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

Непрерывна

Пропаганда штампует сообщения как настоящая инфофабрика, не оставляя в потоке сообщений брешей. Реципиенты получаются непрерывную картинку обо всём происходящем вокруг. Дополнительную эффективность эта непрерывность получает благодаря многоканальности современной пропаганды. Ведь на слуху у всех сюжеты с пары-тройки пропагандистских телеканалов и сайтов, но на самом деле продвигающих линию партии сайтов и телеграм-каналов, по утверждению авторов доклада, десятки. И такая многоканальность очень помогает пропаганде в достижении своих целей по причине того, что людям свойственно полагать, что информация, полученная из различных источников, скорее всего, основана на различных точках зрения, а значит заслуживает внимания. Поскольку эти каналы в сумме имеют огромный охват, то реципиенты находят как в своём окружении, так и в интернете множество людей, которые одобряют эту информацию, и тем самым достоверность этой информации в глазах реципиента повышается. Помимо этого, есть ещё один интересный эффект: когда интерес потребителя информации невысок (иными словами, когда у потребителя нет времени и желания разбираться в информации), убедительность сообщения зависит более от количества аргументов, приводимых в его защиту, чем от их качества.

Пропаганда использует ещё один баг нашего мозга: он получает свою дозу дофамина каждый раз, когда мы кликаем на клавишу проигрывания видео на Youtube, и очень легко подсаживается на потребление видеоконтента и просмотр лент соцсетей. Человек оказывается в состоянии потока, выбраться из которого очень сложно. Просто кто-то привыкает просматривать интервью, сериалы или короткие видео-вайны, а кто-то посты на политические темы и ток-шоу.

Нелогична

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

Использует принцип многократного повторения

Как вы уже поняли, пропаганда эксплуатирует несколько интересных багов нашего мышления. Один из них эффект иллюзорной правды. Люди скорее воспримут утверждение как правдивое, если уже слышали его раньше, чем если бы это было совершенно новое сообщение. Эффект иллюзорной правды проистекает из того факта, что повторяющиеся утверждения мы воспринимаем легче и принимаем за правдивые. Интересная деталь от авторов доклада: Даже в случае с нелепыми историями и городскими легендами те, кто слышал их множество раз, склоняются к тому, чтобы в это поверить.

Как можно перехватить первое впечатление?


image
Фотограф: Rene Maltete

Итак, мы рассмотрели теорию пропаганды, мы поняли, почему она опасна и почему она действенна. Только представьте себе тысячи, если не миллионы своих сограждан, которым день за днём объясняют, кого любить и выбирать, а кого ненавидеть и преследовать очевидно, что такая ситуация нездорова для государства, ведь граждане должны делать свой собственный выбор, сделанный на основе собственных убеждений, сформированных на правдивых фактах. В такую ситуацию попал я. И, как программисту, мне захотелось сделать что-то своими руками.

Меня особенно зацепил тот факт, что пропаганда старается создать первое впечатление, и достигает этого путём своей многоканальности по крайней мере, в онлайне. Я сразу представил себе человека, который после тяжёлого рабочего дня заходит в интернет, открывает новости в своём браузере и открывает портал в поток сознания ловких манипуляторов. И вот тут-то я понял, что самый простой способ перехватить первое впечатление, а точнее помешать пропагандистами создать его это создать расширение для веб-браузера, которое сможет анализировать материалы в режиме живого времени. Открыл веб-страницу получил аналитику с предупреждениями: вот тут, там и здесь характерные для пропаганды признаки!

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

  1. В своё время у исследователей медиа и политологов была популярной теория, именуемая Теорией установления повестки дня (agenda-setting theory), согласно которой часто освещаемые события кажутся реципиентам более важными таким образом, СМИ могут влиять на их решения (например, на выборах). Но позже исследователи доработали эту теорию, признав, что формирование повестки дня является обоюдным процессом, и публика тоже принимает участие в формировании повестки дня. Это говорит о том, что в идеале люди должны проявлять интерес к происходящему вокруг, находить время и силы, чтобы разбираться в информации и делать соответствующие выводы и конкретные действия. Короче говоря, быть политграмотными что довольно трудно, когда при всех делах и проблемах рутинной жизни желание на получение подобной грамотности сходит на нет. Если же человек сможет получать немедленную оценку качества материалов, да ещё и иметь возможность поставить свою обоснованную оценку, то его вовлечение повышается. В плагин для браузера легко встроить возможность прямого реагирования реципиента на контент (например, возможно выставления рейтинга материалу или СМИ на основе некоего check-list; эти данные потом могут агрегировать в единый рейтинг СМИ).
  2. Илай Парайзер (Eli Pariser) придумал понятие пузырь фильтров (filter bubble), которое описывает феномен, когда современные социальные сети подбирают для нас информацию на основе того, что нам (как кажется их алгоритмам) интересно. Из-за этого мы постепенно оказываемся в пузыре, получая лишь однобокую информацию и совсем не узнавая, что происходит за пределами этого пузыря. Это, например, привело к ещё большей поляризации американского общества, в котором разделение на демократов и республиканцев в последние годы усилилось. Возможно, этот эффект не был бы столь силён, если бы не очередной баг нашего мышления, названный предвзятостью подтверждения (confirmation bias): мы отдаём предпочтение той информации, которая согласуется с нашей точкой зрения. Пузырь фильтров лишь усиливает эту нашу когнитивную ловушку. Ухудшается вся ситуация тем, что убеждения человека начинают усиливаться из-за возникновения вокруг него некоего сообщества, которое вследствие тех же когнитивных ошибок и особенностей работы алгоритмов имеет одинаковые с твоими убеждения, и эти убеждения взаимно усиливаются путём передачи и повторения сообщения внутри сообщества (эта ситуация называется эхо-камерой, или echo chamber). Вот так и получается, что человек, по той или иной причине подверженный влиянию пропаганды, со временем всё больше ввязывается в её путы, и даже не подозревает о том, что им манипулируют. Получение немедленной обратной связи относительно потребляемых материалов могло бы многим открыть глаза (при условии общей открытости реципиентов к новому).

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

Следующим шагом была бы собственно разработка плагина для браузеров и, соответственно, автоматизация поисков признаков пропаганды. И вот тут я наткнулся на границы своих познаний. Для автоматизированного поиска этих признаков необходимы познания в NLP (Natural Language Processing), коих у меня нет. Я что-то где-то когда-то слышал, но именно на таком уровне: мне кажется, что вот для этого есть какие-то там алгоритмы. Лезть в чужой огород не хочется, ибо наверняка найдутся люди, которые умеют в обработку русского языка и которые могли бы

  1. Выразить своё общее мнение по поводу моих идей;
  2. Предложить варианты решения описанных проблем.

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


Определение и автоматизация процесса поиска признаков пропаганды в материалах СМИ


image
Ну вот как-то так оно должно работать.

Очевидно, что существуют различные медийные форматы: текстовые трансляции, видеорепортажи, аналитические телеграм-каналы и ток-шоу. И у каждого формата есть свои особенности, которые нужно, наверное, учитывать. Или нет? Так или иначе, я предлагаю начать с простого формата: статьи (то есть, тексты) на новостных сайтах. Человек открывает сайт и начинает читать тексты на этом сайте. Поставьте себя на его место: на что он должен обратить внимание? Как именно он сможет понять, что перед ним попытка манипуляции?

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

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

Качество подачи материала


Эта категория содержит несколько правил, которых должна придерживаться новостная журналистика.

Был ли дан контекст?


Смысл: В конце новостного текста часто можно встретить краткое описание событий, предшествовавших произошедшему событию. Например, если в новости приведены выдержки из последнего интервью Трампа, то в конце обычно объясняется, что сейчас в США проходит президентская гонка, и по социологическим опросам пока что лидерство у того-то, а тот-то считает вот так.

Критика: Не у всех событий есть контекст некоторые из них просто происходят. Например, взрыв в Бейруте.

Автоматизация:

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

Наличие источников


Смысл:

  • Общее правило: если есть новость, то должно быть сказано, откуда поступила эта новость ведь у новости всегда есть какой-то источник.
  • Если статья содержит ссылку на какой-то источник информации (например, политик или другое медиа), то должна быть дана гиперссылка.

Критика:

  • Что делать с анонимными источниками (без которых не может существовать журналистика)? Что делать с расследовательской журналистикой (которая по формату отличается от новостной)?
  • Не у всех источников могут быть свои сайты. Либо теоретически возможна ситуация, в которой информация была передана по ТВ, но не в интернете. Оба фактора могут осложнить дачу гиперссылки.

Автоматизация:

  • Алгоритм должен уметь определять в тексте наличие источников информации. Либо по ключевым словам: сообщил, сказала, либо с помощью техник NLP.
  • Проверять наличие гиперссылок легко;
  • Если гиперссылка дана в новости Б, то можно было бы вызвать текст источника А и проверить, была ли в тексте Б использована статистически важная информация из А?
  • Также можно проверить, правильно ли были переданы цифры (например, из соцопроса) из текста А в тексте Б.

Корректность перевода


Смысл: если статья целиком или частями переведена, то был ли перевод сделан корректно?

Критика: Оценить корректность перевода автоматизированно практически невозможно. Поскольку манипуляция может скрываться в выборе отдельных слов, то нам требуется алгоритм, который очень чуток к мельчайшим оттенкам понятий, а таковых, насколько я понимаю, пока не существует. Значит, такой вид манипуляции при переводе найти будет нереально. Но что реально обнаружить, это действительно ли оригинальная статья содержала тезис, похожий на тот, что приводится в переводе (или он был полностью выдуман?).

Автоматизация: перевод либо оригинального текста на язык перевода, либо наоборот, через вызов некоего API, и сравнение двух текстов на семантическую близость (надеюсь, я правильно это назвал?).

Анализ контента


Эта категория содержит действия, которые можно применять вдобавок к перечисленным в первом пункте.

При наличии конфликта: были ли выслушаны все стороны?


Смысл: самый простой пример: если президент критикует оппозиционера, то было бы хорошо, если бы новостное издание спросило мнение оппозиционера по этому поводу.

Критика: не всегда такое правило имеет смысл. Если президент в целом про протестующих на улицах говорит, что это марионетки Запада, то не совсем понятно, у кого спрашивать мнение по этому поводу, и добавит ли ответ на эту реплику информационной ценности материалу. Поэтому это правило нужно попытаться более жёстко формализовать: например, если какой-то конкретный человек или организация обвиняет другого конкретного человека или организацию в чём-то конкретном, то тогда действительно нужно спросить мнение другой стороны. Но реакция другой стороны может последовать не сразу и опубликована какое-то время спустя, что вновь обуславливает сложность выполнения данного правила.

Автоматизация:

  • Подобно тому, как мы собираемся автоматизированно выявлять источник информации, нужно научиться выявлять стороны конфликта (если это возможно алгоритмически).
  • Просто мысль: имеет ли смысл сохранять информацию про общественно значимых персон и организации в социальном графе? Для того, чтобы понимать, от кого ждать ответную реплику?

Сравнение: как тот же инфоповод осветили другие издания?


Смысл: сравнить подачу событий данным изданием с подачей других изданий.

Критика: честно говоря, не вижу слабых сторон. Если найдёте, скажите.

Автоматизация:

  • Выделить из текста главные тезисы или понятия, и делать поиск по этим тезисам или понятиям в других общественно значимых изданиях (о том, как их определить, поговорим отдельно).
  • Более простое решение предлагать на основе анализа текста ключевые слова, по которым читатель сразу может начать искать дополнительную инфомарцию, например, в Google News.

Анализ на манипуляции


Если прошлые категории предлагали некие стандарты качества для новостных материалов, то в этой категории речь пойдёт непосредственно о намеренных манипуляциях путём выразительных средств.

Предвзятость ньюсмейкеров


Смысл: манипулятивные действия могут совершаться не только самими СМИ, но и теми, кого СМИ цитируют. Поэтому довольно неплохо знать, что ранее говорил субъект про явления, про которые высказывается сейчас.

Критика: у любого человека есть некий набор установок, ценностей и мировоззрений, то есть, по сути, любой человек необъективен. Поможет ли реципиенту знание того, что Вячеслав Володин и раньше делал выпаду в сторону Запада? Ну разве что, поможет на примере других людей задуматься о своих установках и том, насколько они пластичны. Что думаете?

Автоматизация: можно сохранять взаимоотношения между субъектами в социальном графе. И под рёбрами графов сохранять прошлые высказывания субъектов друг о друге.

Слова-маркеры


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

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

Автоматизация: поиск по словам (и их склонениям) и выражениям (и семантически очень близким к ним). Поиск можно осуществлять как по высказываниям ньюсмейкеров, так и по текстам в целом.

Анализ оттенков слов


Смысл: я назвал эту функцию так, потому что это название наиболее близко передаёт её смысл. Есть же разница в том, чтобы сказать протестующие вышли на улицы или протестующие заполонили улицы? Очень часто манипуляции заключаются именно в использовании определённой лексики, которую можно, наверное, назвать оценочной. То есть, происходит не просто констатация факта, а сразу даётся некая оценка этому факту.

Критика: Это должна быть непростая задача для алгоритма, но я придумал другое решение (которое, впрочем, тоже не из простых смотрите ниже).

Автоматизация: психолингвисты разработали модель под названием Linguistic Category Model, которая имеет такой инструмент, как шкала конкретности / абстрактности. Чтобы понять, как она работает, давайте рассмотрим следующие высказывания:

  • Протестующие выходят на улицы
  • Протестующие заполонили все улицы
  • Протестующие ненавидят власть
  • Протестующие фашисты.

Я, конечно, утрирую, и простите меня, лингвисты, если я привёл не совсем корректные с точки зрения этой теории формулировки, но общий смысл примерно такой: существуют 4 ступени конкретности / абстрактности, от самой конкретной формулировки (фактической) до самой абстрактной (оценочной).

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

Нарративы госпропаганды


Смысл: я уже говорил, что меня в первую очередь интересует госпропаганда, и хотя все предыдущие пункты могут быть использованы для поиска любой пропаганды, этот пункт я посвящаю именно государственной. Дело в том, что набор сюжетов, которые использует госпропаганда в своих материалах, довольно ограничен и пополняется новыми сюжетами довольно редко. Сколько лет мы уже слышим про марионеток и спецслужбы Запада, или украинских националистов? То есть, новые мини-мотивы, конечно, появляются (диабетная кома Навального), но на некоем более высоком уровне абстракции, как правило, это всё те же старые мотивы, что были и год, и пять лет назад.

Критика: не нашёл. Если найдёте, скажите.

Автоматизация:

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

Язык вражды и войны


Справка:

Через несколько лет после Октябрьской революции 1917 г. детский поэт Корней Чуковский написал: С величайшей гордостью вспоминают советские люди, как чудесно обновила наш язык революция. Она очистила его от таких омерзительных слов, как жид, малоросс, инородец, простонародье, мужичье и т. д. Из действующих слов они сразу же стали архивными. К сожалению, он ошибался, ведь не все из этих слов были искоренены, а многие были заменены ещё более оскорбительными.

Слова, которе перечислил детский писатель, относятся к лексикону так называемого языка вражды (синонимичное выражение риторика ненависти). Общепринятого определения языка ненависти в международном праве нет, но в основном этот термин интепретируют в контексте ненависти к людям, имеющим так называемые защищённые характеристики это личные характеристики, по которым вас не имеют права дискриминировать: раса, цвет кожи, пол, язык, религия, политические и иные убеждения, национальное или социальное происхождение, собственность, возраст, рождение, происхождение из коренного народа или самоидентификация с коренным народом, инвалидность, статус мигранта или беженца, сексуальная ориентация, гендерная идентичность или интерсекс вариация.

В целом, это довольно широкая категория признаков. Вражда же это интенсивное и иррациональное чувство осуждения и отвращения по отношению к отдельному индивиду или группе, избранных в качестве объекта по причине обладания определенными реальными или приписываемыми защищенными характеристиками (признанными международным правом). Вражда это больше, чем просто предвзятость, и она обязательно имеет дискриминационный характер. Вражда является проявлением эмоционального состояния или мнения и, таким образом, отличается от любого явного действия. И это важный момент использование языка вражды необязательно непосредственно приводит к каким-то конкретным последствиям. То есть, услышав давайте резать хоббитов, вы понимаете, что звучит призыв к геноциду. А как относиться к оценке наша гнилая, продажная, смердящая оппозиция (обе формулировки придуманы, любые совпадения случайны)? Призыва к действиям нет, если кто-то добровольно пойдёт что-то делать с оппозиционерами, то найти связь его действий с данной кем-то из публичных лиц оценкой будет проблематично, и тем не менее, в этой оценке звучит как минимум предвзятость, но судя по эмоциональному градусу, это вполне может быть и вражда.

В общем, чёткие трактовки и границы этих терминов найти затруднительно. Например, глубоко оскорбительные выражения не относятся автоматически к языку вражды если они не звучат применительно к некоему объекту именно из-за его защищённых характеристик. В контексте языка вражды часто звучат термины ингруппа и аутгруппа то есть, при использовании языка вражды подразумевается некое противостояние двух групп, наличие деления на своих и чужих. Но существуют и более чёткие классификации риторики ненависти. Согласно одной из них, сформулированной исследователем Верховским (Верховский А. М.: Язык мой Проблема этнической и религиозной нетерпимости в российских СМИ), есть три большие категории языка вражды:

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

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

Смысл: медийный текст не должен содержать выражения из языка вражды. Ни журналистский материал, ни новостной сюжет, ни просто колонка с авторским мнением.

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

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

База языковых штампов госпропаганды


Смысл: в текстах государственной пропаганды часто можно встретить расхожие выражения, которые характерны именно для этого жанра. Например, прошёл митинг в поддержку действующего политического курса страны.

Критика: тяжело находить такие выражения и удостовериться, что они были использованы именно в пропагандистском дискурсе. Кроме того, мы не можем исходить из того, что эти выражения всегда используются лишь в пропагандистских СМИ. Возможно, этот критерий избыточен, но если всё же будет доказана его целесообразность, то это должен быть мягкий критерий пропаганды.

Автоматизация: Как и в прошлом пункте, не знаю, в каком формате должны быть эти выражения сохранены. Ведь нужны, наверное, склонения / спряжения, если мы хотим совершать поиск по выражениям-маркерам? Если мы пойдём путём обучения алгоритма, то нам нужен корпус текстов? Извините, как я уже говорил, я профан в компьютерной лингвистике.

Анализ настроения (sentiment analysis)


Смысл: пропаганда, как мы выяснили, старается влиять на эмоции. Зачастую она вызывает негативные эмоции не из-за представления какого-либо свершившегося факта (гнев из-за избиения человека), а из-за интерпретации, обвинений и оценочных суждений.

Критика: я не знаю, насколько хороши современные алгоритмы sentiment analysis, и какие у них есть ограничения (например, по размеру текстов) для обеспечения хороших результатов.

Автоматизация: анализ настроения по абзацам, главам или всему тексту, и если негатив был найден, то вопрос пользователю: Вероятно, вы чувствуете X. Из-за свершившегося факта или чьей-то интерпретации в отношении Y)?.

Анализ качественности СМИ


Эта категория содержит несколько предложений по тому, как оценивать качественность СМИ. Под качественностью подразумевается то, насколько СМИ соответствует описанным выше критериям качества подачи материала и честности к реципиентам (то есть, когда не пытается ими манипулировать).

Игнорирование событий


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

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

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

Анализ прошлых материалов от СМИ для нахождения закономерностей


Смысл: характеризовать СМИ по одному или нескольким материалам затруднительно. Единожды выдать СМИ ярлык качественного тоже проблематично, ведь у него может поменяться редакция. Поэтому нужно характеризовать СМИ по некоему числу последних N материалов. Вот на какие аспекты можно анализировать материалы СМИ в некоем временном континууме:

  • Перекос в сторону информации из государственных органов; недостаток материалов, где представлено мнение оппозиции или обычных людей;
  • Использование нарративов пропаганды или языка вражды в журналистских материалах в прошлом
  • Систематическое нарушение стандартов качества подачи материалов

Критика: Не нашёл слабых мест.

Автоматизация: сохранение обнаруженных рассмотренными выше функциями признаков в формате time series или каком-либо другом. Возможно, пользователь сможет также сам сохранять какие-то заметки.

Причание 1: можно создать более широкий список критериев качественности СМИ, на основе которого пользователи плагина или некая группа экспертов (хотя я выступаю за открытость всех перечней, процедур и данных) будет оценивать СМИ.

Примечание 2: можно то же самое делать не для СМИ, а для политиков и общественных деятелей. Например: Лукашенко заявил о том, что в белорусских лесах после поимки 33 вагнеровцев всё ещё прячутся 170 российских боевиков. Пользователя это заинтересует, и он сохранит пометку: Жду подтверждения о .... Проходит время, оказывается, что это было неправдой, и пользоветель отмечает это в плагине, и уровень достоверности Лукашенко у этого пользователя падает. Но это совсем другая функциональность, и дизайн функции тоже будем другим.

Разница между медийными форматами


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

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

Заключение


Закончить материал хотелось бы несколькими важными замечаниями.

  1. Цель плагина это повысить осознанность людей при прочтении новостей, научить их определять манипуляции через выразительные и другие средства.
  2. Делать это я хочу через как можно более формализованные правила. Конечно, формализовать можно далеко не всё, и очень часто мы распознаём пропаганду, что называется, в комплексе.
  3. Плагин можно расширять. Например, можно создать целую систему оценки СМИ и даже отдельных журналистов, блогеров и авторов вообще (например, авторов постов в Telegram). То есть, каждый пользователь плагина сможет оценивать СМИ или автора, и эти оценки будут агрегироваться в некое подобие рейтинга для СМИ и авторов. Но это всё потом.
Подробнее..

Перевод Chrome (чуть не) снёс расширение, над которым мы работали три года, и не хочет говорить за что

31.07.2020 14:18:55 | Автор: admin
Представьте себе, что у вас небольшой бизнес. В один прекрасный день вы получаете письмо, составленное роботом, в котором сообщается, что вы нарушаете какой-то пункт правительственных постановлений. Что именно вы нарушаете, не говорится, но вам дают четырнадцать дней на то, чтобы исправить ситуацию, иначе вас закроют. Если от вас поступит слишком много заявок на пересмотр, сообщает робот, вас закроют без права обжалования.

Вот в такую русскую рулетку заставляет играть разработчиков интернет-магазин Chrome. Некоторым везёт, и путём долгих препирательств и игр в угадайку они в конце концов проходят модерацию так было с Pushbullet. Другим везёт меньше им перекрывают кислород. Мы попали в число неудачников: одиннадцатого июня нас убрали с маркета. Бизнес на грани смерти, а решают его судьбу люди, которые отказываются выходить с нами на связь.

Наше расширение инструмент для создания доступной онлайн-среды; оно позволяет людям с нарушениями двигательных функций или травмами использовать при работе с браузером голосовое управление вместо мышки и клавиатуры. Мы работаем честно: ни рекламы, ни выкачивания данных просто прозрачный выбор между бесплатной версией и платной подпиской. Рейтинг составляет 4.7, число активных пользователей в неделю около четырёх тысяч. Мы вложили в этот продукт три года работы от звонка до звонка.

Двадцать шестого мая нас оповестили, что мы нарушаем правила следующим образом:

Приватность пользовательских данных

В вашем продукте обнаружены нарушения правил из раздела Использование разрешений, согласно которым разработчики обязаны:
Запрашивать доступ к минимальному набору возможностей, необходимому для функционирования инструментов или сервисов вашего продукта;
Если несколько разных разрешений могут обеспечивать выполнение функции, выбирать то, которое даёт минимальный доступ к личным данным или функциональности;
Не создавать задел на будущее, запрашивая разрешения, которые могут оказаться полезны для еще не реализованных инструментов или возможностей.

Поломав голову над тем, какие разрешения они могут иметь в виду, мы несколько дней просидели допоздна, внося в расширение изменения, и отправили версию с урезанными запросами. Затаили дыхание и стали ждать.

Было: debugger, notifications, tabs, activeTab, tts, storage, unlimitedStorage, host permission
Стало: tabs, debugger, notifications, tts, storage, host permission

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

Текст повторного отказа:

Cпам и реклама в магазине

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

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

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

Семнадцатого июня мы получили письмо с отказом всё по той же причине спам и реклама в магазине. Тут мы уже вообще перестали что-либо понимать и стали ужимать описание по максимуму. Может, им не понравилось, что мы указывали конкретные сайты, под которые делали инструменты (Gmail, Google Sheets, Reddit, Hacker News)? У нас в расширении есть плагины, в которых предусмотрены особые функции именно для этих ресурсов. Ну, например, для Gmail есть специальные команды написать, ответить, назад во входящие и так далее. Возможно, модераторы не слишком вникали в частности.

Мы по-быстрому повыкидывали лишнее из текста, пока не осталось что-то такое.

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

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

Все письма от администрации Chrome заканчиваются такими словами:

Регулярные или грубые нарушения правил интернет-магазина Chrome могут привести к заморозке вашего аккаунта разработчика или к запрету на использование платформы.

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

tabs


Разрешение activeTab пускает нас на ту вкладку, с которой пользователь кликнул на иконку расширения. Но для наших нужд этого недостаточно. Представьте: пользователь запускает расширение нажатием на иконку, а затем говорит: Следующая вкладка, чтобы перейти на соседнюю вкладку в том же окне. При таком раскладе без разрешения tabs подавать команды он уже не сможет, ведь activeTab действует только в пределах той вкладки, где произошел запуск. Поэтому-то и требуется tabs, которое не имеет настолько строгих ограничений.

debugger


Необходимо, чтобы голосом нажимать клавиши (нажать на левую стрелку, нажать на Enter). Слушатели, реагирующие на сгенерированные события, во многих случаях не срабатывают, как например в Google Sheets или с некоторыми операторами div с атрибутом contenteditable. Сделать разрешение необязательным невозможно (ограничение прописано в манифесте).

host permission


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

tts


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

notifications


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

storage


Разрешение служит для хранения пользовательских настроек и кастомных плагинов.

Дополнение к статье, опубликованное позже


В этой битве мы победили, но войну не выиграли.

Мне повезло. Если бы я в тот день не выиграл главный приз в лотерее Интерес интернетов, наш проект бы прикрыли и пользователи остались бы брошенными на произвол судьбы с инструментом, который выручал их в повседневной жизни, а теперь больше не поддерживается. Тысячи людей с ограниченными возможностями могли потерять комфортную онлайн-среду, а мы свой бизнес, потому что судьба того и другого находилась в руках обезличенного контролёра, который тоже иногда ошибается.

Вкратце повторим: наше приложение для Chrome удалили с маркета, якобы потому что оно нарушало правила. После обширных правок кода, многочисленных неудачных попыток пройти модерацию и недели изгнания с маркета без возможности обсудить ситуацию с администрацией мы стали во весь голос возмущаться на Reddit. Наш пост попался на глаза кому-то, кто вхож во внутреннюю кухню интернет-магазина Chrome; этот человек написал нам в Твиттере сказал, что произошло недоразумение и извинился. В тот же день мы в очередной раз отправили расширение на модерацию и снова появились на маркете.

Но жалобы в Сети не должны становиться каналом связи с администрацией. Разработчики не должны от безысходности полагаться на лотерею Интерес интернетов. Магазин Chrome существует уже десять лет, пора бы им как-то навести у себя порядок. Ну а мы, команда LipSurf, хотим воспользоваться своим завидным положением в центре внимания, и помочь остальным разработчикам улучшить систему.

Для начала, хотим поблагодарить героя дня @DotProto. Он не только нас спас, но еще Pushbullet и многих других. Мало того, он этим занимается в свободное от работы время. Хотя @DotProto говорит, что администрация работает над отладкой процессов изнутри, с нашей стороны было бы как-то глупо стоять в сторонке, ждать и надеяться. Проблема явно носит системный характер, судя по тому, что форумы маркета усеяны мольбами о помощи, а в комментариях к нашему посту на Reddit собралась целая перепись подобных историй. Это может случиться и с другими и, скорее всего, случится.

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

Вместе у нас будет больше шансов на успех в следующем:

  1. Убедить Google Chrome разрешить магазины со сторонними расширениями. Это позволит внести разнообразие в прежде огороженный ассортимент расширений, поставит разработчиков в более выгодные условия и снизит риск того, что ваш продукт безвозвратно снесут просто потому что.
  2. Добиться со стороны администрации магазина Chrome более справедливого отношения и большей готовности вступать в контакт. От шаблонных писем с отказами, в которых информация о нарушения даётся только в самых общих чертах, страдают все и разработчики, и сотрудники компании. Тем и другим приходится зря терять время в попытках прояснить ситуацию, особенно когда кого-то отклоняют по ошибке.

Начинать сбиваться в кучу и выстраивать оборону нужно уже сейчас если этого не сделать, всё так и останется в руках контролёра по имени Chrome. Форум будет открыт также для сотрудников компании и людей, которые отстаивают интересы разработчиков, как @DotProto. Мы ведь не воевать с ними собираемся, в самом деле хорошая платформа и сама выступает за, а не против своих клиентов.

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

ЧаВо
А что нам это даст?

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

Как быть с adware и расширениями, которые шпионят за людьми?

Если существование магазинов со сторонними расширениями были бы разрешено, им бы предоставлялась возможность самим создавать необходимые барьеры хоть финансовые, хоть любые другие. Есть основания считать, что они справились бы с отсеиванием мошеннических продуктов не хуже Google.
Подробнее..

Конструктор интерактивных туров

11.09.2020 10:13:26 | Автор: admin


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


Процесс обучения


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


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


Автоматизация обучения


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



Постановка задачи


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


При выборе инструмента, прежде всего, необходимо было учитывать, что его потенциальными пользователями являются не программисты, а специалисты предметных областей. Следовательно, разработка туров должна происходить на основе манипуляции графическими объектами, а не на языке программирования. Существующие решения, удовлетворяющие данному критерию, ориентированы на создание туров по обычным сайтам и не подходят для предприятий, занимающихся автоматизацией сложных бизнес-процессов. Также существующие решения не позволяют получить программный код созданного тура. Следовательно, нет возможности управлять его хранением. Это критично для НПО Криста, так как информационная безопасность является важным требованием к программным продуктам компании. Поэтому было принято решение разработать собственный инструмент для создания интерактивных туров по функционалу web-приложений.


Входными данными для разрабатываемой системы является загружённое в браузер web-приложение с функционалом, по которому создается тур. Выходными данными являются туры, сохранённые в реляционную базу данных под управлением PostgreSQL. Для получения входных данных необходимо, чтобы разрабатываемая программа работала в браузере. Следовательно, требуется создать web-приложения, что предполагает использование клиент-серверной технологии.



Структура системы


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



Взаимодействие между клиентом и сервером происходит посредством передачи HTTP-сообщений с данными о турах в формате JSON. Обращение к БД осуществляется на языке SQL. Основным языком программирования, используемым при разработке клиентского приложения, является TypeScript. Архитектура клиента определяется использованием библиотек React и Redux. Серверное приложение разработано как Maven-проект на языке Java.



Технологические решения


Основной частью при создании туров является редактор кода тура. За его основу была взята библиотека Blockly. Она разрабатывается и поддерживается компанией Google с 2012 года. Blockly свободно распространяется вместе c исходным кодом и включает в себя графический редактор, а также генераторы кода для подготовки исполнения программы в среде web-приложения. Программы в этом редакторе создаются на визуальном языке программирования Blockly путём соединения соответствующих блоков. Существует возможность определения новых блоков с заданием их формы и генерируемого ими программного кода (подробнее). Благодаря этому редактор может быть расширен за счёт добавления блоков, реализующих логику создания тура.


Так как клиентское приложение предоставляет инструментарий для web-разработки, было принято решение добавить его в инструменты разработчика DevTools браузера Chrome в качестве расширения (подробнее: раз, два). При этом часть клиента, реализующая вспомогательную подсистему, встраивается на инспектируемую страницу web-приложения, по которому создается тур (по примеру). Связь между частями обеспечивается по схеме.


Следовательно, программа функционирует в двух окнах: в окне web-приложения и в окне DevTools. Соответствующий пользовательский интерфейс изображён ниже. В окне DevTools пользователь управляет созданием тура. На инспектируемой странице он выбирает элементы интерфейса, которые необходимо выделить, а также тестирует созданный тур.



Алгоритм работы системы


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



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



Самое первое взаимодействие между клиентом и сервером (6 7) происходит всякий раз, когда пользователь открывает вкладку с плагином (4). Тогда же происходит добавление части клиентской программы к веб-приложению, по которому создается тур (5).



Результат разработки


При создании нового тура откроется встроенный редактор Blockly, в левой части которого расположены стандартные разделы. К ним добавлен раздел Тур. Он содержит специальные графические объекты, которые позволяют, например, добавить подсказку к элементу на инспектируемой странице, затемнение вокруг элемента, ожидание события и прочие возможности.



При помощи таких блоков описывается сценарий тура, на основании которого генерируется соответствующий JavaScript-код.



При запуске воспроизведения в окно web-приложения, по которому создавался тур, загружается и выполняется JavaScript-код тура. При этом на странице появляется навигационная панель для управления воспроизведением тура, а также описанные в сценарии элементы. В представленном примере на первом шаге отрисуется пульсирующий указатель на элемент интерфейса, нажатие на который запустит воспроизведение следующего шага тура.



Несмотря на то что разработанное приложение ориентировано на программные продукты компании НПО Криста, оно может использоваться для создания туров по любому web-приложению.



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


Подробнее..

Серверный WebRTC в 2020 году обзор возможностей

26.07.2020 06:16:13 | Автор: admin
1. Кому нужен серверный WebRTC?

Как все мы знаем, WebRTC это peer-to-peer технология, реализующая канал коммуникации между двумя браузерами, для передачи аудио, видео и любых других данных с низкой задержкой. Технология совершенно бесплатная, и если вашему приложению нужно наладить общение в браузерах для двух удаленных участников, то вы можете добавить соответствующий javascript код на веб страницы и задача решена. Браузеры будут общаться напрямую, никакого сервера не требуется.

Серверный WebRTC выходит на сцену тогда, когда нужно чтобы участников было больше чем два, и данные от одного участника передавались сразу нескольким другим участникам.
В этом случае одним из участников может выступить сервер, который наладит общение один на один с первым участником, получит от него данные, затем наладит общение, тоже в режиме
один на один с другими участниками и перешлет им эти данные. Т.е. сервер держит множество peer-to-peer каналов связи и просто копирует данные во все эти каналы. В терминологии WebRTC такой сервер служит как Selective Forwarding Unit (SFU).
image
Однако, коммуникация в группе возможна не только с помощью SFU. Вы можете спросить почему каждый не может посылать данные каждому, без всякого сервера, и будете совешенно правы. Это называется MESH коммуникация.

Здесь есть два ключевых момента:

  1. В MESH схеме каждый из участников посылает и получает N-1 потоков данных, где N размер группы. Т.е. требования на upload speed для каждого участника в MESH схеме увеличиваются с ростом группы. Тогда как в SFU схеме каждый участник всегда посылает только один поток. Не у каждого участника скорость соединения с сетью потянет посылку N-1 потоков.
  2. К сожалению, в MESH схеме браузер делает аудио-видео сжатие на каждый посылаемый поток. А это, как мы знаем, самы ресурсо-затратный процесс. В MESH схеме, приведенной выше, браузер каждого участника будеть сжимать видео VP8/VP9/H264 кодеком 4 раза. Это вызвано требованием WebRTC к адаптации качества данных к качеству канала если связь не очень, то компрессия станет посильнее. Что есть хорошо, но влечет необходимость сжимать независимо на каждый канал (PeerConnection). Увы, на обычной машине браузер при сжатии 720p видео уже занимает 30% процессора, т.е больше трех каналов не потянет.

Из-за этих двух ключевых моментов MESH схема становится плохо реализуемой при растущем числе участников и приходится применять SFU схему.

Итак, при большом количестве участников коммуникации необходим сервер (SFU).
Давайте приведем примеры таких приложений, где сервер необходим:

  • Видео конференции с множеством участников (всеми горячо любимый Zoom использует WebRTC сервер, как и все подобные сервисы).
  • Видео наблюдение в реальном времени, когда от одной камеры видео посылается нескольким зрителям и записывающим устройствам. Системы безопасности, мониторинга.
  • Интерактивные системы, такие как: интернет-аукционы, обучающие и другие веб-приложения, где требуется низкая задержка аудио/видео.


2. Если вам нужен-таки серверный WebRTC, что можно использовать в 2020 году?

Облачный сервис или своими силами?

Здесь вначале обычные для IT аргументы в пользу того либо другого: облако обеспечит и сэкономит IT-затраты на сервера, конфигурацию, масштабируемость. Но своими силами, если все получится (нет гарантии), то выйдет гораздо дешевле. Ведь за облачный сервис нужно помесячно платить.

Теперь к аргументам специфичным к описанным выше приложениям. Если у вас глобальная, огромная аудитория, в разных странах и регионах, то своими силами вам будет сложно все собрать вместе. К примеру, для аукциона Sotheby's подойдет облачный сервис. Но если у вас 2-3 отделения компании в разных городах, 200-500 юзеров, и для них нужно организовать вебинар/конференции/обучение и т.п., то вы можете сами рентовать несколько серверов на AWS или подобных хостинг платформах, установить там софтверный WebRTC сервер, и все получится. Сервера могут даже быть у вас в компании, если скорость интернет-подключения позволяет. Ну и для всех решений меньших по масштабам, все можно сделать своими силами.

На текущий момент хорошо известны и проверены два облачных WebRTC сервиса: Millicast и Phenix. У обоих глобальное покрытие, хорошая связь между серверами на разных континентах (оно вам надо?) и действительно задержка видео (latency) на уровне пол-секунды и ниже.

Теперь поговорим про своими силами.

Здесь вам понадобится WebRTC server software. Существуют 3 способа получить такой сервер.

  1. Сделать его самим, пользуясь открытым API. Самый известный из них это Google c++ WebRTC API. Также можно использовать GStreamer API. Интересна имплементация на Go: Pion WebRTC. Вам понадобятся квалифицированные c++ программисты и очень много терпения и времени на отладку. Про трудности этого подхода я подробно писал в своей предыдущей статье.
  2. Взять уже готовый бесплатный сервер с открытым кодом. Заслуживают упоминания Ant Media Server, Kurento, Janus, Jitsi. Эти сервера вполне подойдут для небольших проектов, хотя код там не оптимизирован, не оттестирован, встречаются баги. На github есть множество других проектов, еще более экспериментальных и сырых. Чтобы оптимизировать, заточить и починить баги, нужны, см. выше, собственные квалифицированные c++ программисты. Или нужно просить разработчиков этих продуктов все для вас заточить. Что делает продукт уже не бесплатным, а весьма дорогостоящим.
  3. Купить лицензию на платный сервер. Как правило, более законченный, надежный продукт и бесплатная поддержка. В этой категории следует отметить Red5 Pro, Flashphoner и Unreal Media Server.

Интеграция WebRTC сервера в ваши существующие продукты и решения.

Это самая проблематичная тема. Предположим, ваша компания выпускает софтверный продукт, в который надо внедрить WebRTC сервер. Пусть это система видеозаписи и наблюдения для терминалов аэропортов, вокзалов, транспортных узлов. Или медицинское оборудование с уже существующим сопровождающим софтом для трансляции и записи видео от эндоскопов, который нужно расширить до трансляции этого видео в браузер. Или система симуляции полетов, в которую надо внедрить возможность визуализации в браузере и/или интеракции с удаленным юзером. Мы постоянно сталкиваемся с подобными требованиями. У вашей существующей системы множество ограничений. Может не быть доступа в интернет. Никаких облаков. Нельзя на сервере открывать порты. Только Windows или только Linux. Иногда даже только определенная версия Windows, ведь существующий продукт заточен под нее. WebRTC сервер, добавляющийся в такую систему, должен быть подстроен под все эти ограничения.

Здесь, возможно, у вас нет иного выхода, чем брать открытый код сервера, такого как Ant Media Server или Janus, и менять его. Такова ситуация на Linux. Для Windows подойдет Unreal Media Server это софт написанный и оптимизированный только для Windows OS.

WebRTC сервер очень ресурсо-затратный.

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

Привожу диаграмму тестов произведенных с Unreal Media Server v13.0 на AWS EC2 m4.2xlarge instance: Intel Xeon 8 cores CPU E5-2686 v4 @ 2.30 GHz, 32 Gb RAM, Windows Server 2016.
image
Как видно из диаграммы, при 1000 одновременных веб плеерах вот этой IP камеры загрузка процессора составляет 5% при RTMP протоколе, и 75% при WebRTC протоколе, т.е. WebRTC более чем в 10 раз ресурсо-затратнее чем RTMP.
Подробнее..

Устанавливаем кастомную раскладку на klava.org

15.01.2021 22:23:38 | Автор: admin

Что будет рассказано?

  • Очевидная проблема при изучении своих клавиатурных раскладок

  • Немного о нашем пациенте: klava.org

  • То, как получилось решить данную проблему (спасибо F12)

  • Как правильно настраивать клавиши (при нажатии Shift или AltGr)

  • Автоматизация ручного труда с помощью расширения User JS and CSS

То, с чего всё началось

Когда мы изучаем десятипальцевый метод, для ускорения обучения мы используем различные тренажёры: typingStudy, klava.org, ratatype, rapidTyping и другие. Однако, когда встаёт вопрос об освоении своей особенной, кастомной, раскладки, то "оказывается", что ни один сайт, ни одна программа не предусматривает их существование:

  • В списке поддерживающихся раскладок, своей "конечно же" нет

  • В настройках свою добавить невозможно

  • Самому писать тренажёр - трындец полный

В качестве пациента я выбрал сайт klava.org: неплохой визуал, клавиатура на экране есть, пальцы показываются, разные режимы, ОК. Изначально на сайте есть весьма неплохой список раскладок для русского и английского языков, но нет кучи других, не менее интересных раскладок (да и разработчиков сайта нет смысла судить: раскладок куча, плюсом завтра может появиться новая -> всем не угодить).

Откапываем словарь с раскладками

Как многие из вас знают, есть нажать F12, то выскочит "волшебная" панель с HTML-кодом, CSS, JS, файлами, которые можно без проблем редактировать, и многим другим функционалом, необходимым для разработчиков. Если немного порассуждать, то можно прийти к следующему предположению:

Если сайт писали хорошие ребята, то скорее всего абсолютно всё: расположение символов на экране, автоматическая подсветка нужной буквы/клавиши, отрисовка, будет зависеть только от одного источника: словаря/массива/списка, соответственно, нужно найти тот самый словарь и расположить всё по-своему!

И, да, заветный словарь был найден! В JS этот "словарик" описан одной переменной keyboards. Там ооочень много кода и он, как назло, весь минимизирован, но разобраться можно. Найти этот код достаточно просто:

  1. Жмём F12

  2. Прожимаем Ctrl+F (появится поле для ввода)

  3. Вводим "var keyboards"

  4. Копируем словарик в блокнот (слово var удалите, оно нам больше не понадобится)

  5. Словарь полностью в нашем расположении!!!

Ставим кастомную раскладку вместо ненужной

Теперь нужно подобрать "жертву" - ненужную раскладку, которую будем редактировать. После этого её нужно отыскать (берём название из сайта и не забываем про Ctrl+F). В итоге, получаем массив строк, который нужно обработать: машинописть например выглядит так:

//название раскладки в процессе редактирования менять нельзя!!!'машинопись': ['|<sup>+</sup>', '<sup>1</sup>', '-<sup>2</sup>', '/<sup>3</sup>', '"<sup>4</sup>', ':<sup>5</sup>', ',<sup>6</sup>', '.<sup>7</sup>', '_<sup>8</sup>', '?<sup>9</sup>', '%<sup>0</sup>', '!<sup>=</sup>', ';<sup>\\</sup>', 'Й', 'Ц', 'У', 'К', 'Е', 'Н', 'Г', 'Ш', 'Щ', 'З', 'Х', 'Ъ', ')<sup>(</sup>', 'Ф', '', 'В', 'А', 'П', 'Р', 'О', 'Л', 'Д', 'Ж', 'Э', 'Я', 'Ч', 'С', 'М', 'И', 'Т', 'Ь', 'Б', 'Ю', 'Ё']

Теперь поясню, что здесь происходит:

Строки, где находятся только заглавные буквы, это обычные символы, система с ними всё сама сделает (просто нажали - прописная буква, нажали Shift - заглавная). В остальных местах присутствуют знакомые HTML-теги: в такой строке следующие правила.

  1. Самый первый символ, символ, который вводится без Shift или AltGr, то есть, просто нажатие

  2. Внутри тегов <sup></sup> находятся символы, которые вводятся при нажатом Shift; символы отрисовываются сверху

  3. Внутри тегов <sub></sub> находятся символы, которые вводятся при нажатом AltGr; символы отрисовываются снизу

'S'       //просто буква, и так всё понятно'(<sup>{</sup><sub>[</sub>' //нажатие ->  (                            //+ Shift ->  {                            //+ AltGr ->  ['ь<sup>ъ</sup>'   //разные буквы тоже можно

Отредактировали? Заменили? Теперь осталось протестировать.

  1. Отрываем сайт

  2. Жмём F12

  3. Открываем Console

  4. Вставляем наш "модифицированный код" (надеюсь var удалить не забыли)

  5. Жмём Enter

  6. Если всё сделано правильно, то сообщений об ошибке не будет

После этого закрываем панельку, выбираем нашу "жертву" и ЧУДО!!! кастомная раскладка работает (вот, что у меня получилось):

Автоматизация

Всё-таки при каждом входе на сайт не хочется каждый раз вручную вставлять этот код. Для решения этой проблемы было создано расширение под названием User Javascript and CSS. Ставим расширение. После уставновки открываем наш сайт, жмём на иконку расширения и жмём Add new. Перед вами откроется 2 поля: JS и CSS, теперь остаётся вставить наш код в поле JS, сохраниться, проверить флажок и кайфануть, что всё работает "само".

Ура!!!! Вы установили свою кастомную раскладку на сайт klava.org. Теперь тренить свою раскладку будет проще, быстрее и (наверное) интереснее.

Подробнее..

Просмотр youtube-видео фрагментами и циклически с целью обучения

17.12.2020 00:16:58 | Автор: admin
Сегодня прошел ровно 1 год с прошлой статьи и в связи с этим я решил поделиться своим вариантом решения проблемы просмотра youtube-видео фрагментарно и циклически. Это проблема как никогда актуальна для многих учащихся в этом году, если им дают ссылки на обучающие youtub-материалы.

Решение не 100% реализованное, но и в таком видео может кого-то натолкнет на желание реализовать это в расширении или подскажет мне где-то ресурс, который смог бы реализовать требуемую задачу или кто создал бы профессиональный сайт с подобным функционалом.

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

image

Итак, проблема

Видео на youtube бывает полезно для обучения, но требуется просмотр определенных фрагментов помногу раз.

Уже готовые найденные решения:

1. Скачать видео и вырезать требуемое или требуемые части и разместить у себя.
(долго, проблемы с правами на это, но кому надо, то есть даже сайт www.clipconverter.cc/2 который поможет скачать фрагмент видео)

2. Разместить ссылку на просмотр 1 фрагмента видео на подобных ресурсах как:


возможно и другие, но не найдено удобное и главное, чтобы много разных фрагментов
(не всегда ссылка удобна, бывает куча рекламы на таких сайтах и блокировщики рекламы не всегда помогают)

3. Использование расширений
(расширение должны быть у пользователя, в мобильных браузерах тоже с этим будет проблема)



  • Video Speed Controller расширение для гуглхром
    (можно задать горячие клавиша на скорость, можно выставить временную точку начало фрагмента и перейти назад когда надо)
  • Magic Actions for YouTube расширение для гуглхром
    (более 1 000 000 пользователей уже говорит, о интересности расширения, а фрагменты можно выделять кликая то левой, то правой кнопкой но вот сохранение этих фрагментов где-то в запросе не обнаружил)

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

  • перемотка на 1 секунду назад, чтобы просто прослушать только что сказанное слово;
  • возможность изменить скорость видео быстро (замедлить для иностранных языков, убыстрить для новостей);
  • хорошо бы пометить какое-то время и потом быстро перейти на него.

Основное можно найти в расширении Video Speed Controller, ютюб же горячими клавишами хоть и позволяет скорость менять (хелп по горячим клавишам тут был на хабре, но есть в официальный), но на 1 секунду проблематично вернуться назад.

Требовалось для удобства и автоматизации:

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

Недостатки реализации: (ссылка на сайт не гарантирую бесперебойную работу и вечное расположение этого кода)

  • если видео только для просмотра на ютюб, то вы такое видео не посмотрите на этом сайте;
  • хоть и может работать в мобильном браузере (добавлены кнопки поверх области видео), но изначально создавался под десктопное применение и лучше пользоваться на большом экране;
  • реклама ютюба никак не блокируется в нем (в расширениях вроде браузер дает такое право, но я не разработчик их);
  • очень много фрагментов скорее всего не получится вписать просто из-за ограничения длины GET-запроса;
  • и еще 1000 недостатков на ваше усмотрение и доделку.

Достоинства реализации:

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

Простой пример использования

Требуется выучить фрагмент стихотворения Не ветер бушует над бором. Пример чтения есть в ютюбе, но там слишком длинно и по середине есть лишнее музыкальное проигрывание.
Создаем 2 фрагмента, ставим проигрывание 1 раз и получаем такую ссылку, которая задает уже готовые фрагменты. Для начала циклического воспроизведения достаточно только нажать на кнопку Повтор А-В.

Рекомендации для оптимального заучивания:

  • заучивать частями, для стихотворения один столбик можно записать как 1 фрагмент и запустить как вечный цикл (0 раз) и да, не забываем об отдыхе каждые 10 минут;
  • для иностранных языков желательно не более предложения под 1 фрагмент и возможно понизить скорость до 0.85 (идеально для довольно чистого и незаметного замедления);
  • длинные видео разбивать на части по 5-7 минут не более и делаем перерывы после каждого такого блока на те же 5 минут (отвлечься от получения какой-либо информации вообще);
  • вы должны уже заученное успеть внутренне проговорить (вспомнить) раньше проигрывания на видео, а если вы думаете, что фоном оно само запомнится, то это бывает совсем не так;
  • не учить постоянно и долго одно и тоже, делайте большие перерывы в час и более;
  • если болит голова от повторов, то просто выключайте это и идите спать!
Подробнее..

Смотрим любое кино мгновенно

06.03.2021 02:15:47 | Автор: admin

Disclaimer: я не призываю незаконно скачивать контент, пиратство - наказуемо и является преступлением

После ареста серверов Moonwalk жить стало в разы труднее. Лично я уже совсем отвык от торрентов. Нужно что-то качать, ждать, чем-то открывать, куда-то кликать, иногда еще и место на диске кончается. Как можно ждать час пока скачается фильм? За час можно жизнь прожить. Пришлось искать решение, которое позволит смотреть кино также просто, как и раньше. Норматив: от идеи посмотреть что-нибудь и до начала непосредственного просмотра - не более минуты.

Вы скажете: есть Popcorntime, не морочь нам голову. Все так, есть Popcorntime, идея классная, но реализация не совсем та, какую хотелось бы. Часто нет нужных дорожек, субтитров, все как-то непрозрачно работает. Вот бы можно было иметь интерфейс, который ищет необходимое кино по всем нужным трекерам и мгновенно его начинает крутить. Есть такой интерфейс.

И вот так он работает:

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

Знакомьтесь, Jackett

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

Jackett можно скачать и запускать на компьютере, но это все усложняет. Лучше захостить его на бесплатном облаке от Oracle, и заходить по адресу. Вам понадобится машина в облаке, linux на ней и docker-compose.yml c приблизительно такими характеристиками:

version: '3.5'services:    jackett:        image: linuxserver/jackett        container_name: jackett        environment:            - PUID=1000            - PGID=1000            - TZ=Europe/Moscow        volumes:            - ./Jackett/config:/config            - ./Jackett/Downloads:/downloads        ports:            - 9117:9117        networks:            - proxy        restart: unless-stoppednetworks:    network:        driver: bridge    proxy:        external:            name: proxy

docker-compose up -d и заходим. Далее нам понадобится добавить все наши трекеры, вбив логины и пароли.

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

Здесь нам приходят на помощь Stremio и Soda player.

Сами по себе это просто потоковые смотрелки торрент файлов. Хорошо, но недостаточно. В комбиации с Jackett они превращаются во что-то совсем невероятное. Soda отлично подойдет для мака, а Stremio, кажется, умеет передавать видео на телевизоры и прочие кофемолки. Про Soda есть статья на reddit, дескать он ворует печеньки. Лично мне плевать, но вас я обязан предупредить.

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

Подробнее..

Habrosanitizer теперь и для Firefox. А еще он научился блокировать хабы

21.12.2020 22:14:07 | Автор: admin

habrosanitizer says happy new year


В конце октября, после волны статей от хайповых авторов, я написал небольшое расширение для Хрома которое позволяет прятать нежелательные статьи из ленты. Расширение было встречено очень тепло (+285, 53_000 просмотров и 70+ звезд на гитхаб) и я даже опубликовал его в Chrome Extension Store. Потом был опрос о наиболее желаемой следующей фиче и самой востребованной (129 голосов) оказалась поддержка Firefox. И вот, спустя месяц, расширение опубликовано в Firefox Addons.


Кому интересно по каким граблям пришлось потоптаться, прошу под кат!


Про Firefox


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


Сначала тестовый код не хотел даже загружаться в Firefox из-за неверного формата манифеста. Пришлось гуглить и пробовать несколько раз, причем даже манифест из официального примера работать не захотел. Потом, после того как Firefox вдруг принял файлы, он, естественно, отказался их запускать, потому что "файлы не проверены, подписи не сделаны, работать не буду". В гугле нашелся специальный флаг -xpinstall.signatures.required = false который нужно выставить что бы разрешить загрузку расширений без подписи, но ни в стабильной версии ни в бете он не работает. Помогло только в Nightly.


Потом, поскольку мне нужно использовать хранилище что-бы хранить настройки, Firefox потребовал дать ему id (ставится в "browser_specific_settings":{"gecko": {"id":"{GUID}"}})). На что Chrome тут же заявил, что свойство browser_specific_settings он не знает и выдал предупреждение. Это исправить так и не удалось, но все вроде бы работает.


Следом возникли проблемы со страницей настроек. Если в Firefox она отображалась красиво, то в Chrome в виде отдельного окна. Полечилось с помощью изменения options в манифесте на "options_ui": {"page": "options.html", pen_in_tab": true}


После чего все наконец то запустилось, и я решил, что наконец-то всех победил. Но не тут-то было. Когда вы грузите бандл, Firefox автоматически запускает линтинг кода и если что-то ему не так, отказывает в загрузке для проверки. В моем случае не так было использования свойств классов (что не страшно и легко лечится), а также использование es6 модулей, что, внезапно, лечится гораздо хуже. Сначала я думал свалить все в один файл (благо размер кодовой базы просто смешной), но потом решил "не комильфо" и настроил WebPack для билда (все равно давно хотел посмотреть на 4ый вебпак)


Кстати, несмотря на то что теперь я публикую собранные артефакты, вы все еще можете использовать код как есть, прямо из src папки. Так что все осталось так же прозрачно, как и было. Мне по-прежнему можно не верить и пользоваться простым и понятным кодом из репозитория.


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


В результате, 20.12.2020 я отправил расширение на ревью (и был 63 в очереди), а уже 21.12.2020 получил письмо счастья о том, что оно одобрено к публикации. Спасибо команде ревьверов за оперативность.


Новый функционал


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


Итого, на сегодняшний день реализована блокировка:


  • По нику автора
  • По имени компании
  • По имени хаба

UI остался прежним, одно поле для всех.


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


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


И немного статистики


Сейчас у расширения 68 :) пользователей и три оценки. Так что мои опасения что расширение может хоть как-нибудь повлиять на сам Хабр и навредить ему оказались полностью беспочвенными. 40 пользователей из России, 11 из Украины, и еще по нескольку из Казахстана, Узбекистана, Чехии, Штатов, Британии и Израиля.


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


Если есть пожелания или вы нашли баг, пишите в комментариях или в issues кому как удобнее.


Ссылки:



Всех с наступающими праздниками, и хорошего нового года!
P.S. Спасибо Sharon McCutcheon за КПДВ Mozilla Corporation за их лого

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru