#!/usr/bin/env python3 # -*- coding: utf-8 -*- """blog manager""" from __future__ import annotations import asyncio import datetime import hashlib import json import os import re import shutil import string import subprocess import sys import tempfile import time import typing import xml.etree.ElementTree as etree from glob import iglob from html import escape as html_escape from threading import Thread from timeit import default_timer as code_timer from warnings import filterwarnings as filter_warnings import mistune import mistune.core import mistune.inline_parser import mistune.plugins import unidecode from css_html_js_minify import html_minify # type: ignore from css_html_js_minify import process_single_css_file # type: ignore from readtime import of_markdown as read_time_of_markdown # type: ignore __version__: typing.Final[int] = 2 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/png", }, ], }, "author": "John Doe", "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, "proxy-api": "https://gimmeproxy.com/api/getProxy?post=true&get=true&user-agent=true&supportsHttps=true&protocol=http&minSpeed=20&curl=true", "test-proxy": "https://example.com/", "test-proxy-timeout": 15, "license": "GPL-3.0-or-later", "recent-title-trunc": 32, "server-host": "127.0.0.1", "server-port": 8080, "post-preview-size": 196, "read-wpm": 150, "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 + """