summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hugo-merge-sections/script.py83
-rw-r--r--hugo-tag-wrangler/script.py55
2 files changed, 138 insertions, 0 deletions
diff --git a/hugo-merge-sections/script.py b/hugo-merge-sections/script.py
new file mode 100644
index 0000000..7ff110a
--- /dev/null
+++ b/hugo-merge-sections/script.py
@@ -0,0 +1,83 @@
+import os
+import shutil
+import frontmatter
+from pathlib import Path
+
+# 配置路径
+CONTENT_DIR = 'content'
+SOURCE_SECTIONS = ['essays', 'posts']
+TARGET_SECTION = 'articles'
+
+def process_file(file_path, root_section_name):
+ """
+ 处理 Markdown 文件
+ file_path: 当前文件的 Path 对象
+ root_section_name: 所属的根分区名 ('essays' 或 'posts')
+ """
+ # 1. 加载 Front Matter (使用 TOML)
+ try:
+ with open(file_path, 'r', encoding='utf-8') as f:
+ post = frontmatter.load(f, handler=frontmatter.TOMLHandler())
+ except Exception as e:
+ print(f"解析错误 {file_path}: {e}")
+ return
+
+ # 2. 确定基础标识 (Stem)
+ # 如果是 index.md,标识取其父文件夹名;否则取文件名本身
+ is_bundle = (file_path.name == 'index.md')
+ file_stem = file_path.parent.name if is_bundle else file_path.stem
+
+ # 3. 确定最终文件名与 Slug 逻辑
+ # 只有当 slug 存在且不为空字符串时才使用它
+ slug = post.get('slug')
+ final_identifier = slug if (slug and str(slug).strip()) else file_stem
+
+ # 4. 构造 URL
+ # 保持原有的 section 路径前缀
+ if 'url' not in post:
+ post['url'] = f"/{root_section_name}/{final_identifier}/"
+
+ # 5. 确定目标路径 (统一移到 articles/ 下)
+ target_dir = Path(CONTENT_DIR) / TARGET_SECTION
+ target_dir.mkdir(parents=True, exist_ok=True)
+ target_file_path = target_dir / f"{final_identifier}.md"
+
+ # 6. 回写并清理
+ new_content = frontmatter.dumps(post, handler=frontmatter.TOMLHandler())
+ with open(target_file_path, 'w', encoding='utf-8') as f:
+ f.write(new_content)
+
+ # 清理原文件/文件夹
+ if is_bundle:
+ shutil.rmtree(file_path.parent)
+ else:
+ file_path.unlink()
+
+ print(f"✓ 转换: {file_path.relative_to(CONTENT_DIR)} -> articles/{final_identifier}.md")
+
+def main():
+ content_root = Path(CONTENT_DIR)
+
+ for section in SOURCE_SECTIONS:
+ section_path = content_root / section
+ if not section_path.exists():
+ continue
+
+ print(f"\n正在递归扫描分区: {section}...")
+
+ # 使用 rglob 递归查找所有 .md 文件 (包括二级目录、Page Bundles)
+ # 注意:使用 list 固化搜索结果,因为我们会边处理边删除
+ all_md_files = list(section_path.rglob("*.md"))
+
+ # 排除 _index.md (分区首页通常不需要这样迁移)
+ files_to_process = [f for f in all_md_files if f.name != "_index.md"]
+
+ for md_file in files_to_process:
+ if not md_file.exists(): # 防止 bundle 模式下 index.md 已被父目录删除
+ continue
+ process_file(md_file, section)
+
+ print("\n--- 迁移完成 ---")
+
+if __name__ == "__main__":
+ main()
diff --git a/hugo-tag-wrangler/script.py b/hugo-tag-wrangler/script.py
new file mode 100644
index 0000000..4e757ea
--- /dev/null
+++ b/hugo-tag-wrangler/script.py
@@ -0,0 +1,55 @@
+import os
+import argparse
+import frontmatter
+from frontmatter.default_handlers import TOMLHandler
+
+def process_files(content_dir, action, target, new_name=None):
+ handler = TOMLHandler()
+ count = 0
+
+ for root, dirs, files in os.walk(content_dir):
+ for file in files:
+ if file.endswith('.md'):
+ path = os.path.join(root, file)
+ try:
+ post = frontmatter.load(path, handler=handler)
+ modified = False
+
+ # 获取 categories(通常是字符串)
+ current_cat = post.get('categories')
+
+ if action == 'delete' and current_cat == target:
+ # 直接从字典中删除该键
+ del post['categories']
+ modified = True
+
+ elif action == 'rename' and current_cat == target:
+ # 更新为新的字符串
+ post['categories'] = new_name
+ modified = True
+
+ if modified:
+ with open(path, 'wb') as f:
+ frontmatter.dump(post, f, handler=handler)
+ print(f"✅ 已处理: {path}")
+ count += 1
+
+ except Exception as e:
+ print(f"⚠️ 跳过/错误 {path}: {e}")
+
+ print(f"\n✨ 完成!修改了 {count} 个文件。")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Hugo TOML 单分类管理工具")
+ parser.add_argument("--dir", default="content", help="Hugo content 目录")
+
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument("--delete", metavar="分类名")
+ group.add_argument("--rename", nargs=2, metavar=("旧分类", "新分类"))
+
+ args = parser.parse_args()
+
+ if args.delete:
+ process_files(args.dir, 'delete', args.delete)
+ elif args.rename:
+ process_files(args.dir, 'rename', args.rename[0], args.rename[1])