A mirror of my website's source code.

Important information: Google announced that, from September 2026, Android devices will require ALL apps to be signed by Google, effectively leading to an iOS situation. Value your right to a computer that does what you want; do not tolerate this monopolistic practice! Contact me if you don't understand why it is bad. Click to learn more.

 build.py

View raw Download
text/x-script.python • 9.01 kiB
Python script, ASCII text executable
        
            
1
from Renderers import RenderTemplate, RenderMarkdown
2
from sys import argv
3
from shutil import rmtree as DeleteDirectory
4
from os import mkdir as CreateDirectory, listdir as ListDirectory, unlink as DeleteFile
5
from os.path import isfile as IsFile, exists as PathExists
6
from distutils.dir_util import copy_tree as CopyDirectory
7
from datetime import datetime
8
from json import dump as DumpJSON
9
from yaml import safe_load as LoadYML
10
11
GITHUB_BUILD_DIR = "docs" # Separate because this site is built with an action that won't work if they aren't
12
LOCAL_BUILD_DIR = "build"
13
14
BUILD_DIRECTORY = GITHUB_BUILD_DIR if len(argv) > 1 and argv[1] == "gh-pages-deploy" else LOCAL_BUILD_DIR
15
16
PAGES = {
17
"index.html": "index.html",
18
"blog-list.html": "blog/index.html",
19
"blog-feed.rss": "blog/feed.rss",
20
"blog-feed.atom": "blog/feed.atom",
21
"404.html": "404.html"
22
}
23
24
DISALLOWED_SITEMAP = [
25
"404.html",
26
"blog-feed.rss"
27
]
28
29
REDIRECTS = [
30
("link-tree.html", "list/link-tree.html") # Old location -> new location
31
]
32
33
SITEMAP_HREF = "https://steve0greatness.github.io/"
34
sitemap = []
35
36
def WipeFinalDir():
37
if not PathExists(BUILD_DIRECTORY):
38
print("Directory didn't existing, creating it...")
39
CreateDirectory(BUILD_DIRECTORY)
40
return
41
print("Directory exists, wiping it...")
42
for item in ListDirectory(BUILD_DIRECTORY):
43
path = BUILD_DIRECTORY + "/" + item
44
if IsFile(path):
45
DeleteFile(path)
46
continue
47
DeleteDirectory(path)
48
49
def PostDateToDateObj(Date):
50
return datetime.strptime(Date, "%Y %b %d")
51
52
def PostSortHelper(Post):
53
return PostDateToDateObj(Post["date"])
54
55
def GetBlogList():
56
print("Grabbing post list")
57
PostSlugs = ListDirectory("blog-posts")
58
Posts = []
59
for slug in PostSlugs:
60
print("Grabbing post list blog-posts/%s" % (slug))
61
with open("blog-posts/" + slug, encoding="utf-8") as MDFile:
62
PostHTML = RenderMarkdown(MDFile.read())
63
Item = PostHTML.metadata
64
Item["content"] = PostHTML
65
Item["rss-post-time"] = PostDateToDateObj(Item["date"]).strftime("%a, %d %b %Y") + " 00:00:00 GMT"
66
Item["atom-post-time"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d") + "T00:00:00Z"
67
Item["atom-update-time"] = Item["atom-post-time"]
68
if "updated" in Item:
69
Item["atom-update-time"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d") + "T00:00:00Z"
70
Item["pathname"] = slug.replace(".md", ".html")
71
Item["plaintext"] = slug.replace(".md", ".txt")
72
Item["origin"] = slug
73
Posts.append(Item)
74
PostsByDate = sorted(Posts, key=PostSortHelper, reverse=True)
75
return PostsByDate
76
77
PostList = []
78
79
def ListParseCategory(Obj, depth):
80
html = "<h%d id=\"%s\">%s</h%d>" % (2+depth, Obj["id"], Obj["title"], 2+depth)
81
if "paragraph" in Obj:
82
html += "<p>%s</p>" % Obj["paragraph"]
83
listType = "ul"
84
if "list-type" in Obj and Obj["list-type"] == "ordered":
85
listType = "ol"
86
html += "<%s>" % listType
87
for item in Obj["list"]:
88
html += "<li>" + LIST_PARSER_DICT[item["type"]](item, depth + 1) + "</li>"
89
html += "</%s>" % listType
90
return html
91
92
def ListParseLink(Obj, depth):
93
html = "<a href=\"%s\">" % Obj["href"]
94
text = Obj["text"]
95
if "text-type" in Obj and Obj["text-type"] == "text/markdown":
96
text = RenderMarkdown(text).replace("<p>", "").replace("</p>", "")
97
html += text + "</a>"
98
if "comment" in Obj:
99
html += "(%s)" % Obj["comment"]
100
return html
101
102
def ListParseText(Obj, depth):
103
text = Obj["text"]
104
# if "text-type" in Obj and Obj["text-type"] == "text/markdown":
105
# print(RenderMarkdown(text))
106
# text = RenderMarkdown(text) # this doesn't work???
107
if "comment" in Obj:
108
text += "(%s)" % Obj["comment"]
109
return text
110
111
LIST_PARSER_DICT = {
112
"category": ListParseCategory,
113
"link": ListParseLink,
114
"text": ListParseText,
115
}
116
117
def GetLists():
118
ListSlugs = ListDirectory("lists")
119
Lists = []
120
for slug in ListSlugs:
121
List = {
122
"title": "",
123
"content": "",
124
"filename": slug
125
}
126
with open("lists/" + slug) as ListYML:
127
ListDict = LoadYML(ListYML.read())
128
List["title"] = ListDict["title"]
129
if "paragraph" in ListDict:
130
List["content"] += "<p>%s</p>" % ListDict["paragraph"]
131
for item in ListDict["list"]:
132
List["content"] += LIST_PARSER_DICT[item["type"]](item, 0)
133
Lists.append(List)
134
return Lists
135
136
def RenderPosts():
137
for post in ListDirectory("blog-posts"):
138
path = "blog-posts/" + post
139
RenderedHTML: str
140
PostMD: str
141
PostPath = post.replace(".md", ".html")
142
PlaintextPath = post.replace(".md", ".txt")
143
with open(path, "r", encoding="utf-8") as PostContent:
144
PostMD = PostContent.read()
145
PostHTML = RenderMarkdown(PostMD)
146
Title = PostHTML.metadata["title"]
147
PostDate = PostHTML.metadata["date"]
148
Revised = False
149
if "updated" in PostHTML.metadata:
150
Revised = PostHTML.metadata["updated"]
151
RenderedHTML = RenderTemplate("blog-post.html", Revised=Revised, Title=Title, PostDate=PostDate, Content=PostHTML, PostPath=PostPath, PlaintextPath=PlaintextPath)
152
print("Building blog/%s to %s/blog/%s" % (post, BUILD_DIRECTORY, PostPath))
153
with open(BUILD_DIRECTORY + "/blog/" + PostPath, "w", encoding="utf-8") as PostHTMLFile:
154
PostHTMLFile.write(RenderedHTML)
155
print("Copying blog/%s to %s/blog/%s" % (post, BUILD_DIRECTORY, PlaintextPath))
156
with open(BUILD_DIRECTORY + "/blog/" + PlaintextPath, "w", encoding="utf-8") as PostPlaintext:
157
PostPlaintext.write(PostMD)
158
sitemap.append(SITEMAP_HREF + "/blog/" + PostPath)
159
160
def RenderPage(PageInput: str, ContentDest: str, AllowSitemap: bool = True, **kwargs):
161
print("Building views/%s to %s/%s" % (PageInput, BUILD_DIRECTORY, ContentDest))
162
if AllowSitemap:
163
sitemap.append(SITEMAP_HREF + ContentDest)
164
with open(BUILD_DIRECTORY + "/" + ContentDest, "w", encoding="utf-8") as DestLocation:
165
DestLocation.write(RenderTemplate(PageInput, **kwargs))
166
167
def CreateJSONFeed():
168
CreatedJSON = {
169
"version": "https://jsonfeed.org/version/1",
170
"title": "Steve0Greatness' Blog",
171
"home_page_url": "https://steve0greatness.github.io",
172
"feed_url": "https://steve0greatness.github.io/blog/feed.rss",
173
"language": "en-US",
174
"favicon": "https://steve0greatness.github.io/favicon.ico",
175
"description": "A blog by a human being.",
176
"authors": [
177
{
178
"name": "Steve0Greatness",
179
"url": "https://steve0greatness.github.io"
180
}
181
],
182
"items": []
183
}
184
for post in PostList:
185
CreatedJSON["items"].append({
186
"id": "https://steve0greatness.github.io/blog/" + post["pathname"],
187
"title": "JSON Feed version 1.1",
188
"icon": "https://steve0greatness.github.io/favicon.ico",
189
"content_html": post["content"],
190
"date_published": post["atom-post-time"],
191
"date_modified": post["atom-update-time"],
192
"url": "https://steve0greatness.github.io/blog/" + post["pathname"]
193
})
194
with open(BUILD_DIRECTORY + "/blog/feed.json", "w") as JSONFeedFile:
195
DumpJSON(CreatedJSON, JSONFeedFile)
196
197
def RenderLists():
198
Lists = GetLists()
199
CreateDirectory(BUILD_DIRECTORY + "/list/")
200
ListIndex = "<ul>"
201
for List in Lists:
202
FileLocation = "/list/" + List["filename"].replace(".yml", ".html")
203
Title = List["title"]
204
print("%s -> %s" % ("lists/" + List["filename"], BUILD_DIRECTORY + FileLocation))
205
with open(BUILD_DIRECTORY + FileLocation, "w") as file:
206
file.write(RenderTemplate("list.html", Content=List["content"], Title=Title, Location=FileLocation))
207
ListIndex += "<li><a href=\"%s\">%s</a></li>" % (FileLocation, Title)
208
ListIndex += "</ul>"
209
print("Building list index")
210
with open(BUILD_DIRECTORY + "/list/index.html", "w") as file:
211
file.write(RenderTemplate("list-index.html", Content=ListIndex))
212
213
def main():
214
PostList = GetBlogList()
215
print("Wiping directory")
216
WipeFinalDir()
217
print("Creating blog holder")
218
CreateDirectory(BUILD_DIRECTORY + "/blog")
219
print("Rendering posts")
220
RenderPosts()
221
CreateJSONFeed()
222
print("Copying static directory")
223
CopyDirectory("static", BUILD_DIRECTORY)
224
print("Creating lists")
225
RenderLists()
226
227
print("Building pages")
228
for file, path in PAGES.items():
229
if file in DISALLOWED_SITEMAP:
230
RenderPage(file, path, False, PostList=PostList)
231
continue
232
RenderPage(file, path, PostList=PostList)
233
234
print("Building redirects")
235
for OldLocation, NewLocation in REDIRECTS:
236
RenderPage("redirect.html", OldLocation, False, redirect=NewLocation)
237
238
with open(BUILD_DIRECTORY + "/sitemap.txt", "w") as SitemapFile:
239
SitemapFile.write("\n".join(sitemap))
240
241
if __name__ == "__main__":
242
main()