Dragon Tea Undo Cipher

7/2/2024, 8:37:14 PM

当前为 2025-03-24 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Dragon Tea Undo Cipher
// @namespace   https://github.com/BobbyWibowo
// @match       *://dragontea.ink/*
// @icon        https://www.google.com/s2/favicons?sz=64&domain=dragontea.ink
// @run-at      document-end
// @version     1.0.0
// @author      Bobby Wibowo
// @license     MIT
// @description 7/2/2024, 8:37:14 PM
// @noframes
// ==/UserScript==

(function () {
  'use strict'

  const _logTime = () => {
    return new Date().toLocaleTimeString([], {
        hourCycle: 'h12',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        fractionalSecondDigits: 3
      })
      .replaceAll('.', ':')
      .replace(',', '.')
      .toLocaleUpperCase();
  };

  const log = (message, ...args) => {
    const prefix = `[${_logTime()}]: `;
    if (typeof message === 'string') {
      return console.log(prefix + message, ...args);
    } else {
      return console.log(prefix, message, ...args);
    }
  };

  /** CONFIG **/

  const SELECTORS_ARTICLE = '.chapter-type-text .reading-content .text-left';

  /** UTILS **/

  class FunctionQueue {
    constructor() {
      this.queue = [];
      this.running = false;
    }

    async go() {
      if (this.queue.length) {
        this.running = true;
        const _func = this.queue.shift();
        await _func[0](..._func[1]);
        this.go();
      } else {
        this.running = false;
      }
    }

    add(func, ...args) {
      this.queue.push([func, [...args]]);

      if (!this.running) {
        this.go();
      }
    }

    clear() {
      this.queue.length = 0;
    }
  };

  const observerFactory = option => {
    let options;
    if (typeof option === 'function') {
      options = {
        callback: option,
        node: document.getElementsByTagName('body')[0],
        option: { childList: true, subtree: true }
      };
    } else {
      options = $.extend({
        callback: () => {},
        node: document.getElementsByTagName('body')[0],
        option: { childList: true, subtree: true }
      }, option);
    }
    const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

    const observer = new MutationObserver((mutations, observer) => {
      options.callback.call(this, mutations, observer);
    });

    observer.observe(options.node, options.option);
    return observer;
  };

  const enAtbash = string => {
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const tebahpla = 'ZYXWVUTSRQPONMLKJIHGFEDCBA';
    const alphabetLower = 'abcdefghijklmnopqrstuvwxyz';
    const tebahplaLower = 'zyxwvutsrqponmlkjihgfedcba';

    let decodedString = '';
    for (let i = 0; i < string.length; i++) {
      const codedLetter = string.charAt(i);

	    if (/[^a-zA-Z]/.test(string[i])) {
		    decodedString += string[i];
	    } else if (string[i] === string[i].toUpperCase()) {
	    	const letterIndex = alphabet.indexOf(codedLetter);
	    	const tebalphaLetter = tebahpla.charAt(letterIndex);
	    	decodedString += tebalphaLetter;
      } else {
	    	const letterIndex = alphabetLower.indexOf(codedLetter);
	    	const tebalphaLetter = tebahplaLower.charAt(letterIndex);
	    	decodedString += tebalphaLetter;
      }
    }
    return decodedString;
  }

  const doArticle = element => {
    if (element.dataset.cipherUndone) {
      return false;
    }

    // Mark as processed.
    element.dataset.cipherUndone = true;

    element.innerText = enAtbash(element.innerText);

    return true;
  };

  const triggerQueue = new FunctionQueue();

  observerFactory((...args) => {
    triggerQueue.add((mutations, observer) => {
      for (let i = 0, len = mutations.length; i < len; i++) {
        const mutation = mutations[i];

        // Whether to change nodes.
        if (mutation.type !== 'childList') {
          continue;
        }

        let _article = 0;

        if (mutation.target.matches(SELECTORS_ARTICLE)) {
          if (doArticle(mutation.target)) {
            _article++;
          }
        } else {
          const articles = mutation.target.querySelectorAll(SELECTORS_ARTICLE);
          for (const article of articles) {
            if (doArticle(article)) {
              _article++;
            }
          }
        }

        if (_article > 0) {
          log(`Undone cipher on ${_article} article(s).`);
        }
      }
    }, ...args);
  });

  log('MutationObserver initiated.');
})();