转到内容

快速開始(V2)

此内容还没有支持您的语言版本.

Miru Alpha 的 JavaScript 插件由純 Go 實現的 goja 引擎運行,插件文件後綴為 .js。本頁介紹 V2(推薦) 的完整 JS 插件寫法;通用元數據與數據返回格式見 開始開發數據格式

在插件加載目錄中創建一個與包名同名的 .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 指紋
});

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,返回 Uint8ArraybytesFromBase64(str) 把 base64 解碼為保留二進制的 Uint8Array
url nodejs url 模塊(new URL()、解析等)。
console 調試輸出(console.log / warn / error),會轉發到 Miru 的開發者日誌。

此外運行環境中還有全局對象 cryptocrypto.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