使用Go语言批量同步微信读书笔记到Flomo
👆点击“博文视点Broadview”,获取更多书讯
“微信读书”和“Flomo”是我们常用的阅读和卡片记忆法软件。
在实际使用时,我们经常会有这样的需求:将微信读书中划线的笔记导入Flomo。传统的做法是先复制文字内容,然后打开Flomo,粘贴文字内容,输入适当的标签后保存,然后回到微信读书中继续阅读。
这一套动作下来,不仅要点击和切换好几次,连续阅读的体验也被破坏了。
恰好,Flomo提供了API,允许开发者通过API添加内容。按照官方文档的指引,使用Go语言就可以实现将微信读书中的笔记批量同步到Flomo的功能。
下面就将方法分享给大家!
01
操作方法
具体来说,实现这一功能的小程序是一个命令行应用程序。在编译出的可执行文件后添加help参数可以看到具体的使用方法,如下图所示。
首先,准备好要提交的笔记内容,从微信读书App中直接将内容复制出来,然后保存到纯文本文件中,比如下面这样。
显然,这里有3条划线笔记,意味着最终将添加3条Flomo。
接下来,想想这3条笔记的标签,我们也可以一次性添加多个标签。
最后,执行以下命令,在若干日志输出后,提示“全部笔记提交完成”,如下图所示。
main笔记,认知 C:\Users\wh199\Desktop\认知红利笔记.txt
打开Flomo,就可以看到刚刚提交的3条笔记了。
如此一来,我们可以专注于阅读和画线,在一个阅读阶段完成后,导出一次笔记。运行一次程序,相应的笔记内容就会被批量同步到Flomo中。是不是特别方便?
02
核心技术点
使用上述小程序确实能省去很多操作,节约很多时间。开发这个程序的过程也非常简单(仅需30分钟左右)。下面我们来细数这个小程序的核心技术点。
命令行参数读取:用户需要“告知”程序读取哪个文件,添加哪些标签;
字符串解析与文件读取:确保将文本文件中的笔记准确地读取出来;
网络请求和解析:将读取出来的每条笔记通过Flomo API进行提交。
就这些吗?对!就只有这些!
03
代码实现
下面,我们基于代码开发,一步步实现这个小程序。
▊ 命令行参数读取
Go SDK中内置了os包os.Args,它可以实现对执行参数的获取。这是一个[]string类型的变量,里面包含着该程序执行时给定的参数。
如果不添加任何参数,执行main.exe的方式为:
main
此时,os.Args中包含1个元素——main。
如果添加了参数,如“help”,执行main.exe时,方式为:
main help
此时,os.Args中包含2个元素——main和help。
由此,我们便可实现以下功能:输出程序的“帮助文档”、解析标签组的内容、解析文件路径。
具体代码如下:
if len(os.Args) >= 2 {
if os.Args[1] == "help" {
fmt.Println("▶▶ 当存在2个命令行参数时:")
fmt.Println("▶▶ 第一个参数是标签,多个标签以逗号隔开;")
fmt.Println("▶▶ 第二个是文件输入源,要求同目录下的完整文件名。")
fmt.Println("��� 注意1:文件要求UTF-8编码,内容直接粘贴微信读书导出的内容即可。��� ")
fmt.Println("��� 注意2:单日最多可上传100条memo。��� ")
fmt.Println("。◕‿◕。")
return
}
// 解析标签
tags = "#" + strings.ReplaceAll(os.Args[1], ",", " #")
fmt.Println("笔记标签为:", tags)
// 读文件,并获取笔记信息
singleExcerpts = readFile(os.Args[2])
fmt.Println("总共笔记数量:", len(singleExcerpts))
// 循环方式,提交每条笔记
for i := 0; i < len(singleExcerpts); i++ {
if singleExcerpts[i] != "" && singleExcerpts[i] != "\n" {
singleExcerpts[i] = strings.ReplaceAll(singleExcerpts[i], ">>", "")
fmt.Println("--------------------------------------------------")
fmt.Printf("提交第%d条笔记\n%s\n", i, singleExcerpts[i])
upload(tags, strings.TrimSuffix(singleExcerpts[i], "\n"))
fmt.Println("--------------------------------------------------")
}
}
fmt.Println("全部笔记提交完成")
}
这段代码实际上就是main()函数的全部内容,它实现了程序执行的完整流程。
解析标签无须多说,当我们在命令行中给定“笔记,认知”作为标签时,程序将替换“,”为“ #”(注意:此处时空格加上井号)。再回到开头补足首个标签的“#”,最终保存到tags中,成为:“#笔记 #认知”。
文件路径保存在os.Args[2]中,readFile()是读文件,并解析每条笔记的函数,它最终将返回[]string类型值。于是,singleExcerpts便包含了所有的笔记,它是[]string类型的变量。
最后,根据singleExcerpts的长度,通过for结构的循环进行提交。upload()函数是具体的提交逻辑,需要标签和单条笔记的文本内容。
▊ 读取文件、解析字符串
文件的读取和全部笔记的分割通过readFile()函数来完成。该函数需要传入完整的文件路径,最终返回包含分割好的每条笔记的string类型切片。
读文件用到两个包,一个是os,另一个是bufio。
仔细观察导出的文本内容,一开始是书名、作者和笔记个数统计,“◆ ”开头表示章节名,“>> ”开头表示单个划线内容。这三者之中,我们只取最后一类即可。
因此,思路是这样的:按行读取文本文件,遇到“◆ ”时,表示接下来将会有具体的划线笔记。遇到“>> ”时,将其汇总到另一个string类型变量中(fullContentFiltered)。重复上述过程,直到文件末尾。最后,以“>> ”为依据,对fullContentFiltered进行拆分,并辅以Trim操作,即可得到单条笔记了。
完整代码如下:
// 读文件内容(UTF-8编码兼容)
func readFile(filepath string) []string {
var returnData []string
file, err := os.Open(filepath)
if err != nil {
panic(err)
}
defer file.Close()
fileScanner := bufio.NewScanner(file)
fullContentFiltered := ""
contentBegin := false
for fileScanner.Scan() {
singleLine := fileScanner.Text()
if strings.HasPrefix(singleLine, "◆ ") || strings.HasPrefix(singleLine, ">> ") {
contentBegin = true
}
if !strings.HasPrefix(singleLine, "◆ ") && singleLine != "" {
if contentBegin {
fullContentFiltered += singleLine + "\n"
}
}
}
fullContentFiltered = strings.ReplaceAll(fullContentFiltered, ">> ", ">>")
fullContentFiltered = strings.TrimSuffix(fullContentFiltered, "\n")
fullContentFiltered = strings.TrimPrefix(fullContentFiltered, " ")
returnData = strings.Split(fullContentFiltered, ">>")
return returnData
}
▊ 网络请求和解析
最后就是网络请求,这里要结合Flomo的官方文档,并使用http、ioutil和json包进行。这一步较为简单,这里就不再详述了,具体代码如下:
// 请求flomo接口,提交数据
func upload(tags string, content string) {
content = content + "\n\n" + tags
uploadDataObj := Content{
Content: content,
}
uploadData, _ := json.Marshal(uploadDataObj)
resp, err := http.Post("https://flomoapp.com/iwh/xxxxxx/",
"application/json",
strings.NewReader(string(uploadData)))
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
到此,整个小程序的代码实现就完成了。
04
还能做什么?
通过实现这样一个简单的程序,我们能得到什么灵感呢?做些改进,通过书名自动添加标签?或是增加更多的字符串解析方法,做一个更通用的程序?或是绘制一个GUI,让用户自己填写识别字符串的正则表达式?
Go语言可以做服务器软件,做起客户端软件来也丝毫不含糊。高效的开发效率不仅可以节省开发者的时间,还“鼓励”着人们亲自动手,方便自己的生活与学习。毕竟,自己写一个这样的小工具比找一个现成的更省时间。
想要使用Go语言实现更多有意思的项目吗?
欢迎阅读《Go语言从入门到项目实战(视频版)》一书了解更多哦~~
粉丝专享六折优惠,快快扫码抢购吧!
审核:陈歆懿
如果喜欢本文欢迎 在看丨留言丨分享至朋友圈 三连
热文推荐
▼点击阅读原文,了解本书详情~