A Static Site Generator using markdown files
Project description
pyssg - Static Site Generator written in Python
Generates HTML files from MD files for a static site, personally using it for a blog-like site.
Initially inspired by Roman Zolotarev's ssg5
and rssg
, Luke Smith's lb
and sup
and, pedantic.software's blogit
.
Features and to-do
NOTE: WIP, there will be changes that will break the setup.
- Build static site parsing
markdown
files (*.md
->*.html
)- Uses
jinja
for templating. - Preserves hand-made
*.html
files. - Tag functionality, useful for blog-style sites.
- Open Graph (and similar) support.
- Technically, this works if you add the correct metadata to the
*.md
files and use the variables available for Jinja.
- Technically, this works if you add the correct metadata to the
- Uses
- Build
sitemap.xml
file.- Include manually added
*.html
files.
- Include manually added
- Build
rss.xml
file.- Join the
static_url
to all relative URLs found to comply with the RSS 2.0 spec. - Include manually added
*.html
files.
- Join the
- YAML for configuration file, uses
PyYAML
.- Handle multiple "documents".
- More complex directory structure to support multiple subdomains and different types of pages.
- Option/change to using an SQL database instead of the custom solution.
- Checksum checking because the timestamp of the file is not enough.
- Use external markdown extensions.
Markdown features
This program uses the base markdown
syntax plus additional syntax, all thanks to python-markdown
that provides extensions. The following extensions are used:
- Extra (collection of QoL extensions).
- Meta-Data.
- Sane Lists.
- SmartyPants.
- Table of Contents.
- WikiLinks.
- yafg - Yet Another Figure Generator
- Markdown Checklist
- PyMdown Extensions
Installation
Install with pip
:
pip install pyssg
Probably will add a PKBUILD (and possibly submit it to the AUR) in the future.
Usage
- Get the default configuration file:
pyssg --copy-default-config -c <path/to/config>
- Where
-c
is optional as by default$XDG_CONFIG_HOME/pyssg/config.yaml
is used.
- Edit the config file created as needed.
config.yaml
is parsed usingPyYAML
, more about the config file.
- Initialize the directory structures (source, destination, template) and move template files:
pyssg -i
-
You can modify the basic templates as needed (see variables available for Jinja).
-
Strongly recommended to edit the
rss.xml
template.
- Place your
*.md
files somewhere inside the source directory. It accepts sub-directories.
- Recommended (no longer mandatory) metadata keys that can be added to the top of
.md
files:
title: the title of your blog entry or whatever
author: your name or online handle
another name maybe for multiple authors?
lang: the language the entry is written on
summary: a summary of the entry
tags: english
short
tutorial
etc
- You can add more meta-data keys as long as it is Python-Markdown compliant, and these will ve available as Jinja variables.
- Build the
*.html
with:
pyssg -b
- After this, you have ready to deploy
*.html
files.
Config file
All sections/options need to be compliant with PyYAML
which should be compliant with YAML 1.2
. Additionaly, I've added the custom tag !join
which concatenates strings from an array, which an be used as follows:
variable: &variable_reference_name "value"
other_variable: !join [*variable_reference_name, "other_value", 1]
Which would produce other_variable: "valueother_value1"
. Also environment variables will be expanded internally.
The following is a list of config items that need to be present in the config unless stated otherwise:
%YAML 1.2
---
# not needed, shown here as an example of the !join tag
define: &root "$HOME/path/to/" # $HOME expands to /home/user, for example
title: "Example site"
path:
src: !join [*root, "src"] # $HOME/path/to/src
dst: "$HOME/some/other/path/to/dst"
plt: "plt"
db: !join [*root, "src/", "db.psv"]
url:
main: "https://example.com"
fmt:
date: "%a, %b %d, %Y @ %H:%M %Z"
list_date: "%b %d"
list_sep_date: "%B %Y"
dirs:
/: # root "dir_path", whatever is sitting directly under "src"
cfg:
plt: "page.html"
# the template can be specified instead of just True/False, a default template will used
tags: False
index: True
rss: True
sitemap: True
exclude_dirs: ["articles", "blog"] # optional; list of subdirectories to exclude when parsing the / dir_path
# below are other example "dir_paths", can be named anything, only the / (above) is mandatory
articles:
cfg:
plt: "page.html"
tags: True
index: True
rss: True
sitemap: True
blog:
cfg:
# ...
...
The config under dirs
are just per-subdirectory configuration of directories under src
. Only the /
"dir_path" is required as it is the config for the root src
path files.
The following will be added on runtime:
%YAML 1.2
---
fmt:
rss_date: "%a, %d %b %Y %H:%M:%S GMT" # fixed
sitemap_date: "%Y-%m-%d" # fixed
info:
version: "x.y.z" # current 'pyssg' version (0.5.1.dev16, for example)
debug: True/False # depending if --debug was used when executing
force: True/False # depending if --force was used when executing
rss_run_date: # date the program was run, formatted with 'fmt.rss_date'
sitemap_run_date: # date the program was run, formatted with 'fmt.sitemap_date'
...
You can add any other option/section that you can later use in the Jinja templates via the exposed config object. URL's shouldn't have the trailing slash /
Available Jinja variables
These variables are exposed to use within the templates. The below list is displayed in the form of variable (type) (available from): description. field1/field2/field3/...
describe config file section from the YAML file and option and object.attribute
corresponding object and it's attribute.
config
(dict
) (all): parsed config file plus the added options internally (as described in config file).dir_config
(dict
) (all*): parsed dir_config file plus the added options internally (as described in config file). *This is for all of the specific "dir_path" files, as per configured in the YAML filedirs.dir_path.cfg
(for exmapledirs./.cfg
for the required dir_path).all_pages
(list(Page)
) (all): list of all the pages, sorted by creation time, reversed.page
(Page
) (page.html
): contains the following attributes (genarally these are parsed from the metadata in the*.md
files):title
(str
): title of the page.author
(list[str]
): list of authors of the page.lang
(str
): page language, used for the generalhtml
taglang
attribute.summary
(str
): summary of the page, as specified in the*.md
file.content
(str
): actual content of the page, this is thehtml
.cdatetime
(str
): creation datetime object of the page.cdate
(str
): formattedcdatetime
as the config optionfmt/date
.cdate_list
(str
): formattedcdatetime
as the config optionfmt/list_date
.cdate_list_sep
(str
): formattedcdatetime
as the config optionfmt/list_sep_date
.cdate_rss
(str
): formattedcdatetime
as required by rss.cdate_sitemap
(str
): formattedcdatetime
as required by sitemap.mdatetime
(str
): modification datetime object of the page. Defaults toNone
.mdate
(str
): formattedmdatetime
as the config optionfmt/date
. Defaults toNone
.mdate_list
(str
): formattedmdatetime
as the config optionfmt/list_date
.mdate_list_sep
(str
): formattedmdatetime
as the config optionfmt/list_sep_date
.mdate_rss
(str
): formattedmdatetime
as required by rss.mdate_sitemap
(str
): formattedmdatetime
as required by sitemap.tags
(list(tuple(str))
): list of tuple of tags of the page, containing the name and the url of the tag, in that order. Defaults to empty list.url
(str
): url of the page, this already includes theurl/main
from config file.image_url
(str
): image url of the page, this already includes theurl/static
. Defaults to theurl/default_image
config option.next/previous
(Page
): reference to the next or previous page object (containing all these attributes). Defaults toNone
.og
(dict(str, str)
): dict for object graph metadata.meta
(dict(str, list(str))
): meta dict as obtained from python-markdown, in case you use a meta tag not yet supported, it will be available there.
tag
(tuple(str)
) (tag.html
): tuple of name and url of the current tag.tag_pages
(list(Page)
) (tag.html
): similar toall_pages
but contains all the pages for the current tag.all_tags
(list(tuple(str))
) (all): similar topage.tags
but contains all the tags.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.