Hook 插件
这种类型的插件主要特点是可以介入 Paperlib 的运行流程,修改流程里面的参数,数据流等。比如,当用户拖入一个论文 PDF 时,Paperlib 会搜索该文件的元数据,生成一个 PaperEntity 存在数据库中。我们可以通过 Hook 插件来介入这个过程,比如在生成 PaperEntity 之后,我们将元数据中的某部分进行修改。
实际上,在 Paperlib 3.0 中,官方所有的 Metadata Scraper 都是用插件来实现的。
插件类结构
在这里我们给出一个示例结构,当然你可以根据自己的需要进行修改。
class HookExtension extends PLExtension {
constructor() {
// 你可以在这里设置插件的 id,默认设置
super(...)
}
async initialize() {
// 在这里注册 Hook 点
this.disposeCallbacks.push(
PLAPI.hookService.hookModify(
"scrapeEntryBefore",
this.id,
"modifyPayloads",
),
);
...
}
async dispose() {
// 在这里取消注册,事件监听
for (const disposeCallback of this.disposeCallbacks) {
disposeCallback();
}
}
async modifyPayloads(payloads: SourcePayload[]) {
// 在这里修改 payloads
...
return [payloads]
}
}
钩子点
在 Paperlib 中,我们在不同的地方,放置了不同名字的钩子点。一个钩子插件可以注册到对应的钩子点来介入 Paperlib 的运行流程。一共有两种类型的钩子点。
Modify 钩子点
目的:这种类型的钩子点,用于修改钩子点传来的参数,或者参数内的变量,而不能改变类型,最后返回修改后的参数。
回调返回值类型:该类钩子要求回调函数的返回值必须是一个数组,数组的每个元素,对应着传入的参数数组。比如,钩子点传入的参数为
(arg1: string, arg2: {value: number})
,在钩子的回调函数中可以修改arg1
为别的字符串,修改arg2.value
为别的数字,但是不能修改arg1
的类型为数字,或者修改arg2
的类型为别的类型。回调函数的返回值必须为修改后的参数组成的数组:[arg1, arg2]
。注意,即使传入参数仅为一个,也需要返回元素数量为1的数组。因为传入参数永远被视作一个数组
Transform 钩子点
- 目的:这种类型的钩子点,可以修改 Paperlib 的运行流程中的数据流。用于把传入参数转换为其他形式的数据,然后返回。
- 回调返回值类型:可以为其他类型,但是通常不同钩子点有期望的返回值类型。比如,
scrapeEntry
钩子点,期望的返回值类型为PaperEntity
数组。
可用钩子点
modifyHookPoint
- beforeScrapeEntry - 在论文 payload 进入 scrape 流程之前。
- afterScrapeEntry - 在论文 payload 完成 scrape 流程转换为了
PaperEntity
草稿之后。 - beforeScrapeMetadata - 在论文草稿进入 scrape metadata 流程之前。
- scrapeMetadata - 在论文草稿进行 scrape metadata 流程时。
- afterScrapeMetadata - 在论文草稿完成 scrape metadata 流程之后。
- locateFile - 在论文草稿进行 locate file 流程时。
transformhookPoint
- scrapeEntry - 在论文 payload 进入 scrape 流程,转换为 PaperEntity 时。
Paperlib 的详细流程和钩子点的详细介绍,请参考 运行流程与钩子。
钩子注册
我们可以通过 PLAPI.hookService.hookModify
方法来注册插件所使用的 Modify
钩子点,或者使用 PLAPI.hookService.hookTransform
方法来注册插件所使用的 Transform
钩子点:
PLAPI.hookService.hookModify(
hookPoint: string,
extensionId: string,
callbackFuncName: string,
)
PLAPI.hookService.hookTransform(
hookPoint: string,
extensionId: string,
callbackFuncName: string,
)
hookPoint
:Paperlib 提供的钩子点的 id,想要设置钩子的位置。extensionId
:插件的 id,用于标识插件。callbackFuncName
:插件中的回调函数的名称,用于在钩子点触发时调用。
钩子回调函数
钩子回掉函数的名字,需要和注册时的 callbackFuncName
保持一致。钩子回调函数的参数,以及返回值的形式,根据钩子位置不同,以及钩子类型不同,会有所不同。详细介绍请参考 运行流程与钩子。
在钩子点小节中我们总体上描述了两类钩子回调函数的形式。在此不再赘述。
超时限制
因为钩子类插件会侵入 Paperlib 的运行流程,所以我们需要对钩子回调函数的运行时间进行限制。如果钩子回调函数运行时间超过了预设时间,Paperlib 会强制绕过该回调函数的运行:
modifyHookPoint
:默认超时时间为 5 秒。transformHookPoint
:默认超时时间为 15 秒。
额外钩子点
尽管我们的钩子机制支持我们几乎在任何地方放置钩子,但是因为钩子类插件的侵入性,我们非常谨慎的开放钩子点。如果目前的钩子点无法满足您插件的开发需求,请前往 GitHub Discussions 提出您的需求,我们会考虑在未来的版本中添加新的钩子点。