-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
PhunkyBob
committed
Apr 20, 2022
1 parent
243f446
commit 5adaee4
Showing
9 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,3 +127,5 @@ dmypy.json | |
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# ICS to CSV | ||
|
||
Ce script permet de convertir un fichier ICS (format d'export du calendrier Google Agenda) en fichier CSV (fichier texte délimité). | ||
|
||
## Utilisation | ||
`python ics_to_csv.py` | ||
|
||
Cela ouvrira une interface graphique (générée par [Gooey](https://github.com/chriskiehl/Gooey)). | ||
![interface](./doc/interface.png) | ||
|
||
### Arguments obligatoires | ||
- Fichier d'entrée : un fichier CSV généré par Google Agenda. | ||
### Arguments optionnels | ||
- Fichier de sortie : le chemin du fichier à sauvegarder. Par défaut : le même nom que le fichier d'entrée, mais avec l'extension CSV. | ||
- Avec lieu uniquement : permet de ne sauvegarder que les enregistrements pour lesquels un lieu a été renseigné. | ||
- Date de début : permet de fitrer les évènements postérieurs à cette date (format `AAAA-MM-JJ`). | ||
- Date de fin : permet de filtrer les évènements antérieurs à cette date (format `AAAA-MM-JJ`) | ||
|
||
|
||
## Utilisation en ligne de commande | ||
Vous pouvez commenter la ligne de décorateur `@Gooey(...)` qui se trouve jsute au dessus de la fonction `main()` et le programme fonctionnera en ligne de commande : | ||
``` | ||
usage: ics_to_csv.py [-h] [--output-file Fichier de sortie] [--location-only] [--from-date Date de début] | ||
[--to-date Date de fin] | ||
Fichier d'entrée | ||
Script qui transforme un fichier ICS en fichier CSV. | ||
positional arguments: | ||
Fichier d'entrée chemin du fichier ICS à convertir | ||
optional arguments: | ||
-h, --help show this help message and exit | ||
--output-file Fichier de sortie, -o Fichier de sortie | ||
chemin du fichier CSV à créer | ||
--location-only, -l si on ne souhaite que les évènements avec un lieu renseigné | ||
--from-date Date de début, -f Date de début | ||
date de début de la période à convertir | ||
--to-date Date de fin, -t Date de fin | ||
date de fin de la période à convertir | ||
``` | ||
|
||
|
||
## Installation | ||
Nécessite Python 3.9+. | ||
- Dans une ligne de commande, allez dans le répertoire de votre choix. | ||
Exemple : | ||
``` | ||
cd c:\Python | ||
``` | ||
- Clonez le repo : | ||
``` | ||
git clone https://github.com/PhunkyBob/ics_to_csv.git | ||
``` | ||
- Allez dans le répertoire qui vient d'être créé : | ||
``` | ||
cd ics_to_csv | ||
``` | ||
- (optionnel, mais conseillé) Créez un environnement virtuel et activez le : | ||
``` | ||
python -m venv venv | ||
.\env\Script\activate | ||
``` | ||
- Installez les librairies nécessaires : | ||
``` | ||
pip install -r requirements.txt | ||
``` | ||
|
||
### Exécutable | ||
Vous pouvez essayer d'utiliser directement [la version binaire](https://github.com/PhunkyBob/ics_to_csv/releases) (expérimental). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Ce script permet de convertir un fichier ICS en un fichier CSV, tout en filtrant les évènements | ||
- selon une date de début et une date de fin | ||
- selon la présence d'un lieu | ||
""" | ||
import re | ||
import csv | ||
from datetime import datetime | ||
import argparse | ||
import os | ||
from gooey import Gooey, GooeyParser | ||
import codecs | ||
import sys | ||
|
||
VERSION = "1.0" | ||
|
||
def valid_date(s): | ||
""" Fonction de validation de date : soit vide, soit au format YYYY-MM-DD. """ | ||
if not s: | ||
return None | ||
try: | ||
return datetime.strptime(s, "%Y-%m-%d") | ||
except ValueError: | ||
msg = "ce n'est pas une date valide: {0!r}".format(s) | ||
raise argparse.ArgumentTypeError(msg) | ||
|
||
@Gooey(program_name=f"ICS to CSV {VERSION}", default_size=(700, 600), language='french', image_dir='images') | ||
def main(): | ||
# Patch parce que Gooey ne sait pas gérer les entrées / sorties utf-8. | ||
if sys.stdout.encoding != 'UTF-8': | ||
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict') | ||
if sys.stderr.encoding != 'UTF-8': | ||
sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer, 'strict') | ||
|
||
# Définition des arguments de la ligne de commande par Gooey. | ||
parser = GooeyParser( | ||
description="""Script qui transforme un fichier ICS en fichier CSV.""" | ||
) | ||
parser.add_argument( | ||
"from_file", | ||
type=str, | ||
metavar="Fichier d'entrée", | ||
help="chemin du fichier ICS à convertir", | ||
widget='FileChooser', | ||
) | ||
parser.add_argument( | ||
"--output-file", | ||
"-o", | ||
default="", | ||
# nargs='?', | ||
type=str, | ||
metavar="Fichier de sortie", | ||
help="chemin du fichier CSV à créer", | ||
widget='FileSaver', | ||
) | ||
parser.add_argument( | ||
"--location-only", | ||
"-l", | ||
default=False, | ||
action='store_true', | ||
metavar="Avec lieu uniquement", | ||
help="si on ne souhaite que les évènements avec un lieu renseigné", | ||
) | ||
parser.add_argument( | ||
"--from-date", | ||
"-f", | ||
default=None, | ||
type=valid_date, | ||
metavar="Date de début", | ||
help="date de début de la période à convertir", | ||
widget='DateChooser', | ||
) | ||
parser.add_argument( | ||
"--to-date", | ||
"-t", | ||
default=None, | ||
type=valid_date, | ||
metavar="Date de fin", | ||
help="date de fin de la période à convertir", | ||
widget='DateChooser', | ||
) | ||
|
||
args = parser.parse_args() | ||
from_file = args.from_file | ||
to_file = args.output_file | ||
from_date = args.from_date | ||
to_date = args.to_date | ||
location_only = args.location_only | ||
|
||
if not to_file: | ||
to_file = from_file.replace(".ics", ".csv") | ||
|
||
# Vérification de l'existance du fichier ICS. | ||
if not os.path.isfile(from_file): | ||
print(f"ERREUR : Impossible de trouver le fichier \"{from_file}\".") | ||
exit(1) | ||
|
||
with open(from_file, 'r', encoding='utf-8') as f: | ||
lines = f.readlines() | ||
|
||
# On récupère les évènements. | ||
res = re.findall(r"BEGIN:VEVENT(.+?)END:VEVENT", "".join(lines), re.DOTALL) | ||
to_csv = [] | ||
for elem in res: | ||
elem = elem.replace("\n ", "") | ||
current_item = {item.split(':')[0].split(";")[0]: item.split(':')[-1] for item in elem.split("\n") if item} | ||
if 'DTSTART' in current_item: | ||
# On transforme la date en datetime. | ||
if re.match(r"^\d{8}$", current_item['DTSTART']): | ||
start_date = datetime.strptime(current_item['DTSTART'], "%Y%m%d") | ||
if re.match(r"^\d{8}T\d{6}Z$", current_item['DTSTART']): | ||
start_date = datetime.strptime(current_item['DTSTART'], "%Y%m%dT%H%M%SZ") | ||
# On stocke en plus la date au format "YYYY-MM-DD HH:mm:SS". | ||
current_item['DTSTART_2'] = start_date | ||
# On vérifier que la date est dans la période souhaitée et qu'il y a un lieu de défini. | ||
if (not from_date or start_date >= from_date) and (not to_date or start_date <= to_date): | ||
if not location_only or ('LOCATION' in current_item and current_item['LOCATION'].strip()): | ||
to_csv.append(current_item) | ||
|
||
if not to_csv: | ||
print("Aucun évènement à convertir.") | ||
exit(0) | ||
|
||
# On récupère toutes les clés. | ||
keys = to_csv[0].keys() | ||
for line in to_csv: | ||
keys |= line.keys() | ||
|
||
# On écrit le fichier CSV. | ||
with open(to_file, 'w', encoding='utf-8', newline='') as output_file: | ||
dict_writer = csv.DictWriter(output_file, keys) | ||
dict_writer.writeheader() | ||
dict_writer.writerows(to_csv) | ||
print(f"Fichier \"{to_file}\" créé avec succès ({len(to_csv)} éléments).") | ||
|
||
if __name__ == '__main__': | ||
main() | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Gooey==1.0.8.1 |