Files
ConfigData/每日听力/完整版_生成英语听力PDF脚本.py
2026-10-07 10:57:38 +08:00

210 lines
12 KiB
Python
Raw Permalink 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.
# -*- coding: utf-8 -*-
"""
完整版:每日英语听力材料 PDF 生成脚本(学习用)
本版相对精简版的变化:
- 填入今天(2026-10-01 国庆主题)完整的 10 句材料
- 注释更细,每个环节说明"为什么这么做"
- 加入"中文翻译 + 听力技巧 + 页脚"完整结构
依赖:pip install reportlab
系统字体(以 Ubuntu/Debian 为例):
- DejaVu Sans:英文 + IPA 音标字符
- 文鼎 UMingCN(/usr/share/fonts/truetype/arphic/uming.ttc):中文字符
"""
import html as h
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.platypus import (Paragraph, SimpleDocTemplate, Spacer,
Table, TableStyle)
# =====================================================================
# 第 1 步:注册字体
# ---------------------------------------------------------------------
# reportlab 内置的 Helvetica/Times 等字体只有拉丁字符,
# 中文和 IPA 音标(/ˈtə/ 这类符号)必须加载系统字体。
# 注意:reportlab 只支持 TrueType 轮廓,不支持 CFF(OTF),
# 所以 NotoSansCJK.otf 用不了,中文选了文鼎 TrueType。
# =====================================================================
BASE = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
BASE_BOLD = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'
CJK = '/usr/share/fonts/truetype/arphic/uming.ttc'
# 注册英文/IPA 字体(DejaVu 覆盖音标符号)
pdfmetrics.registerFont(TTFont('Base', BASE))
pdfmetrics.registerFont(TTFont('Base-Bold', BASE_BOLD))
# 中文用 .ttc 集合字体,subfontIndex=0 表示取第 0 个子字体(UMingCN)
pdfmetrics.registerFont(TTFont('CJK', CJK, subfontIndex=0))
def esc(s: str) -> str:
"""转义 < > & 等字符。Paragraph 内容按 XML 解析,不转义会把内容当标签。"""
return h.escape(s, quote=False)
# =====================================================================
# 第 2 步:定义排版样式(ParagraphStyle)
# ---------------------------------------------------------------------
# fontName 指定字体;leading 是行高;spaceBefore/After 是段前后间距;
# HexColor 定义颜色('#8B0000' 是深红,'#2F5D8A' 是深蓝)。
# =====================================================================
title = ParagraphStyle('title', fontName='Base-Bold', fontSize=18, leading=24,
textColor=colors.HexColor('#B22222'), alignment=1, spaceAfter=6)
meta = ParagraphStyle('meta', fontName='CJK', fontSize=10, leading=14,
textColor=colors.HexColor('#666666'), alignment=1, spaceAfter=10)
h1 = ParagraphStyle('h1', fontName='CJK', fontSize=13, leading=18,
textColor=colors.HexColor('#8B0000'), spaceBefore=10, spaceAfter=6)
en = ParagraphStyle('en', fontName='Base', fontSize=11.5, leading=17, spaceBefore=4)
ipa = ParagraphStyle('ipa', fontName='Base', fontSize=9.5, leading=14,
textColor=colors.HexColor('#555555'), leftIndent=6, spaceAfter=2)
note = ParagraphStyle('note', fontName='CJK', fontSize=9.5, leading=14,
textColor=colors.HexColor('#2F5D8A'), leftIndent=12, spaceAfter=4)
zh = ParagraphStyle('zh', fontName='CJK', fontSize=11, leading=18, spaceBefore=3)
tip = ParagraphStyle('tip', fontName='CJK', fontSize=10.5, leading=16, spaceBefore=2)
foot = ParagraphStyle('foot', fontName='CJK', fontSize=9, leading=13,
textColor=colors.HexColor('#999999'))
def sen(num: str, text: str):
"""句子行:编号用粗体(Base-Bold),正文用普通字体(Base)。"""
return Paragraph('<font name="Base-Bold">%s</font> %s' % (esc(num), esc(text)), en)
# =====================================================================
# 第 3 步:准备内容数据(今天的 10 句国庆主题)
# =====================================================================
sentences = [
# (编号, 英文原文, IPA 音标, 发音要点中文说明)
("1.", "Today is October 1st — China's National Day.",
"/təˈdeɪ ɪz oʊkˈtoʊbər fɜːrst | ˈtʃaɪnəz ˈnæʃənəl deɪ/",
"● 连读:October 1st 中 /r/ 与 /f/ 自然衔接。"),
("2.", "Streets are decorated with red flags, and cities glow with lanterns and flowers.",
"/striːts ər ˈdekəreɪtɪd wɪð red flægz | ənd ˈsɪtiz gloʊ wɪð ˈlæntərnz ənd ˈflaʊərz/",
"● 重读:decorated、glow 是画面词,加重读出画面感。"),
("3.", "For many, this is the start of a seven-day holiday filled with joy.",
"/fɔːr ˈmeni | ðɪs ɪz ðə stɑːrt əv ə ˈsevən deɪ ˈhɑːlədeɪ fɪld wɪð dʒɔɪ/",
"● 弱读:of a 读 /əv ə/,轻快不拖。"),
("4.", "Families gather for meals and laughter.",
"/ˈfæməliz ˈgæðər fɔːr miːlz ənd ˈlæftər/",
"● 重读:gather、laughter 读出团聚的温馨。"),
("5.", "Some people travel to famous mountains and rivers, while others enjoy quiet time at home.",
"/sʌm ˈpiːpəl ˈtrævəl tuː ˈfeɪməs ˈmaʊntənz ənd ˈrɪvərz | waɪl ˈʌðərz ɪnˈdʒɔɪ ˈkwaɪət taɪm æt hoʊm/",
"● 对比:some...while others... 前后语调一扬一落。"),
("6.", "In the evening, the night sky comes alive with fireworks, painting the darkness with color.",
"/ɪn ði ˈiːvnɪŋ | ðə naɪt skaɪ kʌmz əˈlaɪv wɪð ˈfaɪrwɜːrks | ˈpeɪntɪŋ ðə ˈdɑːrknəs wɪð ˈkʌlər/",
"● 连读:comes alive → /kʌmz əˈlaɪv/,t 弱化带过。"),
("7.", "On this day, we also take a moment to look back at how far the country has come.",
"/ɑːn ðɪs deɪ | wi ɔːlsoʊ teɪk ə ˈmoʊmənt tə lʊk bæk æt haʊ fɑːr ðə ˈkʌntri hæz kʌm/",
"● 重读:how far 是本句情感重心,放慢强调。"),
("8.", "From ancient civilization to modern achievement, the story continues every day, written by ordinary people like you and me.",
"/frəm ˈeɪnʃənt ˌsɪvələˈzeɪʃən tuː ˈmɑːdərn əˈtʃiːvmənt | ðə ˈstɔːri kənˈtɪnjuːz ˈevri deɪ | ˈrɪtən baɪ ˈɔːrdəneri ˈpiːpəl laɪk juː ənd miː/",
"● 节奏:长句用逗号自然换气,ordinary people 放轻读出温暖感。"),
("9.", "So whatever you do today — travel, rest, or celebrate — remember to enjoy the moment.",
"/soʊ wətˈevər ju duː təˈdeɪ | ˈtrævəl | rest | ɔːr ˈseləbreɪt | rɪˈmembər tə ɪnˈdʒɔɪ ðə ˈmoʊmənt/",
"● 并列:travel / rest / celebrate 三个词逐个重读,节奏感十足。"),
("10.", "Wishing you a wonderful National Day, full of happiness and good memories!",
"/ˈwɪʃɪŋ ju ə ˈwʌndərfəl ˈnæʃənəl deɪ | fʊl əv ˈhæpinəs ənd gʊd ˈmeməriz/",
"● 语气:收尾上扬,读出祝福的温度。"),
]
translation = ("今天是 10 月 1 日——中国的国庆节。街道装点着红旗,城市里灯笼与鲜花交相辉映。对许多人来说,"
"这是充满欢乐的七天假期的开始。\n\n"
"家人团聚,共享美食与欢笑。有人去游览名山大川,有人在家享受悠闲时光。到了晚上,夜空被烟花点亮,"
"为黑暗染上绚丽的色彩。\n\n"
"在这个日子里,我们也停下来回望国家走过的路。从古老的文明到现代的成就,故事每天都在继续,"
"由你我这样的普通人书写着。\n\n"
"所以无论你今天做什么——旅行、休息,还是庆祝——记得享受当下。祝你国庆节快乐,幸福满满,"
"留下美好的回忆!")
words = [
# (单词, 音标, 中文释义)
("decorate", "/ˈdekəreɪt/", "装饰"),
("glow", "/gloʊ/", "发光,焕发光彩"),
("lantern", "/ˈlæntərn/", "灯笼"),
("fireworks", "/ˈfaɪrwɜːrks/", "烟花"),
("come alive", "—", "热闹起来,焕发生机"),
("look back", "—", "回顾"),
("achievement", "/əˈtʃiːvmənt/", "成就"),
("ordinary", "/ˈɔːrdəneri/", "普通的,平凡的"),
]
tips = [
"1. 早餐时 / 通勤路上:把音频当背景声循环放 2–3 遍,不求听懂每个词,只抓熟悉的词和整体语气;",
"2. 散步时:听到认识的词(如 fireworks、family)心里默念一遍;",
"3. 睡前:再精听一遍今天带音标的句子,跟着读两句。",
"泛听养“语感”,精听抠“细节”,两者搭配,假期结束你会发现自己耳朵更灵了。",
]
# =====================================================================
# 第 4 步:组装文档内容(story 是一个"流",元素按顺序排列并自动分页)
# =====================================================================
story = []
# 标题:一行里混排中文和英文,用 <font> 标签分别指定字体
story.append(Paragraph('<font name="Base-Bold">Happy National Day!</font>'
'<font name="CJK">(国庆节快乐)</font>', title))
story.append(Paragraph('每日英语听力推送 · 2026-10-01(周四)· 国庆主题 · 约1分钟朗读量', meta))
story.append(Spacer(1, 4))
# 一、英文原文(10 句,每句 = 句子 + 音标 + 要点)
story.append(Paragraph('一、英文原文(逐句 + IPA 音标)', h1))
for num, text, ip, n in sentences:
story.append(sen(num, text))
story.append(Paragraph(esc(ip), ipa))
story.append(Paragraph(esc(n), note))
# 二、中文翻译(<br/> 实现段内换行)
story.append(Paragraph('二、中文翻译', h1))
story.append(Paragraph('<br/>'.join(esc(t) for t in translation.split('\n\n')), zh))
# 三、生词与短语(用 Table 表格呈现,更清晰)
story.append(Paragraph('三、生词与短语', h1))
cell_en = ParagraphStyle('c1', fontName='Base', fontSize=10, leading=13)
cell_ipa = ParagraphStyle('c2', fontName='Base', fontSize=10, leading=13,
textColor=colors.HexColor('#555555'))
cell_zh = ParagraphStyle('c3', fontName='CJK', fontSize=10, leading=13)
head = ParagraphStyle('ch', fontName='CJK', fontSize=10, leading=13, textColor=colors.white)
data = [[Paragraph('单词/短语', head), Paragraph('音标', head), Paragraph('释义', head)]]
for w, ip, z in words:
data.append([Paragraph(esc(w), cell_en),
Paragraph(esc(ip), cell_ipa),
Paragraph(esc(z), cell_zh)])
tbl = Table(data, colWidths=[52*mm, 58*mm, 62*mm])
tbl.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#8B0000')), # 表头深红底
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#F5F0E6')]), # 斑马纹
('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor('#CCCCCC')), # 网格线
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 5),
('TOPPADDING', (0, 0), (-1, -1), 4),
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
]))
story.append(tbl)
# 四、听力技巧
story.append(Paragraph('四、听力小技巧:假日“泛听”法', h1))
for t in tips:
story.append(Paragraph(esc(t), tip))
# 页脚说明
story.append(Spacer(1, 10))
story.append(Paragraph('<font name="CJK">本文档可离线保存,配合 MP3 音频文件使用:先听 → 逐句跟读 → 对照理解。</font>', foot))
# =====================================================================
# 第 5 步:写出 PDF
# ---------------------------------------------------------------------
# SimpleDocTemplate 自动分页;title 参数写入 PDF 文档元信息。
# =====================================================================
doc = SimpleDocTemplate("每日英语听力_2026-10-01_国庆主题_完整版.pdf", pagesize=A4,
rightMargin=18*mm, leftMargin=18*mm,
topMargin=16*mm, bottomMargin=16*mm,
title="每日英语听力 2026-10-01 国庆主题")
doc.build(story)
print("PDF generated OK")
#(注:内容由AI生成)