VK: Check Online

Checks the last online on page user and in dialog

目前为 2022-10-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name VK: Check Online
  3. // @name:ru ВК: Проверка онлайна
  4. // @description Checks the last online on page user and in dialog
  5. // @description:ru Проверяет последний онлайн пользователя на странице и в диалогe
  6. // @namespace vk-check-online.user.js
  7. // @license MIT
  8. // @author askornot
  9. // @version 1.3.0
  10. // @match https://vk.com/*
  11. // @connect vk.com
  12. // @compatible chrome Violentmonkey 2.13.3
  13. // @compatible firefox Violentmonkey 2.13.3
  14. // @compatible firefox Tampermonkey 4.18.0
  15. // @homepageURL https://greasyfork.org/en/scripts/403717-vk-check-online
  16. // @supportURL https://greasyfork.org/en/scripts/403717-vk-check-online/feedback
  17. // @run-at document-end
  18. // @noframes
  19. // ==/UserScript==
  20.  
  21. (function (W, D, T) {
  22. 'use strict';
  23.  
  24. const ID_PATH = 'response,users.get,0,id';
  25.  
  26. const ONLINE_PATH = 'response,users.get,0,online_info';
  27.  
  28. const ONLINE_INFO = {
  29. visible: true,
  30. last_seen: 0,
  31. is_online: false,
  32. is_mobile: false,
  33. };
  34.  
  35. const last = (arr) => arr[arr.length - 1];
  36.  
  37. const match = (s) => /online_info/.test(s);
  38.  
  39. const getByPath = (data, dataPath) => {
  40. const path = dataPath.split(',');
  41. let object = data;
  42. for (const name of path) {
  43. const next = object[name];
  44. if (next === null || next === undefined) return next;
  45. object = next;
  46. }
  47. return object;
  48. };
  49.  
  50. const setByPath = (data, dataPath, value) => {
  51. const path = dataPath.split(',');
  52. const len = path.length;
  53. let obj = data;
  54. let i = 0;
  55. let next, prop;
  56. for (;;) {
  57. if (typeof obj !== 'object') return false;
  58. prop = path[i];
  59. if (i === len - 1) {
  60. obj[prop] = value;
  61. return true;
  62. }
  63. next = obj[prop];
  64. if (next === undefined || next === null) {
  65. next = {};
  66. obj[prop] = next;
  67. }
  68. obj = next;
  69. i++;
  70. }
  71. };
  72.  
  73. const parse = (text) => {
  74. const parser = new DOMParser();
  75. const body = parser.parseFromString(text, 'text/html');
  76. const [element] = body.getElementsByTagName('ya:lastloggedin');
  77. if (!element) return 0;
  78. const date = element.getAttribute('dc:date');
  79. const uts = Math.floor(Date.parse(date) / 1000);
  80. return uts;
  81. };
  82.  
  83. const online = (id) =>
  84. fetch(`/foaf.php?id=${id}`)
  85. .then((res) => res.text())
  86. .then(parse);
  87.  
  88. const patch = (data) => {
  89. const info = getByPath(data, ONLINE_PATH);
  90. if (info && info.visible === true) return data;
  91. const id = getByPath(data, ID_PATH);
  92. return online(id).then((timestamp) => {
  93. const info = { ...ONLINE_INFO, last_seen: timestamp };
  94. setByPath(data, ONLINE_PATH, info);
  95. return data;
  96. });
  97. };
  98.  
  99. W[T] = new Proxy(W[T], {
  100. apply(...args) {
  101. const promise = Reflect.apply(...args);
  102. const argumentsList = last(args);
  103. const { body } = last(argumentsList);
  104. if (!match(body)) return promise;
  105. return promise
  106. .then((res) => res.clone())
  107. .then((res) => res.json())
  108. .then(patch)
  109. .then((patched) => new Response(JSON.stringify(patched), promise))
  110. .catch(() => promise);
  111. },
  112. });
  113. })(unsafeWindow || window, document, 'fetch');