您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Checks the last online on page user and in dialog
当前为
/* globals vk, cur, getDateText, GM, GM_xmlhttpRequest */ /* eslint padded-blocks: ["error", { "blocks": "always" }] object-curly-spacing: ["error", "always", { "objectsInObjects": false }] curly: ["error", "multi"] */ // ==UserScript== // @name VK: Check Online // @name:ru ВК: Проверка онлайна // @description Checks the last online on page user and in dialog // @description:ru Проверяет последний онлайн пользователя на странице и в диалогe // @namespace vk-check-online.user.js // @license MIT // @author askornot // @version 1.0.5 // @match https://vk.com/* // @connect vk.com // @compatible chrome Violentmonkey 2.12.7 // @compatible firefox Violentmonkey 2.12.7 // @homepageURL https://greasyfork.org/en/scripts/403717-vk-check-online // @supportURL https://greasyfork.org/en/scripts/403717-vk-check-online/feedback // @grant GM_xmlhttpRequest // @grant GM.xmlHttpRequest // @run-at document-end // @noframes // ==/UserScript== 'use strict'; const USERS = new Map(); const request = (id, data = {}) => new Promise((resolve, reject) => { data.method = 'GET'; data.url = `/foaf.php?id=${id}`; data.responseType = 'document'; /* eslint-disable unicorn/prefer-add-event-listener, no-unused-expressions, no-constant-condition, operator-linebreak, new-cap */ data.onload = resolve; data.onerror = reject; typeof !GM && typeof !GM.xmlHttpRequest ? GM.xmlHttpRequest(data) : GM_xmlhttpRequest(data); /* eslint-enable */ }); const floor = time => Math.floor(time); const now = () => (floor(Date.now())); const render = uts => { const online = document.querySelector('.mail_box_label_info') || document.querySelector('.profile_online_lv') || document.querySelector('._im_page_peer_online'); const { lang } = vk; const text = lang === 3 ? 'last seen' : 'заходил(а)'; online.textContent = `${text} ${getDateText(uts, null)}`; }; const getTs = rdf => { // eslint-disable-next-line unicorn/prefer-query-selector const [element] = rdf.getElementsByTagName('ya:lastloggedin'); if (!element) return 0; const date = element.getAttribute('dc:date'); const uts = floor(Date.parse(date) / 1000); // A getDateText requires unixtime return uts; }; const getUser = user => USERS.has(user) ? USERS.get(user) : {}; const start = async () => { const { options = {}, peer } = cur; // VK object // eslint-disable-next-line no-prototype-builtins const userId = (peer ? peer : (options.hasOwnProperty('user_id') ? options.user_id : 0)); if (userId === 0 || Math.sign(userId) === -1) return; let { expires = 0, uts = 0 } = getUser(userId); if (expires < now()) { // eslint-disable-line curly try { const { response } = await request(userId); uts = getTs(response); USERS.set(userId, { uts, expires: now() + 60000 // Every one minute }); } catch (error) { console.error(error.stack); } } if (uts === 0) return; render(uts); }; start().catch(console.error); const filterMutsByClassName = muts => { return muts.filter((array, i, self) => self.findIndex(_array => (array.target.className === _array.target.className)) === i); }; new MutationObserver(muts => { muts = filterMutsByClassName(muts); for (const { target, addedNodes } of muts) { const { tagName } = target; if (tagName === 'DIV' || tagName === 'SPAN') { const { classList } = target; if ( // eslint-disable-line curly (classList.contains('wide_column') && addedNodes.length >= 2) || classList.contains('box_body') || classList.contains('_im_page_peer_online') || classList.contains('im-page-chat-contain') ) { setTimeout(start, 1000); } } } }).observe(document.body || document, { childList: true, subtree: true });