大家聖誕快樂🎉
雖然這篇標題跟之前幾乎一樣,但因為替換的目標不同,內容也多了不少
這幾年我也將搜尋引擎換成了 Kagi,所以這篇文章教的是替換成 Kagi
但是 Kagi 明明就出 App 來修改搜尋引擎了,我幹嘛再多此一舉?
因為我想水文章解決幾個小問題
Kagi 的 APP 有三個我覺得比較討厭的問題,
第一個就是偶爾開分頁或無痕會掉登錄,
打開分頁又要再登入一次真的很煩 😡
第二個問題就是 autocomplete
Kagi App 沒辦法做到這個功能(因為擴充的限制),
而且 ecosia 給的關鍵字常常帶有簡體的結果,或是不符合台灣人的使用習慣
第三個問題就是,用 Loon 能做到一樣的功能,幹嘛多裝一個 App XD
TL;DR
https://raw.githubusercontent.com/BeeeeeMo/Loon-plugins/refs/heads/main/Plugins/kagi.plugin
新增完 plugin 後,到 Plugin 設定加上 KagiSession
替換成 Kagi 跟之前的做法有何不同?
Kagi 是一款收費的搜尋引擎,所以不能跟之前一樣 307 換掉請求就好,還需要帶入 token
我猜 Kagi App 的替換方式應該是將用戶的 Token 塞到 url 的 param 中
只是不知道為何偶爾會踩到 Bug 掉登錄,所以如果我想修正這個問題,就不能跟他一樣
我們要找不同的方法,已知在 url 中 param 帶入 token 一次,
後續的請求都不需要加上這個 param,那應該就是他有寫進餅乾裡
所以我們透過 Loon 直接塞進餅乾就能保持登錄了~
修改搜尋請求
這段跟幾年前用 QX 的時候一樣,我們直接踩在自己的肩膀上,直接照抄之前文章的分析結果
使用 307 跳轉換將 ecosia 成 Kagi
^https:\/\/www\.ecosia\.org\/search 307 https://kagi.com/search
加上餅乾 (cookie🍪)
雖然我可以直接修改 header,但我想讓使用者自己輸入 token,
從文件上看起來 request-header 複寫 不能帶入 Argument
所以我們只能繞一下路,用腳本來解決這個問題
req_headers = $request.headers;
req_headers.cookie = "kagi_session=" + $argument.session.replace("https://kagi.com/search?token=", "");
$done({ status: 200, headers: req_headers });
這樣就可以從 Loon 中取出使用者自訂義的 Token,再寫入到餅乾
修復 autocomplete
這個就跟之前不太一樣了,Kagi autocomplete 的返回值跟 ecosia 不同,不能直接 307 跳過去
所以我們要稍微分析一下
透過 Proxyman 分析 Safari 請求
先到 Safari 搜尋一下,本篇文章沒有收 QWQ 夾腳拖的業配,如果有需求歡迎聯繫
我們再到 proxyman 中看看請求長什麼樣
可以看到 Body 的回傳內容跟上圖 Safari 的結果一樣 廢話
結構為兩個 array 組合而成的,第一個 Value 是我們的 Keyword
第二個是 autocomplete 組合而成的 array
等等我們分析完 Kagi 的結果再把它們合併
分析 Kagi autocomplete 請求
從圖中可以知道 Kagi 在 autocomplete 帶有更多內容 e.g. 縮圖、註解
舉個例子
聖誕節到了,瑪麗亞凱莉也解凍了
不開玩笑了,我們看一下回傳
[{
"t": "qwq",
"txt": null,
"img": null,
"k": "kagi"
}, {
"t": "qwq 32b",
"txt": null,
"img": null,
"k": "kagi"
}, {
"t": "qwq夾腳拖",
"txt": null,
"img": null,
"k": "kagi"
}]
從回傳可以知道我們只要 t,其他的在 safari 都用不到
梳理思路
我們已經拿到了 ecosia 跟 Kagi 它們各自 autocomplete 的方法
接下來就是思考要怎麼做,我想到了兩種方法
- 302/307 修改 autocomplete 直送 Kagi,再修改回傳
- 攔截並修改 ecosia 的 Response,取出關鍵字轉送給 Kagi,再回傳 Kagi 的結果
我本來覺得第一個做法很優雅,但在我實測之後可能沒這麼簡單,
中間有太多隱性的條件,這些條件彼此都會相互耦合,不利於後續維護、擴展 而且我沒成功
第二個做法相對簡單,用 Loon 只要一行就能直接修改 response
攔截 ecosia 的搜尋關鍵字,再透過 httpClient 發請求到 Kagi
再把回傳 Parsing 成 Safari 要的格式就完成囉
思路簡單,而且很容易就達成了,前面把問題想得太複雜 XD
接下來就是動手做的環節啦!
JS Time!
又到了我最討厭的寫 JS 時間 =_=
直接上 code 不廢話
const _url = new URL($request.url);
const qValue = _url.searchParams.get('q');
let url = "https://kagi.com/autosuggest/?q=" + qValue;
let headers = {
'Accept': '*/*',
'User-Agent': 'Mozilla/5.0 (iPad; CPU iPhone OS 18.1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1',
'Connection': 'keep-alive',
'Host': 'kagi.com',
'Accept-Encoding': 'gzip, deflate, br',
'Cookie': 'kagi_session=' + $argument.session.replace("https://kagi.com/search?token=","")
};
var params = {
url: url,
timeout: 5000,
headers: headers,
};
$httpClient.get(params, function (errormsg, response, data) {
if (errormsg) {
console.log(errormsg);
} else {
const suggestions = JSON.parse(data).map(item => item.t);
const result = [
qValue,
suggestions
];
const modifiedBody = JSON.stringify(result);
$done({body: modifiedBody });
}
});
還好 Kagi 是用 Json 當作回傳,我們用 JS 很容易就做到了 Parsing 的工作
完成!
來實測一下,我們熟悉的拖鞋又出現啦~