owowify website

owowify website evewywhewe! >w<

当前为 2024-01-28 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        owowify website
// @description owowify website evewywhewe! >w<
// @author      owowed
// @version     0.0.2
// @namespace   fun.owowed.moe
// @license     GPL-3.0-or-later
// @match       *://*/*
// @grant       none
// @run-at      document-end
// @copyright   All rights reserved. Licensed under GPL-3.0-or-later. View license at https://spdx.org/licenses/GPL-3.0-or-later.html
// ==/UserScript==

/**
 * [author note]
 * 
 * honestly, i dont know what the fuck is going on here
 * 
 * this is one of my old personal userscript collection
 * 
 * i made this back when i began learning javascript and
 * userscript stuff, and also when i dont know any better
 * and start writing random stuff, like this
 * 
 * so yeah, expect some really bad poopy programmer code here
 * 
 * anyway, this userscript uses subtree mutation observer,
 * sooo that may degrade your browsing performance, beware
 * 
 * also, good luck when you want to fork it lol
 * 
 * ps: maybe sooner or later, ill clean this stuff up,
 * and rework some of the bits and stuff later
 * 
 * ~~ owowed
 */

/**
 * wincesed undew GNYU! GPL, vewsion 3.0 -w-
 */

const textNodeParentElementBlacklistSelector = "style, script, svg, noscript, iframe, object, code, pre, input";

let lastWindowHref = window.location.href;
let idleTimeout = 0;
{
    initObserver(document.body, {childList: true, subtree: true});

    owowifyElement(document.body);
    
    setInterval(() => {
        if (idleTimeout > 15) {
            if (lastWindowHref != window.location.href) {
                idleTimeout = 0;
                lastWindowHref = window.location.href;
            }
            else {
                return;
            }
        }
        
        owowifyElement(document.body);

        idleTimeout++;
    }, 1000);
    
    document.title = owowify(document.title);
}

function initObserver(node, options = {}) {
    const observer = new MutationObserver(records => {
        for (const mut of records) {
            if (mut.addedNodes.length > 0) {
                for (const nd of mut.addedNodes) {
                    owowifyElement(nd);
                    idleTimeout = 12;
                }
            }
        }
    });

    observer.observe(node, {...options});
}

/** @param {Element} element */
function owowifyElement(element) {
    if (element.nodeType != Node.ELEMENT_NODE) return;

    const currentElementValid =
        (isElementValid(element) && isElementValid(element.parentElement))
        || (element instanceof HTMLAnchorElement && !element.textContent.includes(element.href));
    if (!currentElementValid) {
        element.noOwowify = true;
    }

    if (element.hasAttribute("title")) {
        element.setAttribute("title", owowify(element.getAttribute("title")));
    }

    for (const nd of element.childNodes) {
        if (nd.nodeType == Node.ELEMENT_NODE) {
            owowifyElement(nd);
        }
        if (nd.nodeType == Node.TEXT_NODE && currentElementValid) {
            owowifyNode(nd);
        }
    }

    if (element instanceof HTMLInputElement) {
        if (element.readOnly && !["password", "url", "hidden"].includes(element.type)) {
            element.value = owowify(element.value);
            element.placeholder = owowify(element.placeholder);
        }
    }
}

/** @param {Node} node */
function owowifyNode(node) {
    if (node.nodeType == Node.TEXT_NODE) {
        node.nodeValue = owowify(node.nodeValue);
    }
}

function isElementValid(element) {
    if (element == null) return null;
    return !(element.matches(textNodeParentElementBlacklistSelector)
        || element.noOwowify
        || element.classList?.contains?.("-owo-no-owowify")
        || element.isContentEditable);
}

/**
 * 
 * @param {String} textstr 
 * @param {OwowifyOptions} options 
 * @returns {String}
 */
function owowify(textstr, options) {
    const endSentencePattern = String.raw`([\w ,.!?]+)?`; // endSentencePattern
    const endSentencePattern1 = String.raw`([\w ,.?]+)?`; // endSentencePattern without "!" sign
    const endSentencePattern2 = String.raw`([\w ,.]+)?`; // endSentencePattern without "!" and "?" sign
    const vowel = "[aiueo]";
    const vowelNoE = "[aiuo]"; // vowel without e
    const vowelNoIE = "[auo]"; // vowel without i and e
    const zackqyWord = "[jzckq]";

    let result = Array.isArray(textstr) ? textstr.join(" ") : textstr;

    // OWO EMOTE
    // result = subOwoEmote(result, reg`/(stop\!+)${endSentencePattern1}/gi`, " -M-");
    result = subOwoEmote(result, reg`/(i(?:'|)m(?:\s+|\s+so+\s+)bored)${endSentencePattern}/gi`, " -w-")
    result = subOwoEmote(result, reg`/(love\s+(?:you|him|her|them))${endSentencePattern}/gi`, " uwu");
    result = subOwoEmote(result, reg`/(i\s+don(?:'|)t\s+care|i\s*d\s*c)${endSentencePattern}/gi`, " 0w0");
    // result = subOwoEmote(result, reg`/(i(?:'|)m\s+scared)${endSentencePattern}/gi`, " ;w;");

    // WORD REPLACEMENT
    result = result.replace(reg`/l${vowel}ve?/gi`, g0 => subSameCase(g0, "luv"));
    
    // MAIN TRANSLATION
    result = result.replace(/r/gi, g0 => subSameCase(g0, "w"));
    // result = result.replace(reg`/(?<=(?<!w)(?<!${vowel}+)${vowel}+)l(?!l+\s+|l+$)|l(?=${vowel}+(?!${vowel}+)(?!w))/gi`, g0 => subSameCase(g0, "w")); // nope
    result = result.replace(reg`/(?<=(?<!w${vowel}+)${vowel}+)l(?!l+)/gi`, g0 => subSameCase(g0, "w"));
    result = result.replace(reg`/n(${vowelNoE}+)/gi`, (g0, g1) => subSameCase(g0 + g1, `ny${g1}`));
    result = result.replace(reg`/m(${vowelNoIE}+)(?!w*${zackqyWord})/gi`, (g0, g1) => subSameCase(g0 + g1, `my${g1}`));
    result = result.replace(reg`/p(${vowelNoIE}+)(?!w*${zackqyWord})/gi`, (g0, g1) => subSameCase(g0 + g1, `pw${g1}`));

    return result;
}

/**
 * @param {string} all 
 * @param {RegExp} pattern 
 * @param {string} emote 
 */
function subOwoEmote(all, pattern, emote) {
    const matchEndSpace = /^\s+$/g;
    return all.replace(pattern, (gp0, gp1, gp2) => {
        return gp2 == undefined || matchEndSpace.test(gp2)
            ? gp1 + emote
            : gp0;
    });
}

/** 
 * @param {string} strA
 * @param {string} strB
 */
function subSameCase(strA, strB) {
    let result = "";

    for (let i = 0; i < strB.length; i++) {
        if (strA[i] != undefined && strB[i] != undefined) {
            if (strA[i].toUpperCase() == strA[i]) {
                result += strB[i].toUpperCase();
            }
            else if (strA[i].toLowerCase() == strA[i]) {
                result += strB[i].toLowerCase();
            }
            else {
                result += strB[i];
            }
        }
        else {
            result += strB[i];
        }
    }

    return result;
}

/** @param {[string[], ...any[]]} templateArgs */
function reg(...templateArgs) {
    const rawString = String.raw(...templateArgs);
    const pattern = rawString.substring(1, rawString.lastIndexOf("/"));
    const flags = rawString.substring(rawString.lastIndexOf("/")+1, rawString.length);

    return new RegExp(pattern, flags);
}

// mdn docs
/** @param {string} str */
function regexEscape(str) {
    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}