Ceci n’est pas un exercice, un peu de vie pourrait revenir par ici. Bien sûr, après sept ans d’inactivité, la majeur partie avec le contenu hors-ligne, la question de ce qui pourrait venir à nouveau gracier ces pages est ouverte. L’exercice pourrait se montrer intéressant, ou retomber à plat, je suppose que les mois à venir parleront pour moi.
Plus concrètement, il est fort probable que des articles plus techniques fassent suite. À force d’enquiller les projets au boulot, j’en viens à me dire qu’il va falloir noter tout ça quelque part ou les fuites de cerveau vont finir par devenir assez domageables. Et quelque part, avec le temps et l’assagissement, la démarche de documentation est à présent beaucoup plus naturelle que le YOLO des débuts. Celà dit, mes loisirs n’ont pas changé tant que ça non plus, il est également probable que j’y revienne à un moment ou à un autre.
Sur le plan technique, ce petit coin d’Internet fonctionne à présent sous Pelican. Il me semblait important d’arrêter de dev des trucs moi-même et d’être réaliste, à savoir qu’en repartant à zéro j’allais probablement griller tout mon enthousiasme avant même d’avoir quelque chose de publiable et utilisable, sans même parler de l’entretien sur le long terme. Toutefois, j’ai préféré quand même rester sur un logiciel un peu exotique et low-key, qui a l’avantage de générer un site complètement statique sur lequel je n’aurais pas à me soucier du tout des problématiques de sécurité, la raison principale pour laquelle ce blog avait fini par être débranché.
Je regrette de ne pas avoir transvasé les commentaires et de ne pas ouvrir de nouveau système équivalent, mais d’une je pense qu’en ces temps de Twitter et autres, ces espaces intéressent moins, et de deux ça ne colle plus trop avec la philosophie générale de la publication. Je reste ouvert au dialogue, mais vous savez où me trouver pour toute remarque :)
J’ai passé quelques heures à tant bien que mal essayer de retaper le Textile utilisé d’abord avec le parseur historique PyTextile de Mark Pilgrim, puis avec celui en PHP du plugin Dotclear. L’un comme l’autre étaient franchement périmé et ne fonctionnent plus avec du Python ou PHP moderne, mais Pandoc m’aura permis de dégager le gros de la charge pour convertir tout en reStructuredText qui devrait mieux s’intégrer sous cette plateforme. Après pas mal de nettoyage à coup de regexp, je pense être arrivé à un résultat satisfaisant et lisible. Reste encore un certain travail de remise en page, mais je ferais plutôt ça au fil de l’eau.
Pour les intéressés, voici le code utilisé.
#!/usr/bin/env python3
# -*- encoding: UTF-8 -*-
import os, sys, unicodedata, re
import psycopg2
import psycopg2.extras
import pypandoc
DOTCLEAR_SERVER = '**********'
DOTCLEAR_USER = '*******'
DOTCLEAR_DB = '*******'
DOTCLEAR_PWD = '*************'
OUTPUT_DIR = 'output'
INPUT_FORMAT = 'textile'
OUTPUT_FORMAT = 'rst'
V1_MEDIA = re.compile(r'https://media.lordran.net/alpha/posts/(.*)')
V1_REP = r'{static}/images/v1/\1'
V2_MEDIA = re.compile(r'https://old-alpha.lordran.net/public/(.*)')
V2_REP = r'{static}/images/v2/\1'
BAD_SMILEY = re.compile(r' :sup:``[;"]')
FIX_SMILEY = r'.'
BAD_NBSP = ' '
BAD_IMGLINK = re.compile(r'\|([^\|]+)\|:(\{filename\}/images/[-_/\\a-zA-Z0-9\.]+)')
def suppression_diacritics(s):
def remove(char):
deco = unicodedata.decomposition(char)
if deco:
for c in deco.split():
try:
return chr(int(c, 16))
except ValueError:
pass
return char
return u''.join([remove(a) for a in s])
def slugify(value):
"Converts to lowercase, removes diacritics marks and converts spaces to hyphens"
value = suppression_diacritics(value)
value = re.sub(r'[^\w\s-]', '', value).strip().lower()
return re.sub(r'[-\s]+', '-', value).strip('-')
with psycopg2.connect(dbname=DOTCLEAR_DB, user=DOTCLEAR_USER, password=DOTCLEAR_PWD, host=DOTCLEAR_SERVER) as conn:
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
cur.execute('SELECT post_dt, post_upddt, post_title, post_excerpt, post_content, post_status, cat_title FROM dc_post NATURAL INNER JOIN dc_category ORDER BY post_dt')
for row in cur.fetchall():
filename = '{}_{}.rst'.format(row['post_dt'].isoformat(), slugify(row['post_title']))
#cat_slug = slugify(row['cat_title'])
cat_slug = row['cat_title']
# Create category block
cat_path = os.path.join(OUTPUT_DIR, cat_slug)
if not os.path.exists(cat_path):
os.makedirs(cat_path)
filepath = os.path.join(cat_path, filename)
print(filepath)
with open(filepath, 'w') as fh:
# Title
print(row['post_title'], file=fh)
print('#' * len(row['post_title']), file=fh)
print(file=fh)
# Date
print(':date:', row['post_dt'].isoformat(), file=fh)
print(':modified:', row['post_upddt'].isoformat(), file=fh)
print(':category:', row['cat_title'], file=fh)
print(':slug:', slugify(row['post_title']), file=fh)
print(':author: Johann', file=fh)
print(':lang: fr', file=fh)
if row['post_status'] == 1:
print(':status: published', file=fh)
else:
print(':status: draft', file=fh)
print(file=fh)
output = pypandoc.convert_text(row['post_excerpt'] + "\n\n" + row['post_content'], \
OUTPUT_FORMAT, format=INPUT_FORMAT)
# Specifique output handling starts here
output = V1_MEDIA.sub(V1_REP, output)
output = V2_MEDIA.sub(V2_REP, output)
output = BAD_SMILEY.sub(FIX_SMILEY, output)
f_output = []
for line in output.split('\n'):
if line == BAD_NBSP:
continue
f_output.append(line)
output = '\n'.join(f_output).strip()
# Totoro patch
output = output.replace(' o\_o', '')
idx_imglinks = []
for match in BAD_IMGLINK.finditer(output):
idx_imglinks.append({'tag': match.group(1), 'url': match.group(2)})
output = output.replace('|{}|:{}'.format(match.group(1), match.group(2)),
'|{}|_'.format(match.group(1)))
# Final write
print(output, file=fh)
for imglink in idx_imglinks:
print(".. _{}: {}".format(imglink['tag'], imglink['url']), file=fh)
Bien sûr, c’est plein de spécificités, mais avec un peu de nettoyage, peut-être que ça pourrait servir si l’importateur intégré à Pelican ne fait pas le boulot ou que vous avez besoin d’un export générique de Dotclear vers autres chose.
Et sur ce, à bientôt pour la suite, j’espère.