Files
KSP_project/scripts/build_ghc05_ghc06_galleries.py
T

174 lines
16 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.
#!/usr/bin/env python3
"""Build the GHC-05 and GHC-06 galleries from the existing KSP screenshots."""
from __future__ import annotations
import html
import os
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SOURCE_ROOT = ROOT / "user_input" / "广寒计划"
WIKI_ROOT = ROOT / "data" / "wiki"
STAGING_ROOT = ROOT / "output" / "wiki-gallery-upload"
GALLERIES = {
"GHC-05": {
"title": "广寒基地建设任务-05 任务图集",
"page": "home/mission/Guanghan_Program/GHC-05",
"previous": ("GHC-04", "/home/mission/Guanghan_Program/GHC-04/Gallery"),
"next": ("GHC-06", "/home/mission/Guanghan_Program/GHC-06/Gallery"),
"folder": "guanghan-ghc-05",
"output": "guanghan_ghc05_gallery_zh.html",
"intro": "现有任务影像按任务阶段整理,共 28 张。点击图片可打开大图并使用方向键切换。",
"items": [
("载人发射与地月转移", "CZ-16A二级视角-夜间发射.png", "crew_launch_night.png", "CZ-16A 夜间发射", "CZ-16A 搭载嫦娥六号与吴刚二号升空,画面为夜间上升段的二级视角。"),
("载人发射与地月转移", "CZ-16A执行TLI燃烧.png", "crew_tli_burn.png", "CZ-16A 执行 TLI", "运载火箭上面级执行地月转移注入,将嫦娥六号与吴刚二号组合体送往月球。"),
("载人发射与地月转移", "嫦娥6号分离.png", "change6_separation.png", "嫦娥六号分离", "嫦娥六号与上面级分离,准备执行掉头和着陆器提取操作。"),
("载人发射与地月转移", "嫦娥6号掉头,准备取出吴刚2.png", "change6_turnaround.png", "嫦娥六号掉头", "嫦娥六号完成掉头,接近仍固定在桁架上的吴刚二号。"),
("载人发射与地月转移", "嫦娥6号取出吴刚2.png", "change6_extracts_wugang2.png", "嫦娥六号取出吴刚二号", "嫦娥六号对接吴刚二号并将其从发射桁架中拖出,组合体进入巡航构型。"),
("载人发射与地月转移", "嫦娥6号近月制动.png", "change6_loi.png", "嫦娥六号近月制动", "嫦娥六号与吴刚二号组合体执行近月制动,进入绕月轨道。"),
("吴刚二号着陆", "吴刚2号与嫦娥分离准备着陆.png", "wugang2_separation.png", "吴刚二号分离", "吴刚二号与嫦娥六号分离,开始独立下降与着陆准备。"),
("吴刚二号着陆", "吴刚2号主减速段.png", "wugang2_descent_burn.png", "吴刚二号主减速", "吴刚二号主发动机点火执行下降主减速。"),
("吴刚二号着陆", "吴刚2号着陆.png", "wugang2_landing.png", "吴刚二号着陆", "吴刚二号在东方海广寒基地附近完成月面着陆。"),
("广寒 03 模块运输", "CZ-16发射广寒03模块.png", "gh03_launch.png", "CZ-16 发射广寒 03", "CZ-16 搭载广寒 03 扩建模块从文昌升空。"),
("广寒 03 模块运输", "CZ-16发射广寒03模块2.png", "gh03_launch_second_view.png", "广寒 03 发射另一视角", "广寒 03 模块发射上升段的另一视角。"),
("广寒 03 模块运输", "金蟾1号与广寒03模块对接.png", "jinchan1_docks_gh03.png", "金蟾一号对接广寒 03", "金蟾一号在近地轨道与广寒 03 模块完成对接。"),
("广寒 03 模块运输", "金蟾1号携带广寒03TLI.png", "jinchan1_gh03_tli.png", "金蟾一号携带广寒 03 执行 TLI", "金蟾一号携带广寒 03 模块执行地月转移点火。"),
("广寒 03 模块运输", "冰轮3号和金蟾1号交汇.png", "binglun3_rendezvous_jinchan1.png", "冰轮三号与金蟾一号交会", "冰轮三号在绕月轨道接近携带广寒 03 模块的金蟾一号。"),
("广寒 03 模块运输", "冰轮3号着陆.png", "binglun3_landing_gh03.png", "冰轮三号运送广寒 03 着陆", "冰轮三号携带广寒 03 模块在广寒基地着陆。"),
("冰轮运输调度", "冰轮2号起飞.png", "binglun2_takeoff.png", "冰轮二号起飞", "冰轮二号从月面起飞,执行燃料运输任务。"),
("冰轮运输调度", "冰轮2号与金蟾1号对接.png", "binglun2_docks_jinchan1.png", "冰轮二号对接金蟾一号", "冰轮二号在绕月轨道与金蟾一号对接并转移燃料。"),
("冰轮运输调度", "金蟾1号点火返回地球(可见后方冰轮2号).png", "jinchan1_return_burn_binglun2.png", "金蟾一号返航点火", "金蟾一号执行返回地球点火,画面后方可见冰轮二号。"),
("冰轮运输调度", "金蟾1号近地制动.png", "jinchan1_earth_braking.png", "金蟾一号近地制动", "金蟾一号返回地球附近并执行近地制动。"),
("冰轮运输调度", "冰轮2号着陆中.png", "binglun2_descent.png", "冰轮二号下降", "冰轮二号完成轨道补给后返回月面。"),
("冰轮运输调度", "冰轮2号着陆.png", "binglun2_landing.png", "冰轮二号着陆", "冰轮二号重新着陆于广寒基地。"),
("乘组撤离与返回", "吴刚2号起飞(01-19).png", "wugang2_takeoff.png", "吴刚二号起飞", "吴刚二号搭载 GHC-05 乘组从月面起飞。"),
("乘组撤离与返回", "嫦娥6号与吴刚2号对接(01-19).png", "change6_docks_wugang2.png", "嫦娥六号对接吴刚二号", "嫦娥六号在绕月轨道与吴刚二号完成对接。"),
("乘组撤离与返回", "嫦娥6号携带吴刚2号升轨(01-19).png", "change6_wugang2_raise_orbit.png", "嫦娥六号携带吴刚二号升轨", "组合体升轨至停泊轨道,吴刚二号随后留轨复用。"),
("乘组撤离与返回", "冰轮3号起飞.png", "binglun3_takeoff.png", "冰轮三号起飞", "冰轮三号从月面起飞执行下一轮轨道运输。"),
("乘组撤离与返回", "冰轮3号起飞过程中,从嫦娥6号45公里处略过.png", "binglun3_passes_change6.png", "冰轮三号掠过嫦娥六号", "冰轮三号上升过程中从嫦娥六号约 45 公里外掠过。"),
("乘组撤离与返回", "嫦娥6号点火返回地球(01-20).png", "change6_return_burn.png", "嫦娥六号返回点火", "嫦娥六号离开绕月轨道,执行返回地球点火。"),
("乘组撤离与返回", "嫦娥6号再入(01-22).png", "change6_reentry.png", "嫦娥六号再入", "嫦娥六号返回舱再入地球大气层。"),
],
},
"GHC-06": {
"title": "广寒基地建设任务-06 任务图集",
"page": "home/mission/Guanghan_Program/GHC-06",
"previous": ("GHC-05", "/home/mission/Guanghan_Program/GHC-05/Gallery"),
"next": None,
"folder": "guanghan-ghc-06",
"output": "guanghan_ghc06_gallery_zh.html",
"intro": "现有任务影像按任务阶段整理,共 25 张。点击图片可打开大图并使用方向键切换。",
"items": [
("载人飞行与月面着陆", "CZ-16A二级携带组合体进行TLI.png", "crew_tli.png", "CZ-16A 二级执行 TLI", "CZ-16A 二级携带嫦娥七号与吴刚三号组合体执行地月转移注入。"),
("载人飞行与月面着陆", "嫦娥7号准备和吴刚飞船对接(1月6日).png", "change7_dock_approach.png", "嫦娥七号接近吴刚三号", "嫦娥七号完成掉头,准备与吴刚三号对接。"),
("载人飞行与月面着陆", "嫦娥7号取出吴刚飞船.png", "change7_extracts_wugang3.png", "嫦娥七号取出吴刚三号", "嫦娥七号将吴刚三号从发射桁架中拖出。"),
("载人飞行与月面着陆", "嫦娥7号近月制动.png", "change7_loi.png", "嫦娥七号近月制动", "嫦娥七号与吴刚三号组合体执行近月制动。"),
("载人飞行与月面着陆", "吴刚3号准备着陆(1月11号).png", "wugang3_landing_approach.png", "吴刚三号准备着陆", "吴刚三号脱离绕月轨道,开始月面下降。"),
("载人飞行与月面着陆", "吴刚3号着陆中.png", "wugang3_landing.png", "吴刚三号着陆", "吴刚三号执行末段下降并着陆于东方海。"),
("广寒 04 模块运输", "CZ-10E发射广寒04模块(02-01).png", "gh04_launch.png", "CZ-10E 发射广寒 04", "CZ-10E 搭载广寒 04 扩建模块升空。"),
("广寒 04 模块运输", "金蟾3号准备和广寒04模块对接(02-01).png", "jinchan3_dock_gh04.png", "金蟾三号接近广寒 04", "金蟾三号在近地轨道接近并准备对接广寒 04 模块。"),
("广寒 04 模块运输", "金蟾3号携带广寒04模块执行TLI.png", "jinchan3_gh04_tli.png", "金蟾三号携带广寒 04 执行 TLI", "金蟾三号携带广寒 04 模块开始地月转移。"),
("广寒 04 模块运输", "冰轮3号变轨(02-08).png", "binglun3_deorbit_gh04.png", "冰轮三号变轨", "冰轮三号接收广寒 04 模块后执行下降变轨。"),
("广寒 04 模块运输", "冰轮3号着陆主减速段(02-08).png", "binglun3_descent_gh04.png", "冰轮三号主减速", "冰轮三号携带广寒 04 模块执行着陆主减速。"),
("广寒 04 模块运输", "冰轮3号着陆(02-08).png", "binglun3_landing_gh04.png", "冰轮三号运送广寒 04 着陆", "冰轮三号将广寒 04 模块送达广寒基地。"),
("冰轮编队调度", "冰轮2号起飞(02-08).png", "binglun2_takeoff.png", "冰轮二号起飞", "冰轮二号从月面起飞执行轨道燃料运输。"),
("冰轮编队调度", "冰轮2号与金蟾1号交汇(02-08).png", "binglun2_rendezvous_jinchan1.png", "冰轮二号与金蟾一号交会", "冰轮二号在绕月轨道接近金蟾一号。"),
("冰轮编队调度", "冰轮2号着陆(02-08).png", "binglun2_landing.png", "冰轮二号返回月面", "冰轮二号完成补给任务后返回广寒基地。"),
("冰轮编队调度", "冰轮3号起飞(02-08).png", "binglun3_takeoff.png", "冰轮三号起飞", "完成广寒 04 卸载后,冰轮三号再次起飞执行轨道任务。"),
("冰轮编队调度", "金蟾1号泊入近地轨道(02-13).png", "jinchan1_leo_arrival.png", "金蟾一号泊入近地轨道", "金蟾一号返回地球附近并泊入近地轨道。"),
("乘组撤离与返回", "吴刚3号准备起飞(25-03-14).png", "wugang3_prepares_takeoff.png", "吴刚三号准备起飞", "燃料系统修复完成后,吴刚三号进行月面起飞准备。"),
("乘组撤离与返回", "吴刚3号起飞(25-03-15).png", "wugang3_takeoff.png", "吴刚三号起飞", "吴刚三号搭载 GHC-06 乘组从月面起飞。"),
("乘组撤离与返回", "吴刚3号与嫦娥7号准备对接(25-03-15).png", "wugang3_change7_rendezvous.png", "吴刚三号接近嫦娥七号", "吴刚三号在绕月轨道接近嫦娥七号并完成乘组转移;随后组合体升轨至 400×400 km,吴刚三号留轨复用。"),
("乘组撤离与返回", "嫦娥7号点火返回地球(25-03-16).png", "change7_return_burn.png", "嫦娥七号返回点火", "嫦娥七号离开绕月轨道,开始返回地球。"),
("乘组撤离与返回", "嫦娥7号抛服务舱(25-03-19).png", "change7_service_module_sep.png", "嫦娥七号抛离服务舱", "再入前,嫦娥七号返回舱与服务舱分离。"),
("乘组撤离与返回", "嫦娥7号再入(25-03-19).png", "change7_reentry.png", "嫦娥七号再入", "嫦娥七号返回舱穿越地球大气层。"),
("乘组撤离与返回", "嫦娥7号开主伞(25-03-19).png", "change7_main_chutes.png", "嫦娥七号打开主伞", "返回舱主降落伞展开,进入最终下降阶段。"),
("乘组撤离与返回", "嫦娥7号返回文昌(25-03-19).png", "change7_wenchang_landing.png", "嫦娥七号返回文昌", "嫦娥七号返回舱在文昌回收场安全着陆,GHC-06 任务完成。"),
],
},
}
BASE_STYLE = """<style>
.wiki-article { max-width: 1180px; margin: 0 auto; padding: 24px 32px 48px; color: #202122; background: #fff; font-family: sans-serif; font-size: 14px; line-height: 1.65; }
.wiki-article h1 { font-family: \"Linux Libertine\", Georgia, serif; font-weight: normal; border-bottom: 1px solid #a2a9b1; margin: 0 0 8px; font-size: 2.15em; }
.wiki-article h2 { font-family: \"Linux Libertine\", Georgia, serif; font-weight: normal; border-bottom: 1px solid #a2a9b1; clear: both; margin: 1.35em 0 0.6em; padding-bottom: 0.18em; font-size: 1.55em; }
.wiki-article p { margin: 0.45em 0 0.85em; }
.wiki-article a { color: #0645ad; text-decoration: none; }
.wiki-article a:hover { text-decoration: underline; }
.wiki-article img { max-width: 100%; height: auto; }
.wiki-article .thumbcaption { padding: 4px 3px 2px; text-align: left; color: #202122; }
.wiki-article .gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; margin: 1em 0; }
.wiki-article .gallery-item { border: 1px solid #c8ccd1; background: #f8f9fa; padding: 4px; font-size: 88%; line-height: 1.4; }
.wiki-article .gallery-item img { display: block; width: 100%; cursor: zoom-in; }
.wiki-article .gallery-item .thumbcaption { padding: 4px 2px 2px; }
@media (max-width: 820px) { .wiki-article { padding: 18px 16px 36px; } .gallery-grid { grid-template-columns: 1fr; } }
</style>"""
def create_staged_asset(source: Path, staged: Path) -> None:
staged.parent.mkdir(parents=True, exist_ok=True)
if staged.exists():
if staged.stat().st_size != source.stat().st_size:
staged.unlink()
else:
return
try:
os.link(source, staged)
except OSError:
staged.write_bytes(source.read_bytes())
def build_gallery(code: str, config: dict) -> None:
source_dir = SOURCE_ROOT / code
staging_dir = STAGING_ROOT / code.lower()
sections: dict[str, list[str]] = {}
for section, source_name, upload_name, alt, caption in config["items"]:
source = source_dir / source_name
if not source.exists():
raise FileNotFoundError(source)
create_staged_asset(source, staging_dir / upload_name)
asset_path = f'/{config["folder"]}/{upload_name}'
card = (
f'<div class="gallery-item"><img src="{asset_path}" alt="{html.escape(alt)}" '
f'data-wiki-asset="{asset_path}"><div class="thumbcaption">{html.escape(caption)}</div></div>'
)
sections.setdefault(section, []).append(card)
previous = config["previous"]
next_item = config["next"]
nav_parts = [f'<a href="{previous[1]}">← {previous[0]} 图集</a>']
if next_item:
nav_parts.append(f'<a href="{next_item[1]}">{next_item[0]} 图集 →</a>')
nav = " | ".join(nav_parts)
body = [BASE_STYLE, '<article class="mw-parser-output wiki-article">']
body.append(f'<h1 id="top">{config["title"]}</h1>')
body.append(f'<p><a href="/{config["page"]}">← 返回任务页</a> {len(config["items"])} 张现有影像</p>')
body.append(f'<p style="margin-bottom:1.5em;"><b>任务图集导航</b>{nav}</p>')
body.append(f'<p>{config["intro"]}</p>')
for section, cards in sections.items():
body.extend((f'<h2>{section}</h2>', '<div class="gallery-grid">', *cards, '</div>'))
body.append(f'<p style="margin-top:1.5em;"><b>任务图集导航</b>{nav}</p>')
body.append(f'<p style="margin-top:1.5em;"><a href="/{config["page"]}">← 返回任务页</a></p>')
body.append('</article>')
output_path = WIKI_ROOT / config["output"]
output_path.write_text("\n".join(body) + "\n", encoding="utf-8", newline="\n")
print(f"gallery_built mission={code} images={len(config['items'])} output={output_path}")
def main() -> int:
for code, config in GALLERIES.items():
build_gallery(code, config)
return 0
if __name__ == "__main__":
raise SystemExit(main())