diff --git a/app/Archive.py b/app/Archive.py index 9199317305b1edf524721790281b077f65a9f231..9d1f56b2fd5bb38e1cbb7733da824140ef635e09 100644 --- a/app/Archive.py +++ b/app/Archive.py @@ -1,56 +1,33 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -import os, sys, glob, re, io -import math, subprocess +import configparser +import io +import json +import os +import re +import sys import urllib.request import zipfile -import requests -import datetime -import configparser +from collections import UserDict from urllib.parse import urlencode +from uuid import uuid4 -from osgeo import gdal, ogr, osr import numpy as np -from uuid import uuid4 +from osgeo import gdal, ogr, osr -from collections import defaultdict, UserDict import app.Outils as Outils -import app.Constantes as Constantes -id_tuile = re.compile("T[0-9]+[A-Z]+") +id_tuile = re.compile("T[0-9]+[A-Z]+") date_tuile = re.compile("[SENTINEL.+?_]([0-9]*?)-") -class Archive(): + +class Archive: """ Classe pour lister, télécharger les archives via site Theia selon un shapefile représentant la zone d'étude. - :param capteur: Nom du satellite utilisé (ex: Landsat, Sentinel2, ...). - :type capteur: Chaîne de caractères - - :param bandes: Bandes à conservées. - :type bandes: Chaîne de caractères - - :param niveau: Niveau de traitement voulu. - :type niveau: Chaîne de caractères - - :param emprise: Chemin vers le shapefile représentant l'emprise. - :type emprise: Chaîne de caractères - - :param zone_etude: Chemin vers le shapefile représentant la zone d'étude. - :type zone_etude: Chaîne de caractères - - :param sortie: Chemin du dossier de sortie. - :type sortie: Chaîne de caractères - - :param annee_debut: Année à partir de laquelle on cherche les images. - :type annee_debut: Entier - - :param annee_fin: Année jusqu'à laquelle on cherche les images. - :type annee_fin: Entier - - :param seuil: Seuil maximal d'ennuagement. - :type seuil: Entier + :param config: Chemin vers le fichier de configuration. + :type config: Chaîne de caractères """ # def __init__(self, capteur, bandes, niveau, emprise, zone_etude, sortie, annee_debut, annee_fin, seuil): @@ -61,12 +38,30 @@ class Archive(): self.logger = Outils.Log("log", "Archive") + self.emprise = None + self.liste_tuiles = None + self.requete = None + self.serveur = None + self.resto = None + self.capteur = None + self.api = None + self.dossier_sortie = None + self.groupe = None + self.extraction = None + self.bandes = None + self.prefix = None + self.extent_img = None + self.zone_etude = None + self.nuage = None + self.seuil_nuage = None + Outils.get_variable(self, config) self.liste_archive = [] self.url = '' - def vector_projection_with_epsg(self, chemin_vecteur, output_path, epsg=32630): + @staticmethod + def vector_projection_with_epsg(chemin_vecteur, output_path, epsg=32630): driver = ogr.GetDriverByName('ESRI Shapefile') @@ -84,39 +79,35 @@ class Archive(): if os.path.exists(vecteur_reproj): driver.DeleteDataSource(vecteur_reproj) - outDataSet = driver.CreateDataSource(vecteur_reproj) - outLayer = outDataSet.CreateLayer(layer.GetName(), projection_reference, geom_type=layer.GetLayerDefn().GetGeomType()) + out_data_set = driver.CreateDataSource(vecteur_reproj) + out_layer = out_data_set.CreateLayer(layer.GetName(), projection_reference, + geom_type=layer.GetLayerDefn().GetGeomType()) # add fields - inLayerDefn = layer.GetLayerDefn() - for i in range(0, inLayerDefn.GetFieldCount()): - fieldDefn = inLayerDefn.GetFieldDefn(i) - outLayer.CreateField(fieldDefn) + in_layer_defn = layer.GetLayerDefn() + for i in range(0, in_layer_defn.GetFieldCount()): + field_defn = in_layer_defn.GetFieldDefn(i) + out_layer.CreateField(field_defn) - outLayerDefn = outLayer.GetLayerDefn() + out_layer_defn = out_layer.GetLayerDefn() - inFeature = layer.GetNextFeature() + in_feature = layer.GetNextFeature() - while inFeature: + while in_feature: # get the input geometry - geom = inFeature.GetGeometryRef() + geom = in_feature.GetGeometryRef() # reproject the geometry geom.Transform(transformation) # create a new feature - outFeature = ogr.Feature(outLayerDefn) + out_feature = ogr.Feature(out_layer_defn) # set the geometry and attribute - outFeature.SetGeometry(geom) - for i in range(0, outLayerDefn.GetFieldCount()): - outFeature.SetField(outLayerDefn.GetFieldDefn(i).GetNameRef(), inFeature.GetField(i)) + out_feature.SetGeometry(geom) + for i in range(0, out_layer_defn.GetFieldCount()): + out_feature.SetField(out_layer_defn.GetFieldDefn(i).GetNameRef(), in_feature.GetField(i)) # add the feature to the shapefile - outLayer.CreateFeature(outFeature) + out_layer.CreateFeature(out_feature) # dereference the features and get the next input feature - outFeature = None - inFeature = layer.GetNextFeature() - - # Save and close the shapefiles - inDataSet = None - outDataSet = None + in_feature = layer.GetNextFeature() def coord_box_dd(self): """ @@ -149,72 +140,76 @@ class Archive(): shp_ogr = data_source.GetLayer() # Extent - extent_ = shp_ogr.GetExtent() # (xMin, xMax, yMin, yMax) + extent_ = shp_ogr.GetExtent() # (xMin, xMax, yMin, yMax) - ## Close source data + # Close source data data_source.Destroy() return "{},{},{},{}".format(extent_[0], extent_[2], extent_[1], extent_[3]) def listing_by_tile(self): - for tuile in self.liste_tuiles : - + for tuile in self.liste_tuiles: self.requete['location'] = tuile - self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, urlencode(self.requete)) + self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, + urlencode(self.requete)) self.get_liste_images() def listing_by_coord(self): self.requete['box'] = self.coord_box_dd() - - self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, urlencode(self.requete)) - + + self.url = "{0}/{1}/api/collections/{2}/search.json?{3}".format(self.serveur, self.resto, self.capteur, + urlencode(self.requete)) + print(self.url) self.get_liste_images() def get_liste_images(self): - + # S'il existe une autre image, suivante = vrai, faux sinon suivante = True # Tant qu'il existe une image à traiter while suivante: - try : + try: request_headers = {"User-Agent": "Magic-browser"} - req = urllib.request.Request(self.url, headers = request_headers) # Connexion à la base de données - data = urllib.request.urlopen(req).read() # Lecture de la base de données + req = urllib.request.Request(self.url, headers=request_headers) # Connexion à la base de données + data = urllib.request.urlopen(req).read() # Lecture de la base de données - new_data = re.sub(b"null", b"'null'", data) # Suppression de l'expression "null" pouvant causer une erreur Python - new_data = re.sub(b"false", b"False", new_data) # Renomme le booléen selon la syntaxe Python + new_data = re.sub(b"null", b"'null'", + data) # Suppression de l'expression "null" pouvant causer une erreur Python + new_data = re.sub(b"false", b"False", new_data) # Renomme le booléen selon la syntaxe Python # Conversion des données sous la forme d'un dictionnaire - data_Dict = defaultdict(list) - data_Dict = UserDict(eval(new_data)) + # data_Dict = defaultdict(list) + data_dict = UserDict(eval(new_data)) # Selection des archives à télécharger - for d in range(len(data_Dict['features'])): - name_archive = data_Dict['features'][d]['properties']['productIdentifier'] - feature_id = data_Dict["features"][d]['id'] - link_archive = data_Dict['features'][d]['properties']['services']['download']['url'].replace("\\", "") - url_archive = link_archive.replace(self.resto, "rocket/#") - archive_download = url_archive.replace("/download", "") # Url de l'archive à télécharger - out_archive = "{0}/{1}.zip".format(self.dossier_sortie, name_archive) # Nom de sortie de l'archive + for d in range(len(data_dict['features'])): + name_archive = data_dict['features'][d]['properties']['productIdentifier'] + feature_id = data_dict["features"][d]['id'] + # link_archive = data_Dict['features'][d]['properties']['services']['download']['url'].replace("\\", + # "") + # url_archive = link_archive.replace(self.resto, "rocket/#") + # archive_download = url_archive.replace("/download", "") # Url de l'archive à télécharger + out_archive = "{0}/{1}.zip".format(self.dossier_sortie, name_archive) # Nom de sortie de l'archive if "SENTINEL2X" not in out_archive or self.requete["processingLevel"] == "LEVEL3A": - self.liste_archive.append([archive_download, out_archive, feature_id]) + # self.liste_archive.append([archive_download, out_archive, feature_id]) + self.liste_archive.append([name_archive, feature_id]) # Vérification si d'autres images sont disponibles - for link in data_Dict['properties']['links'] : - if link["title"] is 'suivant' : + for link in data_dict['properties']['links']: + if link["title"] is 'suivant': self.url = link['href'].replace("\\", "") suivante = True break - else : + else: suivante = False except Exception as e: @@ -228,181 +223,62 @@ class Archive(): if hasattr(self, 'liste_tuiles'): self.listing_by_tile() - else : - self.listing_by_coord() + else: + self.listing_by_coord() self.logger.info("{0} image(s) correspondent aux critères.".format(len(self.liste_archive))) - def download_auto(self): + def download(self): """ Méthode pour télécharger les archives sur le site Theia. - - :param identifiant: Identifant pour le site Theia. - :type identifiant: Chaîne de caractères - - :param mdp: Mot de passe pour le site Theia. - :type mdp: Chaîne de caractères - - :param proxy: Information du proxy. - :type proxy: Chaîne de caractères """ - # Url pour obtenir l'authentification - url = "{0}/services/authenticate/".format(self.serveur) - - - # Dictionnaire contenant les informations du proxy s'il existe - proxyDict = { - "http" : "{0}".format(self.proxy), \ - "https" : "{0}".format(self.proxy), \ - "ftp" : "{0}".format(self.proxy) \ - } - - # Dictionnaire contenant les informations d'authentification - payload = { - 'ident' : "{0}".format(self.id),\ - 'pass' : "{0}".format(self.mdp) - } - - # Requête pour obtenir le jeton d'identification - reponse = requests.post(url, data=payload, proxies=proxyDict) - - # Récupération du jeton d'identification au format texte ou json - try: - if "text" in reponse.headers["Content-Type"] : - token = reponse.text - elif "json" in reponse.headers["Content-Type"] : - token = reponse.json()["access_token"] - else : - raise(BaseException('Format non traité.')) - except Exception as e: - self.logger.error("Error during the identification request") - sys.exit(-1) - - head = {"Authorization": "Bearer {0}".format(token)} + dico_date, sauvegarde = self.get_downloadable_images() - # Dictionnaire des images à traiter regrouper par date - dico_date = dict() + for date, tuiles in dico_date.items(): + for img, url in tuiles.items(): + archive = self.api.get_archive(url) - sauvegarde = configparser.ConfigParser() - - # Pour toutes les images disponible - for l in self.liste_archive : + if archive.status_code == 200: - # Récupération de la date quand l'image a été prise - date = date_tuile.search(l[1]).group(1) - - # Récupération du nom de l'image - nom_image = l[1].split("/")[-1][:-4] - - # Lecture du fichier de sauvegarde - sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie)) - - # Si la date existe dans le fichier de sauvegarde ... - if str(date) in sauvegarde.keys() : - - # ... mais pas l'image, on la rajoute dans la liste des images à traiter. - if nom_image not in sauvegarde[str(date)].keys() : - - sauvegarde[str(date)][nom_image] = "False" - - if date in dico_date.keys() : - dico_date[date].append(l) - else : - dico_date[date] = [l] - - # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter. - elif sauvegarde[str(date)][nom_image] == "False" : - - if date in dico_date.keys() : - dico_date[date].append(l) - else : - dico_date[date] = [l] - - # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste des images à traiter. - else : - sauvegarde[str(date)] = {} - sauvegarde[str(date)][nom_image] = "False" - - if date in dico_date.keys() : - dico_date[date].append(l) - else : - dico_date[date] = [l] - - # Sauvegarde du fichier de sauvegarde mis à jour. - with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile: - sauvegarde.write(configfile) - - # Pour toutes les dates à traiter - for cle in sorted(dico_date): - # Liste des archives - liste_content = [] - - # Pour toutes les images prisent à cette date - for idx, img in enumerate(dico_date[cle]): - - self.logger.info("Requête pour l'archive : {0}".format(img[1].split("/")[-1])) - # Url de l'archive - url = "{0}/{1}/collections/{2}/{3}/download/?issuerId=theia".format(self.serveur, self.resto, self.capteur, img[2]) - self.logger.debug("url : {}".format(url)) - - # Requête pour récupérer l'archive - reponse = requests.get(url, headers=head, proxies=proxyDict) - - if self.extraction : - # Ajout de l'archive à la liste - liste_content.append(reponse.content) - del reponse - else : - if self.groupe == "Tuile" : - dossier_archive = "{0}/{1}".format(self.dossier_sortie, id_tuile.search(img[1]).group(0)) + if self.groupe == "Tuile": + output = "{0}/{1}".format(self.dossier_sortie, id_tuile.search(img).group(0)) else: - dossier_archive = "{0}/Archive/{1}".format(self.dossier_sortie, cle[:4]) + output = "{0}/Archive/{1}".format(self.dossier_sortie, date) - if not os.path.exists(dossier_archive): - os.makedirs(dossier_archive) + if not os.path.exists(output): + os.makedirs(output) - print("{0}/{1}".format(dossier_archive, img[1].split("/")[-1])) - with open("{0}/{1}".format(dossier_archive, img[1].split("/")[-1]), "wb") as fichier: - fichier.write(reponse.content) + if self.extraction: + self.extraction_archive(archive.content, output) + else: - if self.extraction : - # Traitement des images (fusion, découpage selon la zone d'étude ...) - self.traitement_images(cle, liste_content) - del liste_content + dst = "{0}/{1}.zip".format(output, img) + self.save_archive(archive, dst) - # Mis à jour du fichier de sauvegarde - # Lecture du fichier de sauvegarde - sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie)) + sauvegarde[date][img]["Telecharge"] = True - # Pour toutes les images traitées à cette date - for img in dico_date[cle] : - # Image traitée passe à vrai dans le fichier de sauvegarde - sauvegarde[str(cle)][img[1].split("/")[-1][:-4]] = "True" + self.write_save_file(sauvegarde, dossier=self.dossier_sortie) - # Sauvegarde du fichier de sauvegarde mis à jour. - with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile: - sauvegarde.write(configfile) + else: + print(archive.status_code) self.logger.info("All images have been downloaded !") def calcul_ennuagement(self, tuiles_nuage): - option_warp = gdal.WarpOptions(format='Mem', cropToCutline=True, outputType=gdal.GDT_Float32,\ - cutlineDSName=self.emprise, dstNodata="NaN") - mosaic_nuage = gdal.Warp("", tuiles_nuage, options=option_warp) - - rows = mosaic_nuage.RasterYSize # Rows number - cols = mosaic_nuage.RasterXSize # Columns number + option_warp = gdal.WarpOptions(format='Mem', cropToCutline=True, outputType=gdal.GDT_Float32, + cutlineDSName=self.emprise, dstNodata="NaN") + mosaic_nuage = gdal.Warp("", tuiles_nuage, options=option_warp) - data = mosaic_nuage.GetRasterBand(1).ReadAsArray(0, 0, cols, rows) + data = mosaic_nuage.GetRasterBand(1).ReadAsArray() nombre_pixel_zone = 0 nombre_pixel_null = 0 nombre_pixel_non_nuage = 0 - for donnees in data : + for donnees in data: d = donnees.tolist() nombre_pixel_zone += len(d) nombre_pixel_null += d.count(-10000) + np.isnan(d).sum() @@ -412,13 +288,15 @@ class Archive(): del data - ennuagement = (float(nombre_pixel_non_nuage)/float(nombre_pixel_non_null)) if nombre_pixel_non_null != 0 else 0.0 - self.logger.debug("Ennuagement : {}%".format(100 - round(ennuagement*100, 2))) + ennuagement = ( + float(nombre_pixel_non_nuage) / float(nombre_pixel_non_null)) if nombre_pixel_non_null != 0 else 0.0 + self.logger.debug("Ennuagement : {}%".format(100 - round(ennuagement * 100, 2))) # Computer cloud's percentage with dist (sum of cloud) by sum of the image's extent return 1.0 - ennuagement - def calcul_aire(self, tuiles_image): + @staticmethod + def calcul_aire(tuiles_image): """ Méthode pour fusionner un ensemble d'images et calculer l'aire de l'image obtenue. @@ -428,20 +306,19 @@ class Archive(): :returns: Un tuple contenant l'image fusionnée ainsi que son aire. """ - option_warp = gdal.WarpOptions(format='Mem', resampleAlg="lanczos") - mosaic_image = gdal.Warp("", tuiles_image, options=option_warp) - - rows = mosaic_image.RasterYSize # Rows number - cols = mosaic_image.RasterXSize # Columns number + option_warp = gdal.WarpOptions(format='Mem', resampleAlg="lanczos") + mosaic_image = gdal.Warp("", tuiles_image, options=option_warp) - data = mosaic_image.GetRasterBand(1).ReadAsArray(0, 0, cols, rows).astype(np.float16) - mask_spec = ~(np.isnan(data) | np.isin(data, [-10000])) + data = mosaic_image.GetRasterBand(1).ReadAsArray() + mask_spec = ~(np.isnan(data) | np.isin(data, [-10000])) - area = float((np.sum(mask_spec) * mosaic_image.GetGeoTransform()[1] * abs(mosaic_image.GetGeoTransform()[-1]) )/10000) + area = float( + (np.sum(mask_spec) * mosaic_image.GetGeoTransform()[1] * abs(mosaic_image.GetGeoTransform()[-1])) / 10000) return mosaic_image, area - def ecriture_geotiff(self, dataset, chemin): + @staticmethod + def ecriture_geotiff(dataset, chemin): """ Méthode pour enregistrer une image au format GTiff. @@ -458,12 +335,26 @@ class Archive(): outdata.SetGeoTransform(dataset.GetGeoTransform()) outdata.SetProjection(dataset.GetProjection()) - for band in range(dataset.RasterCount) : - data = dataset.GetRasterBand(band + 1).ReadAsArray(0, 0, dataset.RasterXSize, dataset.RasterYSize).astype(np.float32) + for band in range(dataset.RasterCount): + data = dataset.GetRasterBand(band + 1).ReadAsArray(0, 0, dataset.RasterXSize, dataset.RasterYSize).astype( + np.float32) outdata.GetRasterBand(band + 1).WriteArray(data, 0, 0) outdata.GetRasterBand(band + 1).FlushCache() - outdata = None + def extraction_archive(self, archive, output): + + # Lecture de l'archive + tzip = zipfile.ZipFile(io.BytesIO(archive)) + + # Liste des fichiers dans l'archive + zip_img = tzip.namelist() + + if "ALL" in self.bandes: + tzip.extractall(output) + else: + for band in self.bandes: + chemin = self.get_element(zip_img, "{0}_{1}".format(self.prefix, band)) + tzip.extract(chemin, output) def traitement_images(self, date, liste_content): """ @@ -491,7 +382,7 @@ class Archive(): self.logger.info("Extraction des images") # Pour chaque archive - for idx, content in enumerate(liste_content) : + for idx, content in enumerate(liste_content): # Lecture de l'archive tzip = zipfile.ZipFile(io.BytesIO(content)) @@ -504,12 +395,12 @@ class Archive(): liste_mem = [] # Pour tous les fichiers dans l'archive - for id_ext, extension in enumerate(self.extent_img) : + for id_ext, extension in enumerate(self.extent_img): # Si il s'agit d'une bande voulue (R,G,B,PIR) img = [f for f in zip_img if extension in f][0] # On charge l'image en mémoire - mmap_name = "/vsimem/"+uuid4().hex + mmap_name = "/vsimem/" + uuid4().hex liste_mem.append(mmap_name) gdal.FileFromMemBuffer(mmap_name, tzip.read(img)) # liste_bandes.append(gdal.Open(mmap_name)) @@ -525,36 +416,32 @@ class Archive(): del image - if aire > 0.0 : + if aire > 0.0: tuiles_image.append(vrt) # On libère la mémoire - for mmap_name in liste_mem : + for mmap_name in liste_mem: gdal.Unlink(mmap_name) liste_mem = [] - if self.nuage is not None : + if self.nuage is not None: image_nuage = [f for f in zip_img if self.nuage[0] in f][0] - mmap_name = "/vsimem/"+uuid4().hex + mmap_name = "/vsimem/" + uuid4().hex gdal.FileFromMemBuffer(mmap_name, tzip.read(image_nuage)) liste_mem.append(mmap_name) tuiles_nuage.append(Outils.clip(mmap_name, self.zone_etude)) - for mmap_name in liste_mem : + for mmap_name in liste_mem: gdal.Unlink(mmap_name) - liste_mem = [] - - liste_bandes = None - del tzip del liste_content[idx] del liste_content - if len(tuiles_image) > 0 : + if len(tuiles_image) > 0: if len(tuiles_nuage) == 0 or self.calcul_ennuagement(tuiles_nuage) <= self.seuil_nuage: @@ -568,8 +455,145 @@ class Archive(): self.logger.debug("Dossier image : {0}".format(dossier)) # On effectue une mosaïque des images qu'on découpe selon l'emprise. - Outils.clip(tuiles_image, self.emprise, form="GTiff", dst="{0}/{1}.tif".format(dossier,date)) + Outils.clip(tuiles_image, self.emprise, form="GTiff", dst="{0}/{1}.tif".format(dossier, date)) del tuiles_nuage del tuiles_image + + def save_archive(self, archive, dst): + + self.logger.info("Sauvegarde de l'archive : {}".format(dst)) + with open("{0}".format(dst), "wb") as fichier: + fichier.write(archive.content) + + def select_archive(self): + + # Dictionnaire des images à traiter regrouper par date + dico_date = dict() + + sauvegarde = configparser.ConfigParser() + + # Lecture du fichier de sauvegarde + sauvegarde.read("{}/sauvegarde.ini".format(self.dossier_sortie)) + + # Pour toutes les images disponible + for liste in self.liste_archive: + + # Récupération de la date quand l'image a été prise + date = date_tuile.search(liste[1]).group(1) + + # Récupération du nom de l'image + nom_image = liste[1].split("/")[-1][:-4] + + # Si la date existe dans le fichier de sauvegarde ... + if str(date) in sauvegarde.keys(): + + # ... mais pas l'image, on la rajoute dans la liste des images à traiter. + if nom_image not in sauvegarde[str(date)].keys(): + + sauvegarde[str(date)][nom_image] = "False" + + if date in dico_date.keys(): + dico_date[date].append(liste) + else: + dico_date[date] = [liste] + + # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter. + elif sauvegarde[str(date)][nom_image] == "False": + + if date in dico_date.keys(): + dico_date[date].append(liste) + else: + dico_date[date] = [liste] + + # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste + # des images à traiter. + else: + sauvegarde[str(date)] = {} + sauvegarde[str(date)][nom_image] = "False" + + if date in dico_date.keys(): + dico_date[date].append(liste) + else: + dico_date[date] = [liste] + + # Sauvegarde du fichier de sauvegarde mis à jour. + with open("{}/sauvegarde.ini".format(self.dossier_sortie), 'w') as configfile: + sauvegarde.write(configfile) + + @staticmethod + def read_save_file(dossier="", nom="sauvegarde"): + if os.path.exists("{0}/{1}.json".format(dossier, nom)): + return json.load(open("{0}/{1}.json".format(dossier, nom), "r")) + else: + return dict() + + def get_downloadable_images(self): + dico_date = dict() + sauvegarde = self.read_save_file(dossier=self.dossier_sortie) + + # Pour toutes les images disponible + for archive, idx in self.liste_archive: + + # Récupération de la date quand l'image a été prise + date = date_tuile.search(archive).group(1) + + # Si la date existe dans le fichier de sauvegarde ... + if date in sauvegarde.keys(): + + # ... mais pas l'image, on la rajoute dans la liste des images à traiter. + if archive not in sauvegarde[date].keys(): + + # sauvegarde[date][archive] = False + sauvegarde[date][archive] = dict({"Telecharge": False, "Identifiant": idx}) + + if date in dico_date.keys(): + # dico_date[date].append(archive) + dico_date[date][archive] = self.generate_url(idx) + else: + # dico_date[date] = [archive] + dico_date[date] = dict({archive: self.generate_url(idx)}) + + # ... et que l'image exite mais n'a pas été traité, on la rajoute dans la liste des images à traiter. + elif sauvegarde[date][archive]["Telecharge"] is False: + + if date in dico_date.keys(): + # dico_date[date].append(archive) + dico_date[date][archive] = self.generate_url(idx) + else: + # dico_date[date] = [archive] + dico_date[date] = dict({archive: self.generate_url(idx)}) + + # Si la date n'existe pas dans le fichier de sauvegarde, on la rajoute ainsi que l'image dans la liste + # des images à traiter. + else: + sauvegarde[date] = dict() + sauvegarde[date][archive] = dict() + sauvegarde[date][archive]["Telecharge"] = False + sauvegarde[date][archive]["Identifiant"] = idx + + if date in dico_date.keys(): + # dico_date[date].append(archive) + dico_date[date][archive] = self.generate_url(idx) + else: + # dico_date[date] = [archive] + dico_date[date] = dict({archive: self.generate_url(idx)}) + + self.write_save_file(sauvegarde, dossier=self.dossier_sortie) + + return dico_date, sauvegarde + + @staticmethod + def write_save_file(dico, dossier="", nom="sauvegarde"): + # Sauvegarde du fichier de sauvegarde mis à jour. + with open("{0}/{1}.json".format(dossier, nom), 'w') as fichier: + json.dump(dico, fichier, indent=4) + + def generate_url(self, idx): + return "{0}/{1}/collections/{2}/{3}/download/?issuerId=theia".format(self.serveur, self.resto, + self.capteur, idx) + + @staticmethod + def get_element(liste, element): + return [x for x in liste if element in x][0]