Sthira、Drig、Shoola、Navamsha、Niryaana Shoola 与 K.N. Rao 的 Chara 从本盘算出。Lagna Kendradi 不上表。未推送。
169 lines
6.4 KiB
Python
169 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Markdown chapter for the seven report-only rashi dashas."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Mapping
|
|
|
|
try:
|
|
from rashi_dashas_native import calculate_rashi_dashas
|
|
except ImportError: # pragma: no cover - package import
|
|
from scripts.rashi_dashas_native import calculate_rashi_dashas
|
|
|
|
_SIGN_CN = {
|
|
"Aries": "白羊座",
|
|
"Taurus": "金牛座",
|
|
"Gemini": "双子座",
|
|
"Cancer": "巨蟹座",
|
|
"Leo": "狮子座",
|
|
"Virgo": "处女座",
|
|
"Libra": "天秤座",
|
|
"Scorpio": "天蝎座",
|
|
"Sagittarius": "射手座",
|
|
"Capricorn": "摩羯座",
|
|
"Aquarius": "水瓶座",
|
|
"Pisces": "双鱼座",
|
|
}
|
|
# Chinese headings avoid the token Dasha. The report cleaner turns that token
|
|
# into 大运 and then deletes the linebreak before the next Chinese sentence.
|
|
_ORDER = (
|
|
("sthira", "Sthira", "Sthira Dasha"),
|
|
("niryaana_shoola", "Niryaana Shoola", "Niryaana Shoola Dasha"),
|
|
("drig", "Drig", "Drig Dasha"),
|
|
("navamsha", "Navamsha", "Navamsha Dasha"),
|
|
("shoola", "Shoola", "Shoola Dasha"),
|
|
("chara", "Chara", "Chara Dasha"),
|
|
("lagna_kendradi", "Lagna Kendradi", "Lagna Kendradi Rashi Dasha"),
|
|
)
|
|
_CLASSICAL = ("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn")
|
|
|
|
|
|
def _language(packet: Mapping) -> str:
|
|
raw = packet.get("report_language") or packet.get("language") or "zh"
|
|
return "en" if str(raw).lower().startswith("en") else "zh"
|
|
|
|
|
|
def _longitude(row: Mapping) -> float | None:
|
|
# Ascendant "degree" is the degree inside the sign. Full longitude is degree_raw / lon.
|
|
for key in ("degree_raw", "lon", "longitude"):
|
|
value = row.get(key)
|
|
if isinstance(value, (int, float)):
|
|
return float(value)
|
|
sign = row.get("sign")
|
|
degree = row.get("degree_in_sign")
|
|
if sign in _SIGN_CN and isinstance(degree, (int, float)):
|
|
signs = list(_SIGN_CN)
|
|
return signs.index(str(sign)) * 30.0 + float(degree)
|
|
return None
|
|
|
|
|
|
def _birth_date(packet: Mapping) -> str | None:
|
|
birth = packet.get("birth_info")
|
|
if not isinstance(birth, Mapping):
|
|
return None
|
|
if birth.get("date"):
|
|
return str(birth.get("date"))
|
|
year, month, day = birth.get("year"), birth.get("month"), birth.get("day")
|
|
if all(isinstance(part, int) for part in (year, month, day)):
|
|
return f"{int(year):04d}-{int(month):02d}-{int(day):02d}"
|
|
return None
|
|
|
|
|
|
def chart_inputs(packet: Mapping) -> dict | None:
|
|
core = packet.get("core_chart")
|
|
if not isinstance(core, Mapping):
|
|
return None
|
|
asc = core.get("ascendant")
|
|
planets = core.get("planets")
|
|
if not isinstance(asc, Mapping) or not isinstance(planets, Mapping):
|
|
return None
|
|
asc_lon = _longitude(asc)
|
|
birth = _birth_date(packet)
|
|
if asc_lon is None or not birth:
|
|
return None
|
|
longitudes = {}
|
|
for name in list(_CLASSICAL) + ["Rahu", "Ketu"]:
|
|
row = planets.get(name)
|
|
if isinstance(row, Mapping):
|
|
value = _longitude(row)
|
|
if value is not None:
|
|
longitudes[name] = value
|
|
if any(name not in longitudes for name in _CLASSICAL):
|
|
return None
|
|
return {"birth": birth, "ascendant_longitude": asc_lon, "planet_lons": longitudes}
|
|
|
|
|
|
def _sign_label(sign: str, language: str) -> str:
|
|
if language == "zh":
|
|
return _SIGN_CN.get(sign, sign)
|
|
return sign
|
|
|
|
|
|
def _method_line(section: Mapping, language: str) -> str:
|
|
if section.get("status") != "listed":
|
|
return str(section.get("reason_en") if language == "en" else section.get("reason_zh") or "")
|
|
profile = section.get("profile_id") or ""
|
|
if language == "en":
|
|
return (
|
|
f"Method used on this site: {profile}, source: {section.get('source_en')}; "
|
|
"not checked one-by-one against external software."
|
|
)
|
|
return f"本站选用的方法:{profile},出处:{section.get('source_zh')};未与外部软件逐一核对。"
|
|
|
|
|
|
def render_rashi_dasha_chapter(packet: Mapping) -> str:
|
|
"""Return the chapter, or an empty string when the packet has no longitudes."""
|
|
inputs = chart_inputs(packet)
|
|
if inputs is None:
|
|
return ""
|
|
language = _language(packet)
|
|
sections = calculate_rashi_dashas(inputs["birth"], inputs["ascendant_longitude"], inputs["planet_lons"])
|
|
if language == "en":
|
|
lines = [
|
|
"## Sign dashas calculated on this site",
|
|
"",
|
|
"These tables list signs and dates only.",
|
|
"",
|
|
]
|
|
sign_header = "| Index | Sign | Start | End | Years |"
|
|
child_header = "| Index | Maha | Antara | Start | End |"
|
|
else:
|
|
lines = [
|
|
"## 星座大运(本站计算)",
|
|
"",
|
|
"以下只列出星座和日期。",
|
|
"",
|
|
]
|
|
sign_header = "| 序号 | 星座 | 起始 | 结束 | 年数 |"
|
|
child_header = "| 序号 | 主运 | 子运 | 起始 | 结束 |"
|
|
for key, title_zh, title_en in _ORDER:
|
|
section = sections[key]
|
|
title = title_en if language == "en" else title_zh
|
|
lines.extend([f"### {title}", "", _method_line(section, language), ""])
|
|
if key == "chara" and section.get("status") == "listed":
|
|
lines.extend([
|
|
"This section is the K.N. Rao Chara table. It is not the Narayana table."
|
|
if language == "en"
|
|
else "这一节是 K.N. Rao 的 Chara 表,不是 Narayana 表。",
|
|
"",
|
|
])
|
|
periods = section.get("periods") or []
|
|
if not periods:
|
|
continue
|
|
lines.extend([sign_header, "|------|------|------|------|------|"])
|
|
child_rows = []
|
|
for index, period in enumerate(periods, start=1):
|
|
label = _sign_label(str(period.get("sign")), language)
|
|
lines.append(
|
|
f"| {index} | {label} | {period.get('start')} | {period.get('end')} | {period.get('years')} |"
|
|
)
|
|
for child in period.get("antardasha") or []:
|
|
child_rows.append((label, _sign_label(str(child.get("sign")), language), child.get("start"), child.get("end")))
|
|
lines.append("")
|
|
if child_rows:
|
|
lines.extend([child_header, "|------|------|------|------|------|"])
|
|
for index, (parent, child, start, end) in enumerate(child_rows, start=1):
|
|
lines.append(f"| {index} | {parent} | {child} | {start} | {end} |")
|
|
lines.append("")
|
|
return "\n".join(lines).rstrip() + "\n"
|