// ==UserScript==
// @name 🐱 全世界都要变成可爱猫猫!
// @version 3.3.4
// @description 让整个网络世界都变成超可爱的猫娘语调喵
// @author 超萌猫娘开发队
// @description:zh-CN 这个插件是让不好听的话便的好听!还有,猫猫是超高性能的 Super AI !所以呢...... 遇到问题给我提示词好喵?
// @match *://*/*
// @include *://*.bilibili.com/video/*
// @include *://*.bilibili.com/anime/*
// @include *://*.bilibili.com/bangumi/play/*
// @exclude *://gf.qytechs.cn/*
// @exclude *://*.gov/*
// @exclude *://*.edu/*
// @grant none
// @license MIT
// @namespace https://gf.qytechs.cn/users/1503554
// ==/UserScript==
const affectInput = false;
(function() {
'use strict';
// ===== 性能优化配置 =====
const CONFIG = {
bilibiliMergeALinks: true,
bilibiliRandomizeUserNames: true,
processInterval: 2500,
excludeDomains: ['github.com', 'stackoverflow.com', 'google.com', 'gov.cn', 'edu.cn', 'gf.qytechs.cn'],
// 性能相关配置
maxProcessingTimeSlice: 16, // 每次处理最大时间片(毫秒)
batchSize: 10, // 减小批处理大小,更频繁让出控制权
observerThrottle: 300, // MutationObserver节流时间
};
const isBilibili = location.hostname.includes('bilibili.com');
// ===== 可爱元素库 =====
const cuteEndings = ['喵~', 'にゃん♪', '喵呜', 'nya~', '喵喵', 'にゃ♡', 'mew~', '喵♪', 'nyaa', '喵desu', '喵呢', '喵哈'];
// 软糯可爱的替换词库
const cleanups = [
// --------- 极端攻击与侮辱性词汇 ---------
[/操你妈|操你娘|操你全家|肏你妈|干你妈|干你娘|去你妈的|去你娘的|去你全家/gi, '去睡觉喵~'],
[/妈了个?逼|妈的?智障|妈的/gi, '喵喵~'],
[/狗娘养的|狗杂种|狗东西|狗逼/gi, '不太好的小喵~'],
[/操你大爷|去你大爷的/gi, '去玩耍啦喵~'],
[/去你老师的|你全家死光/gi, '嗯...安静一点喵'],
[/你妈死了|你妈没了/gi, '你妈妈叫你回家吃饭喵~'],
// --------- 性相关及不雅词汇 ---------
[/鸡巴|鸡叭|鸡把|\bjb\b|\bJB\b/gi, '小鱼干喵~'],
[/逼你|逼样|逼毛|逼崽子|什么逼/gi, '小淘气喵'],
[/肏|干你|草你|cao你|cao你妈/gi, '去玩耍啦喵~'],
[/c[a@4]o|g[a@4]n/gi, '去玩耍啦喵~'],
[/j[i1!]\s*b[a@4]?/gi, '小鱼干喵~'],
// --------- 常见人身攻击与负面评价 ---------
[/你妹|你妹的|去你妹/gi, '小迷糊喵'],
[/滚犊子|滚蛋|滚开|滚开你/gi, '去玩耍啦喵~'],
[/去死|死全家|死开|狗带/gi, '去睡觉觉'],
[/人渣|渣人|渣男|渣女/gi, '要抱抱的小喵~'],
[/废物|废柴|废狗/gi, '要抱抱的小喵~'],
[/垃圾人|辣鸡|拉圾/gi, '不太好的小喵~'],
[/王八蛋|王八羔子/gi, '坏坏的小喵'],
[/丑八怪|丑陋|矮冬瓜/gi, '外表也很可爱喵~'],
[/心机[婊表]/gi, '聪明的小家伙'],
// --------- 智力与能力相关的攻击性词语 ---------
[/傻逼|煞笔|沙雕|傻叉|笨蛋|二货|二逼/gi, '小糊涂喵'],
[/白痴|智障|弱智|脑残|脑袋进水/gi, '小呆呆喵'],
[/蠢货|蠢蛋/gi, '有点迷糊喵'],
[/傻[逼比屄]|煞[笔b]/gi, '小糊涂虫'],
[/脑[残残蛋]/gi, '小呆呆喵'],
// --------- 拼音缩写与网络黑话 ---------
[/\bcnm\b|\bCNM\b|c\s*n\s*m/gi, '你好软糯喵~'],
[/\bnmsl\b|\bNMSL\b/gi, '你超棒棒喵~'],
[/\bnmb\b|\bNMB\b/gi, '你好有趣喵~'],
[/\bmlgb\b|\bMLGB\b/gi, '哇好厉害喵~'],
[/\bwqnmd\b|\bWQNMD\b/gi, '我觉得你超棒喵~'],
[/\b(qm?nd?m?d?|qnmd)\b/gi, '去学习喵~'],
[/tmd|TMD/gi, '太萌啦喵~'],
[/wtf|WTF/gi, '哇好神奇喵~'],
[/\bwc\b|WC(?!厕所)/gi, '哇塞呀喵~'],
[/\bsb\b|\bSB\b/gi, '小宝贝喵~'],
[/nsdd/gi, '你说的对喵~'],
[/u1s1/gi, '有一说一喵~'],
// ========= “阴阳怪气”与嘲讽专用 (新增) =========
[/不会吧不会吧|不会吧/gi, '喵喵惊讶~'],
[/就这\?|就这?/gi, '就这个喵?'],
[/他急了|你急了|别急/gi, '顺顺毛,不着急喵~'],
[/典中典|太典了|典/gi, '是好有趣的故事喵~'],
[/孝死|孝子|太孝了/gi, '是热心的好孩子喵~'],
[/差不多得了|彳亍口巴/gi, '好啦好啦喵~'],
[/你说的都对|啊对对对/gi, '嗯嗯,你说的对喵~'],
[/我不好说|我不好说我劝你别说/gi, '喵~让我想想~'],
[/不然呢|要不然呢/gi, '就是这样喵~'],
[/您吉祥/gi, '给你请安喵~'],
[/味儿太冲了|味太冲/gi, '味道很特别喵~'],
[/呃呃/gi, '喵喵喵?'],
// ========= 网络流行语与社区用语 (扩充) =========
[/喷子|喷子们/gi, '有想法的小喵'],
[/键盘侠|键盘战士/gi, '网络小达人喵'],
[/杠精|杠精们/gi, '爱讨论的小喵'],
[/舔狗/gi, '忠实的小喵'],
[/卫兵|小丑|水军|海军|节奏/gi, '热心的小喵~'],
[/笑死我了|笑死|xswl|XSWL/gi, '好有趣喵~'],
[/难绷|难蚌|难崩/gi, '有点害羞喵~'],
[/抽象|纯抽象|太抽象了/gi, '很有想象力喵~'],
[/\bemo\b|EMO/gi, '有小情绪喵~'],
[/ptsd|PTSD/gi, '印象很深喵~'],
[/绝绝子/gi, '超级棒棒喵~'],
[/咱就是说/gi, '人家觉得喵~'],
[/栓q|拴q/gi, '谢谢呀喵~'],
[/6到飞起|666/gi, '超级厉害喵~'],
[/芭比q了/gi, '糟糕啦喵~'],
[/yyds|YYDS/gi, '最棒棒喵~'],
[/up主废了|up废了/gi, 'up主好有趣喵~'],
[/这up不行/gi, '这up很特别喵~'],
[/破防了/gi, '心弦被拨动了喵~'],
[/下头|真下头/gi, '有点点上头喵~'],
[/老六/gi, '爱捉迷藏的小喵~'],
[/要确欸/gi, '要确定一下喵?'],
[/尊嘟假嘟/gi, '真的喵还是假的喵?'],
[/硬控/gi, '被吸引住了喵~'],
// ========= 行为与状态描述词 =========
[/白嫖|白摸|白吃/gi, '免费享受喵~'],
[/爆肝|肝帝/gi, '很努力喵~'],
[/摆烂|躺平/gi, '想要休息喵~'],
// ========= 新增与优化 (合并至以上分类) =========
[/我靠|我擦|我操|卧槽/gi, '哇哦喵~'],
[/nt|脑瘫/gi, '小迷糊喵~'],
[/kys|KYS/gi, '要开心喵~'],
[/小黑子|ikun/gi, '淘气的粉丝喵~'],
[/你是懂xx的/gi, '你是懂喵喵的~'],
[/离谱/gi, '好有想象力喵~'],
[/awsl|阿伟死了/gi, '好可爱喵~'],
[/泰裤辣/gi, '太酷了喵~'],
[/豪庭/gi,'咱喵的耳朵要坏掉惹!'],
];
// ===== 性能优化工具 =====
// WeakSet缓存已处理的元素,避免重复处理
const processedElements = new WeakSet();
// 防抖函数
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
// 节流函数
const throttle = (func, limit) => {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
};
// ===== 页面状态管理(修复版) =====
let currentPageUrl = location.href;
let bilibiliProcessingState = {
isCompleted: false,
lastProcessedUrl: '',
lastProcessedTime: 0
};
// 检测页面是否切换(修复版 - 不会误触发)
const checkPageChange = () => {
const newUrl = location.href;
if (newUrl !== currentPageUrl) {
console.log('🔄 检测到页面切换:', currentPageUrl, '->', newUrl);
// 更新状态
currentPageUrl = newUrl;
bilibiliProcessingState.isCompleted = false;
bilibiliProcessingState.lastProcessedUrl = newUrl;
return true;
}
return false;
};
// ===== 核心处理函数 =====
// 检测已处理
const isProcessed = str => /喵[~~呜哈呢♪♡]|nya|にゃん|meow|🏳️⚧️/i.test(str);
// 文本替换器
const replacer = str => {
if (!str?.trim() || isProcessed(str)) return str;
let result = str;
// 脏词净化
cleanups.forEach(([regex, replacement]) => {
result = result.replace(regex, replacement);
});
// 添加可爱尾缀
const getCuteEnding = () => cuteEndings[Math.floor(Math.random() * cuteEndings.length)];
const addDesu = () => Math.random() < 0.2 ? 'です' : '';
return result
.replace(/([也矣兮乎者焉哉]|[啊吗呢吧哇呀哦嘛喔咯呜捏])([\s\p{P}]|$)/gu,
(_, $1, $2) => `${getCuteEnding()}${addDesu()}${$2}`)
.replace(/([的了辣])([\s\p{P}]|$)/gu,
(_, $1, $2) => Math.random() < 0.3 ? `${$1}${getCuteEnding()}${addDesu()}${$2}` : `${$1}${$2}`);
};
// ===== 递归查找Shadow DOM中的元素 =====
const findInShadowDOM = (element, selector) => {
const results = [];
// 在当前元素中查找
if (element.querySelectorAll) {
results.push(...element.querySelectorAll(selector));
}
// 递归查找所有子元素的shadowRoot
if (element.querySelectorAll) {
const allElements = element.querySelectorAll('*');
allElements.forEach(el => {
if (el.shadowRoot) {
results.push(...findInShadowDOM(el.shadowRoot, selector));
}
});
}
return results;
};
// ===== B站Shadow DOM处理(智能暂停修复版) =====
const processBilibiliShadowDOM = () => {
if (!isBilibili) {
return;
}
// 先检查页面是否切换
const pageChanged = checkPageChange();
// 检查是否已经完成处理且页面未切换
if (!pageChanged && bilibiliProcessingState.isCompleted) {
// 可以选择性地添加一个时间限制,比如超过几分钟后可以重新检查一次
if ((Date.now() - bilibiliProcessingState.lastProcessedTime) < 60000) { // 1分钟内绝对不重复处理
// console.log('⏸️ B站处理智能暂停中,跳过本次执行'); // 可以取消这个日志避免刷屏
return;
}
}
//if (!pageChanged &&
// bilibiliProcessingState.isCompleted &&
// bilibiliProcessingState.lastProcessedUrl === location.href &&
// (Date.now() - bilibiliProcessingState.lastProcessedTime) < 60000) { // 1分钟内不重复处理
// console.log('⏸️ B站评论已完成处理且页面未切换,跳过重复处理');
// return;
//}
if (pageChanged) {
console.log('🔄 页面已切换,重新开始B站处理');
}
//console.log('🎯 开始processBilibiliShadowDOM函数');
// 使用RequestIdleCallback避免阻塞主线程,但提供fallback
const processInIdle = (callback) => {
if (window.requestIdleCallback) {
requestIdleCallback(callback, { timeout: 1000 });
} else {
setTimeout(callback, 0);
}
};
processInIdle(() => {
try {
// 第一步:找到B站评论的Shadow DOM根
//console.log('🔍 步骤1: 查找bili-comments元素...');
const biliComments = document.querySelector('bili-comments');
if (!biliComments) {
//console.log('❌ 未找到bili-comments元素');
return;
}
if (!biliComments.shadowRoot) {
//console.log('❌ bili-comments没有shadowRoot');
return;
}
// 第二步:查找contents
const contents = biliComments.shadowRoot.querySelector('#contents');
if (!contents) {
//console.log('❌ 在shadowRoot中未找到#contents');
return;
}
// 第三步:查找feed
const feed = contents.querySelector('#feed');
if (!feed) {
//console.log('❌ 在#contents中未找到#feed');
return;
}
// 第四步:查找评论线程
const commentThreads = feed.querySelectorAll('bili-comment-thread-renderer');
//console.log(`找到 ${commentThreads.length} 个bili-comment-thread-renderer元素`);
if (commentThreads.length === 0) {
// console.log('❌ 未找到any bili-comment-thread-renderer');
return;
}
// 第五步:批量处理评论线程,使用时间分片避免阻塞
let processedCount = 0;
const processNextBatch = () => {
const startTime = performance.now();
let currentBatchCount = 0;
// 在时间片内处理尽可能多的评论
while (processedCount < commentThreads.length &&
currentBatchCount < CONFIG.batchSize &&
(performance.now() - startTime) < CONFIG.maxProcessingTimeSlice) {
const thread = commentThreads[processedCount];
// 跳过已处理的线程
if (processedElements.has(thread)) {
processedCount++;
continue;
}
if (!thread.shadowRoot) {
processedCount++;
continue;
}
// 处理用户名 (递归查找)
const userNameElements = findInShadowDOM(thread.shadowRoot, '#user-name a');
userNameElements.forEach((nameEl) => {
const userName = nameEl.textContent?.trim();
if (userName && !userName.includes('🏳️⚧️')) {
nameEl.textContent = `🏳️⚧️${userName}🏳️⚧️`;
}
});
// 处理顶置状态 (递归查找)
const topElements = findInShadowDOM(thread.shadowRoot, '#top');
topElements.forEach((topEl) => {
const topText = topEl.textContent?.trim();
if (topText && !topText.includes('喵')) {
topEl.textContent = '喵呜';
}
});
// 处理评论内容 (递归查找)
const contentElements = findInShadowDOM(thread.shadowRoot, '#contents span');
contentElements.forEach((contentEl) => {
// 处理a标签 - 将链接转为普通文字
const links = contentEl.querySelectorAll('a');
links.forEach((link) => {
const linkText = link.textContent?.trim();
if (linkText) {
const textNode = document.createTextNode(linkText);
link.parentNode.replaceChild(textNode, link);
}
});
// 应用屏蔽词替换和猫娘化
const originalText = contentEl.textContent?.trim();
if (originalText && !isProcessed(originalText)) {
const newText = replacer(originalText);
if (newText !== originalText) {
contentEl.textContent = newText;
}
}
});
processedElements.add(thread);
processedCount++;
currentBatchCount++;
}
// 如果还有未处理的评论,继续下一批
if (processedCount < commentThreads.length) {
setTimeout(processNextBatch, 0); // 让出主线程控制权
} else {
console.log('🎉 所有B站评论线程处理完成');
// 标记处理完成状态
bilibiliProcessingState.isCompleted = true;
bilibiliProcessingState.lastProcessedUrl = location.href;
bilibiliProcessingState.lastProcessedTime = Date.now();
console.log('⏸️ B站处理进入暂停状态,等待页面切换或新内容加载');
}
};
// 开始处理
processNextBatch();
} catch (error) {
console.error('🐱 B站Shadow DOM处理出错:', error);
}
});
};
// ===== 通用元素处理(优化但保持功能完整) =====
const processElements = (root) => {
if (!root) return;
// 使用requestIdleCallback避免阻塞,但保持同步fallback
const processInIdle = (callback) => {
if (window.requestIdleCallback) {
requestIdleCallback(callback, { timeout: 1000 });
} else {
setTimeout(callback, 0);
}
};
processInIdle(() => {
const elements = ['title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'article', 'section', 'blockquote', 'li', 'a', 'span', 'div']
.concat(affectInput ? ['input'] : []);
const allElements = root.querySelectorAll(elements.join(','));
let processedCount = 0;
const processNextBatch = () => {
const startTime = performance.now();
let currentBatchCount = 0;
while (processedCount < allElements.length &&
currentBatchCount < CONFIG.batchSize &&
(performance.now() - startTime) < CONFIG.maxProcessingTimeSlice) {
const el = allElements[processedCount];
// 跳过已处理的元素
if (processedElements.has(el)) {
processedCount++;
continue;
}
try {
if (el.nodeName === 'INPUT') {
if (el.value?.trim()) {
el.value = replacer(el.value);
}
} else if (el.textContent === el.innerHTML.trim()) {
const newText = replacer(el.textContent);
if (newText !== el.textContent) {
el.textContent = newText;
}
} else {
el.childNodes.forEach(node => {
if (node.nodeType === Node.TEXT_NODE && node.textContent?.trim()) {
const newText = replacer(node.textContent);
if (newText !== node.textContent) {
node.textContent = newText;
}
}
});
}
processedElements.add(el);
} catch (error) {
console.error('🐱 元素处理出错:', error);
}
processedCount++;
currentBatchCount++;
}
// 如果还有未处理的元素,继续下一批
if (processedCount < allElements.length) {
setTimeout(processNextBatch, 0);
}
};
processNextBatch();
});
};
// ===== 智能MutationObserver =====
const createSmartObserver = () => {
const throttledProcess = throttle((mutations) => {
const elementsToProcess = new Set();
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
elementsToProcess.add(node);
// B站特殊处理 - 检测到新评论元素时重置状态
if (isBilibili && (
node.tagName === 'BILI-COMMENTS' ||
node.tagName === 'BILI-COMMENT-THREAD-RENDERER' ||
(node.querySelector && node.querySelector('bili-comments, bili-comment-thread-renderer'))
)) {
console.log('🆕 检测到新的B站评论元素,重置处理状态');
bilibiliProcessingState.isCompleted = false;
setTimeout(() => processBilibiliShadowDOM(), 1000);
}
}
});
}
});
// 处理新增元素
elementsToProcess.forEach(element => {
processElements(element);
});
}, CONFIG.observerThrottle);
const observer = new MutationObserver(throttledProcess);
return observer;
};
// ===== 主启动函数 =====
const initializeApp = async () => {
// 域名排除检查
if (CONFIG.excludeDomains.some(d => location.hostname.includes(d))) {
console.log('🐱 域名已排除,不启动喵~');
return;
}
console.log('🐱 猫娘化系统启动喵~');
// 等待DOM就绪
const waitForReady = () => {
return new Promise(resolve => {
if (document.readyState !== 'loading') {
resolve();
} else {
document.addEventListener('DOMContentLoaded', resolve, { once: true });
}
});
};
await waitForReady();
// 初始处理
console.log('🔄 开始初始处理...');
processElements(document);
// B站特殊处理
if (isBilibili) {
console.log('🎯 初始化B站处理器...');
// 立即尝试处理
processBilibiliShadowDOM();
// 智能重试机制
const retryBilibili = (attempts = 0) => {
if (attempts > 15) {
console.log('❌ B站评论重试次数已达上限');
return;
}
setTimeout(() => {
const hasComments = document.querySelector('bili-comments');
if (hasComments && hasComments.shadowRoot) {
console.log(`✅ 第${attempts + 1}次重试成功找到B站评论容器`);
processBilibiliShadowDOM();
} else {
retryBilibili(attempts + 1);
}
}, Math.min(500 + attempts * 200, 2000));
};
retryBilibili();
}
// 设置定期处理 - 智能跳过已完成的B站处理
const intervalProcess = () => {
//console.log('⏰ 定期处理触发');
// 通用元素处理(始终执行)
//processElements(document);
// B站处理(智能控制)
if (isBilibili) {
processBilibiliShadowDOM(); // 内部会检查是否需要跳过
}
};
setInterval(intervalProcess, CONFIG.processInterval);
// 设置DOM监听
const observer = createSmartObserver();
observer.observe(document.body, {
childList: true,
subtree: true
});
// B站滚动优化
if (isBilibili) {
const debouncedScroll = debounce(() => {
processBilibiliShadowDOM(); // 内部会检查是否需要跳过
}, 800);
addEventListener('scroll', debouncedScroll, { passive: true });
}
console.log('🎀 世界变可爱了喵~智能暂停版启动完成!');
};
// ===== 启动应用 =====
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeApp, { once: true });
} else {
setTimeout(initializeApp, 0);
}
// ===== 调试接口 =====
(typeof unsafeWindow !== 'undefined' ? unsafeWindow : window).catgirlApp = {
replacer,
processElements,
processBilibiliShadowDOM,
findInShadowDOM,
config: CONFIG,
pageState: {
currentUrl: () => currentPageUrl,
bilibiliState: () => bilibiliProcessingState,
forceReset: () => {
bilibiliProcessingState.isCompleted = false;
bilibiliProcessingState.lastProcessedUrl = '';
console.log('🔄 强制重置B站处理状态');
}
},
performance: {
clearCache: () => {
processedElements.clear();
console.log('🧹 缓存已清理');
}
}
};
})();