7

Dropbox rest api, in function metatada has a parameter named "hash" https://www.dropbox.com/developers/reference/api#metadata

Can I calculate this hash locally without call any remote api rest function?

I need know this value to reduce upload bandwidth.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Victor Sanchez
  • 583
  • 9
  • 28

5 Answers5

6

https://www.dropbox.com/developers/reference/content-hash explains how Dropbox computes their file hashes. A Python implementation of this is below:

import hashlib
import math
import os

DROPBOX_HASH_CHUNK_SIZE = 4*1024*1024

def compute_dropbox_hash(filename):
    file_size = os.stat(filename).st_size
    with open(filename, 'rb') as f:
        block_hashes = b''
        while True:
            chunk = f.read(DROPBOX_HASH_CHUNK_SIZE)
            if not chunk:
                break
            block_hashes += hashlib.sha256(chunk).digest()
        return hashlib.sha256(block_hashes).hexdigest()
SMX
  • 1,372
  • 15
  • 14
5

The "hash" parameter on the metadata call isn't actually the hash of the file, but a hash of the metadata. It's purpose is to save you having to re-download the metadata in your request if it hasn't changed by supplying it during the metadata request. It is not intended to be used as a file hash.

Unfortunately I don't see any way via the Dropbox API to get a hash of the file itself. I think your best bet for reducing your upload bandwidth would be to keep track of the hash's of your files locally and detect if they have changed when determining whether to upload them. Depending on your system you also likely want to keep track of the "rev" (revision) value returned on the metadata request so you can tell whether the version on Dropbox itself has changed.

Ben Zittlau
  • 2,345
  • 1
  • 21
  • 30
  • Thanks. He feared what you have told me. I'll have to save url-local_sha1-server_rev :( – Victor Sanchez Oct 23 '12 at 06:48
  • 1
    Doh! I just hit this problem myself. I'm really surprised the Dropbox API doesn't provide a SHA1 sum or something for the files in the metadata so you don't have to keep track of this manually. – rb- Aug 26 '14 at 17:08
1

This won't directly answer your question, but is meant more as a workaround; The dropbox sdk gives a simple updown.py example that uses file size and modification time to check the currency of a file.

an abbreviated example taken from updown.py:

dbx = dropbox.Dropbox(api_token)
...
# returns a dictionary of name: FileMetaData
listing = list_folder(dbx, folder, subfolder)
# name is the name of the file
md = listing[name]
# fullname is the path of the local file
mtime = os.path.getmtime(fullname)
mtime_dt = datetime.datetime(*time.gmtime(mtime)[:6])
size = os.path.getsize(fullname)
if (isinstance(md, dropbox.files.FileMetadata) and mtime_dt == md.client_modified and size == md.size):
    print(name, 'is already synced [stats match]')
user2682863
  • 3,097
  • 1
  • 24
  • 38
1

The rclone go program from https://rclone.org has exactly what you want:

rclone hashsum dropbox localfile

rclone hashsum dropbox localdir

It can't take more than one path argument but I suspect that's something you can work with...

t0|todd@tlaptop/p8 ~/tmp|295$ echo "Hello, World!" > dropbox-hash-demo/hello.txt
t0|todd@tlaptop/p8 ~/tmp|296$ rclone copy dropbox-hash-demo/hello.txt dropbox-ttf:demo
t0|todd@tlaptop/p8 ~/tmp|297$ rclone hashsum dropbox dropbox-hash-demo 
aa4aeabf82d0f32ed81807b2ddbb48e6d3bf58c7598a835651895e5ecb282e77  hello.txt
t0|todd@tlaptop/p8 ~/tmp|298$ rclone hashsum dropbox dropbox-ttf:demo
aa4aeabf82d0f32ed81807b2ddbb48e6d3bf58c7598a835651895e5ecb282e77  hello.txt
toddf
  • 11
  • 1
0

As far as I am concerned, No you can't. The only way is using Dropbox API which is explained here.