Files
py-chan/writer.py
2026-08-11 16:18:44 +08:00

87 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""产物输出图片本地化、TS 数据文件、JSON、Markdown 归档。"""
import re
from pathlib import Path
from config import CHAN_IMG_DIR, CHAN_IMG_URL_PREFIX, CHAN_DATA_FILE
from fetcher import fetch_bytes
def _guess_ext(url: str) -> str:
m = re.search(r"\.(png|jpe?g|gif|webp|bmp|svg)", url, re.I)
return "." + m.group(1).lower() if m else ".png"
def remote_image_resolver(src: str, alt: str) -> str:
"""不下载图片,正文保留远程链接。"""
return f"![{alt}]({src})"
def make_image_resolver(p_num: int, refresh: bool = False):
"""返回一个闭包:把图片下载到 Vue 项目的 public 目录,返回可访问 URL。
下载失败时回退到远程链接,保证正文不会因单张图片而中断。
"""
CHAN_IMG_DIR.mkdir(parents=True, exist_ok=True)
seq = 0
def resolve(src: str, alt: str) -> str:
nonlocal seq
seq += 1
ext = _guess_ext(src)
fname = f"p{p_num:03d}_{seq:02d}{ext}"
dest = CHAN_IMG_DIR / fname
if refresh or not dest.exists():
try:
dest.write_bytes(fetch_bytes(src))
except Exception as e: # noqa: BLE001
print(f" [img] 下载失败,使用远程链接:{src}{e}")
return f"![{alt}]({src})"
url = f"{CHAN_IMG_URL_PREFIX}/{fname}"
return f"![{alt}]({url})"
return resolve
def _ts_escape(s: str) -> str:
"""转义模板字符串中的特殊字符:反斜杠、反引号、${"""
return s.replace("\\", "\\\\").replace("`", "\\`").replace("${", "\\${")
def _ts_str(s: str) -> str:
return "`" + _ts_escape(s) + "`"
def write_ts_file(articles: list[dict], path: Path, stamp: str) -> None:
"""生成 ``chanlun.ts``,导出 ``chanlunLessons: Article[]``。"""
lines: list[str] = []
lines.append("import type { Article } from '@/types/article'")
lines.append("")
lines.append("/**")
lines.append(" * 缠论《教你炒股票》系列原文")
lines.append(f" * 共 {len(articles)} 课 · 抓取自 https://www.kline8.com/chanlun")
lines.append(f" * 由 py-chan 爬虫自动生成 · {stamp}")
lines.append(" */")
lines.append("export const chanlunLessons: Article[] = [")
for a in articles:
lines.append(" {")
lines.append(f" id: {_ts_str(a['id'])},")
lines.append(f" slug: {_ts_str(a['slug'])},")
lines.append(" category: 'chanlun',")
lines.append(f" title: {_ts_str(a['title'])},")
lines.append(f" subtitle: {_ts_str(a['subtitle'])},")
lines.append(f" lesson: {a['lesson']},")
lines.append(f" date: {_ts_str(a['date'])},")
tags = ", ".join(_ts_str(t) for t in a["tags"])
lines.append(f" tags: [{tags}],")
lines.append(f" excerpt: {_ts_str(a['excerpt'])},")
lines.append(f" readingTime: {a['readingTime']},")
lines.append(f" content: {_ts_str(a['content'])},")
lines.append(" },")
lines.append("]")
lines.append("")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("\n".join(lines), encoding="utf-8")