[Library] - GS ENCH

Library For GameSense 2.1

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/518265/1488683/%5BLibrary%5D%20-%20GS%20ENCH.js

  1. class GSEnhancedUI {
  2. constructor() {
  3. if (window.GSEnhancedUIInstance) {
  4. return window.GSEnhancedUIInstance;
  5. }
  6. window.GSEnhancedUIInstance = this;
  7. this.cache = {};
  8. this.currentTheme = GM_getValue('theme', 'default');
  9. const styles = `
  10. :root {
  11. --gs-primary: #e61515;
  12. --gs-secondary: #353534;
  13. --gs-background: #272726;
  14. --gs-text: #ffffff;
  15. --gs-border: #454545;
  16. --gs-hover: #404040;
  17. }
  18.  
  19. .subscribelink {
  20. display: none !important;
  21. }
  22.  
  23. .blocktable h2 {
  24. transition: background-color 0.3s ease;
  25. cursor: pointer;
  26. }
  27.  
  28. .fa-magnet {
  29. margin-right: 8px;
  30. font-size: 14px;
  31. opacity: 0.7;
  32. transition: all 0.3s ease;
  33. }
  34.  
  35. .blocktable h2:hover .fa-magnet {
  36. opacity: 1;
  37. }
  38.  
  39. .fa-eye, .fa-eye-slash {
  40. font-size: 14px;
  41. padding: 2px;
  42. opacity: 0.7;
  43. transition: opacity 0.2s;
  44. }
  45.  
  46. .fa-eye:hover, .fa-eye-slash:hover {
  47. opacity: 1;
  48. }
  49.  
  50. .blockform table td .button {
  51. padding: 3px 10px;
  52. font-size: 0.9em;
  53. white-space: nowrap;
  54. }
  55.  
  56. .blockform table td a:not(.button) {
  57. text-decoration: none;
  58. color: var(--gs-primary);
  59. }
  60.  
  61. .blockform table td a:not(.button):hover {
  62. text-decoration: underline;
  63. }
  64.  
  65. .section-header {
  66. user-select: none;
  67. }
  68.  
  69. .section-header .fa-magnet {
  70. opacity: 0.7;
  71. font-size: 14px;
  72. }
  73.  
  74. .section-header:hover .fa-magnet {
  75. opacity: 1;
  76. }
  77.  
  78. [data-theme="light-red"] .pun a:link,
  79. [data-theme="light-red"] .pun a:visited,
  80. [data-theme="light-red"] .pun .tcl h3 a,
  81. [data-theme="light-red"] #brdmenu a:link,
  82. [data-theme="light-red"] #brdmenu a:visited {
  83. color: #ff4444 !important;
  84. }
  85. [data-theme="light-red"] .pun a:hover,
  86. [data-theme="light-red"] .pun a:active,
  87. [data-theme="light-red"] .pun .tcl h3 a:hover,
  88. [data-theme="light-red"] #brdmenu a:hover {
  89. color: #ff6666 !important;
  90. }
  91. [data-theme="light-orange"] .pun a:link,
  92. [data-theme="light-orange"] .pun a:visited,
  93. [data-theme="light-orange"] .pun .tcl h3 a,
  94. [data-theme="light-orange"] #brdmenu a:link,
  95. [data-theme="light-orange"] #brdmenu a:visited {
  96. color: #ffa500 !important;
  97. }
  98. [data-theme="light-orange"] .pun a:hover,
  99. [data-theme="light-orange"] .pun a:active,
  100. [data-theme="light-orange"] .pun .tcl h3 a:hover,
  101. [data-theme="light-orange"] #brdmenu a:hover {
  102. color: #ffc04d !important;
  103. }
  104.  
  105. .inform {
  106. margin-bottom: 12px;
  107. }
  108. .infldset {
  109. padding: 12px;
  110. }
  111. .button-group {
  112. display: flex;
  113. gap: 8px;
  114. margin-top: 8px;
  115. }
  116. .button-group .button {
  117. display: inline-flex;
  118. align-items: center;
  119. gap: 5px;
  120. }
  121. .button-group .button i {
  122. font-size: 12px;
  123. }
  124. .input-with-button {
  125. display: flex;
  126. gap: 8px;
  127. align-items: center;
  128. }
  129. .input-with-button input {
  130. flex: 1;
  131. }
  132. .contains-error {
  133. border-color: #ff4444 !important;
  134. }
  135. .status-text {
  136. display: flex;
  137. align-items: center;
  138. gap: 5px;
  139. margin-bottom: 8px;
  140. }
  141. .status-text i {
  142. color: var(--gs-primary);
  143. font-size: 14px;
  144. }
  145. `;
  146.  
  147. if (!document.getElementById('gs-enhanced-styles')) {
  148. const styleElement = document.createElement('style');
  149. styleElement.id = 'gs-enhanced-styles';
  150. styleElement.textContent = styles;
  151. document.head.appendChild(styleElement);
  152. }
  153. if (!window.GSEnhancedUIInitialized) {
  154. this.init();
  155. window.GSEnhancedUIInitialized = true;
  156. }
  157. }
  158.  
  159. init() {
  160. this.addThemeToggle();
  161. this.addCollapsibleCategories();
  162. this.removeSubscribeLink();
  163. this.addRollButton();
  164. this.setupUndercoverMode();
  165. this.setupResellerList();
  166. this.setupPremiumUI();
  167. document.body.setAttribute('data-theme', this.currentTheme);
  168. }
  169.  
  170. removeSubscribeLink() {
  171. const subscribeLink = document.querySelector('.subscribelink');
  172. if (subscribeLink) {
  173. subscribeLink.remove();
  174. }
  175. }
  176.  
  177. addThemeToggle() {
  178. if (document.getElementById('theme-toggle')) return;
  179. const logoutLink = document.querySelector('#navlogout');
  180. if (!logoutLink) return;
  181.  
  182. const themeToggle = document.createElement('li');
  183. themeToggle.id = 'theme-toggle';
  184. themeToggle.innerHTML = this.getThemeIcon(this.currentTheme);
  185.  
  186. themeToggle.addEventListener('click', () => {
  187. this.cycleTheme();
  188. themeToggle.innerHTML = this.getThemeIcon(this.currentTheme);
  189. });
  190.  
  191. logoutLink.parentNode.insertBefore(themeToggle, logoutLink.nextSibling);
  192. }
  193.  
  194. getThemeIcon(theme) {
  195. const icons = {
  196. 'default': 'fa-adjust',
  197. 'light-red': 'fa-fire',
  198. 'light-orange': 'fa-sun-o'
  199. };
  200. return `<i class="fa ${icons[theme]} theme-icon"></i>`;
  201. }
  202.  
  203. cycleTheme() {
  204. const themes = ['default', 'light-red', 'light-orange'];
  205. const currentIndex = themes.indexOf(this.currentTheme);
  206. const newTheme = themes[(currentIndex + 1) % themes.length];
  207. this.currentTheme = newTheme;
  208. GM_setValue('theme', newTheme);
  209. document.body.setAttribute('data-theme', newTheme);
  210. }
  211.  
  212. addRollButton() {
  213. if (document.querySelector('.chat-roll')) return;
  214. const emojiSelector = document.querySelector('#emojiselector');
  215. if (emojiSelector) {
  216. const rollButton = document.createElement('div');
  217. rollButton.className = 'chat-roll';
  218. rollButton.innerHTML = '🎲';
  219. rollButton.style.cssText = `
  220. cursor: pointer;
  221. margin-right: 5px;
  222. font-size: 16px;
  223. display: inline-block;
  224. vertical-align: middle;
  225. padding: 0 5px;
  226. `;
  227. rollButton.addEventListener('click', () => {
  228. const chatInput = document.querySelector('#shouttext');
  229. if (chatInput) {
  230. chatInput.value = '/roll';
  231. const event = new KeyboardEvent('keydown', {
  232. key: 'Enter',
  233. code: 'Enter',
  234. keyCode: 13,
  235. which: 13,
  236. bubbles: true
  237. });
  238. chatInput.dispatchEvent(event);
  239. }
  240. });
  241. emojiSelector.parentNode.insertBefore(rollButton, emojiSelector);
  242. }
  243. }
  244.  
  245. setupUndercoverMode() {
  246. const loggedInSpan = document.querySelector('#brdwelcome .conl li:first-child span');
  247. if (!loggedInSpan || loggedInSpan.querySelector('.fa-eye')) return;
  248. const usernameElement = loggedInSpan.querySelector('strong');
  249. if (usernameElement) {
  250. GM_setValue('username', usernameElement.textContent.trim());
  251. }
  252. const eyeButton = document.createElement('i');
  253. eyeButton.className = 'fa fa-eye';
  254. eyeButton.style.cssText = `
  255. cursor: pointer;
  256. margin-left: 5px;
  257. opacity: 0.7;
  258. `;
  259. const isUndercover = GM_getValue('undercover', false);
  260. if (isUndercover) {
  261. this.enableUndercoverMode();
  262. eyeButton.className = 'fa fa-eye-slash';
  263. }
  264.  
  265. eyeButton.addEventListener('click', () => {
  266. const currentState = GM_getValue('undercover', false);
  267. GM_setValue('undercover', !currentState);
  268. if (!currentState) {
  269. this.enableUndercoverMode();
  270. eyeButton.className = 'fa fa-eye-slash';
  271. } else {
  272. this.disableUndercoverMode();
  273. eyeButton.className = 'fa fa-eye';
  274. }
  275. });
  276.  
  277. loggedInSpan.appendChild(eyeButton);
  278. }
  279.  
  280. enableUndercoverMode() {
  281. const username = GM_getValue('username');
  282. if (!username) return;
  283.  
  284. const selectors = [
  285. 'a[href*="profile.php"]',
  286. '#brdwelcome .conl li:first-child strong',
  287. '.username',
  288. '.user-name',
  289. '.author'
  290. ];
  291.  
  292. document.querySelectorAll(selectors.join(', ')).forEach(element => {
  293. if (element.textContent.trim() === username) {
  294. element.setAttribute('data-original', element.textContent);
  295. element.textContent = '<HIDDEN>';
  296. }
  297. });
  298. }
  299.  
  300. disableUndercoverMode() {
  301. document.querySelectorAll('[data-original]').forEach(element => {
  302. if (element.getAttribute('data-original')) {
  303. element.textContent = element.getAttribute('data-original');
  304. element.removeAttribute('data-original');
  305. }
  306. });
  307. }
  308.  
  309. setupResellerList() {
  310. if (!window.location.href.includes('payment.php') || document.querySelector('.reseller-section')) return;
  311. const extendGameSense = document.querySelector('.blockform');
  312. if (!extendGameSense) return;
  313. const resellerSection = document.createElement('div');
  314. resellerSection.className = 'blockform reseller-section';
  315. resellerSection.innerHTML = `
  316. <h2>
  317. <span>
  318. <div style="display: flex; align-items: center; cursor: pointer;" class="section-header">
  319. <i class="fa fa-magnet" style="margin-right: 8px; transition: transform 0.3s ease"></i>
  320. Verified Resellers
  321. </div>
  322. </span>
  323. </h2>
  324. <div class="box">
  325. <div class="fakeform">
  326. <div class="inform">
  327. <fieldset>
  328. <legend>Alternative Payment Methods</legend>
  329. <div class="fakeform">
  330. <p>Below is a list of verified resellers. Please be careful and only deal with listed resellers to avoid scams.</p>
  331. <table>
  332. <tr>
  333. <th class="tcl">Reseller</th>
  334. <th class="tcl">Payment Methods</th>
  335. <th class="tcl">Price</th>
  336. <th class="tcl">Action</th>
  337. </tr>
  338. <tr>
  339. <td><a href="profile.php?id=985">Sigma</a></td>
  340. <td>Crypto, PayPal, CashApp</td>
  341. <td>24 USD</td>
  342. <td><a href="viewtopic.php?id=23385" class="button">Purchase</a></td>
  343. </tr>
  344. <tr>
  345. <td><a href="profile.php?id=2933">death1989</a></td>
  346. <td>花呗,微信,支付宝,QQ红包</td>
  347. <td>135 RMB</td>
  348. <td><a href="viewtopic.php?id=17427" class="button">Purchase</a></td>
  349. </tr>
  350. <tr>
  351. <td><a href="profile.php?id=3031">484481617</a></td>
  352. <td>支付宝/微信/QQ/QIWI/淘宝/PayPal</td>
  353. <td>135 RMB</td>
  354. <td><a href="viewtopic.php?id=17435" class="button">Purchase</a></td>
  355. </tr>
  356. <tr>
  357. <td><a href="profile.php?id=1699">tiagovski</a></td>
  358. <td>PayPal, Bank, Card, Crypto, PSC, Alipay, Pix</td>
  359. <td>20 EUR</td>
  360. <td><a href="viewtopic.php?id=25671" class="button">Purchase</a></td>
  361. </tr>
  362. <tr>
  363. <td><a href="profile.php?id=10043">Margele</a></td>
  364. <td>支付宝,微信</td>
  365. <td>148.88 CNY</td>
  366. <td><a href="viewtopic.php?id=45009" class="button">Purchase</a></td>
  367. </tr>
  368. <tr>
  369. <td><a href="profile.php?id=12434">Samo</a></td>
  370. <td>PayPal, Giropay, TF2, Crypto, Skrill</td>
  371. <td>21 EUR</td>
  372. <td><a href="viewtopic.php?id=43045" class="button">Purchase</a></td>
  373. </tr>
  374. <tr>
  375. <td><a href="profile.php?id=274">ag96</a></td>
  376. <td>TF2 Keys, PayPal, Skins, BTC, ETH</td>
  377. <td>23.5 USD</td>
  378. <td><a href="viewtopic.php?id=17477" class="button">Purchase</a></td>
  379. </tr>
  380. <tr>
  381. <td><a href="profile.php?id=9060">VKVKF</a></td>
  382. <td>Cards RU/EU/KZ/UA/ASIA, All Crypto</td>
  383. <td>30 USD</td>
  384. <td><a href="viewtopic.php?id=27735" class="button">Purchase</a></td>
  385. </tr>
  386. </table>
  387. <p>⚠️ Always verify the reseller's profile and reputation before making any payments. Be aware of scammers impersonating verified resellers.</p>
  388. </div>
  389. </fieldset>
  390. </div>
  391. </div>
  392. </div>
  393. `;
  394. const firstBlockform = document.querySelector('.blockform');
  395. firstBlockform.parentNode.insertBefore(resellerSection, firstBlockform.nextSibling);
  396. this.addCollapseFunctionToSection(resellerSection);
  397. }
  398.  
  399. addCollapseFunctionToSection(section) {
  400. const header = section.querySelector('.section-header');
  401. const content = section.querySelector('.box');
  402. const icon = header.querySelector('.fa-magnet');
  403. const isSectionCollapsed = GM_getValue(`section_${header.textContent.trim()}_collapsed`, false);
  404. if (isSectionCollapsed) {
  405. content.style.display = 'none';
  406. icon.style.transform = 'rotate(180deg)';
  407. }
  408.  
  409. header.addEventListener('click', () => {
  410. const isCollapsed = content.style.display === 'none';
  411. content.style.display = isCollapsed ? '' : 'none';
  412. icon.style.transform = isCollapsed ? '' : 'rotate(180deg)';
  413. GM_setValue(`section_${header.textContent.trim()}_collapsed`, !isCollapsed);
  414. });
  415. }
  416.  
  417. addCollapsibleCategories() {
  418. const categories = document.querySelectorAll('.blocktable h2');
  419. categories.forEach(category => {
  420. if (category.querySelector('.fa-magnet')) return;
  421. const magnetIcon = document.createElement('i');
  422. magnetIcon.className = 'fa fa-magnet';
  423. magnetIcon.style.cssText = `
  424. margin-right: 8px;
  425. transition: transform 0.3s ease;
  426. `;
  427. const headerWrapper = document.createElement('div');
  428. headerWrapper.style.cssText = `
  429. display: flex;
  430. align-items: center;
  431. cursor: pointer;
  432. user-select: none;
  433. `;
  434. const span = category.querySelector('span');
  435. if (!span) return;
  436. const content = span.cloneNode(true);
  437. headerWrapper.appendChild(magnetIcon);
  438. headerWrapper.appendChild(content);
  439. category.innerHTML = '';
  440. category.appendChild(headerWrapper);
  441. const categoryContent = category.closest('.blocktable');
  442. const contentBox = categoryContent.querySelector('.box');
  443. headerWrapper.addEventListener('click', () => {
  444. const isCollapsed = contentBox.style.display === 'none';
  445. contentBox.style.display = isCollapsed ? '' : 'none';
  446. magnetIcon.style.transform = isCollapsed ? '' : 'rotate(180deg)';
  447. const categoryText = content.textContent.trim();
  448. GM_setValue(`category_${categoryText}_collapsed`, !isCollapsed);
  449. });
  450. const savedState = GM_getValue(`category_${content.textContent.trim()}_collapsed`, false);
  451. if (savedState) {
  452. contentBox.style.display = 'none';
  453. magnetIcon.style.transform = 'rotate(180deg)';
  454. }
  455. });
  456. }
  457.  
  458. setupPremiumUI() {
  459. if (!window.location.href.includes('profile.php') ||
  460. !window.location.href.includes('section=premium') ||
  461. document.querySelector('#gs-premium-ui')) return;
  462. const container = document.querySelector('.blockform .box');
  463. if (!container) return;
  464. // Get user ID from URL or page
  465. const userId = window.location.href.match(/id=(\d+)/) ?
  466. window.location.href.match(/id=(\d+)/)[1] :
  467. document.querySelector('#brdwelcome .conl a[href*="profile.php"]')?.href.match(/id=(\d+)/)?.[1];
  468. if (!userId) return;
  469. // Get subscription status from the existing page
  470. const existingStatus = container.querySelector('.infldset p')?.textContent || 'No active subscription';
  471. container.id = 'gs-premium-ui';
  472. container.innerHTML = `
  473. <form id="profile8" method="post" action="profile.php?section=premium&id=${userId}">
  474. <input type="hidden" name="form_sent" value="1" />
  475. <div class="inform">
  476. <fieldset>
  477. <legend>Subscription Status</legend>
  478. <div class="infldset">
  479. <div class="status-text">
  480. <i class="fa fa-clock-o"></i>
  481. <span>${existingStatus}</span>
  482. </div>
  483. <div class="button-group">
  484. <a href="payment.php?game=csgo" class="button">
  485. <i class="fa fa-refresh"></i>
  486. ${existingStatus.includes('No active') ? 'Purchase Subscription' : 'Extend Subscription'}
  487. </a>
  488. </div>
  489. </div>
  490. </fieldset>
  491. </div>
  492. <div class="inform">
  493. <fieldset>
  494. <legend>Game Clients</legend>
  495. <div class="infldset">
  496. <div class="button-group">
  497. ${existingStatus.includes('No active') ? `
  498. <button type="button" disabled class="button">
  499. <i class="fa fa-download"></i>
  500. CS2 Client
  501. </button>
  502. <button type="button" disabled class="button">
  503. <i class="fa fa-download"></i>
  504. CS:GO Client
  505. </button>
  506. ` : `
  507. <button type="submit" name="download_client" class="button">
  508. <i class="fa fa-download"></i>
  509. CS2 Client
  510. </button>
  511. <button type="submit" name="download_client_csgo" class="button">
  512. <i class="fa fa-download"></i>
  513. CS:GO Client
  514. </button>
  515. `}
  516. </div>
  517. </div>
  518. </fieldset>
  519. </div>
  520. <div class="inform">
  521. <fieldset>
  522. <legend>Discord Management</legend>
  523. <div class="infldset">
  524. <div class="input-with-button">
  525. <input id="discord_reset_reason" type="text"
  526. name="discord_reset_reason"
  527. placeholder="Enter reason for Discord ID reset"
  528. maxlength="40"
  529. ${existingStatus.includes('No active') ? 'disabled' : ''} />
  530. <button type="submit" name="reset_discord" class="button"
  531. ${existingStatus.includes('No active') ? 'disabled' : ''}>
  532. <i class="fa fa-refresh"></i>
  533. Reset
  534. </button>
  535. </div>
  536. </div>
  537. </fieldset>
  538. </div>
  539. <div class="inform">
  540. <fieldset>
  541. <legend>Invite Codes</legend>
  542. <div class="infldset">
  543. <p>You have no unused invitation codes.</p>
  544. </div>
  545. </fieldset>
  546. </div>
  547. </form>
  548. `;
  549. const form = container.querySelector('form');
  550. form.querySelectorAll(':submit').forEach(button => {
  551. button.addEventListener('click', function(e) {
  552. const discordReason = document.getElementById('discord_reset_reason');
  553. if (this.name === 'reset_discord' && discordReason.value.trim() === '') {
  554. discordReason.classList.add('contains-error');
  555. e.preventDefault();
  556. return;
  557. }
  558. this.disabled = true;
  559. const hiddenInput = document.createElement('input');
  560. hiddenInput.type = 'hidden';
  561. hiddenInput.name = this.name;
  562. hiddenInput.value = this.value;
  563. form.appendChild(hiddenInput);
  564. });
  565. });
  566. }
  567. }

QingJ © 2025

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