给笔记批量添加 front matter
2025/4/17...大约 2 分钟
给笔记批量添加 front matter
什么是 front matter
markdown 文件中的front matter指的是以yaml格式在文件开头增加的元数据。front matter需要用---包裹
为什么要添加 front matter
文件的创建时间不准。基于 git 做同步的,比如在公司新建了几个文件,但是回家后并没有立即打开 obsidian 做同步,过了几天再拉下最新的文件,文件创建时间肯定变成当天了,而且是同时拉下来的,创建时间肯定一致了。
 怎么解决呢?front matter就能解决这个问题。
增量文档
使用Templater插件制作front matter模板
---
title: <% tp.file.title %>
category:
tag:
date: <% tp.date.now("YYYY-MM-DD") %>
create_date: <% tp.file.creation_date() %>
---
# <% tp.file.title %>存量文档
用 python 脚本批量添加
# 添加依赖 处理 front matter的库
pip install python-frontmatter脚本内容,添加了 title、category、tag、date、create_date ,可以根据自己喜好调整
# coding: utf-8
import os
import re
import time
import frontmatter
# 更新md文件的front matter:1.增加创建时间;2.提取tag
def update_front_matter(file):
    with open(file, 'r', encoding='utf-8') as f:
       post = frontmatter.loads(f.read())
    
    is_write = False
    if not post.metadata.get('title', None):
        post['title'] = file.split('\\')[-1].split('.')[0]
        if not is_write:
            is_write = True
    if not post.metadata.get('create_date', None):
        timeArray = time.localtime((os.path.getctime(file)))
        post['create_date'] = time.strftime("%Y-%m-%d %H:%M", timeArray)
        if not is_write:
            is_write = True
    
    if not post.metadata.get('date', None):
        timeArray = time.localtime((os.path.getctime(file)))
        post['date'] = time.strftime("%Y-%m-%d", timeArray)
        if not is_write:
            is_write = True
        
    ret_category = file.split('\\')[4].split('.')
    if post.get("category", []) != set(ret_category): 
        post['category'] = ret_category
        if not is_write:
            is_write = True
    # 将代码块内容去掉
    temp_content = re.sub(r'```([\s\S]*?)```[\s]?','',post.content)
    # 获取tag列表
    tags = re.findall(r'\s#[\u4e00-\u9fa5a-zA-Z]+', temp_content, re.M|re.I)
    ret_tags = list(set(map(lambda x: x.strip(), tags)))
    print('tags in content: ', ret_tags)
    print('tags in front matter: ', post.get("tags", []))
    if len(ret_tags) == 0:
        pass
    elif post.get("tags", []) != set(ret_tags): 
        post['tags'] = ret_tags
        if not is_write:
            is_write = True
    
    if is_write:
        with open(file, 'w', encoding='utf-8') as f:
            f.write(frontmatter.dumps(post))
# 递归获取提供目录下所有文件
def list_all_files(root_path, ignore_dirs=[]):
    files = []
    default_dirs = [".git", ".obsidian", ".config"]
    ignore_dirs.extend(default_dirs)
    for parent, dirs, filenames in os.walk(root_path):
        dirs[:] = [d for d in dirs if not d in ignore_dirs]
        filenames = [f for f in filenames if not f[0] == '.']
        for file in filenames:
            if file.endswith(".md"):
                files.append(os.path.join(parent, file))
    return files
if __name__ == "__main__":
    # file_path = 'D:/life-doc/docs/view/algorithm/readme.md'
    # update_front_matter(file_path)
    ignore_dirs = [".obsidian"]
    files = list_all_files('D:\\life-doc\\docs\\view', ignore_dirs=ignore_dirs)
    print("current dir: ", os.path.dirname(os.path.abspath(__file__)))
    for file in files:
        print("---------------------------------------------------------------")
        print('current file: ', file)
        update_front_matter(file)
        time.sleep(1)