| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- 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''
- 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)
|