Custom JS 自定义搜索 · 沙箱内写 search() 与 scrape()
什么时候用 Custom JS
如果你需要一个 RikkaHub 内置搜索服务都不支持的场景——比如:
- 搜索一个极小众的网站(不是通用搜索引擎)
- 搜索结果需要特殊格式处理
- 整合多个数据源
- 想完全自定义抓取逻辑
Custom JS 是最强大的解决方案。
沙箱环境
RikkaHub 提供一个受限的沙箱环境执行你的 JS 脚本:
| 能力 | 可用 | 不可用 |
|---|---|---|
| 网络请求 | ✅ 同步 fetch() | ❌ async/await |
| DOM 操作 | ❌ | 整个 DOM API |
| 文件系统 | ❌ | 设备存储、RikkaHub 内部 |
| Android API | ❌ | 任何系统调用 |
| 外部库 | ❌ | 只可用原生 JS |
| ES6+ | 看版本 | 以沙箱支持为准 |
关键限制:只有同步 fetch(),没有 async/await。这意味着你要用同步风格写所有网络请求。
必需实现:search()
function search(query, resultSize) {
const encoded = encodeURIComponent(query);
const res = fetch("https://example.com/search?q=" + encoded + "&limit=" + resultSize);
const data = res.json();
return {
items: data.results.map(function(r) {
return {
title: r.title,
url: r.url,
text: r.snippet
};
})
};
}
search() 参数
query(string):搜索关键词resultSize(number):希望返回的结果数量
search() 返回
{
items: [
{
title: "结果标题", // 必填
url: "https://...", // 必填
text: "摘要内容" // 必填
}
],
answer: "可选的 AI 生成摘要" // 可选
}
可选实现:scrape()
如果模型需要抓取完整页面内容(不只是搜索摘要),可以实现 scrape(urls):
function scrape(urls) {
return urls.map(function(url) {
const res = fetch(url);
const text = res.text();
return { url: url, text: text };
});
}
scrape() 参数
urls(string[]):要抓取的 URL 数组
scrape() 返回
[
{ url: "https://...", text: "页面完整内容..." }
]
fetch() API(沙箱专用)
和浏览器 fetch() 类似,但同步、无 Promise:
const res = fetch("https://api.example.com/search?q=test");
// res 是同步可用的 Response 对象
res.status // HTTP 状态码
res.ok // 是否成功
res.text() // 同步获取文本内容
res.json() // 同步解析 JSON
fetch() 不支持的
await fetch()→ 不支持异步- 自定义 headers / method / body(取决于沙箱实现)→ 可能不支持
- Cookie / localStorage → 不支持
完整示例
// 实现一个简单的 DuckDuckGo Instant Answer 搜索
function search(query, resultSize) {
const encoded = encodeURIComponent(query);
const res = fetch("https://api.duckduckgo.com/?q=" + encoded + "&format=json&no_html=1");
const data = res.json();
const items = [];
// Abstract 部分
if (data.Abstract) {
items.push({
title: data.Heading || query,
url: data.AbstractURL || "https://duckduckgo.com/?q=" + encoded,
text: data.Abstract
});
}
// Related Topics
if (data.RelatedTopics) {
data.RelatedTopics.slice(0, resultSize - items.length).forEach(function(topic) {
if (topic.FirstURL && topic.Text) {
items.push({
title: topic.Text,
url: topic.FirstURL,
text: topic.Text
});
}
});
}
return { items: items.slice(0, resultSize) };
}
调试 Custom JS
Custom JS 没有调试工具。建议:
- 先在浏览器控制台里把脚本跑通(记得改成同步风格)
- 再粘贴到 RikkaHub 设置里
- 测试搜索几次,观察返回结果是否正确
- 出错时 RikkaHub 会在搜索日志里显示错误信息
安全提醒
- 沙箱虽然受限,但你的脚本可以访问任何公网 URL
- 不要在脚本里硬编码敏感 token(虽然沙箱里拿不到,但最好还是别)
- 从可信来源复制 Custom JS 脚本——沙箱虽然受限,但恶意脚本可能发起网络请求泄露信息