···
1
+
#!/usr/bin/env -S uv run --script
10
+
# 1. Take a markdown blog post as input, convert it to gemtext.
11
+
# 2. Update gemlog index.
12
+
# 3. Update the gemlog Atom feed.
15
+
from datetime import datetime
16
+
from pathlib import Path
17
+
from zoneinfo import ZoneInfo
20
+
from feedgen.feed import FeedGenerator
21
+
from md2gemini import md2gemini
23
+
# This is so that Python doesn't yell at me if I forget an argument. Not
24
+
# likely to happen, but still.
25
+
if len(sys.argv) != 3:
26
+
print('Usage: blog2gemlog /path/to/blog/post.md "Blog Post Title"')
29
+
# Set the absolute path to the gemini content directory
30
+
gemini_dir = Path.home().joinpath(
31
+
"repos/tildegit.org/hyperreal/hyperreal.coffee/gemini"
34
+
# Get the current date in YYYY-MM-DD format
35
+
date_now = datetime.now().strftime("%Y-%m-%d")
37
+
# Read blog post path from sys.argv[1] and ensure it is an absolute path
38
+
blog_post_path = Path(sys.argv[1])
39
+
if not blog_post_path.is_absolute():
40
+
print("Supply absolute path to blog post.")
43
+
# Convert the markdown blog post to gemtext
44
+
with open(blog_post_path, "r") as md_f:
45
+
content = md2gemini(md_f.read(), frontmatter=True, links="paragraph", md_links=True)
47
+
# Set the absolute path to the gemlog post
48
+
gemlog_post_path = gemini_dir.joinpath(f"gemlog/{blog_post_path.stem}.gmi")
50
+
# Write the gemtext content to the gemlog post path
51
+
with open(gemlog_post_path, "w") as gmi_f:
52
+
gmi_f.write(content)
54
+
# Set the string for the END section of the gemlog post
55
+
gemlog_end = f"\n\n## END\nLast updated: {date_now}\n\n=> ../gemlog Gemlog archive\n=> ../ hyperreal.coffee"
57
+
# Append gemlog_end to the end of the gemlog post
58
+
with open(gemlog_post_path, "a") as gmi_f:
59
+
gmi_f.write(gemlog_end)
61
+
# Read the gemlog post file lines into a list
62
+
with open(gemlog_post_path, "r") as gmi_f:
63
+
contents = gmi_f.readlines()
65
+
# Get the gemlog post title from sys.argv[2]
66
+
gemlog_post_title = str(sys.argv[2])
68
+
# Insert the gemlog post title as the level 1 heading on line 1
69
+
contents.insert(0, f"# {gemlog_post_title}\n\n")
71
+
# Write the new contents as a string to the gemlog file
72
+
with open(gemlog_post_path, "w") as gmi_f:
73
+
contents = "".join(contents)
74
+
gmi_f.write(contents)
76
+
# Read the lines of the gemlog index into a list
77
+
with open(gemini_dir.joinpath("gemlog/index.gmi"), "r") as index_f:
78
+
contents = index_f.readlines()
80
+
# Set the content of the gemlog index entry line
81
+
gemlog_index_line = f"=> ./{gemlog_post_path.name} {date_now} {gemlog_post_title}\n"
83
+
# Insert the new gemlog index line into the list on line 6
84
+
contents.insert(5, gemlog_index_line)
86
+
# Write the new contents as a string to the gemlog index file
87
+
with open(gemini_dir.joinpath("gemlog/index.gmi"), "w") as index_f:
88
+
contents = "".join(contents)
89
+
index_f.write(contents)
91
+
# Get a timezone-aware datetime object from a timestamp of the present moment
92
+
aware_ts = datetime.fromtimestamp(
93
+
datetime.timestamp(datetime.now()), tz=ZoneInfo("America/Chicago")
96
+
# Format the timezone-aware datetime object for the <updated> element of the
98
+
updated_ts = aware_ts.strftime("%Y-%m-%dT%H:%M:%S%z")
100
+
# Instantiate a FeedParserDict object
101
+
d = feedparser.parse(gemini_dir.joinpath("gemlog/atom.xml"))
103
+
# Update the <updated> element's value to the current timestamp
104
+
d["updated"] = updated_ts
106
+
# Define a dictionary for the new Atom feed entry
108
+
"id": f"gemini://hyperreal.coffee/gemlog/{gemlog_post_path.name}",
109
+
"title": gemlog_post_title,
110
+
"updated": updated_ts,
113
+
"href": f"gemini://hyperreal.coffee/gemlog/{gemlog_post_path.name}",
114
+
"rel": "alternate",
115
+
"type": "text/gemini",
120
+
# Insert the new Atom feed entry into the FeedParserDict
121
+
d["entries"].insert(0, new_entry_dict)
123
+
# Instantiate a FeedGenerator object and set the methods for the feed
124
+
fg = FeedGenerator()
125
+
fg.id(d["feed"]["id"])
126
+
fg.title(d["feed"]["title"])
127
+
fg.updated(d["feed"]["updated"])
128
+
fg.link(d["feed"]["links"])
130
+
# Reverse the order of d["entries"] so that they are written to the file in
131
+
# the correct order
132
+
d["entries"].reverse()
134
+
# For each entry, add a new entry to the FeedGenerator object
135
+
for entry in d["entries"]:
136
+
fe = fg.add_entry()
138
+
fe.title(entry["title"])
139
+
fe.updated(entry["updated"])
140
+
fe.link(entry["links"])
142
+
# Finally, render the FeedGenerator object as an Atom feed and write it to
143
+
# the atom.xml file
144
+
fg.atom_file(gemini_dir.joinpath("gemlog/atom.xml"), pretty=True)
146
+
# vim: ai et ft=python sts=4 sw=4 ts=4