-
Notifications
You must be signed in to change notification settings - Fork 1
/
geminer.py
executable file
·185 lines (152 loc) · 6.33 KB
/
geminer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env python3
from md2gemini import md2gemini
import frontmatter
from slugify import slugify
from jinja2 import Template
import os
import locale
from datetime import datetime
import config
# locale (for templates, for example dates rendering)
locale.setlocale(locale.LC_ALL, config.locale)
md_path = os.path.abspath(os.path.expanduser(config.md_path))
gmi_path = os.path.abspath(os.path.expanduser(config.gmi_path))
tpl_path = os.path.abspath(os.path.expanduser(config.tpl_path))
posts_path = os.path.abspath(gmi_path + "/" + config.posts_dir)
# Initiate meta lists
posts = [] # This is a flat, unsorted list of posts
posts_prop_index = {} # This is a dict containing posts sorted by properties
for prop_dict in config.index_props:
posts_prop_index[prop_dict["property"]] = {}
def add_ext_gmi(link):
# Custom function to apply to links
if "://" not in link: # apply only on local links
return os.path.splitext(link)[0] + ".gmi"
else:
return link
# Walk through markdown directories
for dirname, subdirlist, mdlist in os.walk(md_path):
# Create same hierarchy in GMI directory
gmi_subpath = os.path.abspath(posts_path + "/" + os.path.relpath(dirname, md_path))
os.makedirs(gmi_subpath, exist_ok=True)
for mdfile in mdlist:
basename, extension = os.path.splitext(mdfile)
# We want to ignore the file if this isn't a markdown file
if extension not in config.md_extensions:
print(
'Ignoring file {}: "{}" not in markdown extensions list'.format(
mdfile, extension
)
)
pass
post = {}
gmifile = basename + config.gmi_extension
post["path"] = config.posts_dir + "/" + os.path.relpath(dirname + "/" + gmifile, md_path)
# Read the Markdown file
with open(dirname + "/" + mdfile, "r") as md:
mdtext = md.read()
# Parse the YAML header
meta = frontmatter.parse(mdtext)[0]
# Extract template
post["template"] = meta.get("template", config.default_post_template)
# Extract post properties
for prop in config.post_props:
post[prop] = meta.get(prop, None)
# Extract index properties
for prop_dict in config.index_props:
prop = prop_dict["property"]
prop_raw = meta.get(prop, None)
if prop_dict.get("list", False) and prop_raw:
post[prop] = [
{"name": word, "slug": slugify(word)}
for word in prop_raw.split(",")
]
for item in post[prop]:
slug = item["slug"]
if slug in posts_prop_index[prop]:
posts_prop_index[prop][slug]["posts"].append(post)
else:
posts_prop_index[prop][slug] = {
"name": item["name"],
"posts": [post],
}
else:
post[prop] = {"name": prop_raw, "slug": slugify(prop_raw)}
slug = post[prop]["slug"]
if slug in posts_prop_index[prop]:
posts_prop_index[prop][slug]["posts"].append(post)
else:
posts_prop_index[prop][slug] = {
"name": post[prop]["name"],
"posts": [post],
}
posts.append(post)
# For now, list properties must be comma-separated strings.
# TODO: make possible to list values as a YAML list
# Replace stuff
for item in config.replace:
mdtext = mdtext.replace(item[0], item[1])
# Convert the post into GMI
gmitext = md2gemini(
mdtext,
code_tag=config.code_tag,
img_tag=config.img_tag,
indent=config.indent,
ascii_table=config.ascii_table,
frontmatter=True,
links=config.links,
plain=config.plain,
strip_html=config.strip_html,
base_url=config.base_url,
link_func=add_ext_gmi,
table_tag=config.table_tag,
)
post["content"] = gmitext
# Read template file
with open(tpl_path + "/" + post["template"] + ".tpl", "r") as tpl:
template = Template(tpl.read())
# Integrate the GMI content in the template
gmitext = template.render(post=post)
# Dirty fix a weird bug where some lines are CRLF-terminated
gmitext = gmitext.replace("\r\n", "\n")
# Time to write the GMI file
with open(gmi_subpath + "/" + gmifile, "w") as gmi:
gmi.write(gmitext)
# Generate custom extra pages
for page_dict in config.custom_pages:
rel_path, filename = os.path.split(page_dict["name"])
if rel_path:
os.makedirs(rel_path, exist_ok=True)
basename, extension = os.path.splitext(filename)
if extension == "":
filename = basename + config.gmi_extension
else:
filename = basename + extension
filepath = os.path.join(rel_path, filename)
with open(tpl_path + "/" + page_dict.get("tpl", basename) + ".tpl", "r") as tpl:
template = Template(tpl.read())
template.globals['now'] = datetime.now
text = template.render(posts=posts)
text = text.replace("\r\n", "\n")
with open(gmi_path + "/" + filepath, "w") as gmi:
gmi.write(text)
# Generate custom meta pages
for prop_dict in config.index_props:
prop = prop_dict["property"]
if "index_name" in prop_dict:
with open(
tpl_path + "/" + prop_dict.get("index_tpl", prop) + ".tpl", "r"
) as tpl:
template = Template(tpl.read())
text = template.render(prop=posts_prop_index[prop])
with open(gmi_path + "/" + prop_dict["index_name"] + config.gmi_extension, "w") as gmi:
gmi.write(text)
os.makedirs(gmi_path + "/" + prop_dict.get("item_dir", prop), exist_ok=True)
with open(tpl_path + "/" + prop_dict.get("item_tpl", prop) + ".tpl", "r") as tpl:
template = Template(tpl.read())
for item in posts_prop_index[prop]:
text = template.render(prop_item=posts_prop_index[prop][item])
with open(
gmi_path + "/" + prop_dict.get("item_dir", prop) + "/" + item + config.gmi_extension, "w"
) as gmi:
gmi.write(text)