MierdiTwist

Notifies about new messages in tab's title & icon

  1. // ==UserScript==
  2. // @name MierdiTwist
  3. // @namespace http://yelidmod.com/
  4. // @version 0.1
  5. // @description Notifies about new messages in tab's title & icon
  6. // @author You
  7. // @match https://twist.com/a/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. const defaultFavicon = "https://twist.com/a/img/fav/favicon.ico";
  15. const warningFavicon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAD5ElEQVRoQ+2aW2wMURjH/2d2u5e6tNtGrLYPgkR4aVqSShpa4pbSekG8iAiNxCVC6oFEUa/6IDQEr4iQeHAJdQlCG0GLIGiLoqWhF73YtjM7R850d7N2Z3bOrtnujvQkk0wy38z8f9/tnMkZAv+glBQd/lUO0FKAzAWoO3At8ScUQDMIeUqBMw/2p9/1SyLspPDgjyyrYD0LoDjxWnUVUFByst+dtvPZFiISKJ7vYURmEB9MV3W/0nWAFB3qKQehp3S5k89AkmU5lxRVdV8BsDL59OkrogQVDKAdwBR98yS0IOQ8A2AVbspBgftjAIkMnRKB6qsDtLFVwpdOOZFaYnq3AkApVWrgZ5+Mxk9S4PjWk/xAfwGEuuB7jw+odQTqR2/yAUUECAVq65LR4IvQ81YJXf2JB1IALj4ejL6NUuBNm4S7r8WYcteom8baqJonM8cLyMkQkJMpIDvDMnKeIeBrp4zKSwNGOV95TswRcI0jyGHiMn1ifUKzMwQ4UpQVethgTWHdsV7VazYrwZoCOySZ4kL9EDdkRIAUCzBzitXnSSbUgmzXiGdTbeoiQ98seoHnnyTUNYmoey+i41d44S+YlYKti51wpwto/u7F5tN9xgCcKZ+AGW4L98P8ht0DFPVNonI8/SDBM6zeI6ZPtmD7UifyploD72jp8GLTKQMAmPdv7UvnFs88x7xc/17E23Yvy03NMdFJsGmhA6X5dgghgTQMgOVk7d40TRFDEkXjR5YakuJpnknOIgCr5tixsdiBCQ71FIwrAPPqzRfDePBWRMNHCYMi//Qxd5pVSZepkyKnZFwBLj8ZwtEbHu60YoZZLgHbljhRODOF6764AtTUenDxMV+Lc9oI1s93KK2R1VPEkRaeTsUV3VzAmm1UrQaO13pwSQeASVmWa0P5IgfYhKY5VESr2eqBGAowO9uKHcudmJWl43JO8cFAWiCaAKy9XdmThnF2orTE9i4ZJ2578PBd+OLNKgC7SlJRkmeD7vQWg3g/iBpExJmYdYzxDoIPHV781piM2MPXzrNj6xInV85iNAH4FAG7S5wom2PXN/8H8VpRiHkxF6x294pUlOXb/nMAA7yvFoXRi4BZAdhy+tyjQWwo5Sxy/UREcDeKawRefpZQfc2D1p9e3Dvi4pDGZxJ3gL5BipO3PbjeOBxYVpsG4M6rYbAlB/uoCR5JDbC6wI6VeTbU3PLgSYukmQdGQITOxobUAF/mwpA6SCgAA/2XKES9FuL1bDR2pgeINQpRL6ej8WqstjzR4P2gSegmnxqInvCA03ybfCbfZjX7RrfpfzVg+WTunz38FWHS323+ANzUOYmSO/P8AAAAAElFTkSuQmCC";
  16. const pendingMessagesWarning = "(!)";
  17.  
  18. const showWarning = () => {
  19. const title = document.querySelector('title').innerText;
  20.  
  21. // warning already present or is looking at the tab
  22. if (title.includes(pendingMessagesWarning) || !document.hidden) {
  23. return;
  24. }
  25. document.querySelector('title').innerText = pendingMessagesWarning + " " + title;
  26. document.querySelectorAll('[rel="icon"], [rel="shortcut icon"]').forEach((el) => {
  27. el.href = warningFavicon;
  28. });
  29. }
  30.  
  31. const hideWarning = () => {
  32. document.querySelector('title').innerText = document.querySelector('title').innerText.replace(pendingMessagesWarning, "");
  33. document.querySelectorAll('[rel="icon"], [rel="shortcut icon"]').forEach((el) => {
  34. el.href = defaultFavicon;
  35. });
  36. };
  37.  
  38. // whenever user opens twist tab, hide the warnings
  39. document.addEventListener("visibilitychange", () => {
  40. if (!document.hidden) {
  41. hideWarning();
  42. }
  43. }, false);
  44.  
  45. (function(originalFetch) {
  46. window.fetch = function(url, options) {
  47. if (!url.includes("getMessages")) {
  48. return originalFetch(url, options);
  49. }
  50.  
  51. // apply MITM
  52. return new Promise((resolve, reject) => {
  53. originalFetch(url, options).then((response) => {
  54. let result = response.clone();
  55.  
  56. resolve(response);
  57.  
  58. result.json().then((json) => {
  59. json.data.forEach((event) => {
  60. // private message
  61. if (event.type == "message_added" && event.to_user == true) {
  62. showWarning();
  63. }
  64. });
  65. });
  66. }).catch(reject);
  67. });
  68. };
  69. })(fetch);
  70. })();