|
| 1 | +# @tdamdouni gists |
| 2 | +# https://gist.github.com/2ba53a6270a6772645655913becb361f |
| 3 | + |
| 4 | +# https://gist.github.com/KainokiKaede/015601fc9f29c354a805fc56deef1bbe |
| 5 | + |
| 6 | +from __future__ import absolute_import |
| 7 | +from __future__ import print_function |
| 8 | +import os |
| 9 | +import sys |
| 10 | +import pickle |
| 11 | +import console |
| 12 | +import editor |
| 13 | +import dropbox |
| 14 | + |
| 15 | +# I moved 'dropboxlogin' into a sub folder so it doesn't clutter my main folder |
| 16 | +sys.path += [os.path.join(os.path.dirname(os.path.abspath(__file__)),)] |
| 17 | +import dropboxloginv2 # this code can be found here https://gist.github.com/4034526 |
| 18 | + |
| 19 | +STATE_FILE = '.dropbox_state_v2' |
| 20 | + |
| 21 | +class dropbox_state: |
| 22 | + def __init__(self): |
| 23 | + self.cursor = None |
| 24 | + self.local_files = {} |
| 25 | + self.remote_files = {} |
| 26 | + |
| 27 | + # use ignore_path to prevent download of recently uploaded files |
| 28 | + def execute_delta(self, client, ignore_path = None): |
| 29 | + if not self.cursor: |
| 30 | + delta = client.files_list_folder('', recursive=True) |
| 31 | + else: |
| 32 | + delta = client.files_list_folder_continue(self.cursor) |
| 33 | + self.cursor = delta.cursor |
| 34 | + |
| 35 | + for entry in delta.entries: |
| 36 | + if type(entry) == dropbox.files.DeletedMetadata: continue |
| 37 | + path = entry.path_display[1:] |
| 38 | + meta = entry |
| 39 | + |
| 40 | + # this skips the path if we just uploaded it |
| 41 | + if path != ignore_path: |
| 42 | + if meta != None: |
| 43 | + path = meta.path_display[1:] # caps sensitive |
| 44 | + if type(meta) == dropbox.files.FolderMetadata: |
| 45 | + print('\n\tMaking Directory:',path) |
| 46 | + self.makedir_local(path) |
| 47 | + elif path not in self.remote_files: |
| 48 | + print('\n\tNot in local') |
| 49 | + self.download(client, path) |
| 50 | + elif meta.rev != self.remote_files[path].rev: |
| 51 | + print('\n\tOutdated revision') |
| 52 | + self.download(client, path) |
| 53 | + # remove file or directory |
| 54 | + else: |
| 55 | + if os.path.isdir(path): |
| 56 | + print('\n\tRemoving Directory:', path) |
| 57 | + os.removedirs(path) |
| 58 | + elif os.path.isfile(path): |
| 59 | + print('\n\tRemoving File:', path) |
| 60 | + os.remove(path) |
| 61 | + del self.local_files[path] |
| 62 | + del self.remote_files[path] |
| 63 | + else: |
| 64 | + pass # file already doesn't exist localy |
| 65 | + |
| 66 | + # makes dirs if necessary, downloads, and adds to local state data |
| 67 | + def download(self, client, path): |
| 68 | + print('\tDownloading:', path) |
| 69 | + head, tail = os.path.split(path) |
| 70 | + if not os.path.exists(head) and head != '': |
| 71 | + os.makedirs(head) |
| 72 | + meta = client.files_download_to_file(path, os.path.join('/',path)) |
| 73 | + self.local_files[path] = {'modified': os.path.getmtime(path)} |
| 74 | + self.remote_files[path] = meta |
| 75 | + |
| 76 | + def upload(self, client, path): |
| 77 | + print('\tUploading:', path) |
| 78 | + with open(path,'rb') as local: |
| 79 | + overwrite = dropbox.files.WriteMode('overwrite') |
| 80 | + meta = client.files_upload(local, os.path.join('/',path), overwrite) |
| 81 | + # meta = client.put_file(os.path.join('/',path), local, True) |
| 82 | + |
| 83 | + self.local_files[path] = {'modified': os.path.getmtime(path)} |
| 84 | + self.remote_files[path] = meta |
| 85 | + |
| 86 | + # clean out the delta for the file upload |
| 87 | + self.execute_delta(client, ignore_path=meta.path_display[1:]) |
| 88 | + |
| 89 | + def delete(self, client, path): |
| 90 | + print('\tFile deleted locally. Deleting on Dropbox:',path) |
| 91 | + try: |
| 92 | + client.files_delete('/' + path) |
| 93 | + except Exception as e: |
| 94 | + # file was probably already deleted |
| 95 | + print(e) |
| 96 | + print('\tFile already removed from Dropbox') |
| 97 | + |
| 98 | + del self.local_files[path] |
| 99 | + del self.remote_files[path] |
| 100 | + |
| 101 | + # safely makes local dir |
| 102 | + def makedir_local(self,path): |
| 103 | + if not os.path.exists(path): # no need to make a dir that exists |
| 104 | + os.makedirs(path) |
| 105 | + elif os.path.isfile(path): # if there is a file there ditch it |
| 106 | + os.remove(path) |
| 107 | + del self.files[path] |
| 108 | + os.makedir(path) |
| 109 | + |
| 110 | + # recursively list files on dropbox |
| 111 | + def _listfiles(self, client, path = ''): |
| 112 | + meta = client.files_list_folder(path, recursive=True) |
| 113 | + filelist = [] |
| 114 | + filelist += meta.entries |
| 115 | + while meta.has_more: |
| 116 | + meta = client.files_list_folder_continue(meta.cursor) |
| 117 | + filelist += meta.entries |
| 118 | + |
| 119 | + filelist = [i for i in filelist if type(i) == dropbox.files.FileMetadata] |
| 120 | + return filelist |
| 121 | + |
| 122 | + def download_all(self, client, path = '/'): |
| 123 | + filelist = self._listfiles(client) |
| 124 | + for file in filelist: |
| 125 | + self.download(client, file.path_display[1:]) # trim root slash |
| 126 | + |
| 127 | + def check_state(self, client, path): |
| 128 | + # lets see if we've seen it before |
| 129 | + if path not in self.local_files: |
| 130 | + # upload it! |
| 131 | + self.upload(client, path) |
| 132 | + elif os.path.getmtime(path) > self.local_files[path]['modified']: |
| 133 | + # newer file than last sync |
| 134 | + self.upload(client, path) |
| 135 | + else: |
| 136 | + pass # looks like everything is good |
| 137 | + |
| 138 | +def loadstate(): |
| 139 | + fyle = open(STATE_FILE,'rb') |
| 140 | + state = pickle.load(fyle) |
| 141 | + fyle.close() |
| 142 | + |
| 143 | + return state |
| 144 | + |
| 145 | +def savestate(state): |
| 146 | + fyle = open(STATE_FILE,'wb') |
| 147 | + pickle.dump(state,fyle) |
| 148 | + fyle.close() |
| 149 | + |
| 150 | +if __name__ == '__main__': |
| 151 | + console.show_activity() |
| 152 | + |
| 153 | + print(""" |
| 154 | +**************************************** |
| 155 | +* Dropbox File Syncronization * |
| 156 | +****************************************""") |
| 157 | + |
| 158 | + client = dropboxloginv2.get_client() |
| 159 | + print('\nLoading local state') |
| 160 | + # lets see if we can unpickle |
| 161 | + try: |
| 162 | + state = loadstate() |
| 163 | + except: |
| 164 | + print('\nCannot find state file. ***Making new local state***') |
| 165 | + # Aaaah, we have nothing, probably first run |
| 166 | + state = dropbox_state() |
| 167 | + |
| 168 | + print('\nDownloading everything from Dropbox') |
| 169 | + # no way to check what we have locally is newer, gratuitous dl |
| 170 | + state.download_all(client) |
| 171 | + |
| 172 | + print('\nUpdating state from Dropbox') |
| 173 | + state.execute_delta(client) |
| 174 | + |
| 175 | + print('\nChecking for new or updated local files') |
| 176 | + # back to business, lets see if there is anything new or changed localy |
| 177 | + filelist = [] |
| 178 | + for root, dirnames, filenames in os.walk('.'): |
| 179 | + for filename in filenames: |
| 180 | + if filename != STATE_FILE: |
| 181 | + filelist.append( os.path.join(root, filename)[2:]) |
| 182 | + |
| 183 | + for file in filelist: |
| 184 | + state.check_state(client,file) |
| 185 | + |
| 186 | + print('\nChecking for deleted local files') |
| 187 | + old_list = list(state.local_files.keys()) |
| 188 | + for file in old_list: |
| 189 | + if file not in filelist: |
| 190 | + state.delete(client, file) |
| 191 | + |
| 192 | + print('\nSaving local state') |
| 193 | + savestate(state) |
| 194 | + |
| 195 | + print('\nSync complete') |
| 196 | + console.hide_activity() |
| 197 | + |
| 198 | + print('\nReload file') |
| 199 | + if editor.get_path(): |
| 200 | + editor.open_file(editor.get_path()) |
0 commit comments