Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

runner.py 2.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env python3
  2. import os
  3. from dataclasses import dataclass
  4. from datetime import date, datetime
  5. from html import escape
  6. from operator import attrgetter
  7. from pathlib import Path
  8. from time import perf_counter
  9. from jinja2 import Environment as Env
  10. from jinja2 import FileSystemLoader
  11. from minicli import cli, run, wrap
  12. from utils import each_markdown_from, parse_markdown
  13. HERE = Path(".")
  14. DAVID = HERE / "david"
  15. DOMAIN = "https://larlet.fr"
  16. # Hardcoding publication at 12 in Paris timezone.
  17. NORMALIZED_STRFTIME = "%Y-%m-%dT12:00:00+01:00"
  18. environment = Env(loader=FileSystemLoader(str(DAVID / "templates")))
  19. @dataclass
  20. class Note:
  21. title: str
  22. content: str
  23. file_path: str
  24. def __post_init__(self):
  25. suffix = len("/index.md")
  26. prefix = len("YYYY/MM/DD") + suffix
  27. date_str = self.file_path[-prefix:-suffix]
  28. self.url = f"/david/stream/{date_str}/"
  29. self.full_url = f"{DOMAIN}{self.url}"
  30. self.date = datetime.strptime(date_str, "%Y/%m/%d").date()
  31. self.normalized_date = self.date.strftime(NORMALIZED_STRFTIME)
  32. self.escaped_title = escape(self.title)
  33. self.escaped_content = escape(
  34. self.content.replace('href="/', f'href="{DOMAIN}/').replace(
  35. 'src="/', f'src="{DOMAIN}/'
  36. )
  37. )
  38. self.extract = self.content.split("</p>", 1)[0] + "</p>"
  39. @staticmethod
  40. def all(source, only_published=True):
  41. """Retrieve all (published) notes sorted by date desc."""
  42. note_list = []
  43. for file_path in each_markdown_from(source):
  44. title, content, _ = parse_markdown(file_path)
  45. note = Note(title, content, file_path)
  46. if only_published and note.date > date.today():
  47. continue
  48. note_list.append(note)
  49. return sorted(note_list, key=attrgetter("date"), reverse=True)
  50. @cli
  51. def stream(when=None):
  52. """Create a new note and open it in iA Writer.
  53. :when: Optional date in ISO format (YYYY-MM-DD)
  54. """
  55. when = datetime.strptime(when, "%Y-%m-%d") if when else date.today()
  56. note_path = DAVID / "stream" / str(when.year) / str(when.month) / str(when.day)
  57. os.makedirs(note_path)
  58. filename = note_path / "index.md"
  59. open(filename, "w+").write("title: ")
  60. os.popen(f'open -a "iA Writer" "{filename}"')
  61. @cli
  62. def feed():
  63. """Generate a feed from 15 last published Notes in stream."""
  64. template = environment.get_template("feed.xml")
  65. content = template.render(
  66. note_list=Note.all(source=DAVID / "stream" / "2019")[:15],
  67. current_dt=datetime.now().strftime(NORMALIZED_STRFTIME),
  68. BASE_URL=f"{DOMAIN}/david/",
  69. )
  70. open(DAVID / "log" / "index.xml", "w").write(content)
  71. @wrap
  72. def perf_wrapper():
  73. start = perf_counter()
  74. yield
  75. elapsed = perf_counter() - start
  76. print(f"Done in {elapsed:.5f} seconds.")
  77. if __name__ == "__main__":
  78. run()