Better Hydro

Improve the Hydro interface with custom settings!

目前为 2024-08-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Better Hydro
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.5
  5. // @description Improve the Hydro interface with custom settings!
  6. // @author Cheerimy
  7. // @match *://hydro.ac/*
  8. // @match *://oiclass.com/*
  9. // @match *://www.oiclass.com/*
  10. // @match *://106.53.100.188:1000/*
  11. // @icon https://s21.ax1x.com/2024/08/22/pAi6KDP.png
  12. // @grant none
  13. // @license GPLv3
  14. // ==/UserScript==
  15. (function() {
  16. 'use strict';
  17. //Cookies 初始化函数
  18. function setCookieIfNotExists(name, value) {
  19. if (!document.cookie.split('; ').map(cookie => cookie.split('=')[0]).includes(name)) {
  20. document.cookie = `${name}=${encodeURIComponent(value)};path=/;expires=${new Date(Date.now()+365*24*60*60*1000).toUTCString()}`
  21. }
  22. }
  23. //获取 Cookies 模块
  24. function getCookie(name) {
  25. const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
  26. return match ? decodeURIComponent(match[2]) : null
  27. }
  28. //初始化 Cookies 模块
  29. function initCookies() {
  30. setCookieIfNotExists('browserupdateorg', 'pause');
  31. setCookieIfNotExists('background', 'https://api.imlazy.ink/mcapi/mcbg.php');
  32. setCookieIfNotExists('music', '//music.163.com/outchain/player?type=2&id=133567&auto=0&height=66');
  33. console.log('Cookies 模块加载成功!');
  34. }
  35. //处理 IDE 频率限制模块(Demo)
  36. function handleElement(element) {
  37. const initialHTML = element.innerHTML;
  38. const observer = new MutationObserver((mutationsList) => {
  39. for (const mutation of mutationsList) {
  40. if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
  41. const currentClass = mutation.target.className;
  42. if (currentClass.includes('disable')) {
  43. mutation.target.className = currentClass.replace('disable', 'enable');
  44. console.log('Class "disable" detected and changed to "enable".');
  45.  
  46. // 更新 HTML 内容
  47. mutation.target.innerHTML = initialHTML;
  48. console.log('HTML updated to:', initialHTML);
  49. }
  50. }
  51. }
  52. });
  53.  
  54. const config = {
  55. attributes: true,
  56. attributeFilter: ['class']
  57. };
  58. observer.observe(element, config);
  59. }
  60. //基本模块(欢迎栏与 UI 优化)
  61. function loadWelcomeMessage() {
  62. const username = Array.from(document.querySelectorAll('li[data-dropdown-target="#menu-nav-user"]')).map(item => item.querySelector('a')).find(link => link && link.textContent.trim() !== 'Language')?.textContent.trim() || 'Visitor';
  63. const panel = document.getElementById('panel');
  64. panel.style.backgroundImage = `url(${getCookie('background')})`;
  65. panel.style.backgroundSize = 'cover';
  66. panel.style.backgroundPosition = 'center';
  67. const style = document.createElement('style');
  68. style.textContent = `.section{border-radius:8px!important;opacity:0.75!important}.section:hover{opacity:1!important}.section__table-header{border-radius:8px 8px 0 0;opacity:0.75!important}.section__table-header:hover{opacity:1!important}`;
  69. document.head.append(style);
  70. const title=document.title;
  71. const name=title.split(" - ").pop().trim();
  72. const newHTML = `<div class="section visible"><div class="section__header"><h1 class="section__title">欢迎 ${username} 来到 ${name}!</h1><h1 class="section__title"style="text-align: end;">Let's Coding Now!</h1></div></div>`;
  73. const main = panel.querySelector('.main');
  74. const element = main.querySelector('div');
  75. element.insertAdjacentHTML('afterbegin', newHTML);
  76. console.log('基本模块加载成功!');
  77. }
  78. //音乐模块(播放音乐源音乐)
  79. function loadMusicPlayer() {
  80. const musicURL = getCookie('music');
  81. const musicHTML = `<div class="section side visible"><div class="section__header"><h1 class="section__title">一首歌曲</h1></div><div class="section__body typo"><iframe frameborder="no"border="0"marginwidth="0"marginheight="0"width="100%"height="86"src="${musicURL}"></iframe></div></div>`;
  82. const row = document.getElementById('panel').querySelector('.main').querySelector('.row');
  83. const divs = row.querySelectorAll(':scope > div');
  84. divs.forEach(div => {
  85. const className = div.className;
  86. if (className.includes('medium-3') && className.includes('columns')) {
  87. div.insertAdjacentHTML('afterbegin', musicHTML)
  88. }
  89. });
  90. console.log('音乐播放器加载成功!')
  91. }
  92. //个性化面板模块
  93. function loadSettingsPanel() {
  94. const settingDiv = document.createElement('div');
  95. settingDiv.id = 'setting';
  96. settingDiv.innerHTML = `<div class="section side visible"><div class="section__header"><h1 class="section__title">设置</h1></div><style>.input-group{display:flex;flex-direction:column;gap:10px;max-width:400px;margin:0 auto}.input-group label{font-size:14px;color:#333}.input-group input[type="text"]{padding:8px;font-size:14px;border:1px solid#ccc;border-radius:4px;width:100%;box-sizing:border-box}.input-group input[type="text"]::placeholder{color:#999}</style><div class="section__body typo"><div class="input-group"><label for="background-url">背景图片:</label><input type="text"id="background-url"placeholder="输入背景图片地址"><button id="save-background">保存背景</button><label for="music-url">音乐地址:</label><input type="text"id="music-url"placeholder="输入音乐播放器地址"><button id="save-music">保存音乐</button></div></div></div>`;
  97. const omnibarContent = document.getElementById('omnibar-content');
  98. omnibarContent.insertAdjacentElement('afterend', settingDiv);
  99. const setCookie = (name, value, days = 365) => {
  100. const expires = new Date(Date.now() + days * 24 * 60 * 60 * 1000).toUTCString();
  101. document.cookie = `${name}=${value};expires=${expires};path=/`
  102. };
  103. const saveInput = (inputId, cookieName) => {
  104. const input = document.getElementById(inputId);
  105. if (input) {
  106. setCookie(cookieName, input.value)
  107. } else {
  108. console.error(`Element#${inputId}not found`)
  109. }
  110. };
  111. document.getElementById('save-background').onclick = () => saveInput('background-url', 'background');
  112. document.getElementById('save-music').onclick = () => saveInput('music-url', 'music');
  113. console.log('个性化面板模块加载成功!')
  114. }
  115. //去除在线 IDE 提交频率限制模块
  116. function killidelimit() {
  117. const elements = document.querySelectorAll('.scratchpad__toolbar__submit');
  118. elements.forEach(handleElement);
  119.  
  120. // 观察整个文档,以便检测未来添加的目标元素
  121. const observer = new MutationObserver((mutationsList) => {
  122. for (const mutation of mutationsList) {
  123. if (mutation.type === 'childList') {
  124. mutation.addedNodes.forEach((node) => {
  125. if (node.nodeType === 1) {
  126. // 如果节点是目标元素的后代,进行深度检查
  127. if (node.matches('.scratchpad__toolbar__item')) {
  128. handleElement(node);
  129. } else {
  130. // 深度检查子节点
  131. const descendantElements = node.querySelectorAll('.scratchpad__toolbar__item');
  132. descendantElements.forEach(handleElement);
  133. }
  134. }
  135. });
  136. }
  137. }
  138. });
  139.  
  140. const config = {
  141. childList: true,
  142. subtree: true
  143. };
  144. observer.observe(document.body, config);
  145. console.log('IDE 优化模块开始运行!');
  146. }
  147. //尝试加载 Cookies 模块
  148. try {
  149. initCookies();
  150. } catch (error) {
  151. console.error('Cookies 模块加载失败,错误::', error);
  152. }
  153. //尝试加载基础模块
  154. try {
  155. loadWelcomeMessage();
  156. } catch (error) {
  157. console.error('基础模块加载失败,错误::', error);
  158. }
  159. //尝试加载音乐模块
  160. try {
  161. loadMusicPlayer();
  162. } catch (error) {
  163. console.error('音乐模块加载失败,错误::', error);
  164. }
  165. //尝试 IDE 优化模块
  166. try {
  167. killidelimit();
  168. } catch (error) {
  169. console.error('IDE 优化模块加载失败,错误::', error);
  170. }
  171. //尝试个性化面板面板模块
  172. setTimeout(function() {
  173. try {
  174. loadSettingsPanel();
  175. } catch (error) {
  176. console.error('个性化面板模块加载失败,错误::', error);
  177. }
  178. }, 2000);
  179. })();