nadrez/firefox/modules/killer/core.js

371 lines
16 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict'
/**
* Страница настроек ВКонтакте
*/
class killer {
constructor() {
/**
* Обработка группы сообщений
*
* Иницилизионная функция запускающая процессы обработки сообщений
*
* @param {string} group Группа для обработки
*
* @return {bool} Статус выполнения
*
* @todo 1. Добавить режим в котором проверяется не каждая группа сообщений, а
* сначала читаются все найденные группы сообщений и только потом обрабатываются все вместе
*/
this.tribunal = async function (group = this.last(), list = this.list()) {
if (await this.search(await this.account(group), await list)) {
// Найдена цель на удаление
// Инициализация типа действия с группой сообщений заблокированного аккаунта
const action = await settings.read('killer_action');
// Обработка найденной цели (сортировано по предполагаемой востребованности)
if (action === 'clear') return this.clear(group);
else if (action === 'delete') return this.delete(group);
else if (action === 'hide') return this.hide(group);
else {
// Не скрывать группу сообщений
// Размытие
if (await settings.read('killer_action_blur_status') ?? true) return this.blur(group);
// Пометка цветом
if (await settings.read('killer_action_highlight_status') ?? false) return this.highlight(group);
return true;
}
}
}
/**
* Обработка всех видимых групп сообщений
*
* Все сообщения загруженные в документе будут обработаны
*
* @return {number} Количество обработанных групп сообщений
*/
this.genocide = async function () {
// Инициализация списка сообщений
const wrap = this.wrap();
// Инициализация счётчика обработканных групп сообщений
let handled = 0;
for (let i = 0, l = wrap.children.length; i < l; ++i) {
// Перебор групп сообщений
// Обработка
this.tribunal(wrap.children[i]);
// Запись в счётчик
++handled;
}
return handled;
}
/**
* Найти элемент-оболочку групп сообщений
*
* Элемент хранит в себе все группы сообщений (окно чата)
*
* @return {Element} Оболочка групп сообщений
*/
this.wrap = function () {
return document.getElementsByClassName('_im_peer_history im-page-chat-contain')[0];
}
/**
* Найти последнюю группу сообщений
*
* Группа сообщений - элемент-оболочка в котором хранятся
* сообщения от одного и того же пользователя. Группу сообщений
* закрывает сообщение от другого пользователя или прохождение
* некоторого времени, таким образом будет создана отдельная группа.
*
* Определить группы можно по аватарам пользователей (у каждой группы
* аватар отправителя отображается только 1 раз)
*
* @return {Element} Группа сообщений, если найдена
*/
this.last = function () {
// Инициализация списка сообщений
const wrap = this.wrap();
// Инициализация последней группы сообщений
const group = wrap.children[wrap.children.length - 1];
return group;
}
/**
* Найти и прочитать пользователя группы сообщений
*
* @param {string} group Группа для обработки (иначе самая последняя, новая)
*
* @return {number} Идентификатор страницы ВКонтакте (только цифры)
*/
this.account = function (group = this.last()) {
// Инициализация идентификатора отправителя
const id = +group.getAttribute('data-peer');
return id;
}
/**
* Прочитать список аккаунтов на удаление из реестра
*
* Реестр очищается через определённое в настройках время
* он должен быть маленьким, чтобы не проводить длительные поиски аккаунта,
* но при этом он должен быть большим, чтобы проверять каждого пользователя
* в чате слишком часто, что ещё хуже, посколько выполняет отдельный запрос
* и ищет данные о нахождении в чёрном списке.
*
* Реестр может хранить в себе данные об аккаунтах записанных туда непосредственно,
* то есть аккаунты не обязательно находятся в чёрном списке
*
* @return {object} Список аккаунтов на удаление
*/
this.list = async function () {
// Инициализация списка аккаунтов на удаление
return await settings.read('killer_targets');
}
/**
* Поиск аккаунта в списке на удаление
*
* @param {number} account Аккаунт для обработки
*
* @return {boolean} Статус наличия аккаунта в списке на удаление
*
* @todo 1. Возможно оно может асинхронно перезаписывать само себя когда сохраняет нового
* пользователя в реестр и сразу же после этого сохраняет реестр с другим пользователем без первого
* из-за того что оба процесса были запущены одновременно
*/
this.search = async function (account = this.account(), targets = this.list()) {
if (account === this.self()) {
// Обрабатывается свой аккаунт
// Инициализация статуса разрешения блокировки самого себя
return await settings.read('killer_self') ?? false;
}
if (typeof await targets === 'object') {
// Пройдена проверка на тип
if (Object.keys(targets).length >= await settings.read('killer_targets_limit') ?? 500) {
// Достигло ограничения количество аккаунтов в реестре
// Реинициализация реестра
this.purge();
} else {
// Не достигло ограничения rоличество аккаунтов в ресстре
// Перебор искомых целей для удаления
for (const target in targets) if (+target === +account) return true;
}
} else {
// Не пройдена проверка на тип и пустоту
// Инициализация реестра
this.purge();
}
if (await this.blocked(account)) {
// Пройдена проверка (заблокирован)
// Инициализация буфера записи в хранилище
let buffer = targets;
// Запись аккаунта в буфер записи в хранилище
buffer[account] = true;
// Запись в реестр в хранилище
settings.write('killer_targets', buffer);
return true;
}
return false;
}
/**
* Удаление группы сообщений (из HTML-документа)
*
* Для удаления на аккаунте со стороны ВКонтакте использовать this.delete()
*
* @param {string} group Группа для обработки
*
* @return {bool} Статус выполнения
*/
this.clear = async function (group = this.last()) {
// Удаление
group.remove();
return true;
}
/**
* Скрытие группы сообщений (из HTML-документа)
*
* Для удаления из документа использовать this.clear()
*
* @param {string} group Группа для обработки
*
* @return {bool} Статус выполнения
*/
this.hide = async function (group = this.last()) {
// Скрытие
group.style.display = 'none';
return true;
}
/**
* Пометка цветом группы сообщений (в HTML-документе)
*
* @param {string} group Группа для обработки
*
* @return {boolean} Статус выполнения
*/
this.highlight = async function (group = this.last()) {
// Инициализация цвета для фона
let color = await settings.read('killer_action_highlight_color');
// Проверка полученных значений
if (typeof color !== 'string') color = '#aeafd0';
// Запись цвета
group.style.background = color;
return true;
}
/**
* Размытие группы сообщений (в HTML-документе)
*
* @param {string} group Группа для обработки
*
* @return {boolean} Статус выполнения
*/
this.blur = async function (group = this.last()) {
// Инициализация значения степени размытия
let degree = await settings.read('killer_action_blur_degree');
// Проверка полученных значений
if (typeof degree !== 'number') degree = 3;
// Запись размытия
group.style.filter = 'blur(' + degree + 'px)';
return true;
}
/**
* Удаление группы сообщений на стороне ВКонтакте
*
* @param {string} group Группа для обработки
*
* @return {bool} Статус выполнения
*/
this.delete = async function (group = this.last()) {
return false;
}
/**
* Проверка аккаунта на наличие в списке заблокированных ВКонтакте
*
* @param {number} account Аккаунт для обработки
*
* @return {boolean} Статус аккаунта (true - заблокирован)
*/
this.blocked = async function (account = this.account()) {
// Запрос на чтение страницы
const response = await fetch('https://vk.com/id' + account);
// Инициализация полученных данных
const data = new TextDecoder('windows-1251').decode(new DataView(await response.arrayBuffer()));
// Инициализация парсера
const parser = new DOMParser();
// Инициализация HTML-страницы в понятном JS формате
const page = parser.parseFromString(data, "text/html");
// Инициализация кнопки "Заблокировать пользователя"
const button = page.body.querySelector('a[data-task-click="ProfileAction/toggle_blacklist"]');
// Возвращает true если заблокирован пользователь (подразумевается наличие текста "Разблокировать {пользователь}")
return (button.innerText.trim()[0] === 'Р') ?? false;
}
/**
* Прощение
*
* Удаляет аккаунт из реестра заблокированных
*
* @return {boolean} Статус выполнения
*
* @todo Доделать
*/
this.forgive = async function (account, targets) {
if (typeof account !== 'undefined' && typeof account !== 'null') {
// Пройдена проверка полученных значений аргументов
// Инициализация буфера записи в хранилище
let buffer = {};
for (const target in targets) {
// Перебор заблокированных аккаунтов
// Проверка на совпадение
if (+target === +account) continue;
// Запись в буфер записи в хранилище
buffer.push(account);
}
// Запись в реестр в хранилище
return settings.write('killer_targets', buffer);
}
return false;
}
/**
* Очистка реестра аккаунтов
*
* Полностью удаляет все аккаунты из реестра
*
* @return {boolean} Статус выполнения
*/
this.purge = async function () {
alert('попа');
return await settings.write('killer_targets', {});
}
/**
* Прочитать свой идентификатор аккаунта
*
* Ищет кнопку "Выход из аккаунта" и через неё узнает идентификатор
*
* @return {number} Идентификатор аккаунта, если найден
*/
this.self = function () {
// Поиск идентификатора
const id = +document.getElementById('top_logout_link').getAttribute('onclick').match(/[^_]*(?='\);\slogout\(\);)/)[0];
// Проверка найденного идентификатора
if (typeof id === 'number') return id;
return null;
}
}
}