2022-08-09 CalCleaner: J’ai développé un petit outil pour supprimer les vieux événements des calendriers par https://twitter.com/flogisoft

Pourquoi ?

Que ce soit pour le boulot ou en perso, je travaille sur énormément de projets différents. Il suffit de voir combien de temps je mets à répondre à certaines issues sur Github ou la durée très variable qui sépare deux articles de ce blog pour s’en rendre compte 😅️.

Du fait de cette multiplication de projets, j’utilise intensivement des calendriers pour m’organiser.

Mais depuis quelques semaines, Thunderbird, le logiciel que j’utilise pour gérer mes calendriers est de plus en plus lent ; faute à la synchronisation qui prend de plus en plus de temps.

J’ai donc décidé de supprimer les vieux événements de mes calendriers : ça ne me sert à rien de garder des années d’historique…

J’ai donc commencé à chercher dans les menus de Thunderbird s’il était possible de lui faire supprimer facilement les vieux événements ou si au moins on pouvait lui demander de ne synchroniser que les plus récents… Rien. J’ai également regardé s’il existait quelque chose du côté de Nextcloud (qui gère mon serveur de calendrier), mais rien non plus. 😞️

J’ai donc commencé à chercher s’il n’existait pas un petit utilitaire, un script ou autre qui me permettrait d’arriver à mes fins… Mais tout ce que j’ai trouvé, c’est un vieux plugin Thunderbird. Ce plugin fait exactement ce que je veux… mais il n’est plus compatible avec Thunderbird depuis une trentaine de versions… Encore raté ! 😩️

En désespoir de cause j’ai lancé une bouteille à la mer sur Twitter et Mastodon.

Il y a eu pas mal de réactions sur Mastodon, mais personne n’avait de solution à proposer. J’ai donc décidé de faire les choses moi-même ! 😤️

À partir de là, j’avais plusieurs possibilités :

  • Faire un plugin Thunderbird ou essayer de reprendre celui existant,

  • Faire une application Nextcloud pour régler directement le problème à la source,

  • Supprimer directement les événements dans la base de données de Nextcloud (oui oui),

  • Essayer de faire un script Python vite fait qui supprime les événements via le protocole CalDAV .

J’ai rapidement écarté le plugin Thunderbird et l’application Nextcloud : ça restreint l’usage qui pourrait être fait de l’outil. Si jamais je change de client email ou de serveur de calendrier je ne pourrai plus l’utiliser.

J’ai failli partir sur l’idée d’aller supprimer directement les éléments dans la base de données, mais avant d’en arriver à de telles extrémités, j’ai préféré regarder s’il n’existerait pas une bibliothèque Python permettant de dialoguer facilement avec un serveur CalDAV .

Premier PoC (Proof of Concept)

J’ai donc commencé à chercher une bibliothèque Python qui me permette de parler à des serveurs de calendriers. Il n’était en effet pas question de faire cette partie moi-même : les serveurs CalDAV respectent généralement assez mal la norme, et les clients contiennent la plupart du temps des bricolages pour assurer la compatibilité avec tel ou tel serveur… Ça aurait été trop de travail de gérer correctement tous les serveurs de calendriers cassés qui existent.

Je suis donc assez rapidement tombé sur la bibliothèque caldav qui fait très bien le taf, même si sa documentation est très perfectible. 😄️

 1 #!/usr/bin/env python3
 2
 3 from datetime import datetime, timedelta
 4
 5 from caldav import DAVClient
 6
 7
 8 # Informations de connexion au serveur de calendriers.
 9 CALDAV_URL = "http://localhost:8080/remote.php/dav"
10 CALDAV_USER = "admin"
11 CALDAV_PASSWORD = "password"
12
13 # Date au-delà de laquelle les événements sont considérés comme trop vieux
14 # Ici il s'agit des événements qui ont plus de 4 mois (aujourd'hui moins 16
15 # semaines)
16 DATE_OLD = datetime.now() - timedelta(weeks=16)
17
18 # On ouvre la connexion avec le serveur
19 with DAVClient(CALDAV_URL, username=CALDAV_USER, password=CALDAV_PASSWORD) as dav_client:
20
21     # On récupère le principal (objet « racine » du serveur)
22     dav_principal = dav_client.principal()
23
24     # On récupère tous les calendriers accessibles
25     calendars = dav_principal.calendars()
26
27     # On prend les calendriers un par un
28     for calendar in calendars:
29         # On affiche le nom du calendrier et le nombre total d'événements qu'il
30         # contient
31         print("Calendar: %s" % calendar.name)
32         print("  Events: %i" % len(calendar.events()))
33
34         # On récupère les vieux événements.
35         # Comme il faut fournir un intervalle on récupère ceux entre le premier
36         # janvier 1900 et la date calculée plus haut
37         old_events = calendar.date_search(
38             start=datetime(1900, 1, 1),
39             end=DATE_OLD,
40             expand=True,
41         )
42
43         # On en profite pour afficher le nombre de vieux événements qui seront
44         # supprimés
45         print("  Old events: %i" % len(old_events))
46
47         # On supprime tous les vieux événements, un par un
48         for old_event in old_events:
49             old_event.delete()

Si on lance ce script, on obtient un résultat de ce style:

$ ./clean_calendars.py
Calendar: Personnel
  Events: 937
  Old events: 822
Calendar: Work
  Events: 2205
  Old events: 1848

Après ça j’ai poussé un peu plus loin le développement de ce script pour y ajouter des barres de progression histoire de voir où on en est dans le nettoyage. Et puis voilà, c’est terminé… Enfin pas tout à fait… 😁️

Naissance de CalCleaner

Étant donné que je serai amené à nettoyer mes calendriers de temps en temps, et que le sujet semblait intéresser quelques personnes, je me suis dit qu’une petite interface graphique serait plus pratique. C’est ainsi que je me suis lancé dans l’écriture de CalCleaner, qui est donc l’aboutissement du script dont je viens de vous parler.

Au niveau du développement de l’application en elle-même il n’y a pas eu de grandes difficultés. En fait, l’élément qui m’a posé le plus de problèmes a été de réussir à récupérer la couleur des calendriers (ai-je déjà mentionné que la documentation de la bibliothèque caldav était perfectible ? 😅️)… Mais j’ai assez vite résolu cette petite difficulté grâce à un ticket sur le bug tracker de la lib.

Le développement de cette application a toutefois été l’occasion de pousser plus loin ma compréhension du widget GTK GtkTreeView (il s’agit d’un élément graphique permettant d’afficher des listes et des arborescences).

J’ai notamment appris comment afficher plusieurs colonnes du modèle de données dans une seule colonne du composant graphique (c’est ce qui me permet d’afficher le nom du compte en dessous de chaque calendrier). Ça semble un peu anecdotique dit comme ça, mais ça me sera prochainement utile pour rendre la vue principale de YOGA Image Optimizer plus compacte.

Un autre point d’intérêt pour moi lors du développement de cette application a été le stockage sécurisé des identifiants et des mots de passe. Ici il n’est pas question de réinventer la roue, les environnements de bureau fournissent des services de stockage pour ce type d’informations sensibles. Chez GNOME, ce service s’appelle GNOME Keyring, chez KDE il s’agit de kwallet. Que vous utilisiez l’un ou l’autre n’a pas une grande importance : ils implémentent tous deux la même interface puisqu’il s’agit en fait d’une norme Freedesktop nommée « Secret Service »

Dans mon cas, l’accès au stockage des mots de passe s’est fait très facilement à travers la bibliothèque libsecret .

Et après ?

La version de CalCleaner disponible au moment où j’écris ces lignes est la v0.9.1 (beta). Je pense sortir la version v1.0.0 début septembre.

Cette version 1.0 ne contiendra pas de grands changements par rapport à la version actuelle, seulement de petites améliorations esthétiques, des traductions supplémentaires (comme l’italien, qu’un contributeur m’a envoyé il y a quelques jours) et éventuellement des corrections de bug, si jamais on en trouve. 😅️

Je ne pense pas faire de portage Windows de l’application pour le moment car ça demande pas mal de travail et que j’en ai pas l’utilité. Mais je changerai peut-être d’avis un jour, si jamais il y a de la demande… On verra… 😛️

J’espère en tout cas que ce petit outil pourra vous être utile si jamais vous avez besoin d’alléger vos calendriers. 😁️