Dropbox – Restaurar carpeta a una fecha concreta
A veces, por errores, virus, o pura mala suerte, una carpeta de dropbox se echa a perder y necesitamos recuperarla tal y como estaba en una fecha anterior. Este Script de Python, preparado por clark800 -Kudos Clark!- es una solución magnifica que nos ahorrará mucho mucho tiempo y dolores de cabeza.
Hace poco lo tuve que usar y hacer algunos cambios para que funcionase con Python 3.5.2, así que lo comparto aquí tal y como me funcionó a mí.
Instrucciones de uso:
- Instala Python 3.5.2 desde la página de Python
- Asegúrate de añadir la ubicación de Python.exe a tu variable PATH si estás en Windows
- Descarga el sdk de Dropbox, puede hacerlo simplemente abriendo una ventana de comando (Windows+R > cmd) y tecleando >>
pip install dropbox
- Crea una App de Dropbox en el área de desarrolladores. Guarda las claves para incluirlas luego en el script.
- Guarda el script como restore.py y actualizalo con tus claves
- Ejecuta el script desde una línea de comando >>
python restore.py /ruta/carpeta/dentro/dropbox YYYY-MM-DD
- Tu ruta ha de empezar con “/”, donde “/” es la raiz de tu Dropbox
- La primera vez que ejecutes el script tendrás que autorizarlo con un token que obtendrás de la url que verás en pantalla
Te recomiendo que hagas pruebas con una carpeta sin valor antes de darle duro.
#!/usr/bin/env python
import sys, os, dropbox, time
from datetime import datetime
APP_KEY = '' # INSERT APP_KEY HERE
APP_SECRET = '' # INSERT APP_SECRET HERE
DELAY = 0.2 # delay between each file (try to stay under API rate limits)
HELP_MESSAGE =
"""Note: You must specify the path starting with "/", where "/" is the root
of your dropbox folder. So if your dropbox directory is at "/home/user/dropbox"
and you want to restore "/home/user/dropbox/folder", the ROOTPATH is "/folder".
"""
HISTORY_WARNING =
"""Dropbox only keeps historical file versions for 30 days (unless you have
enabled extended version history). Please specify a cutoff date within the past
30 days, or if you have extended version history, you may remove this check
from the source code."""
def authorize():
flow = dropbox.client.DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)
authorize_url = flow.start()
print('1. Go to: ' + authorize_url)
print('2. Click "Allow" (you might have to log in first)')
print('3. Copy the authorization code.')
#try:
#input = input
#except NameError:
#pass
code = input("Enter the authorization code here: ").strip()
access_token, user_id = flow.finish(code)
return access_token
def login(token_save_path):
if os.path.exists(token_save_path):
with open(token_save_path) as token_file:
access_token = token_file.read()
else:
access_token = authorize()
with open(token_save_path, 'w') as token_file:
token_file.write(access_token)
return dropbox.client.DropboxClient(access_token)
def parse_date(s):
a = s.split('+')[0].strip()
return datetime.strptime(a, '%a, %d %b %Y %H:%M:%S')
def restore_file(client, path, cutoff_datetime, is_deleted, verbose=False):
revisions = client.revisions(path)
revision_dict = dict((parse_date(r['modified']), r) for r in revisions)
# skip if current revision is the same as it was at the cutoff
if max(revision_dict.keys()) < cutoff_datetime:
if verbose:
print(path + ' SKIP')
return
# look for the most recent revision before the cutoff
pre_cutoff_modtimes = [d for d in revision_dict.keys()
if d < cutoff_datetime]
if len(pre_cutoff_modtimes) > 0:
modtime = max(pre_cutoff_modtimes)
rev = revision_dict[modtime]['rev']
if verbose:
print(path + ' ' + str(modtime))
client.restore(path, rev)
else: # there were no revisions before the cutoff, so delete
if verbose:
print(path + ' ' + ('SKIP' if is_deleted else 'DELETE'))
if not is_deleted:
client.file_delete(path)
def restore_folder(client, path, cutoff_datetime, verbose=False):
if verbose:
print(path)
#print('Restoring folder: ' + path.encode('utf-8'))
try:
folder = client.metadata(path, list=True,
include_deleted=True)
except dropbox.rest.ErrorResponse as e:
print(str(e))
print(HELP_MESSAGE)
return
for item in folder.get('contents', []):
if item.get('is_dir', False):
restore_folder(client, item['path'], cutoff_datetime, verbose)
else:
restore_file(client, item['path'], cutoff_datetime,
item.get('is_deleted', False), verbose)
time.sleep(DELAY)
def main():
if len(sys.argv) != 3:
usage = 'usage: {0} ROOTPATH YYYY-MM-DDn{1}'
sys.exit(usage.format(sys.argv[0], HELP_MESSAGE))
root_path_encoded, cutoff = sys.argv[1:]
#root_path = root_path_encoded.decode('utf-8')
root_path = root_path_encoded
cutoff_datetime = datetime(*map(int, cutoff.split('-')))
if (datetime.utcnow() - cutoff_datetime).days >= 30:
sys.exit(HISTORY_WARNING)
if cutoff_datetime > datetime.utcnow():
sys.exit('Cutoff date must be in the past')
client = login('token.dat')
restore_folder(client, root_path, cutoff_datetime, verbose=True)
if __name__ == '__main__':
main()