2023-06-25 16:05:15 -06:00
|
|
|
|
import re
|
|
|
|
|
import sys
|
|
|
|
|
import json
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
2023-06-26 13:35:10 -06:00
|
|
|
|
|
|
|
|
|
def parse_md(txt):
|
|
|
|
|
"""
|
|
|
|
|
Implementación mínima con este soporte: párrafos, encabezados, listas,
|
|
|
|
|
cita, negrita, itálica y enlaces
|
|
|
|
|
"""
|
|
|
|
|
# Regex para detectar Markdown
|
|
|
|
|
header = r"(#+)\s*(.+)"
|
|
|
|
|
quote = r">\s*(.+)"
|
2023-06-28 16:21:50 -06:00
|
|
|
|
ulist = r"[\*-]\s+"
|
|
|
|
|
olist = r"\d\.\s+"
|
2023-06-26 13:35:10 -06:00
|
|
|
|
bolditalic = r"\*\*\*([^\*]+)\*\*\*"
|
|
|
|
|
bold = r"\*\*([^\*]+)\*\*"
|
|
|
|
|
italic = r"\*([^\*]+)\*"
|
|
|
|
|
link = r"\[([^\[]+)\]\(([^\(]+)\)"
|
2023-06-28 16:21:50 -06:00
|
|
|
|
emdash = r"---"
|
|
|
|
|
endash = r"--"
|
|
|
|
|
dash = r"-"
|
|
|
|
|
ellipsis = r"\.\.\."
|
2023-06-26 13:35:10 -06:00
|
|
|
|
# Obtiene los bloques a partir de una cadena de caracteres
|
|
|
|
|
blocks = map(lambda x: x.strip(), re.split(r"\n\s*\n", txt))
|
|
|
|
|
blocks = list(filter(None, blocks))
|
|
|
|
|
# Analiza cada bloque
|
|
|
|
|
for i, block in enumerate(blocks):
|
|
|
|
|
# Si es encabezado
|
|
|
|
|
if re.match(header, block):
|
|
|
|
|
groups = re.match(header, block).groups()
|
|
|
|
|
tag = "h" + str(len(groups[0]))
|
|
|
|
|
block = f"<{tag}>{groups[1]}</{tag}>"
|
|
|
|
|
# Si es cita
|
|
|
|
|
elif re.match(quote, block):
|
|
|
|
|
groups = re.match(quote, block).groups()
|
|
|
|
|
block = f"<blockquote><p>{groups[0]}</p></blockquote>"
|
|
|
|
|
# Si es lista no ordenada
|
|
|
|
|
elif re.match(ulist, block):
|
|
|
|
|
items = re.sub(r"^" + ulist, "", block)
|
|
|
|
|
items = re.split(r"\n\s*" + ulist, items)
|
|
|
|
|
items = "".join(map(lambda x: f"<li><p>{x}</p></li>", items))
|
|
|
|
|
block = f"<ul>{items}</ul>"
|
|
|
|
|
# Si es lista ordenada
|
|
|
|
|
elif re.match(olist, block):
|
|
|
|
|
items = re.sub(r"^" + olist, "", block)
|
|
|
|
|
items = re.split(r"\n\s*" + olist, items)
|
|
|
|
|
items = "".join(map(lambda x: f"<li><p>{x}</p></li>", items))
|
|
|
|
|
block = f"<ol>{items}</ol>"
|
|
|
|
|
# De lo contrario, se trata como párrafo
|
|
|
|
|
else:
|
|
|
|
|
block = f"<p>{block}</p>"
|
|
|
|
|
# Limpia y aplica los estilos en línea (negritas, itálicas y enlaces)
|
|
|
|
|
block = " ".join(block.split())
|
|
|
|
|
block = re.sub(bolditalic, r"<b><i>\1</i></b>", block)
|
|
|
|
|
block = re.sub(bold, r"<b>\1</b>", block)
|
|
|
|
|
block = re.sub(italic, r"<i>\1</i>", block)
|
|
|
|
|
block = re.sub(link, r'<a target="_blank" href="\2">\1</a>', block)
|
2023-06-28 16:21:50 -06:00
|
|
|
|
block = re.sub(emdash, "—", block)
|
|
|
|
|
block = re.sub(endash, "–", block)
|
|
|
|
|
block = re.sub(dash, "-", block)
|
|
|
|
|
block = re.sub(ellipsis, "⁠…", block)
|
2023-06-26 13:35:10 -06:00
|
|
|
|
blocks[i] = block
|
|
|
|
|
# Une los bloques y hace limpiezas
|
|
|
|
|
html = "\n".join(blocks)
|
|
|
|
|
html = re.sub(r"</blockquote>\n<blockquote>", "", html)
|
|
|
|
|
return html
|
|
|
|
|
|
|
|
|
|
|
2023-06-25 16:05:15 -06:00
|
|
|
|
root = Path(__file__).parent.parent
|
2023-06-28 16:21:50 -06:00
|
|
|
|
about = """
|
2023-06-25 16:05:15 -06:00
|
|
|
|
Hola, soy perro tuerto. Mi formación académica es en Filosofía, mi
|
2023-06-26 13:35:10 -06:00
|
|
|
|
profesión es en la edición de publicaciones (libros, fanzines, revistas…)
|
2023-06-25 16:05:15 -06:00
|
|
|
|
y mi programación se enfoca en el desarrollo de metodologías libres para la
|
|
|
|
|
publicación. Soy fan de las humanidades, la paleoantropología y las
|
|
|
|
|
ciencias de la computación, así como soy voluntario en organizaciones sobre
|
2023-06-26 14:01:16 -06:00
|
|
|
|
edición, *software* y cultura libres, como
|
|
|
|
|
[Programando LIBREros](https://programando.li/breros),
|
|
|
|
|
[Miau](https://t.me/miau2018), [Cuates](https://cuates.net/) o
|
|
|
|
|
[Wikipedia](https://wikimedia.mx/). Doy soporte técnico a la
|
2023-06-26 13:35:10 -06:00
|
|
|
|
[Academia Mexicana de la Lengua](https://academia.org.mx/) y puedo ayudarte
|
2023-06-28 16:21:50 -06:00
|
|
|
|
en tus proyectos.
|
|
|
|
|
|
2023-06-28 16:23:41 -06:00
|
|
|
|
**En este espacio comparto enlaces que me parecen chéveres.**
|
2023-06-28 16:21:50 -06:00
|
|
|
|
""".strip()
|
2023-06-25 16:05:15 -06:00
|
|
|
|
contact = {
|
|
|
|
|
"site": "https://perrotuerto.blog",
|
|
|
|
|
"gitlab": "https://gitlab.com/perrotuerto",
|
|
|
|
|
"cuates": "https://git.cuates.net/perro",
|
|
|
|
|
"wikipedia": "https://es.wikipedia.org/wiki/Usuario:Perrotuerto",
|
|
|
|
|
"github": "https://github.com/perrotuerto",
|
|
|
|
|
"email": "hi@perrotuerto.blog",
|
|
|
|
|
}
|
2023-06-26 10:29:22 -06:00
|
|
|
|
json_file = Path(sys.argv[1])
|
|
|
|
|
links = json.loads(json_file.read_text())
|
2023-06-26 13:41:37 -06:00
|
|
|
|
data = {"acerca": about, "contacto": contact, "enlaces": links["results"]}
|
2023-06-25 16:05:15 -06:00
|
|
|
|
index = root / "public" / "index.html"
|
|
|
|
|
template = (root / "src" / "template.html").read_text()
|
|
|
|
|
body = ""
|
|
|
|
|
|
|
|
|
|
for key, val in data.items():
|
|
|
|
|
if key == "contacto":
|
|
|
|
|
for name, url in val.items():
|
2023-06-26 13:35:10 -06:00
|
|
|
|
template = re.sub(f"#{name.upper()}#", url, template)
|
2023-06-25 16:05:15 -06:00
|
|
|
|
continue
|
|
|
|
|
body += f'\n<section id="{key}">'
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += f"\n<h1>{key.capitalize()}</h1>"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
if isinstance(val, str):
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += f"\n{parse_md(val)}"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
else:
|
|
|
|
|
body += '<ul class="list">'
|
|
|
|
|
for link in val:
|
2023-06-26 10:18:09 -06:00
|
|
|
|
date1 = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
|
|
|
date2 = "%d/%m/%Y"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
url = link["url"]
|
2023-06-26 13:35:10 -06:00
|
|
|
|
archive = f"https://web.archive.org/web/*/{url}"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
created = link["date_added"]
|
|
|
|
|
updated = link["date_modified"]
|
2023-06-26 10:29:22 -06:00
|
|
|
|
created = datetime.strptime(created, date1).strftime(date2)
|
|
|
|
|
updated = datetime.strptime(updated, date1).strftime(date2)
|
2023-06-28 13:01:13 -06:00
|
|
|
|
desc = link["description"]
|
|
|
|
|
desc = desc[0:-1] if desc[-1] == "." else desc
|
2023-06-25 16:05:15 -06:00
|
|
|
|
tags = filter(lambda x: x != "blog", link["tag_names"])
|
2023-06-28 13:01:13 -06:00
|
|
|
|
tags = map(lambda x: f"<a>#{x}</a>", tags)
|
2023-06-25 16:05:15 -06:00
|
|
|
|
body += f'\n<li class="link" id="{link["id"]}">'
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += f'\n<h1><a class="anchor" href="#{link["id"]}">⚓</a>'
|
|
|
|
|
body += f'<a class="name" target="_blank" href="{url}">'
|
|
|
|
|
body += f'{link["title"]}</a></h1>'
|
2023-06-25 16:05:15 -06:00
|
|
|
|
body += '\n<p class="dates">'
|
|
|
|
|
body += f'<span class="created">{created}</span>'
|
|
|
|
|
body += f'<span class="updated">{updated}</span></p>'
|
2023-06-28 13:01:13 -06:00
|
|
|
|
body += f'\n<p class="description">{desc}</p>'
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += f'\n<p class="tags">{" ".join(tags)}</p>'
|
|
|
|
|
body += '\n<p class="social">'
|
|
|
|
|
body += (
|
|
|
|
|
f'<a target="_blank" href="{archive}">Ver archivado</a></p>'
|
|
|
|
|
)
|
2023-06-25 16:05:15 -06:00
|
|
|
|
if "notes" in link.keys():
|
|
|
|
|
body += '\n<details class="info">'
|
2023-06-28 16:21:50 -06:00
|
|
|
|
body += "\n<summary>Leer mi nota</summary>"
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += parse_md(link["notes"])
|
|
|
|
|
body += "\n</details>"
|
|
|
|
|
body += "\n</li>"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
body += "</ul>"
|
2023-06-26 13:35:10 -06:00
|
|
|
|
body += "\n</section>"
|
2023-06-25 16:05:15 -06:00
|
|
|
|
|
2023-06-26 13:35:10 -06:00
|
|
|
|
index.write_text(re.sub("#LINKS#", body, template))
|
2023-06-26 10:29:22 -06:00
|
|
|
|
json_file.write_text(json.dumps(data))
|