import datetime import os import re from glob import glob from typing import Optional from flask import Flask, Response, abort, send_from_directory, render_template from markdown import markdown basedir = os.path.abspath(os.path.join(os.path.realpath(__file__), '..', '..')) templates_dir = os.path.join(basedir, 'templates') static_dir = os.path.join(basedir, 'static') pages_dir = os.path.join(static_dir, 'pages') img_dir = os.path.join(static_dir, 'img') css_dir = os.path.join(static_dir, 'css') app = Flask(__name__, template_folder=templates_dir) def parse_page_title(page: str) -> str: if page.endswith('.md'): page = page[:-3] return page.replace('-', ' ') def get_page_metadata(page: str) -> dict: if not page.endswith('.md'): page = page + '.md' if not os.path.isfile(os.path.join(pages_dir, page)): abort(404) metadata = {} with open(os.path.join(pages_dir, page), 'r') as f: metadata['uri'] = '/article/' + page[:-3] for line in f.readlines(): if not line: continue if not (m := re.match(r'^\[//]: # \(([^:]+):\s*([^)]+)\)\s*$', line)): break if m.group(1) == 'published': metadata[m.group(1)] = datetime.date.fromisoformat(m.group(2)) else: metadata[m.group(1)] = m.group(2) return metadata def get_page(page: str, title: Optional[str] = None, skip_header: bool = False): if not page.endswith('.md'): page = page + '.md' metadata = get_page_metadata(page) with open(os.path.join(pages_dir, page), 'r') as f: return render_template('article.html', title=title if title else metadata.get('title', 'Platypush blog'), image=metadata.get('image'), description=metadata.get('description'), author=re.match(r'(.+?)\s+<([^>]+>)', metadata['author'])[1] if 'author' in metadata else None, author_email=re.match(r'(.+?)\s+<([^>]+)>', metadata['author'])[2] if 'author' in metadata else None, published=(metadata['published'].strftime('%b %d, %Y') if metadata.get('published') else None), content=markdown(f.read(), extensions=['fenced_code', 'codehilite']), skip_header=skip_header) def get_pages(with_content: bool = False, skip_header: bool = False) -> list: return sorted([ { 'path': path, 'content': get_page(path, skip_header=skip_header) if with_content else '', **get_page_metadata(os.path.basename(path)), } for path in glob(os.path.join(pages_dir, '*.md')) ], key=lambda page: page.get('published'), reverse=True) @app.route('/', methods=['GET']) def home_route(): return render_template('index.html', pages=get_pages()) @app.route('/favicon.ico', methods=['GET']) def favicon_route(): return send_from_directory(img_dir, 'favicon.ico') @app.route('/img/', methods=['GET']) def img_route(img: str): return send_from_directory(img_dir, img) @app.route('/css/