Greasy Fork is available in English.

BLUL

Bilibili Live Userscript Library

Bu script direkt olarak kurulamaz. Başka scriptler için bir kütüphanedir ve meta yönergeleri içerir // @require https://update.greasyfork.org/scripts/407791/881207/BLUL.js

Yazar
SeaLoong
Versiyon
1.0.4
Oluşturulma
27.07.2020
Güncellenme
16.12.2020
Lisans
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()

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

  • 返回

(string): access_token。

BLUL.AppToken.refreshAccessToken()

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

  • 返回

(string): access_token。

BLUL.AppToken.getAccessToken()

获取 accesstoken 和 refreshtoken 。如果没有有效的 accesstoken 则自动获取新的 accesstoken 。失败返回 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): 模块名。

  • 返回

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