2022-06-24 10:54:57 +07:00
|
|
|
|
'use strict'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Страница настроек ВКонтакте
|
|
|
|
|
*/
|
|
|
|
|
class killer {
|
|
|
|
|
constructor() {
|
|
|
|
|
/**
|
|
|
|
|
* Обработка группы сообщений
|
|
|
|
|
*
|
|
|
|
|
* Иницилизионная функция запускающая процессы обработки сообщений
|
|
|
|
|
*
|
|
|
|
|
* @param {string} group Группа для обработки
|
|
|
|
|
*
|
|
|
|
|
* @return {bool} Статус выполнения
|
2022-06-25 12:53:12 +07:00
|
|
|
|
*
|
|
|
|
|
* @todo 1. Добавить режим в котором проверяется не каждая группа сообщений, а
|
|
|
|
|
* сначала читаются все найденные группы сообщений и только потом обрабатываются все вместе
|
2022-06-24 10:54:57 +07:00
|
|
|
|
*/
|
|
|
|
|
this.tribunal = async function (group = this.last(), list = this.list()) {
|
2022-06-25 12:53:12 +07:00
|
|
|
|
if (await this.search(await this.account(group), await list)) {
|
2022-06-24 10:54:57 +07:00
|
|
|
|
// Найдена цель на удаление
|
|
|
|
|
|
|
|
|
|
// Инициализация типа действия с группой сообщений заблокированного аккаунта
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Обработка всех видимых групп сообщений
|
|
|
|
|
*
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* Все сообщения загруженные в документе будут обработаны
|
|
|
|
|
*
|
2022-06-24 10:54:57 +07:00
|
|
|
|
* @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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Найти элемент-оболочку групп сообщений
|
|
|
|
|
*
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* Элемент хранит в себе все группы сообщений (окно чата)
|
|
|
|
|
*
|
2022-06-24 10:54:57 +07:00
|
|
|
|
* @return {Element} Оболочка групп сообщений
|
|
|
|
|
*/
|
|
|
|
|
this.wrap = function () {
|
|
|
|
|
return document.getElementsByClassName('_im_peer_history im-page-chat-contain')[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Найти последнюю группу сообщений
|
|
|
|
|
*
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* Группа сообщений - элемент-оболочка в котором хранятся
|
|
|
|
|
* сообщения от одного и того же пользователя. Группу сообщений
|
|
|
|
|
* закрывает сообщение от другого пользователя или прохождение
|
|
|
|
|
* некоторого времени, таким образом будет создана отдельная группа.
|
|
|
|
|
*
|
|
|
|
|
* Определить группы можно по аватарам пользователей (у каждой группы
|
|
|
|
|
* аватар отправителя отображается только 1 раз)
|
|
|
|
|
*
|
2022-06-24 10:54:57 +07:00
|
|
|
|
* @return {Element} Группа сообщений, если найдена
|
|
|
|
|
*/
|
|
|
|
|
this.last = function () {
|
|
|
|
|
// Инициализация списка сообщений
|
|
|
|
|
const wrap = this.wrap();
|
|
|
|
|
|
|
|
|
|
// Инициализация последней группы сообщений
|
|
|
|
|
const group = wrap.children[wrap.children.length - 1];
|
|
|
|
|
|
|
|
|
|
return group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* Найти и прочитать пользователя группы сообщений
|
2022-06-24 10:54:57 +07:00
|
|
|
|
*
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* @param {string} group Группа для обработки (иначе самая последняя, новая)
|
2022-06-24 10:54:57 +07:00
|
|
|
|
*
|
|
|
|
|
* @return {number} Идентификатор страницы ВКонтакте (только цифры)
|
|
|
|
|
*/
|
|
|
|
|
this.account = function (group = this.last()) {
|
|
|
|
|
// Инициализация идентификатора отправителя
|
|
|
|
|
const id = +group.getAttribute('data-peer');
|
|
|
|
|
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Прочитать список аккаунтов на удаление из реестра
|
|
|
|
|
*
|
2022-06-25 12:53:12 +07:00
|
|
|
|
* Реестр очищается через определённое в настройках время
|
|
|
|
|
* он должен быть маленьким, чтобы не проводить длительные поиски аккаунта,
|
|
|
|
|
* но при этом он должен быть большим, чтобы проверять каждого пользователя
|
|
|
|
|
* в чате слишком часто, что ещё хуже, посколько выполняет отдельный запрос
|
|
|
|
|
* и ищет данные о нахождении в чёрном списке.
|
|
|
|
|
*
|
|
|
|
|
* Реестр может хранить в себе данные об аккаунтах записанных туда непосредственно,
|
|
|
|
|
* то есть аккаунты не обязательно находятся в чёрном списке
|
|
|
|
|
*
|
2022-06-24 10:54:57 +07:00
|
|
|
|
* @return {object} Список аккаунтов на удаление
|
|
|
|
|
*/
|
|
|
|
|
this.list = async function () {
|
|
|
|
|
// Инициализация списка аккаунтов на удаление
|
2022-06-25 12:53:12 +07:00
|
|
|
|
return await settings.read('killer_targets');
|
2022-06-24 10:54:57 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Поиск аккаунта в списке на удаление
|
|
|
|
|
*
|
|
|
|
|
* @param {number} account Аккаунт для обработки
|
|
|
|
|
*
|
|
|
|
|
* @return {boolean} Статус наличия аккаунта в списке на удаление
|
2022-06-25 12:53:12 +07:00
|
|
|
|
*
|
|
|
|
|
* @todo 1. Возможно оно может асинхронно перезаписывать само себя когда сохраняет нового
|
|
|
|
|
* пользователя в реестр и сразу же после этого сохраняет реестр с другим пользователем без первого
|
|
|
|
|
* из-за того что оба процесса были запущены одновременно
|
2022-06-24 10:54:57 +07:00
|
|
|
|
*/
|
2022-06-25 12:53:12 +07:00
|
|
|
|
this.search = async function (account = this.account(), targets = this.list()) {
|
2022-06-24 10:54:57 +07:00
|
|
|
|
if (account === this.self()) {
|
|
|
|
|
// Обрабатывается свой аккаунт
|
|
|
|
|
|
|
|
|
|
// Инициализация статуса разрешения блокировки самого себя
|
2022-06-25 12:53:12 +07:00
|
|
|
|
return await settings.read('killer_self') ?? false;
|
2022-06-24 10:54:57 +07:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-25 12:53:12 +07:00
|
|
|
|
if (typeof await targets === 'object') {
|
2022-06-24 10:54:57 +07:00
|
|
|
|
// Пройдена проверка на тип
|
|
|
|
|
|
|
|
|
|
if (Object.keys(targets).length >= await settings.read('killer_targets_limit') ?? 500) {
|
|
|
|
|
// Достигло ограничения количество аккаунтов в реестре
|
|
|
|
|
|
2022-06-25 12:53:12 +07:00
|
|
|
|
// Реинициализация реестра
|
2022-06-24 10:54:57 +07:00
|
|
|
|
this.purge();
|
|
|
|
|
} else {
|
|
|
|
|
// Не достигло ограничения rоличество аккаунтов в ресстре
|
|
|
|
|
|
2022-06-25 12:53:12 +07:00
|
|
|
|
// Перебор искомых целей для удаления
|
|
|
|
|
for (const target in targets) if (+target === +account) return true;
|
2022-06-24 10:54:57 +07:00
|
|
|
|
}
|
|
|
|
|
} 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 если заблокирован пользователь (подразумевается наличие текста "Разблокировать {пользователь}")
|
2022-06-25 12:53:12 +07:00
|
|
|
|
return (button.innerText.trim()[0] === 'Р') ?? false;
|
2022-06-24 10:54:57 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Прощение
|
|
|
|
|
*
|
|
|
|
|
* Удаляет аккаунт из реестра заблокированных
|
|
|
|
|
*
|
|
|
|
|
* @return {boolean} Статус выполнения
|
|
|
|
|
*
|
|
|
|
|
* @todo Доделать
|
|
|
|
|
*/
|
2022-06-25 12:53:12 +07:00
|
|
|
|
this.forgive = async function (account, targets) {
|
2022-06-24 10:54:57 +07:00
|
|
|
|
if (typeof account !== 'undefined' && typeof account !== 'null') {
|
|
|
|
|
// Пройдена проверка полученных значений аргументов
|
|
|
|
|
|
|
|
|
|
// Инициализация буфера записи в хранилище
|
|
|
|
|
let buffer = {};
|
|
|
|
|
|
2022-06-25 12:53:12 +07:00
|
|
|
|
for (const target in targets) {
|
2022-06-24 10:54:57 +07:00
|
|
|
|
// Перебор заблокированных аккаунтов
|
|
|
|
|
|
|
|
|
|
// Проверка на совпадение
|
2022-06-25 12:53:12 +07:00
|
|
|
|
if (+target === +account) continue;
|
2022-06-24 10:54:57 +07:00
|
|
|
|
|
|
|
|
|
// Запись в буфер записи в хранилище
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|