NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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); }; }); } }); })();