Skip to content

Instantly share code, notes, and snippets.

@joachimesque
Last active November 22, 2024 16:47
Show Gist options
  • Save joachimesque/69a39382c7101ab00b74bf1465c34353 to your computer and use it in GitHub Desktop.
Save joachimesque/69a39382c7101ab00b74bf1465c34353 to your computer and use it in GitHub Desktop.
`100.json` est l’exemple de sortie JSON que Wordpress propose pour chaque post, `import-authors.py` et `import.py` sont deux versions de la moulinette, pas vraiment faites pour être relues, mais bref.
{
"id": 100,
"date": "2012-12-07T00:00:55",
"date_gmt": "2012-12-06T23:00:55",
"guid":
{
"rendered": "http://www.24joursdeweb.fr/?p=100"
},
"modified": "2012-12-06T21:52:21",
"modified_gmt": "2012-12-06T20:52:21",
"slug": "pour-un-gazon-plus-vert",
"status": "publish",
"type": "post",
"link": "https://www.24joursdeweb.fr/2012/pour-un-gazon-plus-vert/",
"title":
{
"rendered": "Pour un gazon plus vert"
},
"content":
{
"rendered": "<p>Ma famille et ma belle-famille travaillent pour la ville de Montréal. Je l’aime bien, cette ville. C’est ma ville. Même si elle est mise à mal depuis quelque temps, j’aime y travailler et je prends soin du quartier où j’habite.</p>\n<p>Il y a quelques semaines, j’ai eu la chance de m’asseoir à la table de mes beaux-parents qui avaient invité des collègues à l’occasion d’un anniversaire. De fil en aiguille, j’ai saisi la chance de discuter de leur processus de travail et de leurs méthodes de prises de décisions. Des sujets franchement inspirants autour d’un très gros gâteau et de beaucoup de café.</p>\n<p>Au moment où l’on parlait de projets qui avaient changé leur façon de faire, une anecdote plutôt accrocheuse intrigua l’auteur de ce billet, votre architecte de l’expérience utilisateur. Deux des fonctionnaires présents avaient eu la tâche de réaménager les chemins d’accès d’un parc, car l’érection de nouveaux bâtiments administratifs en avait obligé la reconfiguration. Les trottoirs bétonnés avaient été retirés et il fallait trouver une solution afin de rendre la promenade agréable et efficace.</p>\n<p>La vision qu’ils avaient sur le trajet que devaient prendre les trottoirs divergeait, mais ils prirent plaisir à travailler ensemble pour trouver la meilleure solution. Ils avaient commencé par se poser des questions comme&nbsp;: les passants allaient-ils préférer contourner la statue&nbsp;? Passeraient-ils par la rue principale ou longeraient-ils le nouveau bâtiment&nbsp;? À la sortie du métro, seraient-ils plus enclins à prendre la sortie nord ou nord-ouest&nbsp;? Etc.</p>\n<p>Les hypothèses avaient toutes été inscrites sur un immense tableau blanc. Ils en discutèrent longtemps devant des cafés comme celui que nous buvions à ce moment et se donnèrent le devoir de créer quelques propositions en plans aériens.<br>\nEnsuite commença la ronde des rencontres internes qui amenèrent leurs lots d’annotations, de changements, de ratifications et de révisions. Plus ils en discutèrent, plus il y avait de personnes qui donnaient leur opinion. Même le responsable des fournitures de bureau, connu pour sa passion pour le jardinage, avait mis son nez dans le projet.</p>\n<p>C’était un bal infernal. Personne ne dansait sur le même rythme et on semblait ne pas entendre la même musique.<br>\nLe superviseur des superviseurs chanta les louanges d’un consultant qu’il avait connu lors de ses voyages d’affaires. Il engagea ce chef d’orchestre, lui donnant le mandat d’ajuster cette cacophonie bureaucrate et d’imposer à l’orchestre de jouer à l’unisson. À ce moment de l’histoire, tous les fonctionnaires dédiés au projet autour de la table, avec qui nous prenions le café, avaient serré les poings en maugréant que nul n’est prophète en son pays.</p>\n<p>Le consultant prit le temps de comprendre le contexte, fit plusieurs entrevues avec tous les acteurs du projet, puis remplit son carnet de notes. Sa solution fut tout de même simple&nbsp;: il demanda de gazonner l’ensemble du terrain, d’attendre deux saisons (printemps &amp; été) pour ensuite bétonner les endroits où l’herbe avait été usée par les passants.</p>\n<p>Ce qui fut fait, avec succès. Un peu déçus de ne pas avoir eu la confiance de leurs supérieurs, ils comprirent tout de même les bénéfices de cette approche.</p>\n<h2 dir=\"ltr\">Nul n’est prophète en son pays.</h2>\n<p>Cette anecdote n’a rien de nouveau ni pour moi, ni peut-être pour vous. Par cette histoire, je ne tente pas nécessairement de vous démontrer qu’il faut laisser les utilisateurs décider à votre place. Au contraire, si pour vous, l’expérience utilisateur suffit d’exiger que des consultants comptabilisent les bonnes pratiques, en dessinant un plan en fil de fer avec des crayons-feutres, vous n’en retirerez que très peu de valeur.</p>\n<p>Peut-être que pour des organisations comme la vôtre, cela permettra d’avoir, à peu de frais, une idée de ce à quoi le produit pourrait ressembler. De toute façon, nous les connaissons bien, ils changeront d’idée lorsque viendra la maquette.</p>\n<p>D’ailleurs, les organisations discutent très souvent tout d’abord de la technologie à utiliser avant même, par exemple, de rencontrer le service à la clientèle. C’est pourtant ce même service qui a connaissance, par sa nature, des besoins des utilisateurs. Le mandat qu’elles donnent est trop souvent géré par une seule personne qui filtre, selon son opinion, l’ensemble des défis de tous les départements. À moins d’être une très petite entreprise, le résultat revient à ce que l’expérience soit développée à l’aide d’une béquille.</p>\n<h2 dir=\"ltr\">L’espoir dans une meilleure pratique</h2>\n<p>Lorsque l’on ajoute&nbsp;«&nbsp;expérience utilisateur&nbsp;»&nbsp;à son titre, c’est que l’on se veut apôtre d’une méthodologie plutôt nouvelle bien que traditionnelle. Celle-ci trouve ses racines dans la science et demande d’être pratiquée dans un environnement qui tient pour acquis que le consommateur est ce qui prime, lorsque l’on parle d’innovation et de développement de produits et / ou de services.</p>\n<p>Bien sûr, quelle entreprise avouera ne pas mettre ses clients au centre de ses préoccupations&nbsp;? Qui dira que l’innovation n’est pas sa priorité&nbsp;? Personne.</p>\n<p>Pourtant, il est facile de deviner ceux qui ne sont pas à l’aise de les écouter et qui n’assurent pas que tous les rouages de leur organisation vont dans un même sens. On retrouve souvent un arrière-goût désagréable lorsqu’on a affaire à eux, par exemple par un site web lent, déficient et inaccessible. Les promotions offertes ne servent que l’acquisition, délaissant la responsabilité de la rétention au service de comptabilité.</p>\n<h2 dir=\"ltr\">L’espoir dans la concurrence</h2>\n<p>Les visiteurs n’acceptent plus aussi facilement de passer du temps sur des sites web qui les contrarient et les assomment, par conséquent, ils en déclinent leur utilisation. Ceux qui se concentrent majoritairement à l’ajout de nouvelles options aux précédentes voient leurs visiteurs migrer vers la concurrence qu’ils ne voyaient pas venir.</p>\n<p>Lorsque la compétition ravage les parts du marché, c’est qu’elle est arrivée à extraire l’essence de l’expérience utilisateur et les réels besoins d’une clientèle. Elles surgissent de nulle part et renversent le statu quo en proposant plus rapidement que la moyenne des solutions en toute convivialité et constamment améliorées. Par-dessus tout, elles assurent un échange ouvert et régulier avec leurs utilisateurs.</p>\n<h2 dir=\"ltr\">L’espoir dans la crise</h2>\n<p>Pour d’autres organisations, l’espoir réside dans la crise. Lorsqu’une innovation surprise venant de l’extérieur vient perturber les habitudes de leurs clients, le choc ressenti peut faire changer les choses.</p>\n<p>Si elles choisissent de se retrancher dans une réaction défensive, elles plafonneront.</p>\n<p>Si elles décident d’être un peu plus proactives, ces organisations se doteront de décideurs. Ceux-ci seront plus à même de comprendre l’écologie de leur entreprise et de savoir comment cet ensemble doit être ficelé afin de rendre meilleurs ceux qu’ils veulent servir. La philosophie de l’expérience utilisateur fera partie intégrante de leur initiative et en prouvera l’éloge par les faits accomplis. On aimera avec confiance ces marques qui émaneront de ce désir d’assurer une expérience optimale, partout, tout le temps. Ces marques nous aimeront aussi et feront tout ce qu’il faut pour nous le rendre.</p>\n<p>Il y a également l’espoir qu’un vice-président possède «&nbsp;chef de l’expérience client&nbsp;/&nbsp;utilisateur&nbsp;» dans son titre. Ne serait-ce pas tout à fait légitime d’ailleurs ?!</p>\n<h2 dir=\"ltr\">L’espoir dans la culture</h2>\n<p>L’expérience utilisateur n’est pas une tactique parmi tant d’autres, c’est un changement de paradigme. Les entreprises qui adoptent enfin ces principes investissent dans la recherche, l’étude, et le développement. Elles abandonnent la promotion à outrance, l’embellissement de l’égo et la complexification sans raison. Elles sortent du huis clos et se font évaluer directement sur le terrain. Elles commencent par des entrevues, utilisent des méthodologies de design logiques et centrées, passent des tests sur des prototypes et vont plus loin que la ligne d’arrivée en évaluant de façon régulière la satisfaction de leur clientèle. Elles possèdent des équipes pluridisciplinaires qui coopétitionnent entre elles pour bâtir agilement et développer de façon durable, sur toutes les plateformes, dans toutes les langues, sur le mobile et sur le mondial</p>\n<p>Je ne devrais pas vous surprendre en vous disant que vos pratiques culturelles sont l’un de vos plus grands chantiers où tout reste à améliorer. Le meilleur moyen de s’en sortir est de développer cette certaine forme de culture nourricière qu’est l’expérience utilisateur.</p>\n",
"protected": false
},
"excerpt":
{
"rendered": "<p>Ma famille et ma belle-famille travaillent pour la ville de Montréal. Je l’aime bien, cette ville. C’est ma ville. Même si elle est mise à mal depuis quelque temps, j’aime y travailler et je prends soin du quartier où j’habite. Il y a quelques semaines, j’ai eu la chance de m’asseoir à la table de […]</p>\n",
"protected": false
},
"author": 7,
"featured_media": 0,
"comment_status": "open",
"ping_status": "closed",
"sticky": false,
"template": "",
"format": "standard",
"meta":
{
"wp_typography_post_enhancements_disabled": false,
"footnotes": ""
},
"categories":
[
1
],
"tags":
[],
"class_list":
[
"post-100",
"post",
"type-post",
"status-publish",
"format-standard",
"hentry",
"category-articles"
],
"_links":
{
"self":
[
{
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/posts/100"
}
],
"collection":
[
{
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/posts"
}
],
"about":
[
{
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/types/post"
}
],
"author":
[
{
"embeddable": true,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/users/7"
}
],
"replies":
[
{
"embeddable": true,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/comments?post=100"
}
],
"version-history":
[
{
"count": 3,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/posts/100/revisions"
}
],
"predecessor-version":
[
{
"id": 104,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/posts/100/revisions/104"
}
],
"wp:attachment":
[
{
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/media?parent=100"
}
],
"wp:term":
[
{
"taxonomy": "category",
"embeddable": true,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/categories?post=100"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://www.24joursdeweb.fr/wp-json/wp/v2/tags?post=100"
}
],
"curies":
[
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
#!/usr/bin/env python3
import os
import json
import urllib.request
from pathlib import Path
import shutil
import time
import unicodedata
import re
from urllib.parse import quote
import hashlib
current = Path(os.path.dirname(__file__))
pathlist = Path(current, "import").glob('*')
ids = []
base_path = Path(current.parent, "24jdw-kirby", "content")
substitutions = (
(r'[éèë]', 'e'),
(r'[àá]', 'a'),
(r'[ç]', 'c'),
(r'[ïî]', 'i'),
)
def slugify(st):
slug = re.sub(r'\W+', '-', st).strip('-').lower()
for tup in substitutions:
slug = re.sub(*tup, slug)
return slug
for path in pathlist:
# because path is object not string
path_in_str = str(path)
with open(path_in_str, 'r') as file:
data = json.load(file)
auteurice_href = f"https://www.24joursdeweb.fr/wp-json/wp/v2/users/{data["author"]}"
slug = data["slug"]
year = data["date"][0:4]
day = data["date"][8:10]
# check article dir
article_path = Path(base_path, f"{int(year) - 2011}_{year}", f"{day}_{slug}", "article.txt")
if (data["author"] in ids):
print(f"{data["author"]} already saved")
with urllib.request.urlopen(auteurice_href) as auteurice_data:
auteurice_data = json.load(auteurice_data)
auteurice_nom = auteurice_data["name"]
link_hash = hashlib.sha256(str.encode(auteurice_nom)).hexdigest()
uuid = f"wp_auteurice_{data["author"]}_{link_hash[0:16]}"
with open(article_path, "a") as myfile:
myfile.write(f"""
----
Auteurice: page://{uuid}
""")
ids.append(data["author"])
article_link_hash = hashlib.sha256(str.encode(data["link"])).hexdigest()
article_uuid = f"{data["id"]}_{article_link_hash[0:16]}"
# Get online stuff
# AUTHOR
with urllib.request.urlopen(auteurice_href) as auteurice_data:
auteurice_data = json.load(auteurice_data)
auteurice_nom = auteurice_data["name"]
auteurice_bio = auteurice_data["description"]
auteurice_url = auteurice_data["url"]
auteurice_avatar = auteurice_data["avatar_urls"]["96"]
auteurice_avatar = f"{auteurice_avatar.split("?")[0]}?s=300&d=blank&r=g"
slug = slugify(auteurice_nom)
print("author", auteurice_nom, slug, end=" -> ")
link_hash = hashlib.sha256(str.encode(auteurice_nom)).hexdigest()
uuid = f"wp_auteurice_{data["author"]}_{link_hash[0:16]}"
# Create dir
auteurice_path = Path(base_path, "auteurices", slug)
if os.path.exists(auteurice_path):
auteurice_path = Path(base_path, "auteurices", f"{slug}-{data["author"]}")
Path(auteurice_path).mkdir(parents=True, exist_ok=True)
# Avatar file
filename = f"avatar_{slug}"
avatar_url = f"{auteurice_avatar.split("?")[0]}.jpg?s=300&d=404&r=g"
# Create a request object with URL and headers
header = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '}
req = urllib.request.Request(url=avatar_url, headers=header)
avatar_file_uuid = ""
try:
# Create an http response object
with urllib.request.urlopen(req) as response:
extension = response.headers.get("Content-Type").split("/")[1].replace("e", "")
filename = f"{filename}.{extension}"
# Create a file object
with open(Path(auteurice_path, filename), "wb") as f:
# Copy the binary content of the response to the file
shutil.copyfileobj(response, f)
avatar_file_uuid = f"wp_auteurice_{data["author"]}_{link_hash[0:16]}_avatar"
attachement_file_content = f"""Uuid: {avatar_file_uuid}
----
"""
attachement_file_name = Path(auteurice_path, f"{filename}.txt")
f = open(attachement_file_name, "w+")
f.write(attachement_file_content)
f.close()
avatar_file_uuid = f"file://{avatar_file_uuid}"
print(" -> ok", end=" ~ ")
except Exception as e:
print(" <<< 404", end=" ~ ")
pass
print("✔︎")
file_content = f"""Title: {auteurice_nom}
----
Bio: {auteurice_bio}
----
Fediverse:
----
Bsky:
----
Urls:
----
WP-avatar-url: {auteurice_avatar}
----
WP-url: {auteurice_url}
----
Avatar: {avatar_file_uuid}
----
Uuid: {uuid}
----
Article: page://{article_uuid}
----
Raw-data: {json.dumps(auteurice_data)}
"""
f = open(Path(auteurice_path, "auteurice.txt"), "w+")
f.write(file_content)
f.close()
with open(article_path, "a") as myfile:
myfile.write(f"""
----
Auteurice: page://{uuid}
""")
time.sleep(1)
#!/usr/bin/env python3
import os
import json
import urllib.request
from pathlib import Path
import shutil
import time
import unicodedata
import re
from urllib.parse import quote
import hashlib
pathlist = Path(os.path.dirname(__file__), "import").glob('*')
for path in pathlist:
# because path is object not string
path_in_str = str(path)
with open(path_in_str, 'r') as file:
data = json.load(file)
title = data["title"]["rendered"]
slug = data["slug"]
texte = data["content"]["rendered"]
year = data["date"][0:4]
day = data["date"][8:10]
auteurice_href = f"https://www.24joursdeweb.fr/wp-json/wp/v2/users/{data["author"]}"
link_hash = hashlib.sha256(str.encode(data["link"])).hexdigest()
uuid = f"{data["id"]}_{link_hash[0:16]}"
attachments = f"https://www.24joursdeweb.fr/wp-json/wp/v2/media?parent={data["id"]}"
comments_json_href = f"{data["link"]}feed/json"
# Create dir
k_path = Path(os.path.dirname(__file__), "export", year, f"{day}_{slug}")
Path(k_path).mkdir(parents=True, exist_ok=True)
print(uuid, f"{year}-12-{day}", end=" -> ")
# Get online stuff
# AUTHOR
with urllib.request.urlopen(auteurice_href) as auteurice_data:
auteurice_data = json.load(auteurice_data)
auteurice_nom = auteurice_data["name"]
auteurice_bio = auteurice_data["description"]
auteurice_url = auteurice_data["url"]
auteurice_avatar = auteurice_data["avatar_urls"]["96"]
auteurice_avatar = f"{auteurice_avatar.split("?")[0]}?s=300&d=blank&r=g"
print("author", auteurice_data["id"], end=" -> ")
# COMMENTS
with urllib.request.urlopen(comments_json_href) as comments_url:
comments_data = json.load(comments_url)
with open(Path(k_path, "comments.json"), "w+") as comments_json:
comments_json.write(json.dumps(comments_data))
comments_json.close()
comments_file_txt = open(Path(k_path, "comments.json.txt"), "w+")
comments_file_txt.write(f"Uuid: {uuid}_comments\n")
comments_file_txt.close()
print("loaded comments", end=" -> ")
print("✔︎")
# with urllib.request.urlopen(attachments) as attachments_url:
# attachments_data = json.load(attachments_url)
# with open(Path(k_path, "attachments.json"), "w+") as f:
# f.write(json.dumps(attachments_data))
# f.close()
# if attachments_data:
# print("attachments:")
# else:
# print("no attachment")
# for attachment in attachments_data:
# filename = attachment["guid"]["rendered"].split("/")[-1]
# attachment_url = f"https://{quote(attachment["source_url"][8:])}"
# # Create a request object with URL and headers
# header = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '}
# req = urllib.request.Request(url=attachment_url, headers=header)
# print(" -> ", filename, end="")
# try:
# # Create an http response object
# with urllib.request.urlopen(req) as response:
# # Create a file object
# with open(Path(k_path, filename), "wb") as f:
# # Copy the binary content of the response to the file
# shutil.copyfileobj(response, f)
# print(" -> ok")
# except Exception as e:
# print(" <<< ERROR")
# print(e)
# print(attachment_url, filename)
# continue
# attachement_file_content = f"""Uuid: attachment_{attachment["id"]}
# ----
# Slug: {attachment["slug"]}
# ----
# Title: {attachment["title"]["rendered"]}
# ----
# Caption: {attachment["caption"]["rendered"]}
# ----
# Alt_text: {attachment["alt_text"]}
# """
# attachement_file_name = Path(k_path, f"{filename}.txt")
# f = open(attachement_file_name, "w+")
# f.write(attachement_file_content)
# f.close()
file_content = f"""Title: {title}
----
Texte:
{texte}
----
Auteurice:
----
Auteurice_href: {auteurice_href}
----
Auteurice_nom: {auteurice_nom}
----
Auteurice_bio:
{auteurice_bio}
----
Auteurice_url: {auteurice_url}
----
Auteurice_avatar: {auteurice_avatar}
----
Date: {year}-12-{day}
----
Metadata-title:
----
Metadata-tags:
----
Metadata-description:
----
Attachments_url: {attachments}
----
Comments_url: {comments_json_href}
----
Uuid: {uuid}
"""
f = open(Path(k_path, "article.txt"), "w+")
f.write(file_content)
f.close()
time.sleep(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment