-
-
Save KainokiKaede/9244241 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! python2 | |
# APN file local installer | |
# Creates local HTTP server to serve APN file. | |
# Place APN file in the same directory of this script. | |
# If "address already in use" shown, re-run the script. | |
# | |
# Based on: File Transfer for Pythonista | |
# 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 | |
from BaseHTTPServer import BaseHTTPRequestHandler | |
import urlparse | |
import urllib | |
import cgi | |
import editor | |
import console | |
from socket import gethostname | |
import os | |
from cStringIO import StringIO | |
import webbrowser | |
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('.') # Changed from original. | |
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] in ['.py', '.mobileconfig']: # Changed from original. | |
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 | |
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://localhost:8080' # Changed from original. | |
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.' | |
webbrowser.get('safari').open(URL) # Changed from original. | |
server.serve_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment