Thursday, 30 March 2023

Uploading to dropbox using the sdk

I used to move my files into a dropbox enabled folder and let them deal with the uploading but that feature has become so unreliable to be uesless to me. Instead I've written this python3 script to upload files using the dropbox sdk instead.

Downloading the dropbox python sdk is as easy as:

 pip install dropbox

 If your file is less than 150MB then dropbox.files_upload can be used, larger than that and dropbox.files_upload_session_start must be called and given a small chunk of your file, with the remaining chunks being uploaded with dropbox.files_upload_session_append and the final chunk with  dropbox.files_upload_session_finish.  

What a faff! So this script will do it all for you and print out a nice progress bar too :) 

 
This has been sped up a lot

Call with upload_to_dropbox(file_path, target_path) where file_path is the file you want to upload and target_path is the dropbox location (including the uploaded file name).
It will also return a True value if the upload was successful.

I work out the dropbox location by finding the folder I want in a browser and getting the url
e.g. "https://www.dropbox.com/home/Projects/Groobles%20Files"
Then remove the dropbox.com/home bit and replace %20s with the spaces they represent, then add the file name
e.g. "/Projects/Groobles Files/uploadedfile.zip"

The script:

import os
import math
import dropbox

## Token required to access dropbox
ACCESS_TOKEN="ABCDEFGHIJKLMNOP1234567890SECRETTOKEN0000"

class UploadProgressBar:    
    def __init__(self, file_size, bar_length=20):
        self.file_size = file_size
        self.bar_length = bar_length
        self.progress = 0
        guide_bar_string=" "
        for _ in range(bar_length):
            guide_bar_string+="_"
        print(guide_bar_string)
        print("|", end="")#start of progress bar
    def updateProgress(self, uploaded_data):
        """! Update the bars progress level.
        @param uploaded_data int - The amount of data uploaded, this will be compared to the self.file_size. (Using file.tell() can be used to collect this information)
        @note Printing anything before the progress bar is finished will ruin the look of the progress bar design
        """
        percentage = (uploaded_data / self.file_size) * self.bar_length
        new_progress = math.floor(percentage)
        
        if (new_progress > self.progress):
            newbars=""
            for _ in range(new_progress - self.progress):
                newbars += "#"
            self.progress = new_progress
            if (self.progress == self.bar_length):
                print(newbars + "|")#end of the progress bar
            else:
                print(newbars, end="", flush=True)
        

def upload_file(file_path,target_path):
    dbx = dropbox.Dropbox(ACCESS_TOKEN, timeout=900)
    with open(file_path, "rb") as f:
        file_size = os.path.getsize(file_path)
        chunk_size = 4 * 1024 * 1024
        if file_size <= chunk_size:
            print("File is smaller than 150MB, uploading to dropbox using the small file method...")
            try:
                result = dbx.files_upload(f.read(), target_path, mode=dropbox.files.WriteMode.overwrite)
            except dropbox.exceptions.ApiError as err:
                print("\nError:", err)
                return False
            else:
                print(result.name , "uploaded successfully to ", result.path_display)
                return True
        else:
            print("File is larger than 150MB, uploading to dropbox using large file method...")
            try:
                print("Starting upload session...")
                progbar = UploadProgressBar(os.path.getsize(file_path), 20);
                progbar.updateProgress(0);
                upload_session_start_result = dbx.files_upload_session_start(f.read(chunk_size))
                cursor = dropbox.files.UploadSessionCursor(session_id=upload_session_start_result.session_id,offset=f.tell())
                commit = dropbox.files.CommitInfo(path=target_path, mode=dropbox.files.WriteMode.overwrite)
                while f.tell() < file_size:
                    if (file_size - f.tell()) <= chunk_size:
                        result = dbx.files_upload_session_finish(f.read(chunk_size), cursor, commit)
                        progbar.updateProgress(os.path.getsize(file_path))
                    else:
                        progbar.updateProgress(f.tell())
                        dbx.files_upload_session_append(f.read(chunk_size), cursor.session_id, cursor.offset)
                        cursor.offset = f.tell()
            except dropbox.exceptions.ApiError as err:
                print("\nError:", err)
                return False
            else:
                print(result.name , "uploaded successfully to", result.path_display)
                return True
    return False #we shouldn't reach here but we might if there's an issue on dropbox's end




  Azure Trusted Signing Signtool Error SignTool Error: An unexpected internal error has occurred. Error information: "Error: SignerSign...