-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfuncionalidad_drive.py
721 lines (563 loc) · 26.9 KB
/
funcionalidad_drive.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
import os
import io
from typing import Dict, Text
import typing
from service_drive import obtener_servicio as service
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
import pathlib
import datetime
from platform import system
def definir_sistema():
sistema = system()
if sistema == "Windows":
sep = "\\"
else:
sep = "/"
return sep
SEP = definir_sistema()
def validar_opcion(opc_minimas: int, opc_maximas: int, texto: str = '') -> str:
"""
PRE: Recibe los int "opc_minimas" y "opc_maximas" que
simbolizan la cantidad de opciones posibles.
POST: Devuelve en formato string la var "opc" con un número
entero dentro del rango de opciones.
"""
opc = input(" -> {}".format(texto))
while not opc.isnumeric() or int(opc) > opc_maximas or int(opc) < opc_minimas:
opc = input("Por favor, ingrese una opcion valida: ")
return opc
def retroceder(paths: list) -> tuple:
"""
PRE: Recibe la lista "paths" con info sobre las carpetas por las que
ya navego el usuario:
"paths" =[ [nombre_carpeta, id_carpeta], ]
POST: Devuelve en un tupla los str "id_carpeta" y " nombre_carpeta" para retroceder
a dicha carpeta.
"""
ultima_carpeta = paths.pop() #saco la ultima que eleji
if paths: # si no queda vacia depues del pop
nombre_carpeta = paths[-1][0] #devuelvo el nombre
id_carpeta = paths[-1][1] #y id de la anterior en la que estuve SIN SACARLO
else: #si queda vacia, la cargo de nuevo
paths.append(['Directorio principal(root)','root'])
id_carpeta, nombre_carpeta = 'root', 'Directorio principal(root)'
return id_carpeta, nombre_carpeta
##---------- SELECCIONAR CARPETAS O ARCHIVOS ---------------
def seleccionar_elementos(info_elementos: dict) -> tuple:
"""
PRE: Recibe el diccionario "info_elementos" con info sobre
carpetas o archivos segun corresponda:
info_elementos = { num_elemento: ['nombre elemento', 'id elemento', ['id parents'],
'mimeType' ] }
POST: devuelve en una 4-upla los str
"id_elemento", "nombre_elemento", "id_parents", "mime_type"
"""
texto = 'cual?: '
#info_elementos.keys() es {1,2,3... correspondiente a cada ele
num_ele = int(validar_opcion( min( info_elementos.keys() ), max ( info_elementos.keys() ), texto ) )
nombre_elemento = info_elementos[num_ele][0]
id_elemento = info_elementos[num_ele][1]
id_parents = info_elementos[num_ele][2]
mime_type = info_elementos[num_ele][3]
print(f'se ha seleccionado {nombre_elemento}')
return id_elemento, nombre_elemento, id_parents, mime_type
def generador_de_id_elemento(info_carpetas: dict, info_archivos:dict, paths:dict) -> tuple:
"""
PRE: Recibe los diccionarios "info_carpetas" e "info_archivos":
info_carpetas = { num_carpeta: ['nombre carpeta', 'id carpeta', ['id parents'],
'mimeType' ] }
info_archivos = { num_archivo: ['nombre archivo', 'id elemento', ['id parents'],
'mimeType' ] }
y la lista "paths":
paths =[ [nombre_carpeta, id_carpeta], ]
POST: Permite retroceder a la carpeta si se elije esa opcion.
Devuelve en una 4-upla los str: "id_elemento", "id_elemento", "nombre_elemento",
"id_parents", "elemento", "mime_type".
"""
print('1-Seleccionar una carpeta\n2-Seleccionar un archivo\n3-Atras')
opc = int( validar_opcion(1,3) )
if opc == 1 and info_carpetas: #si hay carpetas para seleccionar
elemento = 'carpeta'
id_elemento, nombre_elemento, id_parents, mime_type = seleccionar_elementos(info_carpetas)
elif opc == 2 and info_archivos: #archivos
elemento = 'archivo'
id_elemento, nombre_elemento, id_parents, mime_type = seleccionar_elementos(info_archivos)
else: #retroceder
elemento = 'retroceder'
id_elemento, nombre_elemento = retroceder(paths)
id_parents = []
mime_type = 'application/vnd.google-apps.folder'
return id_elemento, nombre_elemento, id_parents, elemento, mime_type
##---------- GUARDADO Y ORGANIZACION DE ARCHIVOS Y CARPETAS DE DRIVE ---------------
def mostrar_elementos(info_elementos: dict, tipo_ele: str) -> None:
"""
PRE: Recibe el diccionario "info_elementos" que puede contener informacion
de carpetas o archivos:
info_elementos = { num_elemento: ['nombre elemento', 'id elemento', ['id parents'],
'mimeType' ] }
POST: No devuelve nada solo muestra por panatalla los elementos del diccionario.
"""
for num_ele, elemento in info_elementos.items():
print (f'{num_ele}-{elemento[0]}')
if info_elementos: #debo preguntarlo porque si esta vacio, tira error
print(f'Se encontraron {num_ele} {tipo_ele}\n')
else:
print(f'No se encontraron {tipo_ele}\n')
def ordenar_info_elementos(elementos: dict) -> dict:
"""
PRE: Recibe el diccionario "elementos" que puede conetener
"carpetas" o "archivos":
elementos = {nombre_elemento: ['id elemento', 'fecha_modif', ['id_parents'], 'mimeType'] }
POST: Crea y devuelve el diccionario "info_elementos" que
puede contener "carpetas" o "archivos":
info_elementos = {num_elemento: ['nombre elemento','id elemento', ['id parents'],
'mimeType' ]}
"""
info_elementos = dict()
num_ele = 0
for nombre_elemento, info_elemento in elementos.items():
num_ele += 1 #name #id #2
info_elementos[num_ele] = [nombre_elemento, info_elemento[0], info_elemento[2], info_elemento[3]]
return info_elementos
def guardar_info_elementos(elementos: dict, carpetas:dict, archivos:dict) -> None:
"""
PRE: Recibe la lista de diccionarios (cada diccionario es un elemento):
elementos = [{id: 'id_elemento', name: 'nombre del elemento', 'mimeType': 'txt/plain(por ej)',
'modifiedTime': 'fecha de modif','parents': ['id_parents'] } ],
y los diccionarios "carpetas" y "archivos":
carpetas = {nombre_carpeta: ['id carpeta', 'fecha_modif', '[id_parents'], 'mimeType' ]} y
archivos = {nombre_carpeta: ['id carpeta', 'fecha_modif', ['id_parents'], 'mimeType' ]}.
POST: No devuelve nada. Modifica por parametro los diccionarios "carpetas" y
"archivos" colocando como claves los nombres de los elementos y su informacion en una lista
como valores.
"""
for elemento in elementos:
if elemento['mimeType'] == 'application/vnd.google-apps.folder':
#chequea q no existe
carpetas[ elemento['name'] ] = [elemento['id'], elemento['modifiedTime'], elemento['parents'], elemento['mimeType']]
else:
archivos[ elemento['name'] ] = [elemento['id'], elemento['modifiedTime'], elemento['parents'], elemento['mimeType']]
def listar_elementos(query: str) -> tuple:
"""
PRE: Recibe el string "query" con la consulta a enviar a la API de drive.
POST: Devuelve en una tupla los diccionarios "carpetas" y "archivos":
carpetas = {nombre_carpeta: ['id carpeta', 'fecha_modif', ['id_parents'], mimetype ]} y
archivos = {nombre_carpeta: ['id carpeta', 'fecha_modif', ['id_parents'], mimetype ]}.
"""
page_token = None
cortar = False
carpetas = dict()
archivos = dict()
while not cortar:
#files().list() devuelve un diccionario de diccionarios, q guardo en "resultados"
resultados = service().files().list(q= query,
spaces='drive',
fields='nextPageToken, files(id, name, mimeType, modifiedTime, parents)',
pageToken=page_token).execute()
#En el dict resultados, una clave es "files", que es una lista de diccionarios donde
#cada diccionario es un elemento de dicha lista. (NB: xa google, todo son archivos,
#incluso las carpetas: mimType = 'application/vnd.google-apps.folder')
#Guardo la lista de dicts "files" en elementos.
elementos = resultados['files']
guardar_info_elementos(elementos, carpetas, archivos)
#chequeo si hay mas resultados
page_token = resultados.get('nextPageToken')
if page_token is None:
cortar = True
return carpetas, archivos
def armado_de_consulta(id_elemento: str) -> tuple:
"""
PRE: Recibe el str "id_elemento" con el id de la carpeta o archivo que selecciono
el usurario.
POST: devuelve una tupla con los str "query" con la consulta a buscar en el drive
y "cortar" que es una variable de control para el menu.
"""
print('0- LISTA TODO MYDRIVE ')
print('1- Busqueda por numero')
print('2- Busqueda por palabra (Escribir palabra clave : palabra COMPLETA )')
print("----> ej - archivo -> '< nombre archivo >.< extension >' ")
print("----> ej - carpeta -> '< nombre carpeta >' ")
print("3 - Volver al menu principal ")
opc = int(validar_opcion(0,3))
cortar = False
if opc == 0:
query = "not trashed"
elif opc == 1:
query = f" '{id_elemento}' in parents and (not trashed) "
elif opc == 2:
palabra = input('ingerse palabra clave COMPLETA: ') #contains solo busca palabras completas no letras!
query = f" '{id_elemento}' in parents and fullText contains '{palabra} and (not trashed)' "
elif opc == 3:
query = ""
cortar = True
return query, cortar
##---------- MENU DE DRIVE ---------------
def consultar_elementos():
"""
PRE: No recibe nada. Funciona como un menu gestor de drive
POST: Redirige a otras funciones de filtro y busqueda de archivos.
Devuelve los str "id_elemento", "nombre_elemento", "id_parents", "mime_type"
"""
print('BUSCADOR DE DRIVE'.rjust(50))
print('--- My Drive -> Directorio principal---'.rjust(57))
cortar = False
nombre_elemento = "directorio_principal('root')"
id_elemento = 'root'
paths = [[nombre_elemento, id_elemento]]
while not cortar:
query, cortar = armado_de_consulta(id_elemento)
if not cortar:
carpetas, archivos = listar_elementos(query)
info_carpetas = ordenar_info_elementos(carpetas)
info_archivos = ordenar_info_elementos(archivos)
print('CARPETAS')
mostrar_elementos(info_carpetas, 'carpetas')
print('ARCHIVOS')
mostrar_elementos(info_archivos,'archivos')
id_elemento, nombre_elemento, id_parents, elemento, mime_type = generador_de_id_elemento(info_carpetas, info_archivos, paths)
if elemento == 'carpeta':
paths.append([nombre_elemento, id_elemento])
print('1-Abrir carpeta\n2-Selccionar elemento')
opc = int(validar_opcion(1,2))
elif elemento == 'retroceder':
opc = 1
else: #es un archivo
opc = 2
if opc == 2:
cortar = True
else:
ruta = ""
for carpeta in paths:
ruta += " -> " + carpeta[0]
print(f"Historial: {ruta}\n")
print(f'---{nombre_elemento}---\n'.rjust(50))
else:
id_elemento = ""
nombre_elemento = ""
id_parents = ""
mime_type = ""
return id_elemento, nombre_elemento, id_parents, mime_type
def validar_elemento(elemento:str) -> tuple:
"""
PRE:Recibe el str "elemento" con el tipo de elemento a validar. Este puede ser
"carpeta" o "archivo"
POST: Redirige a consultar elementos hasta el fin de la especie humana o hasta el
devolver una carpeta o archivo segun corresponda.
Devuelve una 3-upla con los str "id_elemento", "nombre_elemento", "id_parents"
"""
mime_type_carpeta = 'application/vnd.google-apps.folder'
id_elemento, nombre_elemento, id_parents, mime_type = consultar_elementos()
if elemento == 'carpeta':
while mime_type != mime_type_carpeta:
print('Por favor elija una carpeta')
id_elemento, nombre_elemento, id_parents, mime_type = consultar_elementos()
else: # necesito un archivo
while mime_type == mime_type_carpeta or mime_type == "":
print('Por favor elija un archivo')
id_elemento, nombre_elemento, id_parents, mime_type = consultar_elementos()
return id_elemento, nombre_elemento, id_parents
##---------- DESCARGAR CARPETAS O ARCHIVOS ---------------
def descargar_archivo_binario(id_elemento:str):
"""
PRE: Recibe el str "id_elemento" con el id del archivo a descargar
POST: Descarga el archivo cuyo id es el indicado y
devuelve el objeto "arch" con el archivo q se descargo
"""
file_id = id_elemento
request = service().files().get_media(fileId=file_id)
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print(f"Descarga progres {status.progress() * 100}")
fh.seek(0)
return fh
def descargar_carpeta(id_elemento:str, nombre_elemento:str, ruta_actual:str) ->None:
"""
Recibe los str "id_elemento" , "nombre_elemento" y "ruta_actual"
POST: No devuelve nada. Descarga la carpeta, subcarpetas y archivos que
se encuentren en la carpeta seleccionada.
"""
ruta_actual = ruta_actual + SEP + nombre_elemento
os.mkdir(ruta_actual)
page_token = None
cortar = False
while not cortar:
resultados = service().files().list(q= f" '{id_elemento}' in parents",
spaces='drive',
fields='nextPageToken, files(id, name, mimeType)',
pageToken= page_token).execute()
elementos = resultados['files']
for elemento in elementos:
id_elemento = elemento['id']
nombre_elemento = elemento['name']
mimeType = elemento['mimeType']
fh = io.BytesIO()
if mimeType == 'application/vnd.google-apps.folder':
descargar_carpeta(id_elemento,nombre_elemento, ruta_actual)
else:
fh = descargar_archivo_binario(id_elemento)
with open(os.path.join(ruta_actual,nombre_elemento), 'wb') as arch:
arch.write(fh.read())
arch.close()
page_token = resultados.get('nextPageToken')
if page_token is None:
cortar = True
def menu_descargar_elementos(ruta_local:str) -> None:
"""
PRE: recibe el str "ruta_local" con la ruta local en la que esta paardo el usuario
POST: Redirige a otras funciones para permitir descargar el archivo o carpeta
seleccionado en drive por el usuario.
"""
print('\n ------------- MENU DESCARGAR ------------- ')
print('Que desea descargar?')
print('1-Carpeta\n2-Archivo')
opc = int( validar_opcion(1,2))
if opc == 1:
print('seleccione la carpeta que desea descargar')
id_carpeta, nombre_elemento, id_parents = validar_elemento('carpeta')
descargar_carpeta(id_carpeta,nombre_elemento,ruta_local)
print()
print(f'se descargo correctamente "{nombre_elemento}"\n')
else: #descargar un archivo
print('seleccione el archivo que desea descargar')
id_archivo, nombre_elemento, id_parents = validar_elemento('archivo')
fh = descargar_archivo_binario(id_archivo)
with open(os.path.join(ruta_local,nombre_elemento), 'wb') as arch:
arch.write(fh.read())
print(f'se descargo correctamente "{nombre_elemento}"\n')
##---------- SUBIR CARPETAS O ARCHIVOS ---------------
## -----> SUBIR ARCHIVOS AL DRIVE
def subir_archivos(nombre_archivo:str, ruta_archivo: str, carpeta_id: str) -> None:
"""
PRE:Recibe los str "nombre_archivo", "ruta_archivo" y "carpeta_id"
POST: No devuelve nada. Sube los archivos a la carpeta indicadas.
"""
file_metadata = {
'name': nombre_archivo,
'parents': [carpeta_id]
}
print(ruta_archivo)
media = MediaFileUpload(filename = ruta_archivo)
service().files().create(body = file_metadata,
media_body = media,
fields = 'id').execute()
print(f" --- El archivo {nombre_archivo} se subio exitosamete --- ")
def encontrar_carpeta_upstream(carpeta_contenedora: str) -> tuple:
"""
PRE: Recibe el str "carpeta_contenedora" con el nombre de la carpeta en
la que esoy parado en el local
POST: Busca entre los nombres de las carpetas del remoto la carpeta
correspondiente a la que me encuentro en el local y
devuelve los str "carpeta_id" y "nombre_carpeta".
"""
#primero listo todas las carpetas de la nube
print(carpeta_contenedora)
query = f" mimeType = 'application/vnd.google-apps.folder' and name contains '{carpeta_contenedora}' and not trashed "
carpetas, archivos = listar_elementos(query)
if carpeta_contenedora in carpetas.keys(): #si existe la carpeta en el remoto
#si coincide con la local lo subo ahi
for nombre_carpeta, info_carpeta in carpetas.items():
if nombre_carpeta == carpeta_contenedora:
carpeta_id = info_carpeta[0]
else:
print('La carpeta no existe con este mismo nombre en la nube')
print('Por favor elija otra carpeta')
carpeta_id = '' #xa q no falle
nombre_carpeta = '' #xa q no falle
return carpeta_id, nombre_carpeta
def opciones_subir_archivos( nombre_archivo: str, ruta_archivo: str, carpeta_contenedora: str) -> None:
"""
PRE: Recibe los str "nombre_archivo", "ruta_archivo" y "carpeta_contenedora"
POST: No devuelve nada. Funciona como menu intermedio para permitirle subir
archivos a una carpeta a eleccion del usuario.
"""
print('SUBIR ARCHIVOS')
print('1-Subir a carpeta homonima en drive\n2-Elegir otra carpeta')
opc = int(validar_opcion(1,2))
if opc == 1:
carpeta_id, nombre_carpeta = encontrar_carpeta_upstream(carpeta_contenedora)
if carpeta_id != '' and nombre_carpeta != '': #si encontro la carpeta
subir_archivos(nombre_archivo, ruta_archivo, carpeta_id)
else:
print('Selccione la carpeta a la que desea subir el archivo')
carpeta_id, nombre_carpeta, id_parents = validar_elemento('carpeta')
subir_archivos(nombre_archivo, ruta_archivo, carpeta_id)
## -----> SUBIR CARPETAS AL DRIVE
def crea_carpetas(nombre_carpeta: str, parent: str = "")->str:
"""
PRE: Recibo la carpeta que quiero subir
POST: Creo la carpeta en remoto y retorno su id
"""
if parent == "":
file_metadata = {
"name": nombre_carpeta,
"mimeType": "application/vnd.google-apps.folder",
'parents': []
}
else:
file_metadata = {
"name": nombre_carpeta,
"mimeType": "application/vnd.google-apps.folder",
'parents': [parent]
}
folder = service().files().create(body = file_metadata).execute()
id_carpeta = folder.get("id")
return id_carpeta
def recorrer_carpeta(ruta_actual: str, parent: str = "")->None:
"""
PRE: Recorro la carpeta en el local
POST: En caso de leer un archivo lo subo , en caso de leer una carpeta
repito el proceso de crear carpeta
"""
contenido = os.listdir(ruta_actual)
nombre_carpeta = ruta_actual.split(SEP)[-1]
id_carpeta = crea_carpetas(nombre_carpeta, parent)
for ficheros in contenido :
if os.path.isfile(ruta_actual + SEP + ficheros):
ruta_archivo = ruta_actual + SEP + ficheros
subir_archivos(ficheros, ruta_archivo, id_carpeta)
else:
ruta_fichero = ruta_actual + SEP + ficheros
recorrer_carpeta(ruta_fichero, id_carpeta)
# --------> MENU PARA SUBIR CARPETAS/ARCHIVOS
def menu_subir_archivos(ruta_archivo:str, nombre_archivo:str, carpeta_contenedora:str, elemento:str) -> None:
"""
PRE: Recibe los str "nombre_archivo", "ruta_archivo" y "carpeta_contenedora"
POST: No devuelve nada. Funciona como menu intermedio para permitirle subir
archivos a una carpeta a eleccion del usuario.
"""
eleccion = input("1 - MyDrive\n2 - Otra Carpeta \n -> ")
if elemento == 'archivo':
if eleccion == "1":
subir_archivos(nombre_archivo, ruta_archivo, "root")
elif eleccion == "2":
print()
print("carpeta contenedora a buscar: ",carpeta_contenedora)
opciones_subir_archivos(nombre_archivo, ruta_archivo, carpeta_contenedora)
else: #osea subo una carpeta # OJO AGREGO permitir subirla a el root
if eleccion == "1": #subi directamente
recorrer_carpeta(ruta_archivo, "root")
elif eleccion == "2": #le doy a elegir una carpeta de drive y dsp subo
carpeta_id = validar_elemento('carpeta')[0]
recorrer_carpeta(ruta_archivo, carpeta_id)
## ---------- MOVER ARCHIVOS ENTRE CARPETAS DE DRIVE ---------------
def mover_archivos() -> None:
"""
PRE: No recibe parametros.
POST: No devuelve nada. Permite mover archivos de a uno a la vez de una carpeta
a otra en drive
"""
print('\n\t### Seleccione el archivo que desea mover ###\t\n')
id_archivo, nombre_arch, id_parents = validar_elemento('archivo')
id_carpeta_salida = id_parents[0] #cuidado! parents es una lista
print('\nSeleccione la carpeta a la que desea mover el archivo')
id_carpeta_destino, nombre_carpeta, id_parents = validar_elemento('carpeta')
service().files().update(fileId = id_archivo,
addParents = id_carpeta_destino,
removeParents = id_carpeta_salida
).execute()
print(f'Se movio exitosamente {nombre_arch} a {nombre_carpeta}')
## ---------- SINCRONIZAR ---------------
def remplazar_archivos(ruta_archivo:str, id_archivo:str) -> None:
"""
PRE: Recibe los str "ruta_arch" y "id_arch"
POST: No devuelve nada. Reemplaza en la nube el archivo de id "id_archivo"
por el archivo que se encuentra en "ruta_archivo"
"""
media = MediaFileUpload(filename = ruta_archivo)
service().files().update(fileId = id_archivo,
media_body = media).execute()
def fecha_modificacion_remoto(id_carpeta: str)->dict:
"""
PRE: Recibo el id de la carpeta
POST: Retorno un dicc con la informacion de cuando fue modificada la carpeta
"""
## drive = {nombre fichero = [id fichero , fecha de modificacion]]}
page_token = None
drive = dict() # diccionario con {nombre carpeta : [id, mimetype, parent]}
# lista_padres es una lista [(padre1, id ), (padre2, id) ... ]
response = service().files().list(q = f" '{id_carpeta}' in parents and (not trashed) ",
fields='nextPageToken, files(id, name, mimeType,modifiedTime)').execute()
for file in response.get('files', []):
file_date = file.get("modifiedTime")[:18].replace('T', ' ')
drive[file.get("name")] = [file.get("id"),file_date]
return drive
def fecha_modificacion_local(ruta_actual: str)->tuple:
"""
PRE: Recibo la ruta donde el usuario esta ubicado
POST: Retorno una tupla con dos dic, uno que contiene las fechas de modificacion
de cada archivo y otra con la modificacion de las carpetas
"""
## archivo_fecha_local = {nombre fichero = fecha_modificacion}
archivos_fechas_local = dict()
carpetas_fechas_local = dict()
with os.scandir(ruta_actual) as ficheros:
for fichero in ficheros:
if os.path.isfile(fichero):
fecha_modificacion_archivo = datetime.datetime.fromtimestamp(os.path.getmtime(fichero))
horas_sumadas = datetime.timedelta(hours = 3)
fecha_modificacion_archivo += horas_sumadas
fecha_modificacion_archivo = str(fecha_modificacion_archivo)[:18]
archivos_fechas_local[fichero.name] = fecha_modificacion_archivo
elif os.path.isdir(fichero):
fecha_modificacion_carpeta = datetime.datetime.fromtimestamp(os.path.getmtime(fichero))
horas_sumadas = datetime.timedelta(hours = 3)
fecha_modificacion_carpeta += horas_sumadas
fecha_modificacion_carpeta = str(fecha_modificacion_carpeta)[:18]
carpetas_fechas_local[fichero.name] = fecha_modificacion_carpeta
return archivos_fechas_local , carpetas_fechas_local
def descargar_archivo(archivo_id: str, ruta: str)->None:
"""
PRE: Recibo el id del archivo
POST: Descargo el archivo
"""
print("ruta en funcion descargar_archivo : ", ruta)
nombre_archivo = ruta
file_id = archivo_id
request = service().files().get_media(fileId=file_id)
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print(f"Descarga progres {status.progress() * 100}")
fh.seek(0)
with open(nombre_archivo, "wb") as f:
f.write(fh.read())
f.close()
def sincronizar(archivos_drive: dict, archivos_local: dict, carpeta_local: dict, ruta: str, c_id)->None:
"""
PRE: Recibo los diccionarios con informacion del remoto y del local
POST: Sincronizo cada archivo segun su horario de modificacion
"""
for archivo , fecha in archivos_local.items():
ruta_archivo = ruta + SEP + archivo
if archivo in archivos_drive.keys():
print(ruta_archivo)
# comparo fechas
if fecha > archivos_drive[archivo][1]:
print(fecha)
print(archivos_drive[archivo][1])
# actualizo el archivo al remoto
print(ruta_archivo)
print(archivos_drive[archivo][0])
remplazar_archivos(ruta_archivo, archivos_drive[archivo][0])
elif fecha < archivos_drive[archivo][1]:
print(fecha)
print(archivos_drive[archivo][1])
# actualizo archivo al local
os.remove(ruta_archivo)
descargar_archivo(archivos_drive[archivo][0], ruta_archivo)
else:
subir_archivos(archivo, ruta_archivo,c_id )
for carpeta , fecha in carpeta_local.items():
if carpeta in archivos_drive.keys():
ruta_archivo = ruta + SEP + carpeta
# actualizo los archivos dentro de la carpeta
carpeta_id = encontrar_carpeta_upstream(carpeta)[0]
archivos_r = fecha_modificacion_remoto(carpeta_id)
archivos_l = fecha_modificacion_local(ruta_archivo)[0]
carpeta_l = fecha_modificacion_local(ruta_archivo)[1]
sincronizar(archivos_r, archivos_l, carpeta_l, ruta_archivo)