From eb04e0878ed5ee04d0cf78dc9d7e18e8424a4baa Mon Sep 17 00:00:00 2001 From: m1kadev Date: Sat, 24 Jan 2026 13:45:41 +0100 Subject: [PATCH] kethel: add rss feed support --- kethel/lib/pages.ex | 3 +++ kethel/lib/scriprs | 0 kethel/lib/scripts.ex | 5 ++++- kethel/lib/styles.ex | 5 +++++ kethel/lib/thoughts.ex | 34 ++++++++++++++++++++++------------ kethel/main.exs | 35 +++++++++++++++++++++++++++++++++-- rss/feed.txml | 1 + rss/item.txml | 1 + 8 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 kethel/lib/scriprs create mode 100644 rss/feed.txml create mode 100644 rss/item.txml diff --git a/kethel/lib/pages.ex b/kethel/lib/pages.ex index d211bc7e2bf0e10728ba46d71c63d5f4670be53c..e142cc18f48c9ddd7bebcca32d7b9e8184f23c09 100644 --- a/kethel/lib/pages.ex +++ b/kethel/lib/pages.ex @@ -28,8 +28,11 @@ defmodule Pages do @spec compile(%Pages{}) :: none() def compile(pages) do + t_begin = System.monotonic_time(:millisecond) Task.async_stream(pages.source_files, fn page -> compile_file(pages, page) end) |> Enum.to_list() + t_end = System.monotonic_time(:millisecond) + t_end - t_begin end # doc "compiles a file, already read into process memory. Does not return the binary, but instantly writes it to disk" diff --git a/kethel/lib/scriprs b/kethel/lib/scriprs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/kethel/lib/scripts.ex b/kethel/lib/scripts.ex index aafe0f4c520c28a4af3f979d1f6708d37fd943c0..40ec2ef013cddc431fc83f7ec882b8ba5bb02714 100644 --- a/kethel/lib/scripts.ex +++ b/kethel/lib/scripts.ex @@ -27,13 +27,16 @@ defmodule Scripts do end def compile(scripts) do + t_begin = System.monotonic_time(:millisecond) + ensure_file_structure(scripts.project_root) scripts.scripts |> Task.async_stream(fn script -> compile_file(script, scripts.project_root) end) |> Enum.map(fn {:ok, val} -> val end) - :ok + t_end = System.monotonic_time(:millisecond) + t_end - t_begin end # data | npx lightningcss -m diff --git a/kethel/lib/styles.ex b/kethel/lib/styles.ex index 793d41c79e5ff1e47c86cc5309db5a67cdbb3a0e..05815996782f2d2cbbfe3e57068e5ba89ea1af46 100644 --- a/kethel/lib/styles.ex +++ b/kethel/lib/styles.ex @@ -27,11 +27,16 @@ defmodule Styles do end def compile(styles) do + t_begin = System.monotonic_time(:millisecond) + ensure_file_structure(styles.project_root) styles.styles |> Task.async_stream(fn style -> compile_file(style, styles.project_root) end) |> Enum.map(fn {:ok, val} -> val end) + + t_end = System.monotonic_time(:millisecond) + t_end - t_begin end # data | npx lightningcss -m diff --git a/kethel/lib/thoughts.ex b/kethel/lib/thoughts.ex index 9586b626653d3782cee97139d2f6137ce06c6ff7..4ad401ff7d75498b8964418dd725f7db325dd347 100644 --- a/kethel/lib/thoughts.ex +++ b/kethel/lib/thoughts.ex @@ -14,12 +14,13 @@ defmodule Thoughts do binary_part(path, begin, byte_size(path) - begin) end - @spec collect(binary(), %{binary() => binary()}) :: %{} + @spec collect(binary(), %{binary() => binary()}) :: %Thoughts{} def collect(project_root, bricks) do %Thoughts{ thoughts: Path.wildcard("#{project_root}/thoughts/*") - |> Enum.map(fn path -> {path, File.read!(path)} end), + |> Enum.map(fn path -> {path, get_file_commit_date(path), File.read!(path)} end) + |> Enum.sort_by(fn {_, date, _ } -> date end, :desc), template: File.read!("#{project_root}/templates/thought.thtml"), bricks: bricks, project_root: project_root @@ -31,21 +32,23 @@ defmodule Thoughts do File.mkdir_p!("#{project_root}/build/thoughts/") end - @spec compile(%Thoughts{}) :: :ok + @spec compile(%Thoughts{}) :: pos_integer() def compile(thoughts) do + t_begin = System.monotonic_time(:millisecond) ensure_folders(thoughts.project_root) thoughts.thoughts |> Task.async_stream(fn thought -> - compile_file(thought, thoughts.template, thoughts.bricks, thoughts.project_root) - end) + compile_file(thought, thoughts.template, thoughts.bricks, thoughts.project_root) end) |> Enum.to_list() + + t_end = System.monotonic_time(:millisecond) + + t_end - t_begin end - defp compile_file({path, thought}, template, bricks, project_root) do + defp compile_file({path, date, thought}, template, bricks, project_root) do name = trim_abs_path(path, project_root) - # unix timestamp - date = get_file_commit_date(path) output_path = "#{project_root}/build/thoughts/#{urlify(name)}.html" mustache_context = Map.merge(bricks, %{thought: thought, name: name, date: date}) @@ -55,10 +58,17 @@ defmodule Thoughts do def get_file_commit_date(path) do {ts_string, 0} = System.cmd("git", ["log", "--format=%ct", path]) + + String.trim_trailing(ts_string) + |> String.to_integer() + end - time = - String.to_integer(String.trim_trailing(ts_string)) - |> DateTime.from_unix!() - |> Calendar.strftime("%d/%m/%y (%H:%M)") + def to_rss({path, date, thought}, template, project_root) do + location = String.replace_prefix(path, project_root <> "/thoughts/", "") + link = "https://m1kadev.nl/thoughts/" <> urlify(location) <> ".html" + rfc_date = date + |> DateTime.from_unix!() + |> Calendar.strftime("%a, %d %b %Y %H:%M:%S %Z") + Mustache.render(template, %{title: location, date: rfc_date, description: thought, category: "thoughts", link: link } ) end end diff --git a/kethel/main.exs b/kethel/main.exs index 385026271d6d9f951bcd69c23f613c6e523d2884..a66d3cd8c38aa3a6afbd20439ac4a5e0c34f24ab 100644 --- a/kethel/main.exs +++ b/kethel/main.exs @@ -8,6 +8,8 @@ if folder != nil do File.rm_rf!("#{project_root}/build") File.mkdir_p("#{project_root}/build") + collection_time_start = System.monotonic_time(:millisecond) + # other contents depend on this, so we cant async it bricks = Bricks.collect(project_root) @@ -22,21 +24,50 @@ if folder != nil do [styles, pages, scripts, thoughts] = Task.await_many([styles_task, pages_task, scripts_task, thoughts_task], :infinity) + collection_time_end = System.monotonic_time(:millisecond) + + compilation_time_start = System.monotonic_time(:millisecond) + pages_compile_task = Task.async(fn -> Pages.compile(pages) end) styles_compile_task = Task.async(fn -> Styles.compile(styles) end) scripts_compile_task = Task.async(fn -> Scripts.compile(scripts) end) thoughts_compile_task = Task.async(fn -> Thoughts.compile(thoughts) end) - Task.await_many( + [ pages_time, styles_time, scripts_time, thoughts_time] = Task.await_many( [ pages_compile_task, styles_compile_task, - statics_task, scripts_compile_task, thoughts_compile_task ], :infinity ) + + compilation_time_end = System.monotonic_time(:millisecond) + + rss_header = File.read!("#{project_root}/rss/feed.txml") + rss_footer = "" + rss_item_template = File.read!("#{project_root}/rss/item.txml") + + rss_thoughts = thoughts.thoughts + |> Enum.take(10) + |> Enum.map(fn thought -> Thoughts.to_rss(thought, rss_item_template, project_root) end) + |> Enum.join(); + + File.write!("#{project_root}/build/rss.xml", rss_header <> rss_thoughts <> rss_footer) + + IO.puts("[COMPILED] #{project_root}/build/rss.xml") + + IO.puts("Finalising..."); + + File.cp!("#{project_root}/favicon.ico", "#{project_root}/build/favicon.ico") + IO.puts("") + IO.puts(:stderr, "===== BUILD RESULTS =====") + IO.puts(:stderr, "FILE READING (*.collect()) | #{collection_time_end - collection_time_start}ms") + IO.puts(:stderr, "Root page (compile) | #{pages_time}ms") + IO.puts(:stderr, "Styles (compile) | #{styles_time}ms") + IO.puts(:stderr, "Scripts (compile) | #{scripts_time}ms") + IO.puts(:stderr, "Thoughts (compile) | #{thoughts_time}ms") else IO.puts(:stderr, "The root project folder should be provided on the command line") end diff --git a/rss/feed.txml b/rss/feed.txml new file mode 100644 index 0000000000000000000000000000000000000000..40c35c88e7b7033ac6453cdb3194124794d240bf --- /dev/null +++ b/rss/feed.txml @@ -0,0 +1 @@ +m1kadev.nl updates :3placeholder descriptionen diff --git a/rss/item.txml b/rss/item.txml new file mode 100644 index 0000000000000000000000000000000000000000..46d8752686c5805e6b3c48fb7a86956d48775f74 --- /dev/null +++ b/rss/item.txml @@ -0,0 +1 @@ +{{title}}{{description}}{{link}}{{date}}{{category}}