Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Dropbox File Picker.py
# IMPORTANT SETUP INSTRUCTIONS:
#
# 1. Go to http://www.dropbox.com/developers/apps (log in if necessary)
# 2. Select "Create App"
# 3. Select the following settings:
# * "Dropbox API app"
# * "Files and datastores"
# * "(No) My app needs access to files already on Dropbox"
# * "All file types"
# * (Choose any app name)
# 4. On the newly-created app's summary page, click the "Generate"
# button under "Generated access token"
# 5. Copy the generated token (a long string of gibberish) and
# paste it below (replace YOUR_TOKEN_HERE).
# 6. (optional) Open the "wrench" (actions) menu in Pythonista and add
# this script, so you can run it from everywhere.
# Notes:
# All selected files are downloaded into the root folder of the Pythonista
# script library. If a file with the same name already exists, a numeric
# suffix is appended automatically.
TOKEN = 'YOUR_TOKEN_HERE'
import requests
import urllib
import os
import ui
def list_folder(folder_path='/'):
headers = {'Authorization': 'Bearer %s' % (TOKEN,)}
r = requests.get('https://api.dropbox.com/1/metadata/dropbox/%s?list=true' % (urllib.quote(folder_path.encode('utf-8')),), headers=headers)
result = r.json()
return result.get('contents', None)
def download_file(path, dest_filename, progress=None):
headers = {'Authorization': 'Bearer %s' % (TOKEN,)}
url_path = urllib.quote(path.encode('utf-8'))
url = 'https://api-content.dropbox.com/1/files/dropbox/%s' % (url_path,)
r = requests.get(url, stream=True, headers=headers)
dest_path = os.path.join(os.path.expanduser('~/Documents'), dest_filename)
i = 1
while os.path.exists(dest_path):
base, ext = os.path.splitext(dest_filename)
dest_path = os.path.join(os.path.expanduser('~/Documents'), base + '-' + str(i) + ext)
i += 1
size = r.headers.get('Content-Length', 0)
bytes_written = 0
canceled = False
with open(dest_path, 'w') as f:
for chunk in r.iter_content(1024*10):
f.write(chunk)
bytes_written += len(chunk)
if size > 0 and callable(progress):
p = float(bytes_written) / float(size)
should_cancel = progress(p)
if should_cancel:
canceled = True
break
if canceled:
os.remove(dest_path)
class DropboxView (ui.View):
def __init__(self, path='/'):
tv = ui.TableView()
tv.frame = self.bounds
tv.flex = 'WH'
ds = ui.ListDataSource([])
ds.action = self.item_selected
tv.data_source = ds
tv.delegate = ds
self.tableview = tv
self.add_subview(self.tableview)
self.name = 'Dropbox'
label = ui.Label(frame=self.bounds)
label.flex = 'WH'
label.background_color = (1, 1, 1, 0.95)
label.text = 'Loading...'
label.touch_enabled = True
label.alignment = ui.ALIGN_CENTER
self.path = path
self.add_subview(label)
self.status_label = label
self.canceled = False
def will_close(self):
self.canceled = True
def item_selected(self, sender):
item = sender.items[sender.selected_row]
if item.get('is_dir', False):
self.status_label.text = 'Loading Folder...'
self.status_label.hidden = False
self.path = item['path']
self.load_folder()
elif item.get('up', False):
self.status_label.text = 'Loading Folder...'
self.status_label.hidden = False
self.path = os.path.split(self.path)[0]
self.load_folder()
else:
path = item.get('path')
self.download_file(path)
@ui.in_background
def download_file(self, path):
self.status_label.text = 'Downloading %s...' % (path,)
self.status_label.hidden = False
download_file(path, os.path.split(path)[1], self.download_progress)
self.status_label.hidden = True
def download_progress(self, p):
self.status_label.text = '%i %% Downloaded...' % (p*100,)
return self.canceled
@ui.in_background
def load_folder(self):
infos = list_folder(self.path)
items = []
if self.path != '/':
items.append({'title': '..', 'image': 'ionicons-arrow-up-c-32', 'up': True})
if not infos:
import console
console.alert('Error', 'Could not load folder. Please check if you entered the access token correctly.', 'OK', hide_cancel_button=True)
self.status_label.hidden = True
return
for info in infos:
path = info.get('path')
name = os.path.split(path)[1]
if name.startswith('.'):
continue
is_dir = info.get('is_dir', False)
item = {'title': name, 'image': 'ionicons-folder-32' if is_dir else 'ionicons-ios7-download-outline-32', 'accessory_type': 'disclosure_indicator' if is_dir else 'none', 'is_dir': is_dir, 'path': info['path']}
items.append(item)
def c(o1, o2):
u_cmp = -1 * cmp(o1.get('up', False), o2.get('up', False))
if u_cmp != 0:
return u_cmp
d_cmp = -1 * cmp(o1.get('is_dir', False), o2.get('is_dir', False))
if d_cmp == 0:
return cmp(o1.get('path', '').lower(), o2.get('path', '').lower())
return d_cmp
items.sort(cmp=c)
self.tableview.data_source.items = items
self.status_label.hidden = True
self.name = self.path
root_view = DropboxView()
root_view.frame = (0, 0, 500, 500)
root_view.present('sheet')
root_view.load_folder()
@Gerzer

This comment has been minimized.

Copy link

Gerzer commented Jun 21, 2014

Awesome, thanks!

@skulrik

This comment has been minimized.

Copy link

skulrik commented Nov 11, 2014

Works great, thanks !

@cclauss

This comment has been minimized.

Copy link

cclauss commented Jun 6, 2015

DropboxView.width and DropboxView.height too small in current beta.

@jjarava

This comment has been minimized.

Copy link

jjarava commented Sep 19, 2015

Hi, I'm trying to get it to run on iPad Air, iOS v9 and latest beta and the "popup" I get is so tiny there's no way to pick any file. Any way to fix?

@xiushu53

This comment has been minimized.

Copy link

xiushu53 commented Nov 4, 2015

Great!!! Thanks!!!!

@yunweiyuan

This comment has been minimized.

Copy link

yunweiyuan commented Jun 16, 2016

Brilliant! Now is coming Pythonista 3! Wish there is a python 3 version

@joeld1

This comment has been minimized.

Copy link

joeld1 commented Jul 11, 2016

Hi everyone! I'm a newbie here and this app. I think this file only works for Pythonista and not Pythonista 3. I added the following lines of code to make it work on Pythonista 3

import urllib.request, urllib.parse, urllib.error

and the following functions that weren't added or converted with 2to3

def cmp(a, b):
    return (a > b) - (a < b)

def cmp_to_key(mycmp):
        class K:
            def __init__(self, obj, *args):
                self.obj = obj
            def __lt__(self, other):
                return mycmp(self.obj, other.obj) < 0
            def __gt__(self, other):
                return mycmp(self.obj, other.obj) > 0
            def __eq__(self, other):
                return mycmp(self.obj, other.obj) == 0
            def __le__(self, other):
                return mycmp(self.obj, other.obj) <= 0
            def __ge__(self, other):
                return mycmp(self.obj, other.obj) >= 0
            def __ne__(self, other):
                return mycmp(self.obj, other.obj) != 0
        return K

and

making this substitution

items.sort(key=cmp_to_key(c))

@brenankeller

This comment has been minimized.

Copy link

brenankeller commented Oct 22, 2016

I've updated this script for Pythonista 3 and Python 3:

https://gist.github.com/c5d5de505fa20d93702eeead1fbd0be1

@GreatCaesar

This comment has been minimized.

Copy link

GreatCaesar commented May 15, 2017

Try dropboxImport.py if your running Pythonista3 ( See link above ) on your iPhone / iPad. It solved the Pythonista3 external file transfer problem on my iPhone 7. DropBox turned out to be a great middle man for the job. I used iFiles 2 to migrate dropboxImport.py over to the iPhone 7. From there I had to import it to a Notes file. After that I was able to copy and paste it into a Pythonista3 script file. The script ran flawlessly. It works stellar after you get the DropBox App Token set up properly. Now that I can call dropboxImport.py within Pythonista3, all I need is DropBox to import Python scripts! Fantastic and Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.