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