用 Python 批量创建思源笔记的 DailyNote

本贴最后更新于 1045 天前,其中的信息可能已经东海扬尘

起因

经过一个多月的使用,已逐渐适应并喜欢上写思源的 dailynote,除了待办、摘录和总结外,当天剪藏的文章会直接用 Alt + [ 保存为子文档,书写格式和流程基本固化。

因我的某象已经沦为“垃圾场”,不适合批量导出导入,如想把之前年度的笔记进行手工“清洁”迁移,需要新建大量 dailynote 文档。

过程

研究思源笔记本地文件

思源笔记的本地文件结构

打开本地目录发现,主要结构为笔记本文件夹——文档,和文档文件夹——子文档两种。

data │ ├─.siyuan ├─yyyymmddhhmmss-随机7位字母和数字组合 # 笔记本文件夹,如对应daily note笔记本 │ │ │ ├─.siyuan │ ├─yyyymmddhhmmss-随机7位字母和数字组合 # 一级文档文件夹,如对应2020子文档文件夹 │ └─yyyymmddhhmmss-随机7位字母和数字组合.sy # 一级文档,如对应2020文档 │ │ │ ├─yyyymmddhhmmss-随机7位字母和数字组合 # 二级文档文件夹,如对应01月子文档文件夹 │ └─yyyymmddhhmmss-随机7位字母和数字组合.sy # 二级文档,如对应01月文档 │ │ │ └─yyyymmddhhmmss-随机7位字母和数字组合.sy # 三级文档,如对应2020-01-01文档 ├─assets ├─emojis ├─icon ├─templates └─widgets

思源笔记的本地文件

打开几个对应仅录入了文档名的本地文件,发现不同的主要为文档的 ID、文档名、段落的 ID 和更新时间戳。其中删改文档内容时,Children 对象的也会变化,考虑是否可先省略。

{ "ID": "yyyymmddhhmmss-随机7位字母和数字组合", # 文档的ID "Type": "NodeDocument", "Properties": { "id": "yyyymmddhhmmss-随机7位字母和数字组合", # 文档的ID "title": "文档名", "updated": "yyyymmddhhmmss" # 更新时间戳 }, "Children": [ { "ID": "yyyymmddhhmmss-随机7位字母和数字组合", # 段落的ID "Type": "NodeParagraph", "Properties": { "id": "yyyymmddhhmmss-随机7位字母和数字组合" # 段落的ID "updated": "yyyymmddhhmmss" # 更新时间戳 } } ] }

ID 的差异化

当创建 2020-01-01 文档时,实际需要分别先创建 2020 和 01 文档和文件夹,3 个文档 ID 的前缀 yyyymmdd 都是 20200101。为了有所区分,对秒数进行了递进,同时方便后续按 ID 排序时不乱序。

文档名 ID 前缀
2020 20200101010101
01 20200101010102
2020-01-01 20200101010103

研究 Python 代码

随机字符串相关

string.ascii_lowercase # 小写字母 string.digits # 数字 random.sample(population, k) # 无重复的随机抽样 str.join(sequence) # 将序列中的元素以指定的字符连接生成一个新的字符串

日期时间相关

datetime.date(year, month, day) # 一个理想化的简单型日期 datetime.datetime.now() # 返回当前时间 strftime(format) # 根据给定的格式将对象转换为字符串 %Y # yyyy,年份 %m # mm,补零月份 %d # dd,补零日 %H # hh,补零24小时制 %M # mm,补零分钟 %S # ss,补零秒 dateutil.relativedelta.relativedelta() # 计算时间间隔,支持年月日等参数

文件相关

f = open(file, mode) "w" # 写入,不存在则新建 "x" # 创建,已存在则报错 f.write() # 文件写入 f.close() # 文件关闭 os.mkdir(path) # 创建文件夹

JSON 相关

json.dumps(obj, indent=4) # 输出 JSON 格式,并缩进四个空格

消息框相关

tkinter.messagebox.showinfo(title, message) # 弹出消息提示框

输出代码

import string import random import os import json import tkinter import tkinter.messagebox import sys from datetime import * from dateutil.relativedelta import * start_date = date(2020, 1, 1) # 需修改起始日期,不能跨年 end_date = date(2020, 12, 31) # 需修改结束日期,不能跨年 # 确定随机数长度为 7 r_num = 7 # 随机数组合为小写字母和数字 token = string.ascii_lowercase + string.digits # 生成年度文档随机数 token_y = ''.join(random.sample(token,r_num)) # 生成年度文档 ID,时间默认为当年 1 月 1 日 01 点 01 分 01 秒 id_y = start_date.strftime('%Y') + "0101010101-" + token_y # 生成年度文档内容 data_y = { "ID": id_y, "Type": "NodeDocument", "Properties": { "id": id_y, # 标题格式 yyyy "title": start_date.strftime('%Y'), # 更新时间为当下时间,格式 yyyymmddhhmmss "updated": datetime.now().strftime('%Y%m%d%H%M%S') } } path_k = "results" if not os.path.exists(path_k): os.mkdir(path_k) else: tkinter.messagebox.showinfo("提示", "请先删除 " + path_k + " 文件夹后再重新运行") sys.exit() # 创建年度文档 filename_y = path_k + "/" + id_y + ".sy" f = open(filename_y, "x") # 输出 JSON 格式,并缩进四个空格 f.write(json.dumps(data_y, indent=4)) # 关闭文件 f.close() # 创建年度文档文件夹 os.mkdir(path_k + "/" + id_y) # 计算起始和结束日期月份差 delta_m = end_date.month - start_date.month + 1 # 月份循环 i 次 for i in range(delta_m): day_m = start_date + relativedelta(months=+i) token_m = ''.join(random.sample(token,r_num)) # 生成月度文档 ID,时间默认为当月 1 日 01 点 01 分 02 秒 id_m = day_m.strftime('%Y%m%d') + "010102-" + token_m data_m = { "ID": id_m, "Type": "NodeDocument", "Properties": { "id": id_m, # 标题格式 mm "title": day_m.strftime('%m'), "updated": datetime.now().strftime('%Y%m%d%H%M%S') } } # 在年度文件夹下,创建月度文档 filename_m = path_k + "/" + id_y + "/" + id_m + ".sy" f = open(filename_m, "x") f.write(json.dumps(data_m, indent=4)) f.close() # 在年度文件夹下,创建月度文件夹 os.mkdir(path_k + "/" + id_y + "/" + id_m) # 计算当月总天数 delta_d = day_m + relativedelta(months=+1) + relativedelta(days=-1) # 日循环 j 次 for j in range(delta_d.day): day_d = day_m + relativedelta(days=+j) token_d = ''.join(random.sample(token,r_num)) # 生成当日文档 ID,时间默认为当日 01 点 01 分 03 秒 id_d = day_d.strftime('%Y%m%d') + "010103-" + token_d data_d = { "ID": id_d, "Type": "NodeDocument", "Properties": { "id": id_d, # 标题格式 yyyy-mm-dd "title": day_d.strftime('%Y-%m-%d'), "updated": datetime.now().strftime('%Y%m%d%H%M%S') } } # 在年度文件夹 / 月度文件夹下,创建当日文档 filename_d = path_k + "/" + id_y +"/" + id_m + "/" + id_d + ".sy" f = open(filename_d, "x") f.write(json.dumps(data_d, indent=4)) f.close() tkinter.messagebox.showinfo("提示", "感谢等待,创建已完成")

操作

环境

  • win10
  • 思源笔记 1.8.4

步骤

  1. 选择 daily note 笔记本——...更多——打开文件位置;
  2. 关闭思源笔记;
  3. 将上方代码保存为 py 文件,修改第 11 和 12 行的起始结束日期,不跨年
  4. 文件运行完成后会出现成功的提示弹窗;
  5. 将生成的 result 文件夹下所有文件及文件夹复制到 daily note 笔记本对应的本地文件夹下。不含 result 文件夹
  6. 打开思源笔记,可能需要等待几分钟,再点击文档树——...更多——重建索引,完成;

风险提示

本人几乎无 Python 基础,代码为搜索 + 摸索产出,此贴主要是分享探讨,不排除使用时引发其他问题,建议新建工作目录测试成功后再用于正式目录。

有更好的优化方案也欢迎大家指教,谢谢!​

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    23372 引用 • 94453 回帖 • 1 关注
2 操作
Syngo 在 2022-02-27 18:45:36 更新了该帖
Syngo 在 2022-02-27 18:25:10 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • abumn

    没有 python 基础还能做出这么厉害的工作!太强了

    1 回复
  • 其他回帖
  • buzzingbee

    楼主虽然可能没有 python 基础,但别的基础好啊,很专业了

  • WeiCJ

    直接新建 sy 文件也可以实现需求

    最近思源的 api 基本稳定了, 如果使用 api 的话会更加简单一些,后续如果有其他功能需求,实现起来也会方便许多

    有兴趣可以尝试一下哈 😄

  • thelamb 1 via iPhone

    lz 是为了把旧资料通过 daily note 的形式补充进来

  • 查看全部回帖