#!/usr/bin/env python3 # -*- coding: utf-8 -*- """blog manager""" from __future__ import annotations import datetime import hashlib import json import os import re import shutil import string import subprocess import sys import tempfile import typing import xml.etree.ElementTree as etree from collections import Counter from glob import iglob from html import escape as html_escape from threading import Thread from timeit import default_timer as code_timer import mistune import mistune.core import mistune.inline_parser import mistune.plugins import unidecode import web_mini from mistune.renderers.html import HTMLRenderer from pygments import highlight from pygments.formatters import HtmlFormatter, html from pygments.lexers import get_lexer_by_name, guess_lexer from readtime import of_markdown as read_time_of_markdown # type: ignore from readtime.result import Result as MarkdownResult # type: ignore # from warnings import filterwarnings as filter_warnings __version__: typing.Final[int] = 2 GEN: typing.Final[str] = f"ari-web blog generator version {__version__}" MEDIA_MIME: dict[str, str] = { "image/jpeg": "jpeg", "image/png": "png", "image/gif": "gif", "image/webp": "webp", "image/avif": "avif", "image/svg+xml": "svg", "audio/mpeg": "mp3", "audio/wav": "wav", "audio/ogg": "ogg", "audio/flac": "flac", } OK: typing.Final[int] = 0 ER: typing.Final[int] = 1 CONFIG_FILE: typing.Final[str] = "blog.json" DEFAULT_CONFIG: dict[str, typing.Any] = { "title": "blog", "header": "blog", "description": "my blog page", "posts-dir": "b", "assets-dir": "content", "rss-file": "rss.xml", "blog-keywords": [ "blog", "blog page", "blog post", "personal", "website", ], "default-keywords": [ "blog", "blog page", "blog post", "personal", "website", ], "website": "https://example.com", "blog": "https://blog.example.com", "source": "/git", "visitor-count": "/visit", "comment": "/c", "theme": { "primary": "#000", "secondary": "#fff", "type": "dark", }, "manifest": { "icons": [ { "src": "/favicon.ico", "sizes": "128x128", "type": "image/x-icon", }, ], }, "author": "John Doe", "email": "me@example.com", "locale": "en_GB", "recents": 14, "indent": 4, "markdown-plugins": [ # good defaults "speedup", "strikethrough", "insert", "superscript", "subscript", "footnotes", "abbr", ], "editor": ["vim", "--", "%s"], "context-words": [ "the", "a", "about", "etc", "on", "at", "in", "by", "its", "i", "to", "my", "of", "between", "because", "of", "or", "how", "to", "begin", "is", "this", "person", "important", "homework", "and", "cause", "how", "what", "for", "with", "without", "using", "im", ], "wslug-limit": 10, "slug-limit": 96, "license": "GPL-3.0-or-later", "recent-title-trunc": 16, "server-host": "127.0.0.1", "server-port": 8080, "post-preview-size": 196, "read-wpm": 150, "top-words": 64, "top-tags": 64, "code-style": "coffee", "note": 'This page uses the Nerd Hack Font, which is licensed under the OFL 1.1 License.', "posts": {}, } NCI: bool = "CI" not in os.environ NOCLR: bool = "NOCLR" in os.environ LOG_CLR: str = "\033[90m" ERR_CLR: str = "\033[1m\033[31m" NEW_CLR: str = "\033[1m\033[32m" IMP_CLR: str = "\033[1m\033[35m" HTML_BEGIN: typing.Final[ str ] = """
""" POST_TEMPLATE: typing.Final[str] = ( HTML_BEGIN + """