Skip to content

Commit ee492f2

Browse files
authored
Update generate.py
1 parent a48dc9a commit ee492f2

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

scripts/generate.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import yaml
2020
import re
2121
import os
22+
from datetime import datetime
23+
from typing import Any, Dict, List
2224

2325
# -----------------------
2426
# Load YAML data
@@ -27,6 +29,115 @@
2729
with open('data/plugins-and-themes.yml', 'r') as f:
2830
data = yaml.safe_load(f)
2931

32+
# -----------------------
33+
# Helpers
34+
# -----------------------
35+
36+
def _parse_date_safe(s: str | None) -> datetime:
37+
"""
38+
Parse ISO-ish date strings for added_at/updated_at.
39+
Falls back to datetime.min if missing/invalid so items without dates
40+
naturally sink to the bottom when sorting by "most recent".
41+
"""
42+
if not s or not isinstance(s, str):
43+
return datetime.min
44+
s = s.strip()
45+
if not s:
46+
return datetime.min
47+
48+
# Try a few common formats first
49+
for fmt in (
50+
"%Y-%m-%d",
51+
"%Y-%m-%dT%H:%M:%S%z",
52+
"%Y-%m-%dT%H:%M:%S",
53+
"%Y-%m-%dT%H:%M:%S.%fZ",
54+
):
55+
try:
56+
return datetime.strptime(s, fmt)
57+
except ValueError:
58+
continue
59+
60+
# Fallback: fromisoformat for other variants
61+
try:
62+
return datetime.fromisoformat(s)
63+
except Exception:
64+
return datetime.min
65+
66+
def _recent_plugins(entries: List[Dict[str, Any]], limit: int = 6) -> List[Dict[str, Any]]:
67+
"""
68+
Return up to `limit` most recently added plugins by `added_at` (desc).
69+
If `added_at` is missing/invalid, that entry will sort as very old.
70+
"""
71+
plugins_only = [e for e in entries if isinstance(e, dict)]
72+
plugins_only.sort(
73+
key=lambda e: _parse_date_safe(e.get("added_at")),
74+
reverse=True,
75+
)
76+
return plugins_only[:limit]
77+
78+
def _escape_inline(text: Any) -> str:
79+
"""
80+
Light inline escaping/sanitizing for markdown text.
81+
Not for tables – just make sure we have a clean string.
82+
"""
83+
if not isinstance(text, str):
84+
return ""
85+
return text.strip()
86+
87+
def generate_recent_plugins_md(entries: List[Dict[str, Any]]) -> str:
88+
"""
89+
Build the 'Recently Added Plugins' section content for PLUGINS.md.
90+
91+
Injected between:
92+
<!--- Recently Added Plugins Start -->
93+
<!--- Recently Added Plugins End -->
94+
"""
95+
if not entries:
96+
return "No recently added plugins found.\n"
97+
98+
lines: List[str] = []
99+
lines.append("> These are the six most recently added plugins (based on `added_at`).")
100+
lines.append("")
101+
102+
for idx, entry in enumerate(entries, start=1):
103+
name = _escape_inline(entry.get("name", "Unknown"))
104+
repo = entry.get("repo")
105+
desc = _escape_inline(entry.get("description", ""))
106+
mc = _escape_inline(entry.get("mc_versions", ""))
107+
108+
creator_obj = entry.get("creator") or {}
109+
creator_name = _escape_inline(creator_obj.get("name", "Unknown"))
110+
creator_url = creator_obj.get("url")
111+
added_at = _escape_inline(entry.get("added_at", ""))
112+
113+
if repo:
114+
name_md = f"[{name}](https://github.com/{repo})"
115+
else:
116+
name_md = name
117+
118+
if creator_url:
119+
creator_md = f"[{creator_name}]({creator_url})"
120+
else:
121+
creator_md = creator_name
122+
123+
meta_bits = []
124+
if mc:
125+
meta_bits.append(f"`MC: {mc}`")
126+
if creator_md:
127+
meta_bits.append(f"by {creator_md}")
128+
if added_at:
129+
meta_bits.append(f"added `{added_at}`")
130+
131+
meta_line = " · ".join(meta_bits) if meta_bits else ""
132+
desc_part = f" – {desc}" if desc else ""
133+
134+
lines.append(f"{idx}. **{name_md}**{desc_part}")
135+
if meta_line:
136+
lines.append(f" {meta_line}")
137+
lines.append("") # blank line between items
138+
139+
return "\n".join(lines).rstrip() + "\n"
140+
30141
# -----------------------
31142
# Markdown generator for each plugin/theme entry
32143
# -----------------------
@@ -126,6 +237,17 @@ def generate_entry_md(entry, is_plugin=True, index=0):
126237
flags=re.DOTALL
127238
)
128239

240+
# Inject "Recently Added Plugins" section (top 6 by added_at)
241+
recent_plugins = _recent_plugins(data.get("plugins", []), limit=6)
242+
recent_md_block = generate_recent_plugins_md(recent_plugins)
243+
244+
plugins_content = re.sub(
245+
r'<!--- Recently Added Plugins Start -->.*<!--- Recently Added Plugins End -->',
246+
f'<!--- Recently Added Plugins Start -->\n{recent_md_block}<!--- Recently Added Plugins End -->',
247+
plugins_content,
248+
flags=re.DOTALL
249+
)
250+
129251
with open('PLUGINS.md', 'w') as f:
130252
f.write(plugins_content)
131253

0 commit comments

Comments
 (0)