A mirror of my website's source code.

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 build.py

View raw Download
text/x-script.python • 11.45 kiB
Python script, Unicode text, UTF-8 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
from re import sub as RegReplace
11
from typing import Literal
12
13
def GetCurTime():
14
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
15
16
START_TIME = GetCurTime()
17
18
DEPLOY_BUILD_DIR = {
19
"gh-pages-deploy": "build",
20
"gl-pages-deploy": "public",
21
"cb-pages": "build",
22
} # Separate because this site is built with an action that won't work if they aren't
23
LOCAL_BUILD_DIR = "build"
24
25
PAGES_DEPLOY = argv[1] if len(argv) > 1 else None
26
BUILD_DIRECTORY = DEPLOY_BUILD_DIR[PAGES_DEPLOY] if PAGES_DEPLOY is not None else LOCAL_BUILD_DIR
27
28
PAGES = {
29
"index.html": "index.html",
30
"blog-list.html": "blog/index.html",
31
"blog-feed.rss": "blog/feed.rss",
32
"blog-feed.atom": "blog/feed.atom",
33
"404.html": "404.html",
34
"404.html": "not_found.html",
35
}
36
37
DISALLOWED_SITEMAP = {
38
"404.html",
39
"blog-feed.rss",
40
"blog-feed.atom",
41
"blog-list.html",
42
"index.html",
43
"not_found.html",
44
}
45
46
REDIRECTS = {
47
"link-tree.html": "list/link-tree.html", # Old location -> new location
48
}
49
50
SITEMAP_HREF = "https://steve0greatness.github.io/"
51
sitemap = [
52
SITEMAP_HREF + "blog/",
53
SITEMAP_HREF,
54
]
55
56
def EscapeHTMLForRSS(HTML: str) -> str:
57
values = {
58
"&": "&", # this is here for a reason, do not change order.
59
"<": "&lt;",
60
">": "&gt;",
61
"§": "&#xa7;",
62
}
63
RssHtml = HTML
64
for old, new in values.items():
65
RssHtml = RssHtml.replace(old, new)
66
return RssHtml
67
68
def WipeFinalDir():
69
if not PathExists(BUILD_DIRECTORY):
70
print("Directory didn't existing, creating it...")
71
CreateDirectory(BUILD_DIRECTORY)
72
return
73
print("Directory exists, wiping it...")
74
for item in ListDirectory(BUILD_DIRECTORY):
75
path = BUILD_DIRECTORY + "/" + item
76
if IsFile(path):
77
DeleteFile(path)
78
continue
79
DeleteDirectory(path)
80
81
def PostDateToDateObj(Date):
82
return datetime.strptime(Date, "%Y %b %d")
83
84
def PostSortHelper(Post):
85
return PostDateToDateObj(Post["date"])
86
87
def GetBlogList():
88
print("Grabbing post list")
89
PostSlugs: tuple[tuple[Literal["blog-posts", "drafts"], str], ...] = tuple( ("blog-posts", file) for file in ListDirectory("blog-posts") )
90
if not PAGES_DEPLOY and PathExists("drafts"):
91
PostSlugs = PostSlugs + tuple( ("drafts", file) for file in ListDirectory("drafts") )
92
Posts = []
93
for dir, slug in PostSlugs:
94
if not slug.endswith(".md"):
95
continue
96
print("Grabbing post list blog-posts/%s" % (slug))
97
with open(dir + "/" + slug, encoding="utf-8") as MDFile:
98
RawMD = MDFile.read()
99
PostHTML = RenderMarkdown(RawMD)
100
Item = PostHTML.metadata
101
Item["content"] = PostHTML
102
Item["raw-content"] = RawMD
103
Item["rss-content"] = EscapeHTMLForRSS(PostHTML)
104
Item["rss-post-time"] = PostDateToDateObj(Item["date"]).strftime("%a, %d %b %Y") + " 00:00:00 GMT"
105
Item["atom-post-time"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d") + "T00:00:00Z"
106
Item["opengraph-date"] = PostDateToDateObj(Item["date"]).strftime("%Y-%m-%d")
107
Item["opengraph-update"] = Item["opengraph-date"]
108
Item["atom-update-time"] = Item["atom-post-time"]
109
if "updated" in Item:
110
Item["atom-update-time"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d") + "T00:00:00Z"
111
Item["opengraph-update"] = PostDateToDateObj(Item["updated"]).strftime("%Y-%m-%d")
112
Item["pathname"] = slug.replace(".md", ".html")
113
Item["plaintext"] = slug.replace(".md", ".txt")
114
Item["origin"] = slug
115
Item["is-draft"] = dir == "drafts"
116
Posts.append(Item)
117
PostsByDate = sorted(Posts, key=PostSortHelper, reverse=True)
118
return PostsByDate
119
120
PostList = []
121
122
123
def ListParseCategory(Obj, depth):
124
html = "<h%d id=\"%s\">%s</h%d>" % (2+depth, Obj["id"], Obj["title"], 2+depth)
125
if "paragraph" in Obj:
126
html += "<p>%s</p>" % Obj["paragraph"]
127
listType = "ul"
128
if "list-type" in Obj and Obj["list-type"] == "ordered":
129
listType = "ol"
130
html += "<%s>" % listType
131
for item in Obj["list"]:
132
html += "<li>" + LIST_PARSER_DICT[item["type"]](item, depth + 1) + "</li>"
133
html += "</%s>" % listType
134
return html
135
136
def ListParseLink(Obj, depth):
137
html = "<a href=\"%s\">" % Obj["href"]
138
text = Obj["text"]
139
if "text-type" in Obj and Obj["text-type"] == "text/markdown":
140
text = RenderMarkdown(text).replace("<p>", "").replace("</p>", "")
141
html += text + "</a>"
142
if "comment" in Obj:
143
html += "(%s)" % Obj["comment"]
144
return html
145
146
def ListParseText(Obj, depth):
147
text = Obj["text"]
148
# if "text-type" in Obj and Obj["text-type"] == "text/markdown":
149
# print(RenderMarkdown(text))
150
# text = RenderMarkdown(text) # this doesn't work???
151
if "comment" in Obj:
152
text += "(%s)" % Obj["comment"]
153
return text
154
155
LIST_PARSER_DICT = {
156
"category": ListParseCategory,
157
"link": ListParseLink,
158
"text": ListParseText,
159
}
160
161
def GetLists():
162
ListSlugs = ListDirectory("lists")
163
Lists = []
164
for slug in ListSlugs:
165
List = {
166
"title": "",
167
"content": "",
168
"filename": slug
169
}
170
with open("lists/" + slug, encoding="utf-8") as ListYML:
171
ListDict = LoadYML(ListYML.read())
172
List["title"] = ListDict["title"]
173
if "paragraph" in ListDict:
174
List["content"] += "<p>%s</p>" % ListDict["paragraph"]
175
List["content"] += "<ul>"
176
for item in ListDict["list"]:
177
List["content"] += "<li>" + LIST_PARSER_DICT[item["type"]](item, 0) + "</li>"
178
List["content"] += "</ul>"
179
Lists.append(List)
180
sitemap.append(SITEMAP_HREF + "list/" + slug)
181
sitemap.append(SITEMAP_HREF + "list/")
182
return Lists
183
184
def RenderPosts():
185
global PostList
186
for post in PostList:
187
Revised = post["updated"] if "updated" in post else False
188
RenderedHTML = RenderTemplate(
189
"blog-post.html",
190
Revised=Revised,
191
Title=post["title"],
192
PostDate=post["date"],
193
Content=post["content"],
194
PostPath=post["pathname"],
195
PlaintextPath=post["plaintext"],
196
IsDraft=post["is-draft"],
197
OpenGraphDate=post["opengraph-date"],
198
post=post,
199
CompileTime=GetCurTime(),
200
SiteCompileTime=START_TIME,
201
ViewName="blog-post.html"
202
)
203
print("Building blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["pathname"]))
204
with open(BUILD_DIRECTORY + "/blog/" + post["pathname"], "w", encoding="utf-8") as PostHTMLFile:
205
PostHTMLFile.write(RenderedHTML)
206
print("Copying blog-posts/%s to %s/blog/%s" % (post["origin"], BUILD_DIRECTORY, post["plaintext"]))
207
with open(BUILD_DIRECTORY + "/blog/" + post["plaintext"], "w", encoding="utf-8") as PostHTMLFile:
208
PostHTMLFile.write(post["raw-content"])
209
sitemap.append(SITEMAP_HREF + "blog/" + post["pathname"])
210
211
def RenderPage(PageInput: str, ContentDest: str, AllowSitemap: bool = True, **kwargs):
212
print("Building views/%s to %s/%s" % (PageInput, BUILD_DIRECTORY, ContentDest))
213
if AllowSitemap:
214
sitemap.append(SITEMAP_HREF + ContentDest)
215
with open(BUILD_DIRECTORY + "/" + ContentDest, "w", encoding="utf-8") as DestLocation:
216
DestLocation.write(RenderTemplate(PageInput, **kwargs))
217
218
def CreateJSONFeed():
219
global PostList
220
CreatedJSON = {
221
"version": "https://jsonfeed.org/version/1",
222
"title": "Steve0Greatness' Blog",
223
"home_page_url": "https://steve0greatness.github.io",
224
"feed_url": "https://steve0greatness.github.io/blog/feed.rss",
225
"language": "en-US",
226
"favicon": "https://steve0greatness.github.io/favicon.ico",
227
"description": "A blog by a human being.",
228
"authors": [
229
{
230
"name": "Steve0Greatness",
231
"url": "https://steve0greatness.github.io"
232
}
233
],
234
"items": []
235
}
236
for post in PostList:
237
CreatedJSON["items"].append({
238
"id": "https://steve0greatness.github.io/blog/" + post["pathname"],
239
"title": "JSON Feed version 1.1",
240
"icon": "https://steve0greatness.github.io/favicon.ico",
241
"content_html": post["content"],
242
"date_published": post["atom-post-time"],
243
"date_modified": post["atom-update-time"],
244
"url": "https://steve0greatness.github.io/blog/" + post["pathname"]
245
})
246
with open(BUILD_DIRECTORY + "/blog/feed.json", "w") as JSONFeedFile:
247
DumpJSON(CreatedJSON, JSONFeedFile)
248
249
def RenderLists():
250
Lists = GetLists()
251
CreateDirectory(BUILD_DIRECTORY + "/list/")
252
ListIndex = "<ul>"
253
for List in Lists:
254
FileLocation = "/list/" + List["filename"].replace(".yml", ".html")
255
Title = List["title"]
256
print("%s -> %s" % ("lists/" + List["filename"], BUILD_DIRECTORY + FileLocation))
257
with open(BUILD_DIRECTORY + FileLocation, "w") as file:
258
file.write(RenderTemplate(
259
"list.html",
260
Content=List["content"],
261
Title=Title,
262
Location=FileLocation,
263
CompileTime=GetCurTime(),
264
SiteCompileTime=START_TIME,
265
ViewName="blog-post.html"
266
))
267
ListIndex += "<li><a href=\"%s\">%s</a></li>" % (FileLocation, Title)
268
ListIndex += "</ul>"
269
print("Building list index")
270
with open(BUILD_DIRECTORY + "/list/index.html", "w") as file:
271
file.write(
272
RenderTemplate(
273
"list-index.html",
274
Content=ListIndex,
275
CompileTime="",
276
SiteCompileTime="",
277
ViewName="list-index.html"
278
)
279
)
280
281
def main():
282
global PostList
283
PostList = GetBlogList()
284
print("Wiping directory")
285
WipeFinalDir()
286
print("Creating blog holder")
287
CreateDirectory(BUILD_DIRECTORY + "/blog")
288
print("Rendering posts")
289
RenderPosts()
290
CreateJSONFeed()
291
print("Copying static directory")
292
CopyDirectory("static", BUILD_DIRECTORY)
293
print("Creating lists")
294
RenderLists()
295
296
print("Building pages")
297
for file, path in PAGES.items():
298
AllowSitemap = file not in DISALLOWED_SITEMAP
299
RenderPage(
300
file,
301
path,
302
AllowSitemap,
303
PostList=PostList,
304
CompileTime=GetCurTime(),
305
SiteCompileTime=START_TIME,
306
ViewName=file
307
)
308
309
print("Building redirects")
310
for OldLocation, NewLocation in REDIRECTS.items():
311
RenderPage("redirect.html", OldLocation, False, redirect=NewLocation, old=OldLocation)
312
313
with open(BUILD_DIRECTORY + "/sitemap.txt", "w") as SitemapFile:
314
SitemapFile.write("\n".join(sitemap))
315
316
if __name__ == "__main__":
317
main()
318
319