~amirouche/babelia.one

babelia.one/maji.py -rwxr-xr-x 4.3 KiB
579024ee — Your Name replace logo with the dark version 10 months ago
                                                                                
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
#!/usr/bin/env python3
"""maji.

Usage:
  maji init
  maji make <base-url>
  maji render <template>
"""
import logging
import os
import sys
from pathlib import Path

from docopt import docopt
from datetime import datetime
from datetime import timezone
from lxml.html import fromstring as string2html
from feedgen.feed import FeedGenerator

from jinja2 import Environment
from jinja2 import FileSystemLoader

import mistune
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import html
from loguru import logger as log


class HighlightRenderer(mistune.Renderer):
    def block_code(self, code, lang):
        if not lang:
            out = '\n<div><pre>{}</pre></div>\n'
            return out.format(mistune.escape(code.strip()))
        lexer = get_lexer_by_name(lang, stripall=True)
        formatter = html.HtmlFormatter()
        return highlight(code, lexer, formatter)


renderer = HighlightRenderer()
markdown = mistune.Markdown(renderer=renderer)


def jinja(template, templates, **context):
    templates = os.path.abspath(templates)
    env = Environment(loader=FileSystemLoader((templates,)))
    template = env.get_template(template)
    out = template.render(**context)
    return out


# make

def make_post(path, base):
    log.info('directory %r', path)
    parts = []
    for subpath in path.glob('*.md'):
        out = dict(name=subpath.name)
        parts.append(out)
        with subpath.open('r') as f:
            source = f.read()
        html = markdown(source)
        html = "<div>{}</div>".format(html)
        out["html"] = html
        html = string2html(html)
        for level in [1,2]:
            headers = html.xpath('h{}/text()'.format(level))
            if not headers:
                continue
            header = headers[0]
            out["header"] = header
            break
    parts = sorted(parts, key=lambda x: x["name"])
    first = parts.pop()
    # compute title and date
    title = first["header"]
    date = title[:len('2017/03/01')]
    date = datetime.strptime(date, '%Y/%m/%d')
    date = date.replace(tzinfo=timezone.utc)
    title = title[len('2017/03/01') + 3 :].strip()
    # sort other files according to the header
    parts = sorted(parts, key=lambda x: x["header"])
    html = first["html"] + ''.join(part["html"] for part in parts)
    post = dict(
        title=title,
        date=date,
        html=html,
        path=path,
        filename=path.name,
    )
    log.debug('rendering blog post')
    page = jinja('post.jinja2', os.getcwd(), base=base, **post)
    output = path / "index.html"
    with output.open('w') as f:
        f.write(page)
    log.debug('wrote: %s', output)
    return post


def make(root, base):
    root = Path(root)
    log.info('getting started at: %s', root)
    blog = root / 'blog'
    paths = blog.glob('*')
    posts = []
    for path in paths:
        if path.is_dir():
            post = make_post(path, base)
            posts.append(post)
        else:
            continue
    posts.sort(key=lambda x: x['date'], reverse=True)
    # populate feed
    output = blog / 'feed.xml'
    log.info('generating feed at: %s', output)
    feed = FeedGenerator()
    feed.id(base)
    feed.title('babelia.one')
    feed.subtitle('Wanna be large scale search engine for the commons')
    feed.link(href=base + '/feed.xml', rel='self')
    for post in posts:
        entry = feed.add_entry()
        url = base + '/blog/' + post['filename']
        entry.id(url)
        entry.title(post['title'])
        entry.link(href=url)
        entry.published(post['date'].isoformat())
    feed.rss_file(str(output))
    log.info('rendering index')
    page = jinja('index.jinja2', os.getcwd(), base=base, posts=posts)
    output = blog / 'index.html'
    with output.open('w') as f:
        f.write(page)


def main():
    args = docopt(__doc__, version='maji 0.1')
    if args.get('init'):
        raise NotImplementedError()
    elif args.get('make'):
        base = args['<base-url>']
        make(os.getcwd(), base)
    elif args.get('render'):
        # render markdown to html
        content = markdown(sys.stdin.read())
        # render template with `content`
        template = args['<template>']
        templates = os.path.abspath(template)
        templates = os.path.dirname(templates)
        out = jinja(template, templates, content=content)
        print(out)


if __name__ == '__main__':
    main()