Skip to content

Instantly share code, notes, and snippets.

@eminarcissus
Forked from omz/FileTransfer.py
Last active April 4, 2016 13:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eminarcissus/8e56a7fe6c348348833291f6f2dd3a0b to your computer and use it in GitHub Desktop.
Save eminarcissus/8e56a7fe6c348348833291f6f2dd3a0b to your computer and use it in GitHub Desktop.
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