快速開始(V2)
此内容还没有支持您的语言版本.
Miru Alpha 的 JavaScript 插件由純 Go 實現的 goja 引擎運行,插件文件後綴為 .js。本頁介紹 V2(推薦) 的完整 JS 插件寫法;通用元數據與數據返回格式見 開始開發 與 數據格式。
創建插件文件
Section titled “創建插件文件”在插件加載目錄中創建一個與包名同名的 .js 文件(例如 my.extension.js)。
// V2:直接在模塊頂層聲明這些函數,無需類var latest = (page) => { /* 最近更新 */ };var search = (kw, page, filter) => { /* 搜索(filter 為可選篩選項) */ };var detail = (url) => { /* 詳情 */ };var watch = (url) => { /* 返回鏡像列表 */ };var mirror = (url) => { /* 解析最終播放地址 */ };var createFilter = (filter) => { /* 返回篩選項描述(可選,默認未實現) */ };var checkUpdate = () => { /* 檢查更新(可選) */ };async function load() { /* 插件加載時執行一次 */ }請求通過全局 Miru 對象發起:
// request:把 url 拼到插件 @webSite 之後(相對地址),並自動嘗試 JSON.parse 響應const json = await Miru.request("/api/list?page=1");// rawRequest:使用完整地址,不會自動以 @webSite 拼接const html = await Miru.rawRequest("https://example.com/page");
// 跨調用保存狀態(goja VM 每次執行後都會銷燬,狀態必須走緩存)。值一律以字符串存儲Miru.saveCache("token", "abc123");const token = Miru.getCache("token");
// Miru 上還暴露了插件自身的元信息Miru.pkg; Miru.name; Miru.website;watch() 在 V2 中返回鏡像列表(而非最終地址),用戶選擇某個鏡像後,前端再調用 mirror(url) 解析出最終播放鏈接:
var watch = (url) => { const groups = { "Server 1": [ { name: "Mirror 1", url: "https://m1.example.com/a.m3u8", headers: {} }, { name: "Mirror 2", url: "https://m2.example.com/a.m3u8", headers: {} }, ], }; return { groups: Object.keys(groups).map((t) => ({ title: t, mirrors: groups[t] })) };};
var mirror = (url) => ({ type: "hls", // hls | mp4 | torrent | magnet(內容類型,不是插件類型) url, headers: { "User-Agent": "Mozilla/5.0" }, // tlsConfig: { profile: "chrome_133" }, // Go 插件可用:後端自動代理並偽裝 TLS 指紋});Node 模塊(require)
Section titled “Node 模塊(require)”goja 運行環境內置了 nodejs 風格的 require,插件可以直接加載宿主預置的模塊,無需自己打包依賴:
const { parseHTML } = require("linkedom"); // 輕量 DOM 解析const CryptoJS = require("crypto-js"); // CryptoJS.MD5 / AES / ...const md5 = require("md5"); // blueimp JavaScript-MD5:md5("str")const JSEncrypt = require("jsencrypt"); // RSA 加密:new JSEncrypt()const zlib = require("zlib"); // 壓縮/解壓(見下表)可用模塊一覽:
| 模塊 | 用途 / 導出 |
|---|---|
linkedom |
parseHTML(html) 返回 DOM(document/querySelector 等),用於抓取頁面。 |
crypto-js |
CryptoJS(MD5、SHA、AES、DES、Base64、Hmac 等,與瀏覽器端 crypto-js 用法一致)。 |
md5 |
blueimp 的 md5(string) 函數。 |
jsencrypt |
JSEncrypt 類(new JSEncrypt() + setPublicKey + encrypt)。 |
zlib |
同步壓縮/解壓:gzipSync / gunzipSync / deflateSync / inflateSync / brotliCompressSync / brotliDecompressSync / zstdCompressSync / zstdDecompressSync,返回 Uint8Array;bytesFromBase64(str) 把 base64 解碼為保留二進制的 Uint8Array。 |
url |
nodejs url 模塊(new URL()、解析等)。 |
console |
調試輸出(console.log / warn / error),會轉發到 Miru 的開發者日誌。 |
此外運行環境中還有全局對象 crypto(crypto.getRandomValues,單次最多 65536 字節)。
// ==MiruExtension==// @name Demo Bangumi// @package demo.bangumi// @author Demo// @license MIT// @lang zh-cn// @icon https://example.com/icon.png// @webSite https://example.com/// @type bangumi// @apiVersion 2// ==/MiruExtension==
var latest = async (page) => { const json = await Miru.request(`/api/latest?page=${page}`); return json.list.map((it) => ({ title: it.title, url: it.id, cover: it.cover, update: it.update }));};
var search = async (kw, page) => { const json = await Miru.request(`/api/search?kw=${kw}&page=${page}`); return json.list.map((it) => ({ title: it.title, url: it.id, cover: it.cover }));};
var detail = async (url) => { const json = await Miru.request(`/api/detail/${url}`); return { title: json.title, cover: json.cover, desc: json.desc, chapters: json.episodes.map((ep) => ({ title: ep.name, urls: ep.sources.map((s) => s.url) })), };};
var watch = (url) => ({ groups: [{ title: "默認", mirrors: [{ name: "源", url, headers: {} }] }],});
var mirror = (url) => ({ type: "mp4", url, headers: {} });請通過 PR 將插件提交到 Miru 插件倉庫,PR 中需包含插件源文件,不需要 index.json。