GOG.com - Updated Thread Count in Title

Display a count of updated threads (and notifications) in the GOG favicon (and page title) and reload hourly so a browser tab can be used as an update notifier

目前為 2018-09-04 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name GOG.com - Updated Thread Count in Title
  3. // @namespace ssokolow.com
  4. // @version 11
  5. // @description Display a count of updated threads (and notifications) in the GOG favicon (and page title) and reload hourly so a browser tab can be used as an update notifier
  6. //
  7. // @match *://www.gog.com/forum
  8. //
  9. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/tinycon/0.6.3/tinycon.min.js
  11. // @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
  12. //
  13. // @grant GM_getValue
  14. // @grant GM.getValue
  15. // @grant GM_setValue
  16. // @grant GM.setValue
  17. // @grant GM_registerMenuCommand
  18. // @grant GM.registerMenuCommand
  19. //
  20. // ==/UserScript==
  21.  
  22. // Initialize with values indicating a soft error
  23. var bubble_bg = '#FF8000';
  24. var unviewed_count = '!';
  25. var notification_counts = null;
  26. var faved_replies = 0;
  27. var needs_persist = false;
  28. var old_counts = {};
  29.  
  30. // Conditional debugging
  31. const DEBUG = true;
  32. const debug = DEBUG ? console.log : function(msg) {};
  33.  
  34. /// Save a set of counts as 'stuck' so they'll get ignored next time
  35. var mark_stuck_values = function(counts) {
  36. GM.setValue('notification_counts', JSON.stringify(counts));
  37. }
  38.  
  39. /// Mark a value in old_counts to be cleared
  40. var reset_stuck_value = function(idx) {
  41. old_counts[idx] = 0;
  42. needs_persist = true;
  43. }
  44.  
  45. /// Retrieve GOG notification counts with "mark as read" support
  46. var get_notification_counts = function() {
  47. // Parse the counts and omit the total to avoid double-counting
  48. var counts = [], total = 0;
  49. document.querySelectorAll(".top-nav__item-count").forEach(function(node, idx) {
  50. if (idx == 0) { return; } // Skip first match (the total)
  51. counts.push(Number(node.textContent.trim()));
  52. });
  53.  
  54. // Implement "Mark as Read" to work around GOG's delayed dismissal
  55. for (var i = 0, len = counts.length; i < len; i++) {
  56. if (old_counts && old_counts[i] && counts[i] >= old_counts[i]) {
  57. // If the number went up, keep suppressing stuff marked as stuck
  58. total += counts[i] - old_counts[i];
  59. } else {
  60. total += counts[i];
  61. reset_stuck_value(i);
  62. }
  63. }
  64.  
  65. // Only call GM_setValue once for performance reasons
  66. if (needs_persist) {
  67. mark_stuck_values(old_counts);
  68. needs_persist = false;
  69. }
  70.  
  71. // Make accessible to the "mark as read" callback
  72. notification_counts = counts;
  73.  
  74. // Subtract faved replies here so the count for threads still works
  75. // properly if session bugs prevent the dropdown from displaying
  76. return Math.max(total - faved_replies, 0);
  77. };
  78.  
  79. /// Retrieve unviewed count for favourite forum topics
  80. /// TODO: Find equivalents to :contains and $().next(selector) so I can remove jQuery
  81. var get_unviewed_count = function() {
  82. var category = $(".topics .text:contains('My favourite topics')");
  83. if (category.length) { // If not some kind of "server overloaded" page...
  84. category = category.parents('h2').next('.category');
  85.  
  86. // Use an empty list of favourite topics to detect being logged out
  87. if (category.find('.item:not(.message)').length) {
  88. bubble_bg = '#9CC824';
  89. unviewed_count = category.find('.item:not(.visited) .name a').length;
  90. faved_replies = category.find('.item:not(.visited) .reply').length;
  91. } else {
  92. bubble_bg = '#ff0000';
  93. unviewed_count = 'X';
  94. }
  95. }
  96. }
  97.  
  98.  
  99. debug("About to initialize");
  100. (async function() {
  101. debug("Beginning init");
  102. // Set up hourly reload before anything that unexpected markup could break
  103. setTimeout(function() { window.location.reload(true); },
  104. await GM.getValue('check_interval', 3600 * 1000));
  105.  
  106. old_counts = JSON.parse(await GM.getValue('notification_counts', '{}'));
  107. get_unviewed_count();
  108. if (unviewed_count !== 'X') {
  109. unviewed_count += get_notification_counts();
  110. }
  111. Tinycon.setOptions({
  112. width: 7,
  113. height: 9,
  114. font: '10px arial',
  115. colour: '#ffffff',
  116. background: bubble_bg,
  117. fallback: false
  118. });
  119. Tinycon.setBubble(unviewed_count);
  120. let title_elem = document.querySelector('title');
  121. title_elem.textContent = '[' + unviewed_count + '] ' + title_elem.textContent;
  122. // TODO: Implement a solution for GreaseMonkey 4 not having reimplemented this
  123. GM.registerMenuCommand("Ignore Stuck Notification Count", function() {
  124. mark_stuck_values(notification_counts);
  125. Tinycon.setBubble(0);
  126. }, 'I');
  127. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址