CalCleaner : J'ai développé un petit outil pour supprimer les vieux événements des calendriers

Je viens de sortir une première version (beta) de CalCleaner, un petit outil permettant de faire le ménage dans les calendriers CalDAV. Le logiciel dispose d'une interface graphique en GTK 3 (oui il serait temps que je me mette à GTK 4) et est pour le moment disponible pour Linux uniquement.

Dans cet article je vais bien sûr vous présenter l'outil et ses fonctionnalités (ça ne devrait pas être trop long 😛️), mais avant ça je vais vous expliquer pourquoi je l'ai créé et je vous parlerai aussi un peu de son développement.

Capture d'écran de CalCleaner

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 ! 😤️

Message du Tweet: « Quelqu'un connaît un outil ou un script, libre ou open source, et disponible sous Linux pour supprimer les vieux événements d'un calendrier CALDav ? Il n'y a aucune fonction pour ça dans Nextcloud, et je n'ai trouvé qu'un vieux plugin Thunderbird qui n'est plus compatible... »

Un tweet à la mer...

À 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. 😄️

En quelques dizaines de minutes j'ai été en mesure de faire un script qui faisait exactement ce que je voulais :

#!/usr/bin/env python3

from datetime import datetime, timedelta

from caldav import DAVClient


# Informations de connexion au serveur de calendriers.
CALDAV_URL = "http://localhost:8080/remote.php/dav"
CALDAV_USER = "admin"
CALDAV_PASSWORD = "password"

# Date au-delà de laquelle les événements sont considérés comme trop vieux
# Ici il s'agit des événements qui ont plus de 4 mois (aujourd'hui moins 16
# semaines)
DATE_OLD = datetime.now() - timedelta(weeks=16)

# On ouvre la connexion avec le serveur
with DAVClient(CALDAV_URL, username=CALDAV_USER, password=CALDAV_PASSWORD) as dav_client:

    # On récupère le principal (objet « racine » du serveur)
    dav_principal = dav_client.principal()

    # On récupère tous les calendriers accessibles
    calendars = dav_principal.calendars()

    # On prend les calendriers un par un
    for calendar in calendars:

        # On affiche le nom du calendrier et le nombre total d'événements qu'il
        # contient
        print("Calendar: %s" % calendar.name)
        print("  Events: %i" % len(calendar.events()))

        # On récupère les vieux événements.
        # Comme il faut fournir un intervalle on récupère ceux entre le premier
        # janvier 1900 et la date calculée plus haut
        old_events = calendar.date_search(
            start=datetime(1900, 1, 1),
            end=DATE_OLD,
            expand=True,
        )

        # On en profite pour afficher le nombre de vieux événements qui seront
        # supprimés
        print("  Old events: %i" % len(old_events))

        # On supprime tous les vieux événements, un par un
        for old_event in old_events:
            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.

Capture d'écran du widget GtkTreeView

GtkTreeView

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.

Aperçu d'un mot de passe enregistré dans le trousseau de clefs de GNOME par CalCleaner

Aperçu des mots de passe enregistrés dans le trousseau de clefs

Présentation de CalCleaner

Voici donc CalCleaner, le nettoyeur de calendriers :

CalCleaner : Écran de premier démarrage CalCleaner : Écran principal, sélection des calendriers a nettoyer CalCleaner : Nettoyage en cours

Comme vous pouvez le constater, l'interface est assez simple. Au premier démarrage, l'application vous propose de vous connecter à un serveur de calendrier (par la suite il est possible d'ajouter, de supprimer et de modifier les comptes via le menu sandwich situé en haut à droite).

La vue suivante nous affiche la liste des calendriers accessibles avec le (ou les) comptes CalDAV configurés. Il est alors possible de décocher les calendriers que l'on ne souhaiterait pas traiter (je n'ai personnellement pas envie de nettoyer le calendrier des anniversaires 😛️). C'est aussi sur cet écran que l'on peut définir l'ancienneté des événements à supprimer et s'il faut ou non traiter les événements récurrents¹... Il suffit ensuite de cliquer sur « Clean Now! » (ou sur « Nettoyer maintenant ! » dans la version française) pour que CalCleaner se mette au boulot. 🗓️🧹️

Étant donné que les événements sont supprimés un par un, cela prend un peu de temps, mais la progression est affichée en temps réel dans l'interface.

Note

NOTE¹ : À propos des événements récurrents.

Les événements récurrents créés avant l'ancienneté configurée sont considérés pour le nettoyage, même s'ils se poursuivent au-delà. Et leurs occurrences futures sont elles aussi supprimées du même coup.

Les événements récurrents sont assez pénibles à gérer, c'est pourquoi j'ai pour le moment seulement ajouté une case à cocher pour les ignorer. Peut-être que j'améliorerai leur traitement dans une future version du logiciel.

Obtenir CalCleaner

Le plus simple pour installer CalCleaner est d'utiliser le paquet Flatpak présent sur Flathub. Pour ce faire, il faut d'abord suivre les instructions spécifiques à votre distribution Linux sur la page suivante :

Ensuite, vous pouvez installer le logiciel soit en cliquant sur le bouton « Install » présent sur la page de l'application :

Soit en tapant la commande suivante :

flatpak install flathub org.flozz.calcleaner

L'application devrait alors apparaitre dans votre lanceur d'applications habituel. Si toutefois ce n'était pas le cas, il est possible de la lancer avec la commande suivante :

flatpak run org.flozz.calcleaner

Il est également possible d'installer le logiciel depuis les sources ; vous trouverez les instructions sur Github :

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. 😁️