Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Button freezes Pythonista
-
@techteej That's good progress you've made, well done. I would change it a little... the extra def in the class will suppress the log messages... randomising the port will let it run multiple times without the "port in use" error... the ui.delay is a trick that seems to help (I think it's to do with the threading issue and maybe cedes control to let other things catch up). Of course you can go on to adapt the HTML to give a better title and button names. You might even be able to automate the upload using
evaluate_javascript
on your WebView.import speech, ui from BaseHTTPServer import BaseHTTPRequestHandler import urlparse import urllib import cgi import editor import console from socket import gethostname import os, webbrowser from cStringIO import StringIO lang = 'en-GB' speed = 0.1 def brit_switch_action(sender): global lang lang = 'en-GB' if sender.value else 'en-US' if sender.value: v['au_switch'].enabled = False else: v['au_switch'].enabled = True def aus_switch_action(sender): global lang lang = 'en-AU' if sender.value else 'en-US' if sender.value: v['brit_switch'].enabled = False else: v['brit_switch'].enabled = True def slider_action(sender): global speed speed = v['slider1'].value def button_speak_action(sender): global speed text = v['user_text'].text if text == 'Enter your text here': speech.say('Please tell me something to say.', lang, speed) else: speech.say(text, lang, speed) TEMPLATE = ('<!DOCTYPE html><html><head>' + '<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/3.2.0/'+ 'css/bootstrap-combined.min.css" rel="stylesheet"></head><body>' + '<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/>' + '</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 do_GET(self): parsed_path = urlparse.urlparse(self.path) path = parsed_path.path if path == '/': html = TEMPLATE html = html.replace('{{ALERT}}', '') 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: 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) ###### def log_message(self, format, *args): pass ###### def record_action(sender): ###### sender.superview['webview1'].hidden = False ###### #console.clear() #from BaseHTTPServer import HTTPServer #server = HTTPServer(('', 8080), TransferRequestHandler) #URL = 'http://localhost:8080' #webbrowser.open('http://localhost:8080', stop_when_done = True) #webview = v['webview1'] #webview.load_url('http://localhost:8080') #server.serve_forever() v = ui.load_view('speech') v['au_switch'].enabled = False v['au_switch'].value = False speech.say('Greetings!', lang, 0.1) v.present(style='full_screen', hide_title_bar=True) from BaseHTTPServer import HTTPServer ###### server = HTTPServer(('', 0), TransferRequestHandler) def f(): pass gport = server.server_address[1] ui.delay(f,0) webview = v['webview1'] webview.hidden = True webview.load_url('http://localhost:' + str(gport)) server.serve_forever() ######
-
@techteej Here's some snippets to get you going with automating the upload... give the file button an id in the HTML... then you can leave the WebView hidden and click the file button automatically from your microphone button. Another nice thing to do would be to make the app close down smoothly by stopping the server... you could do that by subclassing the View and stopping it in the will close.
''' '<input id="file" type="file" name="file"></input><br/><br/>' + ''' def record_action(sender): ###### #sender.superview['webview1'].hidden = False sender.superview['webview1'].evaluate_javascript('document.getElementById("file").click()') ######
-
@techteej I've confirmed that it's possible to complete the automation by checking for the video capture to complete and automatically clicking the upload button when it does... all with the WebView hidden. I'll post the code here if you want.
-
@tony Yes, please. As of right now when I press take photo or video it just crashes.
-
@tony, instead of pasting your code here, it would be best if you edited the program at https://github.com/tjferry14/Fun-Pythonista-Tools/blob/master/speech.py and the submitted a "pull request". That way we can all be looking at the same version.
-
@ccc I'll maybe let techteej to do that when he's happy with his version.
@techteej Import sound (just temporarily while you're testing, the beep will confirm the script is waiting for the video file) and then give ids to the form and submit button of form and submit. Then use this in your microphone button...
sender.superview['webview1'].evaluate_javascript('document.getElementById("file").click()') def loop(): if sender.superview['webview1'].evaluate_javascript('document.forms["form"]["file"].value') == '': sound.play_effect('Beep') ui.delay(loop,2) else: sender.superview['webview1'].evaluate_javascript('document.getElementById("submit").click()') loop()
-
@tony This still crashes Pythonista.
-
@techteej It works here on iPad mini (original). If it doesn't work for you (from a clean start of Pythonista) then it may be to do with the threading issue. It's only a guess why the ui.delay of an empty function for zero time helps, all we can say for sure is 'it does because it does' on one device anyway.
When Pythonista gets into the threading issue... one run of a script is not necessarily the same as a second... so it's worth to try from a clean start of Pythonista, (if you haven't already). Otherwise I don't know what to say except it must be frustrating (been there!)
-
I am struggling to understand this code.
get_unused_filename()
anddo_POST()
never get called.do_GET()
only gets called once with self.path set to '/'.What is supposed to happen after the user clicks "Use Video"?
-
@ccc That part is basically @omz's file transfer script. The flow goes...
First GET to the server is for the HTML.
The POST will happen when the video file is being submitted... maybe you haven't got to that point. In turn it will call 'get unused file name' to get a free one if the name of the uploaded file is in use.
iOS will pop up a choice to take a new photo/video or choose an exiting one... any of the choices are ok, and whatever file results will be uploaded, when the user (or the JavaScript) clicks the submit button.
If you're using the JavaScript the user will never see the web page or the buttons, just the iOS pop up, which is nice and clean.
-
So when you click "Use Video" does
do_Post()
get called? -
@ccc Yes... when the user (or the JavaScript) clicks the submit button. If you're using the JavaScript the user will never see the web page or buttons, just the iOS popup, which is nice and clean.
-
When I check the code out of the repo and run it and tap the record button and select "video" and record a video and tap "Use Video" nothing happens. There is no video file stored in the local directory. The beep in the background continues every 2 seconds until Pythonista times out.
Are you using the current code in the repo? What is the name and full path of the video file that gets saved?
-
@ccc The repo is missing the step of adding ids to the form and submit button of form and submit respectively. The file is saved to the same directory as the script. For a video it's capturedvideo.MOV.
-
I just submitted a pull request with the two ids added.