flyink13 / Слежка за своими ботами в ВКонтакте

// ==UserScript==
// @name         Слежка за своими ботами в ВКонтакте
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Добавляет в меню группы ботов + при нажании на F2 в чате показывает какими ботами пользовался пользователь
// @author       Flyink13
// @match        https://vk.com/*
// @grant        none
// ==/UserScript==

(function() {
var autoupdate = []; // Автообновление счетчиков
setInterval(autoupdate.map(x => x()), 10000);

// Стили для аватарок
document.head.appendChild(document.createElement("style")).innerHTML = `
.l_comm .left_icon{
width: 24px !important;
margin: 2px 8px 2px 3px !important;
border-radius: 100% !important;
height: 24px !important;
}
`;

function addGroups(gids) { // Функция добавления групп в меню
    // Ищем группу в меню для копирования
    var groups = document.getElementsByClassName("l_comm"); 
    if (!groups.length) return;
    var last_group = groups[groups.length - 1];
    // Ищем сепаратор для разделения меню
    var insert_before = document.getElementsByClassName("more_div");
    if (!insert_before.length) return;
    insert_before = insert_before[insert_before.length - 1];
    var insert_after = insert_before.parentNode.insertBefore(insert_before.cloneNode(true), insert_before.nextSibling.nextSibling);
    // Вставляем группы
    gids.filter(x => /бот|bot/i.test(x.name) && x.is_closed < 2).map(function(g) {
        var new_group = last_group.cloneNode(true); // Клонируем группу для копирования
        new_group = last_group.parentNode.insertBefore(new_group, insert_after.nextSibling); // Вставляем в меню
        var counter = new_group.querySelector(".left_count_wrap > span"); // Счетчик
        var name = new_group.querySelector(".left_label"); // Имя
        var left_icon = new_group.querySelector(".left_icon"); // Иконка

        new_group.firstChild.href = "/" + g.screen_name; // Изменяем ссылку на группу
        counter.parentNode.href = counter.href = "/gim" + g.id; // Изменяем ссылку на личку группы в счетчике
        counter.parentElement.removeAttribute("onclick"); // Удаляем onclick
        counter.parentElement.onclick = () => 0;
        counter.onclick = onClickCounter.bind(this, g.id); // Добавляем фичи при клике на счетчик
        counter.parentNode.classList.remove("left_void"); // Делаем видимость счетчика
        counter.parentNode.style.opacity =  "0.5"; // и прозрачность
        counter.textContent = "L"; // Ставим статус Loading в счетчик
        counter.classList.remove("left_count_sign"); // Убираем "+"
        counter.onmouseenter = // Обновление счетчика при наведении мышки
            getInfo.bind(this, g.screen_name, function (m) {
                counter.parentNode.style.opacity = m ? "1" : "0.2";
                counter.textContent = m;
            });
        autoupdate.push(counter.onmouseenter); // Добавляем в Автообновление счетчиков
        counter.onmouseenter(); // Обновляем
        // Ставим имя группы
        name.textContent = g.name;
        // Ставим аватарку вместо иконки
        left_icon.style.background = "url(" + g.photo_100 + ") no-repeat center/contain";
    });
}



function onClickCounter(start, event) {
    var id = prompt("id", location.search); // Спрашиваем куда переходить
    if(id === null) return nav.link("gim" + start, event); // Если не сказали, то в список диалогов
    nav.link("gim" + start + id, event); // Открываем если сказали куда
    cancelEvent(event);
    return false;
}

function getInfo(gid, cb, ignore_cart) {
    if(!ignore_cart) return getInfo.cart.push([gid, cb, 1]); // Добавляем в очередь запросов
    if(parseInt(localStorage["gid" + gid]) > Date.now()) // Если открыто в другой вкладке, и запрос был менее 10 секунд назад
        return cb(localStorage["gid" + gid].split(":")[1] * 1); // то отдаем то что было
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "/al_profile.php?al=-1&__query=" + gid, true); // Открываем группу
    xhr.onload = function() {
        xhr = xhr.responseText;
        var m = xhr.match(/message_cnt.+?>(\d+)</); // Получаем кол-во сообщений
        if(!m && /\[8,/.test(xhr)){ // Если произошла ошибка
            getInfo.cart.push([gid, cb, 1]); // то повторяем запрос чуть позже
        }else{
            m = m ? m[1] * 1 : 0;
            localStorage["gid" + gid] = Date.now() + 10000 + ":" + m; // Сохраняем ответ в localStorage, для экономии запросов
            cb(m); // отдаем
        }
    };
    xhr.send();
}

getInfo.cart = []; // Очередь запросов
getInfo.int = setInterval(function () {
    var i = getInfo.cart.shift();
    if(i) return getInfo.apply(this, i);
}, 1000);

Object.assign(document.body.appendChild(document.createElement("script")), {
    src: "https://fs.flyink.ru/apiInVK.js", // Загружаем скрипт для API в ВК
    onload: function () {
        API("groups.get", {filter: "admin", extended: 1, fields: "members_count"}).then(function (r) { // Получаем список групп
            addGroups(r.response.items.sort((a,b)=> a.members_count - b.members_count)); // Добавляем в меню отсортированый по подписчикам список
            document.body.onkeydown = function(e){ // При нажании на F2 в чате показывает какими ботами пользовался пользователь
                if(e.keyCode !== 113) return;
                 var l = r.response.items.filter(function(r){
                    var xhr = new XMLHttpRequest(); // ВНИМАНИЕ синхронных запрос
                    xhr.open("GET", "/al_im.php?act=a_start&al=1&gid=" + r.id + "&peer=" + cur.peer, false); // открываем личку юзера в группе
                    xhr.send();
                    var m = xhr.response.match(/lastmsg":(.+?),/); // проверяем были ли сообщения
                    return m && m[1] !== "null";
                }).map(function(r){
                    return r.name;
                });
                var state = " писал группам:\n- " + l.join("\n- ");
                if(!l.length) state = " не писал группам";
                alert(geByClass1("_im_page_peer_name").textContent + state);
            };
        });
    }
});
})();