Compare commits
7 Commits
945aa6e57b
...
main
Author | SHA1 | Date | |
---|---|---|---|
694d4b74a4 | |||
4c49d4e96a | |||
c1b730d396 | |||
4321429dbf | |||
8c4cb8dad2 | |||
![]() |
ee19286ee8 | ||
![]() |
1e30909e52 |
@@ -1,5 +1,11 @@
|
||||
theme: './theme/default'
|
||||
author_name: 'Firstname Name'
|
||||
author_mail: 'name@example.com'
|
||||
draft: './draft'
|
||||
# python -m uuid -u uuid4
|
||||
id: 'a06cd9a6-3a48-479b-bf7f-40ddcdde7982'
|
||||
inbox: './inbox'
|
||||
outbox: './outbox'
|
||||
theme: './theme/default'
|
||||
title: 'Blog title'
|
||||
url: 'https://blog.example.com'
|
||||
outbox: './outbox'
|
||||
presentation: 'Blog presentation.'
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ main.spec
|
||||
inbox/
|
||||
outbox/
|
||||
themes/
|
||||
draft/
|
||||
|
1
Makefile
1
Makefile
@@ -1,3 +1,4 @@
|
||||
default: build
|
||||
.PHONY: build install-tools install-dep init clean
|
||||
|
||||
init: install-dep install-tools
|
||||
|
71
blog/blog.py
71
blog/blog.py
@@ -1,11 +1,12 @@
|
||||
import glob
|
||||
import shutil
|
||||
import datetime
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from blog.page import Page
|
||||
from blog.config import Config
|
||||
from jinja2 import Environment, FileSystemLoader, Template
|
||||
|
||||
|
||||
class Blog:
|
||||
|
||||
def __init__(self, conf: Config):
|
||||
@@ -13,18 +14,14 @@ class Blog:
|
||||
self.conf = conf
|
||||
self.pages = dict()
|
||||
|
||||
def load_pages(self):
|
||||
"""Charge tous les fichiers .md dans le dossier inbox"""
|
||||
files_list = glob.glob(f"{self.conf.inbox}/*.md")
|
||||
def make(self, draft: bool = False):
|
||||
"""Convertit les pages en un site html"""
|
||||
|
||||
self.pages = dict()
|
||||
for file in files_list:
|
||||
self.pages[Path(file).stem] = Page(Path(file))
|
||||
self._load_pages(self.conf.inbox)
|
||||
|
||||
def make(self):
|
||||
"""Convertit les pages en un site html"""
|
||||
if not self.pages:
|
||||
self.load_pages()
|
||||
if draft:
|
||||
self._load_pages(self.conf.draft)
|
||||
|
||||
env = Environment(loader=FileSystemLoader(self.conf.theme))
|
||||
|
||||
@@ -34,6 +31,13 @@ class Blog:
|
||||
self._copy_css()
|
||||
self._build_all_pages(page_template)
|
||||
self._build_index(index_template)
|
||||
self._build_atom()
|
||||
|
||||
def _load_pages(self, path: Path):
|
||||
"""Charge tous les fichiers .md dans le dossier inbox"""
|
||||
files_list = glob.glob(f"{path}/*.md")
|
||||
for file in files_list:
|
||||
self.pages[Path(file).stem] = Page(Path(file))
|
||||
|
||||
def _build_all_pages(self, template: Template):
|
||||
"""Convertit les pages markdown dans conf.inbox en html dans conf.outbox"""
|
||||
@@ -43,7 +47,7 @@ class Blog:
|
||||
outbox_path.mkdir()
|
||||
|
||||
for filename in self.pages:
|
||||
html_content = self.pages[filename].html(template)
|
||||
html_content = self.pages[filename].html_template(template)
|
||||
with open(f"{self.conf.outbox}/pages/{filename}.html", "w+") as html_file:
|
||||
html_file.write(html_content)
|
||||
|
||||
@@ -55,7 +59,52 @@ class Blog:
|
||||
with open(f"{self.conf.outbox}/index.html", "w+") as html_file:
|
||||
html_file.write(html_content)
|
||||
|
||||
def _build_atom(self):
|
||||
""" """
|
||||
updated = datetime.date(1970, 1, 1)
|
||||
|
||||
articles = ""
|
||||
for filename in self.pages:
|
||||
date = self.pages[filename].date
|
||||
if updated < date:
|
||||
updated = date
|
||||
articles += textwrap.indent(
|
||||
textwrap.dedent(f"""\
|
||||
<entry>
|
||||
<title>{self.pages[filename].title}</title>
|
||||
<link href="{self.conf.url}/pages/{filename}.html"/>
|
||||
<updated>{date}T00:00:00Z</updated>
|
||||
<id>urn:uuid:{self.pages[filename].id}</id>
|
||||
<content type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
{self.pages[filename].html()}
|
||||
</div>
|
||||
</content>
|
||||
</entry>
|
||||
"""),
|
||||
" ")
|
||||
|
||||
header = textwrap.dedent(f""" <?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>{self.conf.title}</title>
|
||||
<subtitle>{self.conf.presentation}</subtitle>
|
||||
<link href="{self.conf.url}/atom.xml" rel="self"/>
|
||||
<link href="{self.conf.url}/index.html"/>
|
||||
<updated>{updated}T00:00:00Z</updated>
|
||||
<author>
|
||||
<name>{self.conf.author_name}</name>
|
||||
<email>{self.conf.author_mail}</email>
|
||||
</author>
|
||||
<id>urn:uuid:{self.conf.id}</id>
|
||||
""")
|
||||
|
||||
footer = "</feed>"
|
||||
|
||||
with open(Path(self.conf.outbox) / "atom.xml", 'w+') as rss_file:
|
||||
rss_file.write(header + articles + footer)
|
||||
|
||||
def _copy_css(self):
|
||||
"""Copie les fichiers CSS du theme vers l'export"""
|
||||
css_path = Path(self.conf.theme) / "css"
|
||||
dest_path = Path(self.conf.outbox) / "css"
|
||||
|
||||
|
@@ -5,7 +5,18 @@ from pathlib import Path
|
||||
class Config:
|
||||
|
||||
_conf = dict()
|
||||
_list_valid_parameters = {"inbox", "outbox", "theme", "title", "presentation"}
|
||||
_list_valid_parameters = {
|
||||
"inbox",
|
||||
"outbox",
|
||||
"theme",
|
||||
"title",
|
||||
"presentation",
|
||||
"url",
|
||||
"draft",
|
||||
"author_name",
|
||||
"author_mail",
|
||||
"id"
|
||||
}
|
||||
|
||||
def __init__(self, config_file: Path):
|
||||
"""Constructeur : charge les paramètres depuis le fichier de configuration"""
|
||||
|
36
blog/page.py
36
blog/page.py
@@ -1,33 +1,31 @@
|
||||
import re
|
||||
import os
|
||||
import yaml
|
||||
import uuid
|
||||
import jinja2
|
||||
import textwrap
|
||||
import markdown
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from datetime import date
|
||||
|
||||
# from bs4 import BeautifulSoup as bs
|
||||
|
||||
|
||||
def new_page(title: str):
|
||||
def new_page(title: str, path: Path) -> Path:
|
||||
"""Crée un nouvel article à partir du titre de celui ci."""
|
||||
|
||||
today = date.today().strftime("%Y-%m-%d")
|
||||
|
||||
filename = "./inbox/" + re.sub("[^a-zA-Z0-9-]", "_", title) + ".md"
|
||||
|
||||
filename = path + "/" + re.sub("[^a-zA-Z0-9-]", "_", title) + ".md"
|
||||
id = uuid.uuid4()
|
||||
content = textwrap.dedent(
|
||||
f"""\
|
||||
---
|
||||
date: {today}
|
||||
title: {title}
|
||||
id: {id}
|
||||
category:
|
||||
tags:
|
||||
-
|
||||
---
|
||||
# {title}
|
||||
|
||||
"""
|
||||
)
|
||||
@@ -36,7 +34,7 @@ def new_page(title: str):
|
||||
with open(filename, "w") as file:
|
||||
file.write(content)
|
||||
|
||||
subprocess.run(["nvim", "+normal G$", "+startinsert", filename])
|
||||
return filename
|
||||
|
||||
|
||||
class Page:
|
||||
@@ -45,6 +43,8 @@ class Page:
|
||||
md_content = ""
|
||||
filename = ""
|
||||
|
||||
_cache = ""
|
||||
|
||||
def __init__(self, filename: Path):
|
||||
"""Constructeur : nouvelle page"""
|
||||
self.filename = filename
|
||||
@@ -59,13 +59,10 @@ class Page:
|
||||
if "date" not in self.meta or type(self.meta["date"]) is not date:
|
||||
self.meta["date"] = date(1970, 1, 1)
|
||||
|
||||
def __getattr__(self, name):
|
||||
def __getattr__(self, name: str):
|
||||
if name not in self.meta:
|
||||
raise AttributeError(f"L'attribut '{name}' n'existe pas.")
|
||||
|
||||
# if name == date:
|
||||
# return datetime(self.meta['date'], "%Y-%m-%d")
|
||||
|
||||
return self.meta[name]
|
||||
|
||||
def _extract_meta_and_markdown(self, content: str) -> list:
|
||||
@@ -87,14 +84,21 @@ class Page:
|
||||
meta += line + "\n"
|
||||
return meta, markdown
|
||||
|
||||
def html(self, template: jinja2.Template) -> str:
|
||||
def html(self) -> str:
|
||||
"""Convertit le markdown en html"""
|
||||
if not self._cache:
|
||||
self._cache = markdown.markdown(
|
||||
self.md_content, extensions=["codehilite", "fenced_code"]
|
||||
)
|
||||
|
||||
return self._cache
|
||||
|
||||
def html_template(self, template: jinja2.Template) -> str:
|
||||
"""Convertit la page en html a partir d'un template jinja2"""
|
||||
title = self.meta["title"] or "Sans titre"
|
||||
date = self.meta["date"] or None
|
||||
return template.render(
|
||||
title=title,
|
||||
date=date,
|
||||
content=markdown.markdown(
|
||||
self.md_content, extensions=["codehilite", "fenced_code"]
|
||||
),
|
||||
content=self.html(),
|
||||
)
|
||||
|
36
main.py
36
main.py
@@ -2,6 +2,7 @@
|
||||
|
||||
import os
|
||||
import argparse
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from blog.page import new_page
|
||||
from blog.config import Config
|
||||
@@ -18,35 +19,42 @@ def load_args():
|
||||
parser = argparse.ArgumentParser(description="Gestion du blog")
|
||||
parser.add_argument("action", choices=actions_list, help="L'action a réaliser.")
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
default=".blog",
|
||||
help="Chemin vers le fichier de configuration",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--inbox",
|
||||
default="./inbox",
|
||||
help="Chemin vers les fichiers markdown du blog",
|
||||
)
|
||||
parser.add_argument("all", nargs=argparse.REMAINDER)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
action="store_true",
|
||||
help="Construit le blog avec les brouillons si spécifié.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--draft",
|
||||
default="./draft",
|
||||
help="Chemin vers les brouillons",
|
||||
)
|
||||
parser.add_argument("all", nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
|
||||
return vars(parser.parse_args())
|
||||
|
||||
|
||||
def load_make_args(args: str) -> dict:
|
||||
"""Charge les paramêtres spécifiques à l'action make"""
|
||||
parser = argparse.ArgumentParser(description="Compile le blog")
|
||||
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--theme",
|
||||
default="./themes/default",
|
||||
help="Chemin vers le theme utilisé pour exporter le blog",
|
||||
help="Chemin vers le theme utilisé",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
default="./output",
|
||||
help="Nom du dossier ou sera exporté le blog en html",
|
||||
help="Nom du dossier où sera exporté le blog en html",
|
||||
)
|
||||
return vars(parser.parse_args(args))
|
||||
|
||||
@@ -65,15 +73,21 @@ def main():
|
||||
match args["action"]:
|
||||
case "new":
|
||||
page_title = " ".join(args["all"])
|
||||
new_page(page_title)
|
||||
|
||||
path = conf.inbox
|
||||
if args["d"]:
|
||||
path = conf.draft
|
||||
subprocess.run(
|
||||
["nvim", "+normal G$", "+startinsert", new_page(page_title, path)]
|
||||
)
|
||||
os._exit(0)
|
||||
|
||||
case "make":
|
||||
args = load_make_args(args["all"])
|
||||
conf.overload(args)
|
||||
make_args = load_make_args(args["all"])
|
||||
conf.overload(make_args)
|
||||
|
||||
blog = Blog(conf)
|
||||
blog.make()
|
||||
blog.make(draft=args["d"])
|
||||
|
||||
os._exit(0)
|
||||
|
||||
|
Reference in New Issue
Block a user