Home Blog Movies Projects

Building a Emacs Org-Mode Blog

He empezado este sitio web, si revisáis mi sitio web en Github os daréis cuenta de que no es la primera vez que empiezo un proyecto de esta magnitud, sin embargo si es la primera vez que intento hacerlo "bien". Esta vez he pillado un dominio y servidor de la mano de IONOS. Después de tantos años de pensarlo por fin me he decido y espero que esta vez sea de forma definitiva. Que vaya construyendo poco a poco el sitio hasta que sea lo que siempre he soñado.

Tengo una lista gigante de problemas que tuve en las ocasiones anteriores y porqué muchas veces era más fácil empezar desde cero. Enumeraré un par:

  1. Mi sueño desde que concebí la idea era utilizar EMACS, siempre he querido utilizar mi editor de texto favorito.
  2. Esto nos lleva al segundo problema, mi editor de texto favorito me ofrece varias opciones para llevarlo: Org mode; HUGO; html, css y javascript, en fin todo es código lo cual es perfecto, pero seamos realistas… mantenerlo con el tiempo es un lío.
  3. He probado todo lo disponible en blogs de este tipo org2blog, Jekyll, Hugo, etc… y nada me permite tener una personalización cómoda.

    ¿Qué es lo que ha cambiado? La verdad nada, actualmente, está montado con Org-mode puro, pero al tener en un servidor y no en un repo es mucho más cómodo porque me conecto desde cualquier dispositivo edito lo que necesito y mediante un cronjob se actualiza cuando toca si está visible, antes tenía que hacer un commit por el medio, lo tenía todo en local y claro la generarlo tenía que considerar que las rutas del remoto no son las mismas que las del local.

    ¿Por qué no uso una solución estándar como Wordpress? Porque creo que no tiene mucho reto, no es que yo sea un profesional administrado sitios tipo Wordpress, pero grosso-modo sé como funcionan y la verdad siempre me ha gustado el barro y quería editarlo desde emacs, eso es muy importante.

    ¿Cómo está montado esto? Es muy sencillo para desarrollar este archivo me he basado en Taingram y en internet en general

#!/usr/bin/emacs --batch --script

Defino localización

Defino paquetes

(require 'htmlize)
(require 'ox-publish)
(require 'ox-html)

Defino variables y configuro elementos

;; Definición de la cabecera HTML con el enlace al CSS
(defvar rhyloo--head
  "<link rel=\"stylesheet\" href=\"/style.css\" type=\"text/css\"/>")

(defvar rhyloo--blog-head
  (concat rhyloo--head
          "<link rel=\"stylesheet\" href=\"/blog-specific.css\" type=\"text/css\"/>"))

;; Macros globales de exportación, ejemplo de cómo incluir un 'warning'
(setq org-export-global-macros
      '(("warning" . "@@html:<div class=\"warning\">⚠️ $1</div>@@")))

;; Deshabilitar el postamble HTML (no mostrar pie de página)
(setq org-html-postamble nil)

(setq org-export-default-language "es")

;; Cabecera adicional para incluir en la página HTML
(setq org-html-head-extra
      "<link rel=\"icon\" href=\"/index-files/favicon.svg\" type=\"image/svg+xml\">
       <style>
         #org-div-home-and-up a {
           margin-right: 10px;
         }
       </style>
       <div id=\"org-div-home-and-up\">
         <a href=\"https://www.rhyloo.com/\">Home</a>
         <a href=\"https://www.rhyloo.com/blog\">Blog</a>
         <a href=\"https://www.rhyloo.com/movies.html\">Movies</a>
         <a href=\"https://www.rhyloo.com/projects\">Projects</a>
       </div>")

;; Activar la exportación de código con Pygments
(setq org-html-htmlize-output-type 'css)  ;; Use CSS for styling code blocks
(setq org-html-htmlize-fontify-code t)  ;; Enable code fontification with htmlize

;; Configurar Pygments para la colorización de código
(setq org-htmlize-pygments-command "pygmentize -O style=monokai -f html") ;; Modify the style and command if needed

(setq make-backup-files nil) ;; No crear archivos de respaldo
(setq auto-save-default nil) ;; Deshabilitar el auto guardado
;; Función para listar proyectos
(defun listar-proyectos ()
  "Listar todos los proyectos de publicación definidos."
  (dolist (proyecto org-publish-project-alist)
    (message "Proyecto: %s" (car proyecto))))

(defun force-publish-project (project-name)
  "Forzar la publicación de un proyecto dado."
  (org-publish-project project-name :force))

(defun add-lazy-loading-to-images (text backend info)
  "Add `loading=\"lazy\"` to all <img> tags in the HTML export output."
  (when (org-export-derived-backend-p backend 'html)
    (replace-regexp-in-string
     "<img \\([^>]*\\)>"
     "<img \\1 loading=\"lazy\">"
     text)))

(defun my-simple-sitemap (title list)
  "Default site map, as a string.
TITLE is the the title of the site map.  LIST is an internal
representation for the files to include, as returned by
`org-list-to-lisp'.  PROJECT is the current project."
  (concat "#+TITLE: " title "\n\n"
          (org-list-to-org list) "test")
  (message list))

;; Asegúrate de añadir la función al filtro adecuado
(add-to-list 'org-export-filter-final-output-functions
             'add-lazy-loading-to-images)

Configuro el blog

;; Configuración de los proyectos de publicación
(setq org-publish-project-alist
      `(("index"
         :base-directory ,rhyloo--base-directory
         :base-extension "org"
         :exclude "*.*"
         :html-head ,rhyloo--head
         :include ("index.org")
         :publishing-directory ,rhyloo--publish-directory
         :publishing-function org-html-publish-to-html)

        ("index-files"
         :base-directory ,(concat rhyloo--base-directory "index-files/")
         :base-extension "png\\|jpg\\|jpeg\\|gif\\|pdf\\|svg"
         :recursive nil
         :publishing-directory ,(concat rhyloo--publish-directory "index-files/")
         :publishing-function org-publish-attachment)

        ("index-with-files" 
         :components ("index" "index-files"))  ;; Combina "index" y "index-files"

        ("pages"
         :base-directory ,rhyloo--base-directory
         :base-extension "org"
         :exclude ,(regexp-opt '("index.org" ".*-draft\\.org" "drafts/" "blog/"))
         :recursive t
         :html-head ,rhyloo--head
         :publishing-directory ,rhyloo--publish-directory
         :publishing-function org-html-publish-to-html)

        ("blog"
         :base-directory ,(concat rhyloo--base-directory "blog/")
         :base-extension "org"
         :exclude ".*-draft\\.org"
         :publishing-directory ,(concat rhyloo--publish-directory "blog/")
         :publishing-function org-html-publish-to-html
         :html-head ,rhyloo--blog-head
         :auto-sitemap t
         :sitemap-title "Blog Posts"
         :sitemap-filename "index.org"
         :sitemap-function my-simple-sitemap
         :sitemap-sort-files anti-chronologically)

        ("blog-files"
         :base-directory ,(concat rhyloo--base-directory "blog/files/")
         :base-extension "png\\|jpg\\|jpeg\\|gif"
         :recursive t
         :publishing-directory ,(concat rhyloo--publish-directory "blog/files/")
         :publishing-function org-publish-attachment)

        ("blog-with-files" 
         :components ("blog" "blog-files")) ;; Combina "blog" y "blog-files"

        ("projects"
         :base-directory ,(concat rhyloo--base-directory "projects/")
         :base-extension "org"
         :html-preamble '(("es" "<div id=\"updated\">Updated: %C</div>"))
         :exclude ".*-draft\\.org"
         :publishing-directory ,(concat rhyloo--publish-directory "projects/")
         :publishing-function org-html-publish-to-html
         :html-head ,rhyloo--head
         :auto-sitemap t
         :sitemap-title "Projects Posts"
         :sitemap-filename "index.org"
         :sitemap-sort-files anti-chronologically)

        ("projects-files"
         :base-directory ,(concat rhyloo--base-directory "projects/files/")
         :base-extension "png\\|jpg\\|jpeg\\|gif\\|pdf"
         :recursive nil
         :publishing-directory ,(concat rhyloo--publish-directory "projects/files/")
         :publishing-function org-publish-attachment)

        ("projects-with-files" 
         :components ("projects" "projects-files")) ;; Combina "projects" y "projects-files"

        ("static"
         :base-directory ,rhyloo--base-directory
         :base-extension "css"
         :recursive nil
         :publishing-directory ,rhyloo--publish-directory
         :publishing-function org-publish-attachment)

        ("rhyloo.com" 
         :components ("index-with-files" "static" "pages" "blog-with-files" "projects-with-files"))
        ("all-without-index" 
         :components ("static" "pages" "blog-with-files" "projects-with-files"))))