// ==UserScript==
// @name 语雀渲染HTML附件
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 拦截 /api/attachments/*/content 接口返回的 JSON 数据,解析并渲染 HTML
// @author SayHeya
// @match https://www.yuque.com/raw?filekey=yuque*
// @grant none
// @run-at document-start
// @license MIT
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
const isTargetURL = (url) =>
typeof url === 'string' &&
url.includes('/api/attachments/') &&
url.includes('/content');
/** 拦截 fetch */
const hookFetch = () => {
const originalFetch = window.fetch;
window.fetch = async function (...args) {
const [url] = args;
const response = await originalFetch.apply(this, args);
if (isTargetURL(url)) {
const cloned = response.clone();
cloned.json().then(data => {
console.log('[🎯 Intercepted fetch] Data:', data);
// 获取 data.content 节点中的 HTML 内容
const htmlContent = data.data.content;
// 创建一个容器来插入渲染的 HTML
const container = document.createElement('div');
container.style.cssText = `
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f7f7f7;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;
// 将 data.content 中的 HTML 直接赋给 container 的 innerHTML
container.innerHTML = htmlContent;
// 将容器插入到页面中
document.body.innerHTML = ''; // 清空页面
document.body.appendChild(container);
});
}
return response;
};
};
/** 拦截 XHR */
const hookXHR = () => {
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url, ...rest) {
this._intercept_url = url;
return originalOpen.call(this, method, url, ...rest);
};
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (...args) {
this.addEventListener('load', function () {
if (isTargetURL(this._intercept_url)) {
console.log('[🎯 Intercepted XHR]', this._intercept_url, this.responseText);
const data = JSON.parse(this.responseText);
const htmlContent = data.content;
// 创建一个容器来插入渲染的 HTML
const container = document.createElement('div');
container.style.cssText = `
padding: 20px;
font-family: Arial, sans-serif;
background-color: #f7f7f7;
margin: 20px 0;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;
// 将 data.content 中的 HTML 直接赋给 container 的 innerHTML
container.innerHTML = htmlContent;
// 将容器插入到页面中
document.body.innerHTML = ''; // 清空页面
document.body.appendChild(container);
}
});
return originalSend.apply(this, args);
};
};
hookFetch();
// hookXHR();
})();