omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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

    Pythonista
    4
    18
    8867
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ?
      A Former User last edited by

      @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()
      ######
      
      1 Reply Last reply Reply Quote 0
      • ?
        A Former User last edited by

        @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()')
        		######
        
        
        1 Reply Last reply Reply Quote 0
        • ?
          A Former User last edited by

          @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.

          1 Reply Last reply Reply Quote 0
          • techteej
            techteej last edited by

            @tony Yes, please. As of right now when I press take photo or video it just crashes.

            1 Reply Last reply Reply Quote 0
            • ccc
              ccc last edited by

              @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.

              1 Reply Last reply Reply Quote 0
              • ?
                A Former User last edited by

                @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()
                
                1 Reply Last reply Reply Quote 0
                • techteej
                  techteej last edited by

                  @tony This still crashes Pythonista.

                  1 Reply Last reply Reply Quote 0
                  • ?
                    A Former User last edited by

                    @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!)

                    1 Reply Last reply Reply Quote 0
                    • ccc
                      ccc last edited by

                      I am struggling to understand this code. get_unused_filename() and do_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"?

                      1 Reply Last reply Reply Quote 0
                      • ?
                        A Former User last edited by

                        @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.

                        1 Reply Last reply Reply Quote 0
                        • ccc
                          ccc last edited by

                          So when you click "Use Video" does do_Post() get called?

                          1 Reply Last reply Reply Quote 0
                          • ?
                            A Former User last edited by

                            @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.

                            1 Reply Last reply Reply Quote 0
                            • ccc
                              ccc last edited by

                              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?

                              1 Reply Last reply Reply Quote 0
                              • ?
                                A Former User last edited by

                                @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.

                                1 Reply Last reply Reply Quote 0
                                • ccc
                                  ccc last edited by

                                  I just submitted a pull request with the two ids added.

                                  1 Reply Last reply Reply Quote 0
                                  • First post
                                    Last post
                                  Powered by NodeBB Forums | Contributors