izisat 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- izisat/__init__.py +0 -0
- izisat/izisentinel.py +161 -0
- izisat/misc/__init__.py +0 -0
- izisat/misc/connections.py +554 -0
- izisat/misc/dates.py +24 -0
- izisat/misc/files.py +135 -0
- izisat/misc/raster_processing.py +373 -0
- izisat/misc/utils.py +162 -0
- izisat-0.1.0.dist-info/METADATA +151 -0
- izisat-0.1.0.dist-info/RECORD +13 -0
- izisat-0.1.0.dist-info/WHEEL +5 -0
- izisat-0.1.0.dist-info/licenses/LICENSE +21 -0
- izisat-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,554 @@
|
|
1
|
+
import requests
|
2
|
+
from tqdm import tqdm
|
3
|
+
from loguru import logger
|
4
|
+
from datetime import datetime
|
5
|
+
from izisat.misc.utils import Utils
|
6
|
+
from izisat.misc.files import Files
|
7
|
+
from izisat.misc.dates import Dates
|
8
|
+
|
9
|
+
|
10
|
+
class Connections:
|
11
|
+
def __init__(self):
|
12
|
+
pass
|
13
|
+
|
14
|
+
|
15
|
+
def access_token(self, username: str, password: str) -> str:
|
16
|
+
"""
|
17
|
+
Obtain an access token for accessing the Sentinel API.
|
18
|
+
|
19
|
+
Parameters:
|
20
|
+
-----------
|
21
|
+
username: str
|
22
|
+
The username for authentication.
|
23
|
+
password: str
|
24
|
+
The password for authentication.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
--------
|
28
|
+
access_token, refresh_token, dt_now: Tuple[str, str, datetime]
|
29
|
+
A tuple containing the access token, refresh token, and the current datetime when the tokens were obtained.
|
30
|
+
"""
|
31
|
+
logger.info("Trying to establish connection with Copernicus API.")
|
32
|
+
data = {
|
33
|
+
"client_id": "cdse-public",
|
34
|
+
"username": username,
|
35
|
+
"password": password,
|
36
|
+
"grant_type": "password",
|
37
|
+
|
38
|
+
}
|
39
|
+
try:
|
40
|
+
r = requests.post("https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token",
|
41
|
+
data=data,
|
42
|
+
)
|
43
|
+
dt_now = datetime.now()
|
44
|
+
r.raise_for_status()
|
45
|
+
except Exception as e:
|
46
|
+
raise Exception(
|
47
|
+
f"Keycloak token creation failed. Response from the server was: {r.json()}"
|
48
|
+
)
|
49
|
+
|
50
|
+
logger.success("Connection estalished")
|
51
|
+
access_token = r.json()["access_token"]
|
52
|
+
refresh_token = r.json()["refresh_token"]
|
53
|
+
return access_token, refresh_token, dt_now
|
54
|
+
|
55
|
+
def refresh_access_token(self, refresh_token: str):
|
56
|
+
"""
|
57
|
+
Refresh the access token using the provided refresh token.
|
58
|
+
|
59
|
+
Parameters:
|
60
|
+
-----------
|
61
|
+
refresh_token : str
|
62
|
+
The refresh token obtained during the initial authentication process.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
--------
|
66
|
+
r.json()["access_token"], dt_now: Tuple[str, datetime]
|
67
|
+
A tuple containing the new access token and the current datetime when the refresh was performed.
|
68
|
+
"""
|
69
|
+
data = {
|
70
|
+
"client_id": "cdse-public",
|
71
|
+
"refresh_token": refresh_token,
|
72
|
+
"grant_type": "refresh_token",
|
73
|
+
}
|
74
|
+
|
75
|
+
try:
|
76
|
+
r = requests.post(
|
77
|
+
"https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token",
|
78
|
+
data=data,
|
79
|
+
)
|
80
|
+
dt_now = datetime.now()
|
81
|
+
r.raise_for_status()
|
82
|
+
except Exception as e:
|
83
|
+
raise Exception(
|
84
|
+
f"Access token refresh failed. Reponse from the server was: {r.json()}"
|
85
|
+
)
|
86
|
+
|
87
|
+
return r.json()["access_token"], dt_now
|
88
|
+
|
89
|
+
def retrieve_sent_prod_from_query(self, params):
|
90
|
+
"""
|
91
|
+
Retrieve Sentinel products from a specified query.
|
92
|
+
|
93
|
+
Parameters:
|
94
|
+
-----------
|
95
|
+
params: str
|
96
|
+
The query parameters to be appended to the URL.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
---------
|
100
|
+
response.json()['value']: list
|
101
|
+
List of Sentinel products, each represented as a dictionary.
|
102
|
+
None
|
103
|
+
if no products are found.
|
104
|
+
"""
|
105
|
+
logger.info("Searching Sentinel products...")
|
106
|
+
url = "https://catalogue.dataspace.copernicus.eu/odata/v1/Products"
|
107
|
+
url_complet = url + params
|
108
|
+
response = requests.get(url_complet)
|
109
|
+
if response.status_code == 200:
|
110
|
+
if not response.json()['value']:
|
111
|
+
logger.warning("There is no Sentinel data available with this parameters.")
|
112
|
+
return None
|
113
|
+
|
114
|
+
for product in response.json()['value']:
|
115
|
+
if product['Online']:
|
116
|
+
product_name = response.json()['value']
|
117
|
+
logger.success(f"Found successfully {len(product_name)} products!")
|
118
|
+
return response.json()['value']
|
119
|
+
else:
|
120
|
+
# If status code is not 200, raise an exception to trigger the retry mechanism
|
121
|
+
response.raise_for_status()
|
122
|
+
|
123
|
+
|
124
|
+
def retrieve_bands_for_resolution(self, session, headers, response, resolution, band_list, url_index):
|
125
|
+
"""
|
126
|
+
Retrieve links for bands at a specific resolution for Sentinel 2 type L2A.
|
127
|
+
|
128
|
+
Parameters:
|
129
|
+
-----------
|
130
|
+
session: requests.Session
|
131
|
+
The active session for making HTTP requests.
|
132
|
+
headers: dict
|
133
|
+
The headers to include in the HTTP request.
|
134
|
+
response: requests.Response
|
135
|
+
The response object containing information about the product.
|
136
|
+
resolution: str
|
137
|
+
The resolution category ('10m', '20m', '60m').
|
138
|
+
band_list: list
|
139
|
+
List of bands to retrieve links for.
|
140
|
+
url_index: int
|
141
|
+
The index in the response JSON where the URL for bands is located.
|
142
|
+
|
143
|
+
Returns:
|
144
|
+
--------
|
145
|
+
url_bands_resolution: list
|
146
|
+
List of lists containing band names and their corresponding URLs.
|
147
|
+
|
148
|
+
Example:
|
149
|
+
--------
|
150
|
+
session = requests.Session()
|
151
|
+
headers = {'Authorization': 'Bearer YOUR_ACCESS_TOKEN'}
|
152
|
+
response = session.get("https://example.com/api/products/1234")
|
153
|
+
resolution = "10m"
|
154
|
+
band_list = ["band1", "band2"]
|
155
|
+
url_index = 0
|
156
|
+
|
157
|
+
bands_links = retrieve_bands_for_resolution(session, headers, response, resolution, band_list, url_index)
|
158
|
+
|
159
|
+
"""
|
160
|
+
url_resolution = response.json()["result"][url_index]["Nodes"]["uri"]
|
161
|
+
response_resolution = session.get(url_resolution, headers=headers, stream=True)
|
162
|
+
url_bands_resolution = []
|
163
|
+
|
164
|
+
for band in band_list:
|
165
|
+
url_bands = response_resolution.json()["result"]
|
166
|
+
for product in url_bands:
|
167
|
+
# Ensure the band name contains the resolution string (e.g., "10m", "20m")
|
168
|
+
# and the specific band (e.g., "B02")
|
169
|
+
if f"_{resolution}" in product["Name"] and band in product["Name"]:
|
170
|
+
item_to_append = [product["Name"], product["Nodes"]["uri"]]
|
171
|
+
url_bands_resolution.append(item_to_append)
|
172
|
+
|
173
|
+
logger.success(f"Links successfully retrieved for bands {band_list} in resolution {resolution}")
|
174
|
+
return url_bands_resolution
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
|
179
|
+
def get_links_l1c_product(self, access_token, product_id, bands):
|
180
|
+
"""
|
181
|
+
Retrieve links for bands in a Level-1C (L1C) product.
|
182
|
+
|
183
|
+
Parameters:
|
184
|
+
-----------
|
185
|
+
access_token: str
|
186
|
+
The access token for authentication.
|
187
|
+
product_id: str
|
188
|
+
The ID of the Sentinel product.
|
189
|
+
bands: list
|
190
|
+
List of bands to retrieve links for.
|
191
|
+
|
192
|
+
Returns:
|
193
|
+
--------
|
194
|
+
url_l1c_bands: list
|
195
|
+
List of lists containing band names and their corresponding URLs.
|
196
|
+
|
197
|
+
Example:
|
198
|
+
--------
|
199
|
+
access_token = "YOUR_ACCESS_TOKEN"
|
200
|
+
product_id = "1234567890"
|
201
|
+
bands = ["band1", "band2"]
|
202
|
+
|
203
|
+
l1c_bands_links = get_links_l1c_product(access_token, product_id, bands)
|
204
|
+
"""
|
205
|
+
url_l1c_bands = []
|
206
|
+
headers = {'Authorization': f'Bearer {access_token}'}
|
207
|
+
url = f"https://zipper.dataspace.copernicus.eu/odata/v1/Products({product_id})/Nodes"
|
208
|
+
|
209
|
+
try:
|
210
|
+
logger.info("Starting connection to search for band links...")
|
211
|
+
session = requests.Session()
|
212
|
+
session.headers.update(headers)
|
213
|
+
response = session.get(url, headers=headers, stream=True)
|
214
|
+
|
215
|
+
#### Trying to download specific bands #########################
|
216
|
+
url_1 = response.json()['result'][0]["Nodes"]['uri']
|
217
|
+
response_1 = session.get(url_1, headers=headers, stream=True)
|
218
|
+
url_2 = response_1.json()['result']
|
219
|
+
granule_index = next((index for index, d in enumerate(url_2) if d.get('Id') == 'GRANULE'), None)
|
220
|
+
if granule_index is not None:
|
221
|
+
url_2 = url_2[granule_index]["Nodes"]["uri"]
|
222
|
+
response_2 = session.get(url_2, headers=headers, stream=True)
|
223
|
+
url_3 = response_2.json()["result"][0]["Nodes"]["uri"]
|
224
|
+
response_3 = session.get(url_3, headers=headers, stream=True)
|
225
|
+
url_4 = response_3.json()["result"][1]["Nodes"]["uri"]
|
226
|
+
response_4 = session.get(url_4, headers=headers, stream=True)
|
227
|
+
products = response_4.json()["result"]
|
228
|
+
for product in products:
|
229
|
+
for band in bands:
|
230
|
+
if band in product["Name"]:
|
231
|
+
itens_to_append = [product["Name"], product["Nodes"]["uri"]]
|
232
|
+
url_l1c_bands.append(itens_to_append)
|
233
|
+
break
|
234
|
+
logger.success(f"Links for bands {bands} successfully retrieved")
|
235
|
+
|
236
|
+
return url_l1c_bands
|
237
|
+
|
238
|
+
except Exception as e:
|
239
|
+
raise requests.exceptions.RequestException(e)
|
240
|
+
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
def get_links_l2a_product(self, access_token, product_id, bands):
|
245
|
+
"""
|
246
|
+
Retrieve links for bands in a Level-2A (L2A) product.
|
247
|
+
|
248
|
+
Parameters:
|
249
|
+
-----------
|
250
|
+
access_token: str
|
251
|
+
The access token for authentication.
|
252
|
+
product_id: str
|
253
|
+
The ID of the Sentinel product.
|
254
|
+
bands: dict
|
255
|
+
Dictionary mapping resolutions to lists of bands.
|
256
|
+
|
257
|
+
Returns:
|
258
|
+
--------
|
259
|
+
resolution_links: dict
|
260
|
+
Dictionary containing resolution-wise lists of band names and their corresponding URLs.
|
261
|
+
|
262
|
+
Example:
|
263
|
+
--------
|
264
|
+
access_token = "YOUR_ACCESS_TOKEN"
|
265
|
+
product_id = "1234567890"
|
266
|
+
bands = {"10m": ["band1", "band2"], "20m": ["band3", "band4"]}
|
267
|
+
|
268
|
+
l2a_links = get_links_l2a_product(access_token, product_id, bands)
|
269
|
+
"""
|
270
|
+
resolution_links = {}
|
271
|
+
headers = {'Authorization': f'Bearer {access_token}'}
|
272
|
+
url = f"https://zipper.dataspace.copernicus.eu/odata/v1/Products({product_id})/Nodes"
|
273
|
+
|
274
|
+
try:
|
275
|
+
logger.info("Starting connection to search for band links...")
|
276
|
+
session = requests.Session()
|
277
|
+
session.headers.update(headers)
|
278
|
+
response = session.get(url, headers=headers, stream=True)
|
279
|
+
|
280
|
+
#### Trying to download specific bands #########################
|
281
|
+
url_1 = response.json()['result'][0]["Nodes"]['uri']
|
282
|
+
response_1 = session.get(url_1, headers=headers, stream=True)
|
283
|
+
url_2 = next(item['Nodes']['uri'] for item in response_1.json().get('result', []) if item.get('Id') == 'GRANULE')
|
284
|
+
response_2 = session.get(url_2, headers=headers, stream=True)
|
285
|
+
url_3 = response_2.json()["result"][0]["Nodes"]["uri"]
|
286
|
+
response_3 = session.get(url_3, headers=headers, stream=True)
|
287
|
+
url_4 = next(item['Nodes']['uri'] for item in response_3.json().get('result', []) if item.get('Id') == 'IMG_DATA')
|
288
|
+
response_4 = session.get(url_4, headers=headers, stream=True)
|
289
|
+
|
290
|
+
# Mapping resolution to url_index
|
291
|
+
resolution_to_url_index = {'10m': 0,
|
292
|
+
'20m': 1,
|
293
|
+
'60m': 2
|
294
|
+
}
|
295
|
+
|
296
|
+
for resolution, band_list in bands.items():
|
297
|
+
logger.info(f"Searching links for resolution {resolution}...")
|
298
|
+
url_index = resolution_to_url_index.get(resolution, -1)
|
299
|
+
|
300
|
+
if url_index != -1:
|
301
|
+
resolution_links[resolution] = self.retrieve_bands_for_resolution(
|
302
|
+
session, headers, response_4, resolution, band_list, url_index)
|
303
|
+
else:
|
304
|
+
# Handle the case when resolution is not found in the mapping
|
305
|
+
logger.warning(f"Resolution {resolution} not mapped to a valid url_index.")
|
306
|
+
|
307
|
+
except Exception as e:
|
308
|
+
raise requests.exceptions.RequestException(e)
|
309
|
+
|
310
|
+
return resolution_links
|
311
|
+
|
312
|
+
|
313
|
+
|
314
|
+
def retrieve_bands_links(self, access_token, products_info, bands_dict):
|
315
|
+
"""
|
316
|
+
Retrieve links for bands in Sentinel products.
|
317
|
+
|
318
|
+
Parameters:
|
319
|
+
-----------
|
320
|
+
access_token: str
|
321
|
+
The access token for authentication.
|
322
|
+
products_info: list
|
323
|
+
List of lists containing information about Sentinel products.
|
324
|
+
bands_dict: dict
|
325
|
+
Dictionary mapping product types to dictionaries of resolutions and their corresponding bands.
|
326
|
+
|
327
|
+
Returns:
|
328
|
+
--------
|
329
|
+
all_links: dict
|
330
|
+
Dictionary containing links for bands in Sentinel products.
|
331
|
+
The structure is {product_name: {product_type: {resolution: [(band_name, band_link), ...], ...}, ...}, ...}.
|
332
|
+
|
333
|
+
Example:
|
334
|
+
--------
|
335
|
+
access_token = "YOUR_ACCESS_TOKEN"
|
336
|
+
products_info = [
|
337
|
+
["product_id_1", "product_name_1", "path_1", "date_1", "tile_1", "platform_1", "L1C"],
|
338
|
+
["product_id_2", "product_name_2", "path_2", "date_2", "tile_2", "platform_2", "L2A"],
|
339
|
+
]
|
340
|
+
bands_dict = {
|
341
|
+
"L1C": ["band1", "band2"],
|
342
|
+
"L2A": {"10m": ["band3", "band4"], "20m": ["band5", "band6"]},
|
343
|
+
}
|
344
|
+
|
345
|
+
links = retrieve_bands_links(access_token, products_info, bands_dict)
|
346
|
+
"""
|
347
|
+
all_links = {}
|
348
|
+
|
349
|
+
for product_info in products_info:
|
350
|
+
product_id = product_info[0]
|
351
|
+
product_type = product_info[6]
|
352
|
+
product_name = product_info[1]
|
353
|
+
product_name = product_name.replace(".SAFE", "")
|
354
|
+
logger.info(f"Getting bands links for: {product_name}")
|
355
|
+
|
356
|
+
if product_type == "L1C":
|
357
|
+
logger.info(f"{product_name} is type {product_type}...")
|
358
|
+
l1c_bands = bands_dict["L1C"]
|
359
|
+
links_l1c = self.get_links_l1c_product(access_token, product_id, l1c_bands)
|
360
|
+
all_links.setdefault(product_name, {}).setdefault("L1C", links_l1c)
|
361
|
+
elif product_type == "L2A":
|
362
|
+
logger.info(f"{product_name} is type {product_type}...")
|
363
|
+
l2a_bands = bands_dict["L2A"]
|
364
|
+
links_l2a = self.get_links_l2a_product(access_token, product_id, l2a_bands)
|
365
|
+
|
366
|
+
all_links.setdefault(product_name, {}).setdefault("L2A", links_l2a)
|
367
|
+
|
368
|
+
return all_links
|
369
|
+
|
370
|
+
|
371
|
+
|
372
|
+
def download(self, access_token, url, output_path, product_name, name):
|
373
|
+
"""
|
374
|
+
Download data from a specified URL using an access token.
|
375
|
+
|
376
|
+
Parameters:
|
377
|
+
-----------
|
378
|
+
access_token: str
|
379
|
+
The access token obtained from the Sentinel API for authentication.
|
380
|
+
url: str
|
381
|
+
The URL of the data to be downloaded.
|
382
|
+
output_path: str
|
383
|
+
The local path where the downloaded data will be saved.
|
384
|
+
product_name: str
|
385
|
+
The name of the Sentinel product associated with the data.
|
386
|
+
name: str
|
387
|
+
The name or identifier for the downloaded data.
|
388
|
+
|
389
|
+
Returns:
|
390
|
+
--------
|
391
|
+
None
|
392
|
+
"""
|
393
|
+
headers = {'Authorization': f'Bearer {access_token}'}
|
394
|
+
|
395
|
+
try:
|
396
|
+
logger.info("Starting connection to download data...")
|
397
|
+
session = requests.Session()
|
398
|
+
session.headers.update(headers)
|
399
|
+
response = session.get(url, headers=headers, stream=True)
|
400
|
+
|
401
|
+
if response.status_code == 200:
|
402
|
+
logger.success("Connection estabilished!")
|
403
|
+
logger.info(f"Starting download of: {name}")
|
404
|
+
# Get the file size from the 'Content-Length' header of the response
|
405
|
+
total_size = int(response.headers.get('Content-Length', 0))
|
406
|
+
|
407
|
+
# Open a file for writing in binary mode
|
408
|
+
with open(output_path, "wb") as file, tqdm(desc="Downloading", total=total_size, unit="B", unit_scale=True, unit_divisor=1024, ) as bar:
|
409
|
+
# Iterate over the content in chunks (chunk_size=8192 bytes)
|
410
|
+
for chunk in response.iter_content(chunk_size=8192):
|
411
|
+
# Check if the chunk is not empty
|
412
|
+
if chunk:
|
413
|
+
# Write the chunk to the file
|
414
|
+
file.write(chunk)
|
415
|
+
# Update the progress bar with the size of the current chunk
|
416
|
+
bar.update(len(chunk))
|
417
|
+
logger.success(f"Data {name} successfuly downloaded for product {product_name}")
|
418
|
+
else:
|
419
|
+
# If the response status code is not 200, raise an exception
|
420
|
+
response.raise_for_status()
|
421
|
+
except Exception as e:
|
422
|
+
raise requests.exceptions.RequestException(e)
|
423
|
+
|
424
|
+
def download_bands(self, access_token, products_info, bands_links, base_dir, dt_access_token, refresh_token, tile):
|
425
|
+
"""
|
426
|
+
Download bands for Sentinel products based on the provided links.
|
427
|
+
|
428
|
+
Parameters:
|
429
|
+
-----------
|
430
|
+
access_token: str
|
431
|
+
The access token obtained from the Sentinel API for authentication.
|
432
|
+
products_info: List[List]
|
433
|
+
List of lists containing information about Sentinel products.
|
434
|
+
bands_links: Dict[str, Any]
|
435
|
+
Dictionary containing links to bands for each Sentinel product.
|
436
|
+
base_dir: str
|
437
|
+
The base directory where the downloaded bands will be saved.
|
438
|
+
|
439
|
+
Returns:
|
440
|
+
--------
|
441
|
+
None
|
442
|
+
"""
|
443
|
+
|
444
|
+
utils = Utils()
|
445
|
+
files = Files()
|
446
|
+
dates = Dates()
|
447
|
+
for product_info in products_info:
|
448
|
+
product_id = product_info[0]
|
449
|
+
product_type = product_info[6]
|
450
|
+
product_name = product_info[1]
|
451
|
+
product_date = product_info[3]
|
452
|
+
product_platform = product_info[5]
|
453
|
+
product_tile = product_info[4]
|
454
|
+
product_name = product_name.replace(".SAFE", "")
|
455
|
+
logger.info(f"Starting download process for product {product_name}")
|
456
|
+
|
457
|
+
|
458
|
+
if tile == product_tile:
|
459
|
+
if product_name in bands_links:
|
460
|
+
if "MSIL1C" in product_name:
|
461
|
+
product = bands_links[product_name]
|
462
|
+
key = next(iter(product))
|
463
|
+
# Access the nested lists
|
464
|
+
products_link_lists = product[key]
|
465
|
+
for nested_list in products_link_lists:
|
466
|
+
name, link = nested_list
|
467
|
+
link_mod = utils.modify_string(link)
|
468
|
+
filepath = files.check_file_exist(base_dir, product_platform, product_date, product_tile, product_type, name)
|
469
|
+
logger.info(f"Starting download process for band {name}")
|
470
|
+
if filepath[0] == True:
|
471
|
+
logger.warning(f"Band {name} Already downloaded")
|
472
|
+
else:
|
473
|
+
dt_now = datetime.now()
|
474
|
+
expired = dates.is_token_expired(dt_access_token, dt_now)
|
475
|
+
|
476
|
+
if expired:
|
477
|
+
access_token, dt_access_token = self.refresh_access_token(refresh_token)
|
478
|
+
logger.info("Data has not been downloaded. Starting data downloaded...")
|
479
|
+
self.download(access_token, link_mod, filepath[1], product_name, name)
|
480
|
+
|
481
|
+
elif "MSIL2A" in product_name:
|
482
|
+
product = bands_links[product_name]
|
483
|
+
key = next(iter(product))
|
484
|
+
# Access the nested lists
|
485
|
+
products_link_lists = product[key]
|
486
|
+
for resolution, bands_links_list in products_link_lists.items():
|
487
|
+
for band in bands_links_list:
|
488
|
+
name = band[0]
|
489
|
+
link = band[1]
|
490
|
+
link_mod = utils.modify_string(link)
|
491
|
+
filepath = files.check_file_exist(base_dir, product_platform, product_date, product_tile, product_type, name, resolution)
|
492
|
+
|
493
|
+
logger.info(f"Starting download process for band {name}")
|
494
|
+
if filepath[0] == True:
|
495
|
+
logger.warning(f"Band {name} Already downloaded")
|
496
|
+
else:
|
497
|
+
logger.info("Data has not been downloaded. Starting data downloaded...")
|
498
|
+
dt_now = datetime.now()
|
499
|
+
expired = dates.is_token_expired(dt_access_token, dt_now)
|
500
|
+
|
501
|
+
if expired:
|
502
|
+
access_token, dt_access_token = self.refresh_access_token(refresh_token)
|
503
|
+
self.download(access_token, link_mod, filepath[1], product_name, name)
|
504
|
+
|
505
|
+
elif tile == None:
|
506
|
+
if product_name in bands_links:
|
507
|
+
if "MSIL1C" in product_name:
|
508
|
+
product = bands_links[product_name]
|
509
|
+
key = next(iter(product))
|
510
|
+
# Access the nested lists
|
511
|
+
products_link_lists = product[key]
|
512
|
+
for nested_list in products_link_lists:
|
513
|
+
name, link = nested_list
|
514
|
+
link_mod = utils.modify_string(link)
|
515
|
+
filepath = files.check_file_exist(base_dir, product_platform, product_date, product_tile, product_type, name)
|
516
|
+
logger.info(f"Starting download process for band {name}")
|
517
|
+
if filepath[0] == True:
|
518
|
+
logger.warning(f"Band {name} Already downloaded")
|
519
|
+
else:
|
520
|
+
dt_now = datetime.now()
|
521
|
+
expired = dates.is_token_expired(dt_access_token, dt_now)
|
522
|
+
|
523
|
+
if expired:
|
524
|
+
access_token, dt_access_token = self.refresh_access_token(refresh_token)
|
525
|
+
logger.info("Data has not been downloaded. Starting data downloaded...")
|
526
|
+
self.download(access_token, link_mod, filepath[1], product_name, name)
|
527
|
+
|
528
|
+
elif "MSIL2A" in product_name:
|
529
|
+
product = bands_links[product_name]
|
530
|
+
key = next(iter(product))
|
531
|
+
# Access the nested lists
|
532
|
+
products_link_lists = product[key]
|
533
|
+
for resolution, bands_links_list in products_link_lists.items():
|
534
|
+
for band in bands_links_list:
|
535
|
+
name = band[0]
|
536
|
+
link = band[1]
|
537
|
+
link_mod = utils.modify_string(link)
|
538
|
+
filepath = files.check_file_exist(base_dir, product_platform, product_date, product_tile, product_type, name, resolution)
|
539
|
+
|
540
|
+
logger.info(f"Starting download process for band {name}")
|
541
|
+
if filepath[0] == True:
|
542
|
+
logger.warning(f"Band {name} Already downloaded")
|
543
|
+
else:
|
544
|
+
logger.info("Data has not been downloaded. Starting data downloaded...")
|
545
|
+
dt_now = datetime.now()
|
546
|
+
expired = dates.is_token_expired(dt_access_token, dt_now)
|
547
|
+
|
548
|
+
if expired:
|
549
|
+
access_token, dt_access_token = self.refresh_access_token(refresh_token)
|
550
|
+
self.download(access_token, link_mod, filepath[1], product_name, name)
|
551
|
+
else:
|
552
|
+
logger.warning("Tile not selected to download")
|
553
|
+
|
554
|
+
|
izisat/misc/dates.py
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
import datetime
|
2
|
+
from loguru import logger
|
3
|
+
|
4
|
+
class Dates:
|
5
|
+
def __init__(self):
|
6
|
+
pass
|
7
|
+
|
8
|
+
def is_token_expired(self, dt_access_token, dt_download):
|
9
|
+
"""
|
10
|
+
Check if the provided access token has expired.
|
11
|
+
|
12
|
+
Parameters:
|
13
|
+
-----------
|
14
|
+
access_token: str
|
15
|
+
The access token to be checked for expiration.
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
--------
|
19
|
+
bool
|
20
|
+
True if the token has expired, False otherwise.
|
21
|
+
"""
|
22
|
+
|
23
|
+
# Check if the current time is 9 minutes or more past the expiration time
|
24
|
+
return dt_download > dt_access_token + datetime.timedelta(minutes=9)
|