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