AIDungeon Mobile Web Optimizer

A performance script for AID, like my QoL script wihtout all the stuff you can't use on mobile

当前为 2024-05-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name AIDungeon Mobile Web Optimizer
  3. // @version 1.0.1
  4. // @description A performance script for AID, like my QoL script wihtout all the stuff you can't use on mobile
  5. // @author AliH2K
  6. // @match https://*.aidungeon.com/*
  7. // @icon https://play-lh.googleusercontent.com/ALmVcUVvR8X3q-hOUbcR7S__iicLgIWDwM9K_9PJy87JnK1XfHSi_tp1sUlJJBVsiSc
  8. // @require https://code.jquery.com/jquery-3.7.1.min.js
  9. // @require https://update.greasyfork.org/scripts/383527/701631/Wait_for_key_elements.js
  10. // @require https://update.greasyfork.org/scripts/439099/1203718/MonkeyConfig%20Modern%20Reloaded.js
  11. // @grant GM_addStyle
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_deleteValue
  15. // @grant GM_registerMenuCommand
  16. // @license MIT
  17. // @namespace https://greasyfork.org/users/1294499
  18. // ==/UserScript==
  19. /* global jQuery, $, waitForKeyElements, MonkeyConfig */
  20. const $ = jQuery.noConflict(true);
  21.  
  22. const cfg = new MonkeyConfig({
  23. title: 'Configure',
  24. menuCommand: true,
  25. params: {
  26. Response_Underline: { type: 'checkbox', default: true },
  27. Response_Bg_Color: { type: 'checkbox', default: false }
  28. }
  29. });
  30.  
  31. function handleChanges() {
  32. const targetNode = $("[role='article']")[0];
  33. let lastResponse = targetNode.lastChild.lastChild;
  34. targetNode.lastChild.children.length % 2 !== 0 && lastResponse.tagName === 'SPAN' ? (lastResponse.style.pointerEvents = 'none') : lastResponse.style.pointerEvents === 'none' ? (lastResponse.style.pointerEvents = '') : '';
  35. if (lastResponse.firstChild.nodeType !== 3 && lastResponse.tagName === 'SPAN') {
  36. const interval = setInterval(() => {
  37. const opacity = lastResponse.lastChild instanceof HTMLElement ? getComputedStyle(lastResponse.lastChild).opacity : "1";
  38. if (opacity === '1') {
  39. clearInterval(interval);
  40. const SPANS = Array.from(lastResponse.children);
  41. let joinedText = '';
  42. SPANS.forEach((span) => (joinedText += span.textContent));
  43. while (lastResponse.firstChild && lastResponse.firstChild.nodeType !== 3) lastResponse.removeChild(lastResponse.firstChild);
  44. if (joinedText.length > 1) lastResponse.textContent = joinedText;
  45. }
  46. }, 500);
  47. }
  48. }
  49.  
  50. const config = { childList: true, subtree: true };
  51. const observer = new MutationObserver(handleChanges);
  52.  
  53. waitForKeyElements("[role='article']", () => {
  54. if (window.location.href.includes('/read')) return storyGetPrep();
  55. if (!window.location.href.includes('/play')) return;
  56. const targetNode = $("[role='article']")[0];
  57. observer.observe(targetNode, config);
  58. handleChanges();
  59. const CSS = `
  60. div>span:last-child>#transition-opacity:last-child, #game-backdrop-saturate {
  61. border-bottom-color: ${cfg.get('Response_Underline') ? 'var(--color-61)' : 'unset'};
  62. border-bottom-width: ${cfg.get('Response_Underline') ? '2px' : 'unset'};
  63. border-bottom-style: ${cfg.get('Response_Underline') ? 'solid' : 'unset'};
  64. background-color: ${cfg.get('Response_Bg_Color') ? 'var(--color-60)' : 'unset'};
  65. backdrop-filter: unset;
  66. }
  67. `;
  68. GM_addStyle(CSS);
  69. });
  70.  
  71. function storyGetPrep() {
  72. const reference = [...$('[role=button]')].find((e) => e.innerText === 'Aa');
  73. function inject(label, action) {
  74. const button = reference.cloneNode(true);
  75. button.removeAttribute('aria-disabled');
  76. button.setAttribute('style', 'pointer-events: all !important;');
  77. button.querySelector('p').innerText = label;
  78. button.onclick = (e) => {
  79. e.preventDefault();
  80. e.bubbles = false;
  81. action();
  82. };
  83. reference.parentNode.prepend(button);
  84. }
  85. function onSave(type) {
  86. const story = $('[aria-label="Story"]')[0];
  87. const title = $('[role=heading]')[0]?.innerText;
  88. if (!story || !title) return alert('Wait for content to load first!');
  89. let text = story.innerText.replaceAll(/w_\w+\n+\s+/g, type === 'text' ? '' : '> ');
  90. if (type === 'md') text = '## ' + title + '\n\n' + text;
  91. text = text.replaceAll(/\n+/g, '\n\n');
  92. const blob = URL.createObjectURL(new Blob([text], { type: type === 'text' ? 'text/plain' : 'text/x-markdown' }));
  93. const a = document.createElement('a');
  94. a.download = title + (type === 'text' ? '.txt' : '.md');
  95. a.href = blob;
  96. a.click();
  97. URL.revokeObjectURL(blob);
  98. }
  99. inject('.txt', () => onSave('text'));
  100. inject('.md', () => onSave('md'));
  101. }