Front Matter 추가

Front Matter 추가

스크립트

import os
import datetime
import re
import yaml
# 메타데이터 템플릿
metadata_template = {
    "title": "{title}",
    "weight": 10,
    "categories": [],
    "tags": [],
    "toc": True,
    "sidebar": {
        "collapsed": True,
    },
    "cascade": {
        "type": "docs",
    }
}
# YAML 로드 및 덤프 도우미 함수
def load_yaml(content):
    return yaml.safe_load(content)
def dump_yaml(metadata):
    return yaml.dump(metadata, sort_keys=False, default_flow_style=False, allow_unicode=True)
# 파일 경로로부터 카테고리와 태그를 추출하는 함수
def extract_categories_and_tags(file_path, base_dir):
    # base_dir을 기준으로 상대 경로를 얻음
    relative_path = os.path.relpath(file_path, base_dir)
    # 상대 경로를 분할하여 폴더 구조를 얻음
    parts = relative_path.split(os.sep)
    
    # 최상위 폴더를 카테고리로 설정
    category = parts[0]
    # 모든 상위 폴더를 태그로 설정
    tags = parts[:-1]  # 파일 이름을 제외한 모든 폴더
    
    return category, tags
# 메타데이터를 업데이트하거나 추가하는 함수
def update_metadata(content, title, category, tags):
    new_metadata = metadata_template.copy()
    new_metadata["title"] = title
    new_metadata["categories"] = [category]
    new_metadata["tags"] = tags
    # 기존 메타데이터가 있는지 확인
    metadata_match = re.match(r"---(.*?)---", content, re.DOTALL)
    if metadata_match:
        existing_metadata_str = metadata_match.group(1)
        existing_metadata = load_yaml(existing_metadata_str)
        original_metadata = existing_metadata.copy()  # 변경 전 메타데이터를 저장
        # 필요한 필드가 없으면 추가, 있으면 유지
        for key, value in metadata_template.items():
            if key not in existing_metadata:
                existing_metadata[key] = value
            elif isinstance(value, dict):
                for subkey, subvalue in value.items():
                    if subkey not in existing_metadata[key]:
                        existing_metadata[key][subkey] = subvalue
        if existing_metadata != original_metadata:  # 다른 메타데이터가 변경된 경우에만 업데이트
            # 새로운 메타데이터 YAML 생성
            updated_metadata_str = dump_yaml(existing_metadata)
            new_metadata_block = f"---\n{updated_metadata_str}---\n"
            return content.replace(metadata_match.group(0), new_metadata_block).replace('\n\n', '\n'), 'updated'
        else:
            return content, 'unchanged'
    else:
        # 메타데이터가 없는 경우 새 메타데이터 추가
        new_metadata_str = dump_yaml(new_metadata)
        new_metadata_block = f"---\n{new_metadata_str}---\n"
        return new_metadata_block + content.lstrip(), 'added'
# 특정 디렉토리 내의 모든 파일에 메타데이터 추가 또는 업데이트
def add_metadata_to_files(directory):
    total_files_count = 0
    updated_count = 0
    ignored_count = 0
    added_count = 0
    
    for root, dirs, files in os.walk(directory):
        dirs[:] = [d for d in dirs if not d.startswith('.') and not d.startswith('_')]
        for file in files:
            if file.endswith('.md') and file != "_index.md":
                total_files_count += 1
                file_path = os.path.join(root, file)
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                    # 파일 이름을 제목으로 사용 (확장자 제외)
                    title = os.path.splitext(file)[0]
                    # 카테고리와 태그 추출
                    category, tags = extract_categories_and_tags(file_path, directory)
                    updated_content, status = update_metadata(content, title, category, tags)
                    if status == 'updated':
                        updated_count += 1
                    elif status == 'added':
                        added_count += 1
                    if status in ('updated', 'added'):
                        try:
                            with open(file_path, 'w', encoding='utf-8') as f:
                                f.write(updated_content)
                            print(f"Updated metadata in {file_path}")
                        except Exception as e:
                            print(f"Error writing to {file_path}: {e}")
                except Exception as e:
                    print(f"Error reading {file_path}: {e}")
                    ignored_count += 1
    return total_files_count, updated_count, ignored_count, added_count
# 디렉토리 경로를 설정하세요
source_dir = os.environ.get('SOURCE_DIR', r"D:\obsidian")
print(f"Add Metadata start")
total_files_count, updated_count, ignored_count, added_count = add_metadata_to_files(source_dir)
# 로그 출력
print()
print(f"Total files processed: {total_files_count}")
print(f"Metadata updated: {updated_count}")
print(f"Metadata ignored: {ignored_count}")
print(f"Metadata added: {added_count}")
print(f"Add Metadata end")
print()

기능

메타데이터 템플릿 정의

  • 기본 메타데이터 템플릿을 설정하여 파일에 추가할 메타데이터의 기본 구조를 제공합니다.
  • 이 템플릿에는 title, weight, categories, tags, toc, sidebar, cascade가 포함됩니다.

파일 경로 기반 카테고리 및 태그 추출

  • 각 파일의 경로를 기반으로 카테고리와 태그를 자동으로 추출합니다.
  • 최상위 폴더를 카테고리로 사용하고, 모든 상위 폴더를 태그로 사용합니다.

메타데이터 업데이트 및 추가

  • 기존 파일의 메타데이터를 읽고, 누락된 필드는 템플릿을 기반으로 추가합니다.
  • 메타데이터가 없는 파일에는 새 메타데이터를 추가합니다.
  • 메타데이터가 변경되거나 추가된 파일은 수정 후 저장됩니다.