Skip to content

Instantly share code, notes, and snippets.

@encela95dus
Last active February 1, 2021 03:22
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save encela95dus/67fd65aec0c25336ac8e70153ebcf7eb to your computer and use it in GitHub Desktop.
Save encela95dus/67fd65aec0c25336ac8e70153ebcf7eb to your computer and use it in GitHub Desktop.
Dropbox File Picker V2.py
#!python3
#original code https://gist.github.com/omz/fb180c58c94526e2c40b
#bosco added changes dropbox 2 functionality
#minor edits done to run in python3
#see forum post https://forum.omz-software.com/topic/4425/dropbox-file-picker-needs-update
# 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
import functools
import json
def list_folder(folder_path='/'):
headers = {'Authorization': 'Bearer %s' % (TOKEN,),'Content-Type': 'application/json' }
if folder_path == '/': folder_path = ''
data = {'path':folder_path}
r = requests.post('https://api.dropboxapi.com/2/files/list_folder', headers=headers, data=json.dumps(data))
result = r.json()
return result.get('entries', None)
def download_file(path, dest_filename, progress=None):
data = {'path':path}
headers = {'Authorization': 'Bearer %s' % (TOKEN,),'Dropbox-API-Arg': json.dumps(data)}
url = 'https://content.dropboxapi.com/2/files/download'
r = requests.post(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 = int(r.headers.get('Content-Length', 0))
bytes_written = 0
canceled = False
with open(dest_path, 'wb') 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_display')
name = os.path.split(path)[1]
if name.startswith('.'):
continue
is_dir = True if info.get('.tag') == 'folder' else 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_display']}
items.append(item)
def cmp(a, b):
return (a > b) - (a < b )
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(key=functools.cmp_to_key(c))
self.tableview.data_source.items = items
self.status_label.hidden = True
self.name = self.path
root_view = DropboxView()
root_view.present('fullscreen')
root_view.load_folder()
@encela95dus
Copy link
Author

Line 154 indentation done peoperly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment