您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
枝网查重 bilibili 版
当前为
// ==UserScript== // @name bilibili asoulcnki // @namespace https://github.com/sparanoid // @version 0.1.2 // @description 枝网查重 bilibili 版 // @author Sparanoid // @match https://*.bilibili.com/* // @icon https://external-content.duckduckgo.com/ip3/www.bilibili.com.ico // @grant none // @run-at document-start // ==/UserScript== window.addEventListener('load', () => { console.log('bilibili asoulcnki loaded'); const apiBase = 'https://asoulcnki.asia'; const feedbackUrl = 'https://t.bilibili.com/545085157213602473'; async function fetchResult(url = '', data = {}) { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response.json(); } function formatDate(timestamp) { let date = timestamp.toString().length === 10 ? new Date(+timestamp * 1000) : new Date(+timestamp); return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; } function rateColor(percent) { return `hsl(${100 - percent}, 70%, 50%)`; } function attachEl(item) { let injectWrap = item.querySelector('.con .info'); // .text - comment content // .text-con - reply content let content = item.querySelector('.con .text') || item.querySelector('.reply-con .text-con'); let id = item.dataset.id; // simple way to attach element on replies initially loaded with comment // which wouldn't trigger mutation inside observeComments let replies = item.querySelectorAll('.con .reply-box .reply-item'); if (replies.length > 0) { [...replies].map(reply => { attachEl(reply); }); } if (injectWrap.querySelector('.asoulcnki')) { console.log('asoulcnki already loaded for this comment'); } else { // Insert asoulcnki check button let asoulcnkiEl = document.createElement('span'); asoulcnkiEl.classList.add('asoulcnki', 'btn-hover', 'btn-highlight'); asoulcnkiEl.innerHTML = '狠狠的查'; asoulcnkiEl.addEventListener('click', e => { // Need regex to stripe `回复 @username :` let contentProcessed = content.innerText.replace(/回复 @.*:/, ''); console.log('content processed', contentProcessed); fetchResult(`${apiBase}/v1/api/check`, { text: contentProcessed }) .then(data => { console.log(data); let resultContent = ''; if (data.code !== 0) { resultContent = `返回结果错误,可能是文本内容过短,或请访问 <a href="${apiBase}/" target="_blank">枝网</a> 查看服务是否正常`; } else { let result = data.data; let startTime = result.start_time; let endTime = result.end_time; let rate = result.rate * 100; let relatedItems = result.related; if (relatedItems.length === 0) { resultContent = `<a href="${apiBase}" target="_blank">枝网</a>文本复制检测报告(Chrome 脚本版/<a href="${feedbackUrl}" target="_blank">反馈</a>) 查重时间:${formatDate(Date.now())} 数据范围:${formatDate(startTime)} - ${formatDate(endTime)} 总文字复制比:<b style="color: ${rateColor(rate)}">${rate}%</b> 结果:一眼原创,再偷必究(查重结果仅作娱乐参考)`; } else { let fisrtRelatedItem = relatedItems[0]; console.log('rpid', fisrtRelatedItem[1].rpid); console.log('id', id); let selfOriginal = +fisrtRelatedItem[1].rpid === +id ? `(<span style="color: blue;">本文原创,已收录</span>)` : ''; resultContent = `<a href="${apiBase}" target="_blank">枝网</a>文本复制检测报告(Chrome 脚本版/<a href="${feedbackUrl}" target="_blank">反馈</a>) 查重时间:${formatDate(Date.now())} 数据范围:${formatDate(startTime)} - ${formatDate(endTime)} 总文字复制比:<b style="color: ${rateColor(rate)}">${rate}%</b> 重复次数:${relatedItems.length}${selfOriginal} 相似小作文:<a href="${fisrtRelatedItem[2].trim()}" title="${fisrtRelatedItem[1].content}" target="_blank">${fisrtRelatedItem[2].trim()}</a> 作者:${fisrtRelatedItem[1].m_name}(UID <a href="https://space.bilibili.com/${fisrtRelatedItem[1].mid}" target="_blank">${fisrtRelatedItem[1].mid}</a>) 发表时间:${formatDate(fisrtRelatedItem[1].ctime)} 查重结果仅作娱乐参考,请注意辨别是否为原创`; } } // Insert result let resultWrap = document.createElement('div'); resultWrap.style.padding = '.5rem'; resultWrap.style.margin = '.5rem 0'; resultWrap.style.background = 'hsla(0, 0%, 50%, .1)'; resultWrap.style.borderRadius = '4px'; resultWrap.style.whiteSpace = 'pre'; resultWrap.innerHTML = resultContent; injectWrap.append(resultWrap); }); }, false); injectWrap.append(asoulcnkiEl); // Insert comment ID link let idLink = document.createElement('a'); idLink.innerHTML = '#'; idLink.setAttribute('title', '当前评论 ID: ' + id); idLink.setAttribute('href', '#reply' + id); idLink.style.marginRight = '.25em'; injectWrap.prepend(idLink); } } function observeComments(wrapper) { // .comment-list - general list for video, zhuanlan, and dongtai // .reply-box - replies attached to specific comment let commentLists = wrapper ? wrapper.querySelectorAll('.comment-list, .reply-box') : document.querySelectorAll('.comment-list, .reply-box'); if (commentLists) { [...commentLists].map(commentList => { // Directly attach elements for pure static server side rendered comments // and replies list. Used by zhuanlan posts with reply hash in URL. // TODO: need a better solution //[...commentList.querySelectorAll('.list-item, .reply-item')].map(item => { // attachEl(item); //}); const observer = new MutationObserver((mutationsList, observer) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { console.log('observed mutations', [...mutation.addedNodes].length); [...mutation.addedNodes].map(item => { attachEl(item); // Check if the comment has replies // I check replies here to make sure I can disable subtree option for // MutationObserver to get better performance. let replies = item.querySelectorAll('.con .reply-box .reply-item'); if (replies.length > 0) { observeComments(item) console.log(item.dataset.id + ' has rendered reply(ies)', replies.length); } }) } } }); observer.observe(commentList, { attributes: false, childList: true, subtree: false }); }); } } // .bb-comment loads directly for zhuanlan post. So load it directly observeComments(); // .bb-comment loads dynamcially for dontai and videos. So observe it first const wrapperObserver = new MutationObserver((mutationsList, observer) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { [...mutation.addedNodes].map(item => { console.log('mutation element added', item); if (item.classList?.contains('bb-comment')) { console.log('mutation element added (found target)', item); observeComments(item); // Stop observing // TODO: when observer stops it won't work for dynamic homepage ie. https://space.bilibili.com/703007996/dynamic // so disable it here. This may have some performance impact on low-end machines. // wrapperObserver.disconnect(); } }) } } }); wrapperObserver.observe(document.body, { attributes: false, childList: true, subtree: true }); }, false);