|
|
@@ -0,0 +1,95 @@ |
|
|
|
#!/usr/bin/env python3 |
|
|
|
|
|
|
|
import os |
|
|
|
from dataclasses import dataclass |
|
|
|
from datetime import date, datetime |
|
|
|
from html import escape |
|
|
|
from operator import attrgetter |
|
|
|
from pathlib import Path |
|
|
|
from time import perf_counter |
|
|
|
|
|
|
|
from jinja2 import Environment as Env |
|
|
|
from jinja2 import FileSystemLoader |
|
|
|
from minicli import cli, run, wrap |
|
|
|
from utils import each_markdown_from, parse_markdown |
|
|
|
|
|
|
|
HERE = Path(".") |
|
|
|
DAVID = HERE / "david" |
|
|
|
DOMAIN = "https://larlet.fr" |
|
|
|
# Hardcoding publication at 12 in Paris timezone. |
|
|
|
NORMALIZED_STRFTIME = "%Y-%m-%dT12:00:00+01:00" |
|
|
|
|
|
|
|
environment = Env(loader=FileSystemLoader(str(DAVID / "templates"))) |
|
|
|
|
|
|
|
|
|
|
|
@dataclass |
|
|
|
class Note: |
|
|
|
title: str |
|
|
|
content: str |
|
|
|
file_path: str |
|
|
|
|
|
|
|
def __post_init__(self): |
|
|
|
suffix = len("/index.md") |
|
|
|
prefix = len("YYYY/MM/DD") + suffix |
|
|
|
date_str = self.file_path[-prefix:-suffix] |
|
|
|
self.url = f"/david/stream/{date_str}/" |
|
|
|
self.full_url = f"{DOMAIN}{self.url}" |
|
|
|
self.date = datetime.strptime(date_str, "%Y/%m/%d").date() |
|
|
|
self.normalized_date = self.date.strftime(NORMALIZED_STRFTIME) |
|
|
|
self.escaped_title = escape(self.title) |
|
|
|
self.escaped_content = escape( |
|
|
|
self.content.replace('href="/', f'href="{DOMAIN}/').replace( |
|
|
|
'src="/', f'src="{DOMAIN}/' |
|
|
|
) |
|
|
|
) |
|
|
|
self.extract = self.content.split("</p>", 1)[0] + "</p>" |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def all(source, only_published=True): |
|
|
|
"""Retrieve all (published) notes sorted by date desc.""" |
|
|
|
note_list = [] |
|
|
|
for file_path in each_markdown_from(source): |
|
|
|
title, content, _ = parse_markdown(file_path) |
|
|
|
note = Note(title, content, file_path) |
|
|
|
if only_published and note.date > date.today(): |
|
|
|
continue |
|
|
|
note_list.append(note) |
|
|
|
return sorted(note_list, key=attrgetter("date"), reverse=True) |
|
|
|
|
|
|
|
|
|
|
|
@cli |
|
|
|
def stream(when=None): |
|
|
|
"""Create a new note and open it in iA Writer. |
|
|
|
|
|
|
|
:when: Optional date in ISO format (YYYY-MM-DD) |
|
|
|
""" |
|
|
|
when = datetime.strptime(when, "%Y-%m-%d") if when else date.today() |
|
|
|
note_path = DAVID / "stream" / str(when.year) / str(when.month) / str(when.day) |
|
|
|
os.makedirs(note_path) |
|
|
|
filename = note_path / "index.md" |
|
|
|
open(filename, "w+").write("title: ") |
|
|
|
os.popen(f'open -a "iA Writer" "{filename}"') |
|
|
|
|
|
|
|
|
|
|
|
@cli |
|
|
|
def feed(): |
|
|
|
"""Generate a feed from 15 last published Notes in stream.""" |
|
|
|
template = environment.get_template("feed.xml") |
|
|
|
content = template.render( |
|
|
|
note_list=Note.all(source=DAVID / "stream" / "2019")[:15], |
|
|
|
current_dt=datetime.now().strftime(NORMALIZED_STRFTIME), |
|
|
|
BASE_URL=f"{DOMAIN}/david/", |
|
|
|
) |
|
|
|
open(DAVID / "log" / "index.xml", "w").write(content) |
|
|
|
|
|
|
|
|
|
|
|
@wrap |
|
|
|
def perf_wrapper(): |
|
|
|
start = perf_counter() |
|
|
|
yield |
|
|
|
elapsed = perf_counter() - start |
|
|
|
print(f"Done in {elapsed:.5f} seconds.") |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
run() |