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