···
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