流程与钩子
本文介绍了 Paperlib 中重要的流程,以及在这些流程中,可用的钩子。
钩子介绍
在 Paperlib 中,我们在不同的地方,放置了不同名字的钩子点。一个钩子插件可以注册到对应的钩子点来介入 Paperlib 的运行流程。一共有两种类型的钩子点。
Modify 钩子点
目的:这种类型的钩子点,用于修改钩子点传来的参数,或者参数内的变量,而不能改变类型,最后返回修改后的参数。
回调返回值类型:该类钩子要求回调函数的返回值必须是一个数组,数组的每个元素,对应着传入的参数数组。比如,钩子点传入的参数为
(arg1: string, arg2: {value: number}),在钩子的回调函数中可以修改arg1为别的字符串,修改arg2.value为别的数字,但是不能修改arg1的类型为数字,或者修改arg2的类型为别的类型。回调函数的返回值必须为修改后的参数组成的数组:[arg1, arg2]。注意,即使传入参数仅为一个,也需要返回元素数量为1的数组。因为传入参数永远被视作一个数组。在接下来的文章中,我们使用 参数数组<...> 来表示。
Transform 钩子点
- 目的:这种类型的钩子点,可以修改 Paperlib 的运行流程中的数据流。用于把传入参数转换为其他形式的数据,然后返回。
- 回调返回值类型:可以为其他类型,但是通常不同钩子点有期望的返回值类型。比如,
scrapeEntry钩子点,期望的返回值类型为PaperEntity数组。
关于如何注册钩子,以及如何编写钩子插件,请参考 钩子插件。
论文导入流程
无论是从文件拖动导入,还是从浏览器插件导入,在组成相应的 source payload 后,都会进入到论文导入流程。论文导入流程的图示如下:
该流程中,主要的钩子点都在 ScrapeService 的 scrapeEntry() 和 scrapeMetadata() 方法中。
scrapeEntry()
scrapeEntry() 的主要任务就是把这些来自不同类型的源的数据,转换为 Paperlib 内部的数据结构 PaperEntity,并尽可能填充 PaperEntity 的重要字段(例如:title, doi, arxivID 等),以便之后的 scrapeMetadata() 方法搜寻补全其论文 metadata。
在接受到论文源的导入之后,我们首先调用 scrapeEntry()。他的主要参数是 SourcePayload 的数组,即论文源的数据。source payload 包含指示源的类型的 type 字段,以及源的数据:
interface SourcePayload {
type: "file" | "webcontent";
// 对于 file 类型,value 为文件路径的字符串
// 对于 webcontent 类型,value 为 WebContentSourcePayload
value: string | WebContentSourcePayload;
}
interface WebContentSourcePayload {
url: string; // 源网页的 url
document: string; // 源网页的 html
cookies?: string; // 有的网页包含 cookies
}scrapeEntry() 的返回值类型为 PaperEntity 的数组,因为即使传入的 SourcePayload 数组只包含一个 source payload,它也可能包含多个论文。例如,从文件拖动导入,可能拖入的是一个 BibTex 文件,其中包含多个论文的信息。
scrapeMetadata()
scrapeEntry() 的返回值,会被传入到 scrapeMetadata() 方法中。scrapeMetadata() 的主要任务是从网络各种数据库上搜寻论文的 metadata,并补全 PaperEntity 中所有字段。scrapeMetadata() 的返回值类型也是 PaperEntity的数组。
如图中所示,在这个流程中,有六个钩子点可以,五个 Modify 类型的钩子点,以及一个 Transform 类型的钩子点。
beforeScrapeEntry
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | scrapeEntry() 方法的最开始,还未转换为 PaperEntity 之前 |
| Callback 参数 | SourcePayload[] |
| Callback 返回值 | 参数数组<SourcePayload[]> |
scrapeEntry
| 参数 | 值 |
|---|---|
| 类型 | Transform |
| 位置 | scrapeEntry() 的主要钩子点,接受 SourcePayload 数组 转换为 PaperEntity 数组输出 |
| Callback 参数 | SourcePayload[] |
| Callback 返回值 | PaperEntity[] |
afterScrapeEntry
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | scrapeEntry() 方法的最后,已经转换为 PaperEntity 之后 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
beforeScrapeMetadata
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | scrapeMetadata() 方法的最开始,还未搜寻 metadata 之前 |
| Callback 参数 | paperEntities: PaperEntity[], scrapers: string[], force: boolean |
| Callback 返回值 | 参数数组<paperEntities: PaperEntity[], scrapers: string[], force: boolean> |
其中,scrapers 是一个字符串数组,如果不为空,则代表用户选择用特定的搜寻器进行搜寻。force 表示是否强制搜寻,如果为 true,则会忽略 PaperEntity 中已经存在的 metadata,强制搜寻。
scrapeMetadata
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | scrapeMetadata() 的主要钩子点,接受 PaperEntity 数组,可修改每一个的属性后返回 |
| Callback 参数 | paperEntities: PaperEntity[], scrapers: string[], force: boolean |
| Callback 返回值 | 参数数组<paperEntities: PaperEntity[], scrapers: string[], force: boolean> |
afterScrapeMetadata
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | scrapeMetadata() 方法的最后,已经搜寻 metadata 之后 |
| Callback 参数 | paperEntities: PaperEntity[], scrapers: string[], force: boolean |
| Callback 返回值 | 参数数组<paperEntities: PaperEntity[], scrapers: string[], force: boolean> |
论文 PDF 搜寻流程
当一个论文没有对应的 PDF 文件时,Paperlib 会在详情面板显示一个按钮用于在网络资源搜索可用的 PDF 并下载。这个按钮点击后,会进入到论文 PDF 搜寻流程。论文 PDF 搜寻流程的主要函数是 FileService 的 locateFileOnWeb() 方法。在这个流程里可用的钩子有一个。
locateFile
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | locateFileOnWeb() 方法中 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
引用导出流程
总的来说,引用导出时,我们首先得到需要导出的 PaperEntity 数组,然后将其转换为 citation.js 的 Cite 对象。最后,我们将 Cite 对象转化为对应格式的字符串,例如 BibTex 字符串。详情可见 GitHub 代码中,ReferenceService 的各个函数。
beforeExportBibItem
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibItem() 方法的最开始 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
citeObjCreatedInExportBibItem
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibItem() 方法中,Cite 对象已经创建 |
| Callback 参数 | cite: Cite, paperEntities: PaperEntity[] |
| Callback 返回值 | 参数数组<cite: Cite, paperEntities: PaperEntity[]> |
afterExportBibItem
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibItem() 方法的最后 |
| Callback 参数 | string |
| Callback 返回值 | 参数数组<string> |
beforeExportBibTexKey
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexKey() 方法的最开始 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
citeObjCreatedInExportBibTexKey
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexKey() 方法中,Cite 对象已经创建 |
| Callback 参数 | cite: Cite, paperEntities: PaperEntity[] |
| Callback 返回值 | 参数数组<cite: Cite, paperEntities: PaperEntity[]> |
afterExportBibTexKey
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexKey() 方法的最后 |
| Callback 参数 | string |
| Callback 返回值 | 参数数组<string> |
beforeExportBibTexBody
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexBody() 方法的最开始 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
citeObjCreatedInExportBibTexBody
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexBody() 方法中,Cite 对象已经创建 |
| Callback 参数 | cite: Cite, paperEntities: PaperEntity[] |
| Callback 返回值 | 参数数组<cite: Cite, paperEntities: PaperEntity[]> |
afterExportBibTexBody
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportBibTexBody() 方法的最后 |
| Callback 参数 | string |
| Callback 返回值 | 参数数组<string> |
beforeExportPlainText
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportPlainText() 方法的最开始 |
| Callback 参数 | PaperEntity[] |
| Callback 返回值 | 参数数组<PaperEntity[]> |
citeObjCreatedInExportPlainText
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportPlainText() 方法中,Cite 对象已经创建 |
| Callback 参数 | cite: Cite, paperEntities: PaperEntity[] |
| Callback 返回值 | 参数数组<cite: Cite, paperEntities: PaperEntity[]> |
afterExportPlainText
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | exportPlainText() 方法的最后 |
| Callback 参数 | string |
| Callback 返回值 | 参数数组<string> |
模糊元数据搜刮流程
在用户点击模糊搜索之后,用户选中的论文,会经过这个流程,得到模糊搜索的元数据。
该流程中,主要的钩子点都在 ScrapeService 的 fuzzyScrape() 方法中。
fuzzyScrape() 接受 Array<PaperEntity>, 输出 Record<string, Array<PaperEntity>>,即每个论文的 id 于候选 metadata 的映射。
可用的钩子如下:
`beforeFuzzyScrape
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | fuzzyScrape() 方法的最开始,还未搜寻 metadata 之前 |
| Callback 参数 | paperEntities: PaperEntity[] |
| Callback 返回值 | 参数数组<paperEntities: PaperEntity[]> |
fuzzyScrape
| 参数 | 值 |
|---|---|
| 类型 | Transform |
| 位置 | fuzzyScrape() 的主要钩子点,接受 PaperEntity 数组,返回一个数组,每个元素是对应论文的候选匹配数组,即类型为 PaperEntity[][] |
| Callback 参数 | paperEntities: PaperEntity[] |
| Callback 返回值 | PaperEntity[][] |
afterFuzzyScrape
| 参数 | 值 |
|---|---|
| 类型 | Modify |
| 位置 | fuzzyScrape() 方法的最后,已经搜寻 metadata 之后 |
| Callback 参数 | paperEntityDraftCandidates: PaperEntity[][] |
| Callback 返回值 | 参数数组<paperEntityDraftCandidates: PaperEntity[][]> |