BLUL

Bilibili Live Userscript Library

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/407791/881207/BLUL.js

Autor
SeaLoong
Version
1.0.4
Erstellt am
27.07.2020
Letzte Aktualisierung
16.12.2020
Lizenz
MIT

Bilibili Live Userscript Library

B站直播区用户脚本库

此脚本需要作为 前置 使用(单独使用也能跑,但无实际功能)


开源许可证

MIT License


安装

如果你会修改使用我写的 build.js ,只需要在你的 元信息 中加入

// @require      https://raw.githubusercontent.com/SeaLoong/BLUL/dist/require.github.js

即可,然后用 node.js 跑一下 build.js 就能生成能直接使用的脚本。

否则请在你的用户脚本元信息中加入以下 元信息

// @include      /^https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+.*$/
// @connect      bilibili.com
// @connect      *
// @grant        unsafeWindow
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.deleteValue
// @grant        GM.listValues
// @grant        GM.getResourceUrl
// @grant        GM.xmlHttpRequest
// @grant        GM.addStyle
// @grant        GM.getResourceText
// @grant        GM.registerMenuCommand
// @grant        GM.unregisterMenuCommand
// @run-at       document-start
// @license      MIT License
// @require      https://raw.githubusercontent.com/SeaLoong/BLUL/dist/require.github.js

如果因网络不畅等原因导致不能正常加载,你可以使用 本地加载 的方式。只需要再加入以下 元信息

// @resource     jquery https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js
// @resource     lodash https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.19/lodash.min.js
// @resource     toastr https://cdn.bootcdn.net/ajax/libs/toastr.js/2.1.4/toastr.min.js
// @resource     spark-md5 https://cdn.bootcdn.net/ajax/libs/spark-md5/3.0.0/spark-md5.min.js
// @resource     Toast https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/toast.js
// @resource     Util https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/util.js
// @resource     Dialog https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/dialog.js
// @resource     Page https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/page.js
// @resource     Logger https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/logger.js
// @resource     Config https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/config.js
// @resource     Request https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/request.js
// @resource     Worker https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/worker.js
// @resource     Worker/env https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/worker/env.js
// @resource     Worker/channel https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/worker/channel.js
// @resource     AppToken https://raw.githubusercontent.com/SeaLoong/BLUL/master/src/modules/apptoken.js

然后启用脚本并打开受支持的页面,你应当会看到在偏右上方有 弹幕日志设置 等选项

  • 如果使用 import 加载脚本代码,由于部分网站获取js文件时的MIME是 text/plain 而不是 text/javascript,因此只能使用本地加载的方法来使用
  • 例如在脚本设置 自定义源 中把 BLUL根目录 设置成 https://raw.githubusercontent.com/SeaLoong/BLUL/dist 会导致不能加载,但在 //@resource 中加入各个模块的Github链接是可以正常加载的

使用例子

  • 可行的例子A
(async function () {
  BLUL.NAME = 'BLRHH';
  // 设置自己脚本的根目录,如果是本地模式则可以不设置
  BLUL.setBase('https://cdn.jsdelivr.net/gh/SeaLoong/BLRHH@master/dist');
  // 加载自己的模块
  const importModule = BLUL.importModule;
  importModule('MyModule'); // 此时返回值无意义
  /*
  做一些其他的前置操作
  */
  // 执行 BLUL ,参数含义参见后文
  if (!await BLUL.run({ debug: true, slient: false, unique: true, login: true, EULA: '' })) {
    console.error('[BLRHH] BLUL加载失败');
    return;
  }
  /*
  一般来说这里已经没有需要执行代码的地方,因为各个模块应当在 run 事件中执行模块功能
  */
})();
  • 可行的例子B
(async function () {
  BLUL.NAME = 'BLRHH';
  /*
  做一些前置操作
  */
  // 执行 BLUL ,参数含义参见后文
  if (!await BLUL.run({ debug: true, slient: false, unique: true, login: true, EULA: '' })) {
    console.error('[BLRHH] BLUL加载失败');
    return;
  }
  // 设置自己脚本的根目录,如果是本地模式则可以不设置
  BLUL.setBase('https://cdn.jsdelivr.net/gh/SeaLoong/BLRHH@master/dist');
  // 加载自己的模块
  const importModule = BLUL.importModule;
  importModule('MyModule'); // 你可以加上 await 保证先后顺序,因为现在这是一个异步函数,此时返回值为模块返回的内容
  /*
  一般来说这里已经没有需要执行代码的地方,因为各个模块应当在 run 事件中执行模块功能
  */
})();

API

本库分为几个模块,各个模块提供的接口有不同的使用方式,以下按照模块来分别说明用法。

其中在函数声明前带有 async 的说明这个函数应当配合 await 使用,否则可能导致不可预计的后果。

参数/样例的函数声明前带 async 的说明这个参数兼容异步函数,并且会等待异步函数执行完成和使用其返回值作为实际参数值(如果需要的话)。


主脚本

BLUL.onupgrade 事件

在脚本发生版本更新时触发,这是最早触发的事件。

BLUL.onupgrade(async (BLUL, GM) => {});

BLUL.onpreinit 事件

在脚本判断是否发生版本更新之后触发(不论是否触发 BLUL.onupgrade)。

BLUL.onpreinit(async (BLUL, GM) => {});

BLUL.oninit 事件

BLUL.onpreinit 之后触发。

BLUL.oninit(async (BLUL, GM) => {});

BLUL.onpostinit 事件

BLUL.oninit 之后触发。

BLUL.onpostinit(async (BLUL, GM) => {});

BLUL.onrun 事件

BLUL.onpostinit 之后触发,这是最晚触发的事件。其命名也说明了这个事件应当是模块主要逻辑开始执行的入口。

BLUL.onrun(async (BLUL, GM) => {});

初始信息

BLUL.NAME;
BLUL.ENVIRONMENT;
BLUL.ENVIRONMENT_VERSION;
BLUL.VERSION;
BLUL.INFO;
BLUL.INFO.CSRF;
BLUL.INFO.UID;
BLUL.INFO.ROOMID;
BLUL.INFO.ANCHOR_UID;
BLUL.INFO.SHORT_ROOMID;
BLUL.INFO.VISIT_ID;
BLUL.TRACKED_LISTENERS;

async BLUL.addResource(name, urls, [displayName=name])

增加一个脚本加载源,可以使用 await 来保证读取到配置项中的源。

  • 参数

name (string): 设置项在路径中的名称,注意不要有特殊字符,此项会作为键值对的键使用。

urls (string|Array): URL字符串或可选URL的数组。

[displayName=name] (string): 设置项显示给用户的名称,默认与 name 相同。

BLUL.addListenerFilter(type, f)

增加事件监听器(EventListener)的过滤器,调用方式为 f(type, listener, ...args) (与 addEventListener 一致),返回 true 表示允许, false 表示不允许。

  • 参数

type (string): 事件类型。

f (Function): 过滤函数。

BLUL.removeListenerFilter(type, f)

移除事件监听器(EventListener)的过滤器。

  • 参数

type (string): 事件类型。

f (Function): 过滤函数。

BLUL.removeAllListener(type, [rejectType=true])

移除指定事件的所有事件监听器(EventListener)。

  • 参数

type (string): 事件类型。

[rejectType=true] (boolean): 指示是否同时拒绝所有这类事件监听器的增加。

BLUL.setBase(urls)

设置脚本加载源的根目录,该函数只能执行一次。

  • 参数

urls (string|Array): URL字符串或可选URL的数组。

async BLUL.importModule(name)

加载模块,在 run 执行结束后可以使用 await 来保证加载顺序。

  • 参数

name (string): 模块名。

  • 返回

(*): 模块返回的内容。

BLUL.recover()

解除所有钩子。

async BLUL.run([options={}])

  • 参数

[options={}] (Object): 选项对象。

[options.debug] (boolean): 设置是否为调试模式。

[options.slient] (boolean): 设置是否为静默模式,静默模式下不会显示在加载过程中的浮动提示。

[options.unique] (boolean): 设置是否不允许脚本多开。

[options.login] (boolean): 设置是否需要登录才能使用。

[options.EULA] (string): 设置在首次执行前的提示的“最终用户许可协议”中的协议内容。

[options.EULA_VERSION] (string): 设置“最终用户许可协议”的版本,如果版本发生更新会再次显示“最终用户许可协议”。

[options.NOTICE] (string): 设置在脚本发生更新时显示的公告内容。

  • 返回

(number): 0: 成功加载; 1: 无法注入的页面; 2: 重复运行; 3: 未登录; 4: 未同意EULA。


AppToken

BLUL.AppToken.headers(params)

生成表单数据并且带签名。

  • 参数

params (Object): 数据。

  • 返回

(string): 签名后的表单数据。

BLUL.AppToken.getNewAccessToken()

获取新的 access_token 和 refresh_token ,并保存到设置中。失败返回 undefined。

  • 返回

(string): access_token。

BLUL.AppToken.refreshAccessToken()

使用 refresh_token 来获取新的 access_token ,并保存到设置中。失败返回 undefined。

  • 返回

(string): access_token。

BLUL.AppToken.getAccessToken()

获取 access_token 和 refresh_token 。如果没有有效的 access_token 则自动获取新的 access_token 。失败返回 undefined。

  • 返回

(string): access_token。


Config

BLUL.Config.onload 事件

在从存储中读取配置的时候触发。

BLUL.Config.onload(async function (BLUL) {
  console.assert(this === BLUL.Config);
});

BLUL.Config.get(path)

获取配置项。

  • 参数

path (string): 需要读取的配置项的路径。

async BLUL.Config.set(path, value)

设置配置项,如果对应的配置项设置了 corrector ,那么会调用 corrector 并把返回值作为实际写入的值。

  • 参数

path (string): 需要设置的配置项的路径。

value (*): 需要设置的配置项的值。

async BLUL.Config.load()

从存储中读取配置。

async BLUL.Config.save()

保存配置到存储中。

async BLUL.Config.reset([path=''], [sub=false])

恢复默认配置项,并保存到存储中。

  • 参数

[path] (string): 需要恢复默认配置项的路径,为空则指定全部配置。

[sub] (boolean): 指定是否需要把路径下的子配置项也恢复默认配置。

BLUL.Config.upgrade()

检查配置项是否发生升级(指出现配置项的实际类型和预计类型不一致)。

  • 返回

(number): 指发生升级配置项的个数。

BLUL.Config.addItem(path, name, defaultValue, [options={}])

  • 参数

path (string): 配置项的路径。

name (string): 配置项的名称。

defaultValue (*): 配置项的默认值。

[options={}] (Object): 选项对象。

[options.tag] (string|Function): 配置项的HTML标签,一般为 inputselect 。若参数类型为 Function ,则实际参数是函数返回值。

[options.title] (string|Function): 配置项的 <label> 标签的 title 属性。若参数类型为 Function ,则实际参数是函数返回值。

[options.help] (string|Function): 配置项的帮助说明。若参数类型为 Function ,则实际参数是函数返回值。

[options.onclick] (Function): 配置项被点击时的回调,应当用在 radio/checkbox 上,其函数声明为 async function (checked) {} ,返回值传递到下一个处理函数。

[options.list] (Array|Function): 配置项的选择列表,应当用在 select类文本框 上。若参数类型为 Function ,则实际参数是函数返回值。

[options.corrector] (Function): 配置项的数值修正函数,其返回值会作为对应配置项的实际值。

[options.attribute] (Object|Function): 配置项的的HTML标签的属性,其中的所有对象会应用到对应标签上。详见 <input><select>。若参数类型为 Function ,则实际参数是函数返回值。

BLUL.Config.removeItem(path)

  • 参数

path (string): 需要移除的配置项的路径。


Dialog

BLUL.Dialog([content], [title])

对话框(Dialog)的构造函数,应当使用 new 关键字。

  • 参数

[content] (*): 对话框的内容,默认为空字符串。

[title] (string): 对话框的标题,默认为 提示

Dialog.setTitle([title])

设置对话框的标题。

  • 参数

[title] (string): 对话框的标题,默认为 提示

  • 返回

(Dialog): 对话框对象自身。

Dialog.addContent([content])

添加对话框的内容。

  • 参数

[content] (*): 对话框的内容,默认为空字符串。

  • 返回

(Dialog): 对话框对象自身。

Dialog.removeContent([index])

移除对话框的内容。

  • 参数

[index] (number): 对话框的内容的索引,默认为最后一个内容的索引。

  • 返回

(Dialog): 对话框对象自身。

Dialog.addButton(text, onclick, [style])

添加对话框的按钮。

  • 参数

text (string): 按钮的文本。

onclick (Function): 按钮点击时的回调函数。

[style] (number): 按钮的样式,可选样式有 0, 1 。 默认为 0 ,其他值也视为 0

  • 返回

(Dialog): 对话框对象自身。

Dialog.removeButton([index])

移除对话框的按钮。

  • 参数

[index] (number): 对话框的按钮的索引,默认为最后一个按钮的索引。

  • 返回

(Dialog): 对话框对象自身。

async Dialog.show()

显示对话框。

  • 返回

(*): 对话框被关闭时提供的值。

Dialog.close([...returnValues])

关闭对话框,并设定 show 的返回值。

  • 参数

...[...returnValues] (*): 提供给 show 的返回值。


Logger

BLUL.Logger.log(msg, [type='success'])

显示一条日志,日志等级为 warnerror 时会同时调用 BLUL.Toast.warnBLUL.Toast.error

  • 参数

msg (*): 日志显示的内容。

[type='success'] (string): 日志等级,可选值有 success info warn error 。默认为 success

BLUL.Logger.success(...msgs)

显示一条日志,日志等级为 success

  • 参数

...msgs (*): 日志显示的内容,其中每个参数之间会用空格连接。

BLUL.Logger.info(...msgs)

显示一条日志,日志等级为 info

  • 参数

...msgs (*): 日志显示的内容,其中每个参数之间会用空格连接。

BLUL.Logger.warn(...msgs)

显示一条日志,日志等级为 warn,同时会调用 BLUL.Toast.warn

  • 参数

...msgs (*): 日志显示的内容,其中每个参数之间会用空格连接。

BLUL.Logger.error(...msgs)

显示一条日志,日志等级为 error,同时会调用 BLUL.Toast.error

  • 参数

...msgs (*): 日志显示的内容,其中每个参数之间会用空格连接。


Page

BLUL.Page.addTopItem(name, [onselect], [onclick])

增加一个顶部条目。

  • 参数

name (string): 条目标题。

[onselect] (Function): 条目被选择/被取消选择时的回调函数。

[onclick] (Function): 条目被点击时的回调函数。

  • 返回

(jQuery): 条目的jQuery对象。

BLUL.Page.addContentItem([element=''])

增加一个内容条目。

  • 参数

[element=''] (*): 需要被加入的元素。

  • 返回

(jQuery): 条目的jQuery对象。


Request

async BLUL.Request.monkey(options)

调用油猴的 GM.xmlHttpRequest 方法来进行网络请求,详见 GM.xmlHttpRequestTampermonkey/Violentmonkey

  • 参数

options (string|Object): URL字符串或选项对象。

[options.method='GET'] (string): 请求方式。

[options.url] (string): 请求URL。

[options.search] (Object): 请求的查询对象。

[options.headers] (Object): 请求头。

[options.data] (Object): POST请求的传递数据。

[options.*] (*): 剩余参数,取决于用户环境,详见文档。

  • 返回

(类XMLHttpRequest): 取决于用户环境,详见文档。

async BLUL.Request.fetch(options)

调用 Fetch_APIfetch 方法来进行网络请求。详见 fetch

  • 参数

options (string|Object): URL字符串或选项对象。

[options.method='GET'] (string): 请求方式。

[options.url] (string): 请求URL。

[options.search] (Object): 请求的查询对象。

[options.headers] (Object): 请求头。

[options.data] (Object): POST请求的传递数据。

[options.*] (*): 剩余参数,详见文档。

  • 返回

(Response): 详见 Response 文档 。


Toast

BLUL.Toast.success(...msgs)

显示一个浮动提示,等级为 success

  • 参数

...msgs (*): 显示的内容,其中每个参数之间会用 <br> 连接。

BLUL.Toast.info(...msgs)

显示一个浮动提示,等级为 info

  • 参数

...msgs (*): 显示的内容,其中每个参数之间会用 <br> 连接。

BLUL.Toast.warn(...msgs)

显示一个浮动提示,等级为 warn,同时会调用 BLUL.Logger.warn

  • 参数

...msgs (*): 显示的内容,其中每个参数之间会用 <br> 连接。

BLUL.Toast.error(...msgs)

显示一个浮动提示,等级为 error,同时会调用 BLUL.Logger.error

  • 参数

...msgs (*): 显示的内容,其中每个参数之间会用 <br> 连接。


Util

BLUL.Util.getGlobalScope()

获取当前全局作用域的名称。

  • 返回

(string): 当前全局作用域的名称。

async BLUL.Util.sleep(ms)

等待(需要配合 await 使用)。

  • 参数

ms (number): 等待的时间,单位毫秒。

async BLUL.Util.result(value, [thisArg], [...args])

如果 value 是函数,则返回调用后的结果,否则返回本身。

  • 参数

value (*): 值。

[thisArg] (*): 调用时传入的this参数。

[...args] (*): 调用时传入的参数。

  • 返回

(*): value 本身或调用后的结果。

BLUL.Util.codeToURL(code)

生成一个URL,其中内容是这个JavaScript代码。可用于动态执行代码。

  • 参数

code (string): JavaScript代码。

  • 返回

(string): 对应代码文件的URL。

BLUL.Util.toURLSearchParamString(search)

转换为查询字符串,参数可以是 字符串/对象 及其他 URLSearchParams() 支持的参数。

  • 参数

search (*): 要被转换的参数。

  • 返回

(string): 转换得到的查询字符串。

BLUL.Util.getCookie(key)

获取Cookie。

  • 参数

key (string): Cookie的键。

  • 返回

(string): Cookie的值。

BLUL.Util.compareVersion(version1, version2)

比较版本号的大小。

  • 参数

version1 (string): 要比较的版本字符串1。

version2 (string): 要比较的版本字符串2。

  • 返回

(number): 比较的结果:version1 > version2 返回大于的数0;version1 === version2 返回0;version1 < version2 返回小于的数0。

BLUL.Util.beforeNow(ts, [range=86400e3], [offset=60e3])

判断给定的时间戳是不是在当前时间的前一段时间到当前时间之间,为了方便使用,实际用于判断的时间减去了offset。

  • 参数

ts (number): 时间戳。

[range=86400e3] (number): 时间范围,默认为1天,单位毫秒。

[offset=60e3] (number): 允许的时间误差,默认为1分钟,单位毫秒。

  • 返回

(boolean): 判断的结果。

BLUL.Util.isToday(ts)

判断给定的时间戳是不是在当日,以UTC+8为标准(经过时区修正)。

  • 参数

ts (number): 时间戳。

  • 返回

(boolean): 判断的结果。

BLUL.Util.atTime([ts=Date.now()], [hours=0], [min=1], [sec=0], [ms=0])

计算并返回在给定时间戳下,下一次时间对应的时间戳(经过时区修正)。

  • 参数

[ts=Date.now()] (number): 时间戳。

[hours=0] (number): 小时。

[min=1] (number): 分钟。

[sec=0] (number): 秒。

[ms=0] (number): 毫秒。

  • 返回

(number): 下次时间对应的时间戳。

BLUL.Util.isAtTime([ts=Date.now()], [hours=0], [min=1], [sec=0], [ms=0])

判断 atTime(ts, hours, min, sec, ms) 返回的时间戳是否小于当前时间戳(经过时区修正)。

等价于 return atTime(ts, hours, min, sec, ms) <= Date.now()

  • 参数

[ts=Date.now()] (number): 时间戳。

[hours=0] (number): 小时。

[min=1] (number): 分钟。

[sec=0] (number): 秒。

[ms=0] (number): 毫秒。

  • 返回

(boolean): 判断结果。

BLUL.Util.callAtTime(f, [hours=0], [min=1], [sec=0], [ms=0])

在指定的时间(与日期无关)执行给定的函数,以UTC+8为标准(经过时区修正)。

在下一次到达指定的时间时执行,因此可能会在当天或次日执行。

  • 参数

f (Function): 待执行的函数。

[hours=0] (number): 小时。

[min=1] (number): 分钟。

[sec=0] (number): 秒。

[ms=0] (number): 毫秒。

  • 返回

(Promise): 等待过程的Promise。

BLUL.Util.cancelCallAtTime(f)

取消在指定的时间执行给定的函数。

  • 参数

f (Function): 待取消执行的函数。

BLUL.Util.sortByKey(obj, [compareFn], [reverse=false])

对对象中的每个键值对按照键的排序顺序来排序。

  • 参数

obj (Object): 对象。

[compareFn] (Function): 比较函数,将会被传递到 sort() 函数中。

[reverse=false] (*): 是否倒序。

  • 返回

(Object): 排序后的对象。

async BLUL.Util.mapAndWait(array, f, [thisArg])

对数组中的每个元素执行给定的函数,并等待异步结果。

  • 参数

array (Array): 数组。

f (Function): 要执行的函数,其函数声明为 async function (element, index, array) {}

[thisArg] (*): 调用时传入的this参数。

  • 返回

(Array): 所有结果组成的数组。

async BLUL.Util.mapKeysAndWait(object, f, [thisArg])

对对象中的每个键值对执行给定的函数,并等待异步结果,并且将返回值作为键值对的新键。

  • 参数

object (Object): 数组。

f (Function): 要执行的函数,其函数声明为 async function (value, key, object) {}

[thisArg] (*): 调用时传入的this参数。

  • 返回

(Object): 所有结果组成的对象。

async BLUL.Util.mapValuesAndWait(object, f, [thisArg])

对对象中的每个键值对执行给定的函数,并等待异步结果,并且将返回值作为键值对的新值。

  • 参数

object (Object): 数组。

f (Function): 要执行的函数,其函数声明为 async function (value, key, object) {}

[thisArg] (*): 调用时传入的this参数。

  • 返回

(Object): 所有结果组成的对象。

async BLUL.Util.callEachAndWait(funcs, [thisArg], [...args])

分别调用函数数组的每个函数,并等待异步结果。

  • 参数

funcs (Array): 函数数组。

[thisArg] (*): 调用时传入的this参数。

[...args] (*): 调用时传入的参数。

  • 返回

(Array): 所有结果组成的数组。

async BLUL.Util.callChainAndWait(funcs, [thisArg], [...args])

链式调用函数数组的每个函数,前一个函数的返回值作为后一个函数的第一个参数,并等待异步结果。

  • 参数

funcs (Array): 函数数组。

[thisArg] (*): 调用时传入的this参数。

[...args] (*): 调用时传入的参数。

  • 返回

(Array): 所有结果组成的数组。

async BLUL.Util.callUntilTrue(f, [interval=50], [thisArg], [...args])

持续调用函数,并等待异步结果,直到返回被认为 true 的结果。

  • 参数

f (Function): 要执行的函数。

[interval=50] (*): 调用等待间隔,默认50ms。

[thisArg] (*): 调用时传入的this参数。

[...args] (*): 调用时传入的参数。

  • 返回

(*): 调用函数返回的结果。

BLUL.Util.retry(f)

在一定时间后调用给定的函数,每次调用后会使得下一次调用的等待时间翻倍,最长为 1 小时。

  • 参数

f (Function): 待执行的函数。

  • 返回

(Promise): 等待过程的Promise。

BLUL.Util.cancelRetry(f)

取消调用给定的函数,并清空等待时间。

  • 参数

f (Function): 待取消执行的函数。


Worker

async BLUL.Worker.importModule(name)

在 Worker 中加载模块。

  • 参数

name (string): 模块名。

  • 返回

(*): 模块返回的内容。