RB Visual Overhaul

replaces old rank icons and adds new ones, brings back the clock, etc.

目前为 2024-11-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name RB Visual Overhaul
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-11-25
  5. // @description replaces old rank icons and adds new ones, brings back the clock, etc.
  6. // @author Lemniscata
  7. // @match https://www.rusbionicle.com/*
  8. // @match https://rusbionicle.com/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=rusbionicle.com
  10. // @resource DEFAULT_CSS https://www.rusbionicle.com/forumsbio/style.php?&id=8&lang=ru
  11. // @resource IMPORTED_CSS https://raw.githubusercontent.com/OSP-Scata/RB-Visual-Overhaul/refs/heads/main/dark_theme/cssoverride.css
  12. // @resource DATABASE https://raw.githubusercontent.com/OSP-Scata/RB-Visual-Overhaul/refs/heads/main/new_ranks/ranks-database.json
  13. // @grant GM_getResourceText
  14. // @grant GM_addStyle
  15. // @grant GM_getValue
  16. // @grant GM_setValue
  17. // @license MIT
  18. // ==/UserScript==
  19.  
  20. (async() => {
  21. 'use strict';
  22. // часы
  23. var clock = document.createElement('div');
  24. clock.innerHTML = '<div id="clock"> \
  25. <center><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="150" height="150"> \
  26. <param name="wmode" value="transparent" /> \
  27. <param name="movie" value="https://rusbionicle.com/clock/clockfinal2.swf" /> \
  28. <param name="quality" value="high" /> \
  29. <embed src="https://rusbionicle.com/clock/clockfinal2.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="150" height="150" wmode="transparent"></embed> \
  30. </object> \
  31. </center> \
  32. </div>';
  33. document.getElementById('datebar').appendChild(clock);
  34.  
  35. // тёмная тема и кнопка для переключения
  36. const darkTheme = GM_getResourceText("IMPORTED_CSS");
  37. const lightTheme = GM_getResourceText("DEFAULT_CSS");
  38. var button = document.createElement("button");
  39. var header = document.querySelector('#logodesc');
  40. header.appendChild(button);
  41. var currentTheme = await GM_getValue("theme");
  42. var state = false;
  43. button.addEventListener('click', toggle );
  44. if (currentTheme == 'light' && state == false) {
  45. button.innerText = "Тёмная тема";
  46. button.style.cssText = 'float: right; margin: 20px; background-color: #383a40; color: #dbdee1';
  47. }
  48. else {
  49. GM_addStyle(darkTheme);
  50. button.innerText = "Светлая тема";
  51. button.style.cssText = 'float: right; margin: 20px; background-color: unset; color: unset';
  52. }
  53. function toggle(){
  54. if(currentTheme == 'light' && state == false) {
  55. GM_addStyle(darkTheme);
  56. GM_setValue("theme", "dark");
  57. state = true;
  58. }
  59. else {
  60. GM_addStyle(lightTheme);
  61. GM_setValue("theme", "light");
  62. button.innerText = "Светлая тема";
  63. button.style.cssText = 'float: right; margin: 20px; background-color: unset; color: unset';
  64. state = false;
  65. }
  66. }
  67.  
  68. const data = JSON.parse(GM_getResourceText("DATABASE"));
  69.  
  70. // замена рангов
  71. // в постах...
  72. var profiles = document.querySelectorAll('td.profile'); // сведения о пользователе в постах
  73. profiles.forEach((profile) => {
  74. var postDetails = profile.querySelector('span.postdetails') // тут ищем число сообщений
  75. var tdPostDetails = profile.querySelector('td.postdetails') // тут название ранга
  76. if (postDetails && tdPostDetails) {
  77. var userData = postDetails.querySelectorAll('b');
  78. if (userData[0].innerText != "Предупреждения:") {
  79. var numberOfPosts1 = parseInt(userData[1].nextSibling.data) // число постов в темах
  80. var topicRank = tdPostDetails.innerText;
  81. if (!topicRank.toLowerCase().includes('администратор') && !topicRank.toLowerCase().includes('модератор') && !topicRank.toLowerCase().includes('узник')) {
  82. for (var i = 0; i < data.length; i++) {
  83. if (numberOfPosts1 < data[i]['postNumber']) {
  84. var rankIcon = profile.querySelector('img[src*="./images/ranks/"]')
  85. rankIcon.src = rankIcon.src.replace(rankIcon.src, data[i-1]['rankIcon']);
  86. rankIcon.setAttribute("alt", data[i-1]['rankName']);
  87. rankIcon.setAttribute("title", data[i-1]['rankName']);
  88. profile.querySelector('td.postdetails').innerText = data[i-1]['rankName'];
  89. break;
  90. }
  91. else if (numberOfPosts1 >= data[data.length-1]['postNumber']) {
  92. rankIcon = profile.querySelector('img[src*="./images/ranks/"]')
  93. rankIcon.src = rankIcon.src.toLowerCase().replace(rankIcon.src, data[i]['rankIcon']);
  94. rankIcon.setAttribute("alt", data[i]['rankName']);
  95. rankIcon.setAttribute("title", data[i]['rankName']);
  96. profile.querySelector('td.postdetails').innerText = data[i-1]['rankName'];
  97. }
  98. }
  99. }
  100. }
  101. }
  102. });
  103.  
  104. // ...и на странице пользователей
  105. var row = document.querySelectorAll('tr.row1, tr.row2'); // сведения о пользователе в списке пользователей
  106. if (row.length == 50) { // потому что на странице 50 пользователей (чтобы не мешало остальному форуму)
  107. row.forEach((td) => {
  108. var userDataInUsers = td.querySelectorAll('td.gen');
  109. var numberOfPosts2 = parseInt(userDataInUsers[1].innerText); // число постов в списке пользователей
  110. var usersRank = userDataInUsers[2].innerHTML; // ранг в списке пользователей
  111. var rankText = usersRank.split("\"")[usersRank.split("\"").length-2];
  112. if ((rankText) && (!rankText.toLowerCase().includes('администратор') && !rankText.toLowerCase().includes('модератор') && !rankText.toLowerCase().includes('узник'))) {
  113. for (var i = 0; i < data.length; i++) {
  114. if (numberOfPosts2 < data[i]['postNumber']) {
  115. var rankIcon = td.querySelector('img[src*="./images/ranks/"]')
  116. rankIcon.src = rankIcon.src.replace(rankIcon.src, data[i-1]['rankIcon']);
  117. rankIcon.setAttribute("alt", data[i-1]['rankName']);
  118. rankIcon.setAttribute("title", data[i-1]['rankName']);
  119. break;
  120. }
  121. else if (numberOfPosts2 >= data[data.length-1]['postNumber']) {
  122. rankIcon = document.querySelector('img[src*="./images/ranks/"]')
  123. rankIcon.src = rankIcon.src.toLowerCase().replace(rankIcon.src, data[i]['rankIcon']);
  124. rankIcon.setAttribute("alt", data[i]['rankName']);
  125. rankIcon.setAttribute("title", data[i]['rankName']);
  126. }
  127. }
  128. }
  129. });
  130. }
  131. // ещё и страница профиля...
  132. var userProfileRank = document.querySelector('td.postdetails'); // ранг в профиле
  133. var canProfile = userProfileRank ? userProfileRank.innerText : ""; // тест на возможность спарсить ранг (если мы не на странице профиля)
  134. if (canProfile) {
  135. userProfileRank = userProfileRank.innerText;
  136. if (!userProfileRank.toLowerCase().includes('администратор') && !userProfileRank.toLowerCase().includes('модератор') && !userProfileRank.toLowerCase().includes('узник')) {
  137. var bGen = document.querySelectorAll('b.gen')
  138. bGen.forEach((tag) => {
  139. if (!isNaN(parseInt(tag.innerText))) {
  140. var numberOfPosts3 = parseInt(tag.innerText) // число постов в профиле
  141. for (var i = 0; i < data.length; i++) {
  142. if (numberOfPosts3 < data[i]['postNumber']) {
  143. var rankIcon = document.querySelector('img[src*="./images/ranks/"]')
  144. rankIcon.src = rankIcon.src.replace(rankIcon.src, data[i-1]['rankIcon']);
  145. rankIcon.setAttribute("alt", data[i-1]['rankName']);
  146. rankIcon.setAttribute("title", data[i-1]['rankName']);
  147. document.querySelector('td.postdetails').innerText = data[i-1]['rankName']
  148. break;
  149. }
  150. else if (numberOfPosts3 >= data[data.length-1]['postNumber']) {
  151. rankIcon = document.querySelector('img[src*="./images/ranks/"]')
  152. rankIcon.src = rankIcon.src.replace(rankIcon.src, data[i]['rankIcon']);
  153. rankIcon.setAttribute("alt", data[i]['rankName']);
  154. rankIcon.setAttribute("title", data[i]['rankName']);
  155. document.querySelector('td.postdetails').innerText = data[i]['rankName']
  156. }
  157. }
  158. }
  159. })
  160. }
  161. }
  162. /*
  163. // реплейс существующих иконок рангов (старое)
  164. function updateImagesSrc() {
  165. document.querySelectorAll('img[src*="./images/ranks/"]').forEach((previewImage) => {
  166. previewImage.src = previewImage.src.toLowerCase().replace('https://www.rusbionicle.com/forumsbio/images/ranks/', 'https://brickshelf.com/gallery/Roodaka8761/Bionicle/RB-new-ranks/');
  167. })
  168. }
  169.  
  170. if(document.readyState == 'complete') {
  171. updateImagesSrc();
  172. } else {
  173. window.addEventListener('load', updateImagesSrc);
  174. } */
  175. })();