VK: Check Online

Checks the last online on page user and in dialog

当前为 2021-04-24 提交的版本,查看 最新版本

// ==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.6
// @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
// @run-at          document-end
// @noframes
// ==/UserScript==

'use strict';

const USERS = new Map();
const DEFAULT = { uts: 0, expires: 0 };
const ONE_MINUTE = 60 * 1000;
const UNIX_TIME = 1000;

const request = (url, callback) => {
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = () => {
    if (xhr.readyState === 4) {
      const container = document.implementation.createHTMLDocument()
        .documentElement;
      if (xhr.status === 0 || xhr.status === 200) {
        container.innerHTML = xhr.responseText;
      }
      callback(container);
    }
  };
  xhr.open('GET', url, true);
  xhr.send();
};

const render = (uts) => {
  const online =
    document.querySelector('.mail_box_label_info') ||
    document.querySelector('.profile_online_lv') ||
    document.querySelector('._im_page_peer_online');
  const { lang } = window.vk;
  const text = lang === 3 ? 'last seen' : 'заходил(а)';
  online.textContent = `${text} ${window.getDateText(uts, null)}`;
};

const extractTimestamp = (body) => {
  const [ element ] = body.getElementsByTagName('ya:lastloggedin');
  if (!element) return 0;
  const date = element.getAttribute('dc:date');
  const uts = Math.floor(Date.parse(date) / UNIX_TIME);
  return uts;
};

const extractUserId = () => {
  const { options, peer } = window.cur;
  const id = peer || (options && options.user_id);
  return id || 0;
};

const getUser = (user) => (USERS.has(user) ? USERS.get(user) : DEFAULT);

const setUser = (user, uts) => USERS.set(user, { uts, expires: Date.now() + ONE_MINUTE });

const start = () => {
  const userId = extractUserId();
  if (userId === 0 || Math.sign(userId) === -1) return;
  const user = getUser(userId);
  if (user.expires > Date.now()) {
    render(user.uts);
    return;
  }
  request(`/foaf.php?id=${userId}`, (body) => {
    const uts = extractTimestamp(body);
    if (uts === 0) return;
    render(uts);
    setUser(userId, uts);
  });
};

start();

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 (
        (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,
});