Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
File Transfer script for Pythonista (iOS)
# File Transfer for Pythonista
# ============================
# This script allows you to transfer Python files from
# and to Pythonista via local Wifi.
# It starts a basic HTTP server that you can access
# as a web page from your browser.
# When you upload a file that already exists, it is
# renamed automatically.
# From Pythonista's settings, you can add this script
# to the actions menu of the editor for quick access.
#
# Get Pythonista for iOS here:
# http://omz-software.com/pythonista
#Changes
#Added zip upload funcitonality
from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import zipfile
import urllib
import cgi
import editor
import console
from socket import gethostname
import os
from cStringIO import StringIO
TEMPLATE = ('<!DOCTYPE html><html><head>' +
'<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/'+
'css/bootstrap-combined.min.css" rel="stylesheet"></head><body>' +
'<div class="navbar"><div class="navbar-inner">' +
'<a class="brand" href="#">Pythonista File Transfer</a>' +
'</div></div><div class="container">' +
'<h2>Upload File</h2>{{ALERT}}'
'<p><form action="/" method="POST" enctype="multipart/form-data">' +
'<div class="form-actions">' +
'<input type="file" name="file"></input><br/><br/>' +
'<button type="submit" class="btn btn-primary">Upload</button>' +
'</div></form></p><hr/><h2>Download Files</h2>' +
'{{FILES}}</div></body></html>')
class TransferRequestHandler(BaseHTTPRequestHandler):
def get_unused_filename(self, filename):
if not os.path.exists(filename):
return filename
basename, ext = os.path.splitext(filename)
suffix_n = 1
while True:
alt_name = basename + '-' + str(suffix_n) + ext
if not os.path.exists(alt_name):
return alt_name
suffix_n += 1
def get_html_file_list(self):
buffer = StringIO()
buffer.write('<ul>')
root_dir = os.path.expanduser('~/Documents')
files = []
for dn, dc, filenames in os.walk(root_dir):
for fn in filenames:
rel_dir = os.path.relpath(dn, root_dir)
if rel_dir != '.':
rel_file = os.path.join(rel_dir, fn)
else:
rel_file = fn
files.append(rel_file)
for filename in files:
if os.path.splitext(filename)[1] == '.py':
buffer.write('<li><a href="%s">%s</a></li>' % (filename, filename))
buffer.write('</ul>')
return buffer.getvalue()
def do_GET(self):
parsed_path = urlparse.urlparse(self.path)
path = parsed_path.path
if path == '/':
html = TEMPLATE
html = html.replace('{{ALERT}}', '')
html = html.replace('{{FILES}}', self.get_html_file_list())
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(html)
return
file_path = urllib.unquote(path)[1:]
if os.path.isfile(file_path):
self.send_response(200)
self.send_header('Content-Type', 'application/x-python')
self.send_header('Content-Disposition',
'attachment; filename=%s' % file_path)
self.end_headers()
with open(file_path, 'r') as f:
data = f.read()
self.wfile.write(data)
else:
html = TEMPLATE
html = html.replace('{{ALERT}}',
'<div class="alert alert-error">File not found</div>')
html = html.replace('{{FILES}}', self.get_html_file_list())
self.send_response(404)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(html)
def do_POST(self):
form = cgi.FieldStorage(fp=self.rfile, headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type']})
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
field_item = form['file']
uploaded_filename = None
dest_filename = None
file_data = field_item.file.read()
file_len = len(file_data)
uploaded_filename = field_item.filename
if uploaded_filename.endswith('.zip'):
with zipfile.ZipFile(StringIO(file_data)) as zipread:
for name in zipread.namelist():
outpath = os.path.abspath(os.path.dirname(__file__))
zipread.extract(name, outpath)
else:
dest_filename = self.get_unused_filename(uploaded_filename)
with open(dest_filename, 'w') as f:
f.write(file_data)
editor.reload_files()
del file_data
html = TEMPLATE
if uploaded_filename != dest_filename:
message = '%s uploaded (renamed to %s).' % (uploaded_filename,
dest_filename)
else:
message = '%s uploaded.' % (uploaded_filename)
html = html.replace('{{ALERT}}',
'<div class="alert alert-success">%s</div>' % (message))
html = html.replace('{{FILES}}', self.get_html_file_list())
self.wfile.write(html)
if __name__ == '__main__':
console.clear()
from BaseHTTPServer import HTTPServer
server = HTTPServer(('', 8080), TransferRequestHandler)
URL = 'http://%s.local:8080' % gethostname()
print 'Open this page in your browser:'
console.set_font('Helvetica-Bold', 30)
print URL
console.set_font()
print 'Tap the stop button when you\'re done.'
server.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment