Last active
September 6, 2024 01:50
-
-
Save omz/3823483 to your computer and use it in GitHub Desktop.
File Transfer script for Pythonista (iOS)
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
# 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 | |
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 | |
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() |
Very Good!
Very useful!
Hey all,
I took the original FileTransfer.py, and added a few features:
- SSL
- Basic auth
- RESTish endpoint with JSON responses
- Upload to specific directories.
- Other little things.
It can be found here:
- https://github.com/digitalrounin/pythonista-fileserver
- https://gist.github.com/digitalrounin/c533d19ce0ada4738ecf
Hope it's of some use to someone out there!
Cheers!
Hello, new user here (Github, python, pythonista). I wrote some code on python on my computer and would like to use the .py file on pythonista but can't seem to import it. It appears this code here is exactly for that purpose but can someone please explain exactly how I'm supposed to use it? Thank you.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great!