Browse Source

refactor: 抽取工具函数到helpers.py并修复页脚年份

Co-authored-by: aider (deepseek/deepseek-v4-pro) <aider@aider.chat>
Your Name 3 ngày trước cách đây
mục cha
commit
d168e272f7
3 tập tin đã thay đổi với 93 bổ sung88 xóa
  1. 10 87
      app.py
  2. 82 0
      helpers.py
  3. 1 1
      templates/base.html

+ 10 - 87
app.py

@@ -1,8 +1,6 @@
-import os
 import re
 import json
 import time
-import uuid
 import shutil
 from datetime import datetime, timezone
 from pathlib import Path
@@ -18,10 +16,18 @@ from flask import (
     jsonify,
 )
 from werkzeug.utils import secure_filename
-import markdown
-from bs4 import BeautifulSoup
 
 import config
+from helpers import (
+    allowed_file,
+    load_index,
+    save_index,
+    fix_image_paths,
+    extract_summary,
+    extract_thumbnail,
+    render_markdown,
+    generate_static_page,
+)
 
 app = Flask(__name__)
 app.config.from_object(config)
@@ -41,89 +47,6 @@ if not config.INDEX_FILE.exists():
         json.dump([], f, ensure_ascii=False, indent=2)
 
 
-def allowed_file(filename: str) -> bool:
-    """检查文件扩展名是否允许"""
-    return (
-        "." in filename
-        and filename.rsplit(".", 1)[1].lower() in config.ALLOWED_EXTENSIONS
-    )
-
-
-def load_index() -> list:
-    """加载文章索引"""
-    with open(config.INDEX_FILE, "r", encoding="utf-8") as f:
-        return json.load(f)
-
-
-def save_index(index: list):
-    """保存文章索引"""
-    with open(config.INDEX_FILE, "w", encoding="utf-8") as f:
-        json.dump(index, f, ensure_ascii=False, indent=2)
-
-
-def fix_image_paths(md_content: str, post_id: str) -> str:
-    """将 Markdown 中的本地图片路径替换为可访问的 URL"""
-    pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
-
-    def repl(match):
-        alt, src = match.groups()
-        # 仅当 src 不含 '/' 或 'http' 且扩展名为图片时视为本地文件
-        if (
-            not src.startswith(("http://", "https://", "/", "#"))
-            and "." in src
-        ):
-            new_src = f"/static/uploads/posts/{post_id}/{src}"
-            return f'![{alt}]({new_src})'
-        return match.group(0)
-
-    return re.sub(pattern, repl, md_content)
-
-
-def extract_summary(html_body: str, max_chars: int = 200) -> str:
-    """从 HTML 中提取纯文本摘要(返回完整文本)"""
-    soup = BeautifulSoup(html_body, "html.parser")
-    text = soup.get_text()
-    # 去除多余空白
-    text = re.sub(r"\s+", " ", text).strip()
-    return text
-
-
-def extract_thumbnail(html_body: str) -> str:
-    """从 HTML 中提取第一张图片的 URL"""
-    soup = BeautifulSoup(html_body, "html.parser")
-    img = soup.find("img")
-    if img and img.get("src"):
-        return img["src"]
-    return ""
-
-
-def render_markdown(md_content: str) -> str:
-    """将 Markdown 渲染为 HTML"""
-    md = markdown.Markdown(
-        extensions=[
-            "extra",
-            "codehilite",
-            "tables",
-            "fenced_code",
-        ]
-    )
-    return md.convert(md_content)
-
-
-def generate_static_page(post_id: str, title: str, html_body: str, date: str, thumbnail: str):
-    """生成独立的静态 HTML 文件"""
-    rendered = render_template(
-        "post_template.html",
-        title=title,
-        content=html_body,
-        date=date,
-        thumbnail=thumbnail,
-    )
-    output_path = config.GENERATED_FOLDER / f"{post_id}.html"
-    with open(output_path, "w", encoding="utf-8") as f:
-        f.write(rendered)
-
-
 # ==================== 路由 ====================
 
 

+ 82 - 0
helpers.py

@@ -0,0 +1,82 @@
+import re
+import json
+from pathlib import Path
+from datetime import datetime, timezone
+from flask import render_template
+from werkzeug.utils import secure_filename
+import markdown
+from bs4 import BeautifulSoup
+import config
+
+def allowed_file(filename: str) -> bool:
+    """检查文件扩展名是否允许"""
+    return (
+        "." in filename
+        and filename.rsplit(".", 1)[1].lower() in config.ALLOWED_EXTENSIONS
+    )
+
+def load_index() -> list:
+    """加载文章索引"""
+    with open(config.INDEX_FILE, "r", encoding="utf-8") as f:
+        return json.load(f)
+
+def save_index(index: list):
+    """保存文章索引"""
+    with open(config.INDEX_FILE, "w", encoding="utf-8") as f:
+        json.dump(index, f, ensure_ascii=False, indent=2)
+
+def fix_image_paths(md_content: str, post_id: str) -> str:
+    """将 Markdown 中的本地图片路径替换为可访问的 URL"""
+    pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
+    def repl(match):
+        alt, src = match.groups()
+        # 仅当 src 不含 '/' 或 'http' 且扩展名为图片时视为本地文件
+        if (
+            not src.startswith(("http://", "https://", "/", "#"))
+            and "." in src
+        ):
+            new_src = f"/static/uploads/posts/{post_id}/{src}"
+            return f'![{alt}]({new_src})'
+        return match.group(0)
+    return re.sub(pattern, repl, md_content)
+
+def extract_summary(html_body: str, max_chars: int = 200) -> str:
+    """从 HTML 中提取纯文本摘要(返回完整文本)"""
+    soup = BeautifulSoup(html_body, "html.parser")
+    text = soup.get_text()
+    # 去除多余空白
+    text = re.sub(r"\s+", " ", text).strip()
+    return text
+
+def extract_thumbnail(html_body: str) -> str:
+    """从 HTML 中提取第一张图片的 URL"""
+    soup = BeautifulSoup(html_body, "html.parser")
+    img = soup.find("img")
+    if img and img.get("src"):
+        return img["src"]
+    return ""
+
+def render_markdown(md_content: str) -> str:
+    """将 Markdown 渲染为 HTML"""
+    md = markdown.Markdown(
+        extensions=[
+            "extra",
+            "codehilite",
+            "tables",
+            "fenced_code",
+        ]
+    )
+    return md.convert(md_content)
+
+def generate_static_page(post_id: str, title: str, html_body: str, date: str, thumbnail: str):
+    """生成独立的静态 HTML 文件"""
+    rendered = render_template(
+        "post_template.html",
+        title=title,
+        content=html_body,
+        date=date,
+        thumbnail=thumbnail,
+    )
+    output_path = config.GENERATED_FOLDER / f"{post_id}.html"
+    with open(output_path, "w", encoding="utf-8") as f:
+        f.write(rendered)

+ 1 - 1
templates/base.html

@@ -38,7 +38,7 @@
     </main>
 
     <footer class="footer">
-        <p>&copy; {{ now.year if now else 2026 }} 个人博客系统</p>
+        <p>&copy; 2026 个人博客系统</p>
     </footer>
 
     <script src="{{ url_for('static', filename='js/main.js') }}"></script>