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.
Webview and Reader mode
-
Is there a way to construct a webview in reader mode when it is available?
-
@ihf, according to this stackoverflow answer, neither UIWebView or WKWebView have such a mode built in. SKSafariViewController has it, naturally, but I do not know if it is usable in Pythonista.
As a quick fix, they suggest using a web service to scrape the readable content for you. I.e. load this url to the webview: http://www.readability.com/m?url=YOUR_URL_HERE
I guess you could also load the page first with e.g. requests, then get just the text from the page with BeautifulSoup, and present that.
-
@mikael Thanks! Unfortunately, Readability is no longer available and the browser's Reader view/mode produces much prettier output than what I am likely to get by merely parsing text (no images, etc.)
-
-
Apparently there are some ways to get Apple's version of readability on the desktop:
https://github.com/amumu/safari-reader-js
Should be possible, I think, to execute this in a webview, or @mikael's JavaScript framework, though I have not tried.
-
My goal is to permit the RSS Reader script to load articles in Reader mode when possible.
-
Have you tried executing the JavaScript in a webview?
-
@jonb I tried this:
(reader.js is a string with the js code)
wv = ui.Webview()
wv.load_url(‘https://www.nytimes.com/2019/01/29/climate/global-warming-extreme-weather.html’)
wv.eval_js(reader.js)
wv.present()Obviously, missing something...
-
@ihf I think that between load_url and eval.... you need to wait the page is loaded
web.load_url(....) # wait for documentState to start loading, for i in range(10): if web.eval_js('document.readyState')!='complete': break time.sleep(1) # ...then wait for it to complete while web.eval_js('document.readyState')!='complete': time.sleep(1)
My web view is a subview of an ui.View already presented
-
@ihf or use webview.delegate (see help) to check if url did finish loading
-
@ihf Try
import ui class MyWebView(ui.View): def __init__(self,url): self.width, self.height = ui.get_screen_size() self.web = ui.WebView(frame=self.bounds) self.web.scales_page_to_fit = True self.web.delegate = self self.web.load_url(url) self.add_subview(self.web) def webview_should_start_load(self,webview, url, nav_type): print('should start:{}'.format(url)) return True def webview_did_start_load(self,webview): print('did start') return True def webview_did_finish_load(self, webview): print('did finish') pass def webview_did_fail_load(self, webview, error_code, error_msg): print('did fail {} {}'.format(error_code,error_msg)) pass MyWeb = MyWebView('https://www.nytimes.com/2019/01/29/climate/global-warming-extreme-weather.html') MyWeb.present('full_screen')
-
@cvp I understand that I must wait for the page to load but my testing has been in the console so I would have thought that by the time I type the eval_js, the page has loaded. No?
-
@ihf obviously.
Did you see that your site loads several pages -
Yes, indeed. I just want to see if this js code will, in fact, implement a reading mode. What I type in the console is:
import ui
with open ("safari-reader.js", "r") as myfile:
data=myfile.readlines()
data=str(data)
wv = ui.WebView()
wv.load_url('https://www.nytimes.com/2019/01/29/climate/global-warming-extreme-weather.html')
wv.eval_js(data)
wv.present()I wait a bit after the load_urI and end up with the unmodified webpage.
-
@ihf Not sure you can eval_js before webview is presented
Could you paste here your .js file if it is text
-
It is too long to post but I got it from @JonB post above: https://github.com/amumu/safari-reader-js
-
@ihf ok, sorry, too complex for me. I don't know almost anything about js
-
@ihf Try this, it will be ok for you, I hope
import ui from objc_util import * def safariViewControllerDidFinish_(_self, _cmd, _controller): #print('SafariViewControllerDidFinish_') SFSafariViewController = ObjCInstance(_controller) SFSafariViewController.uiview.close() methods = [safariViewControllerDidFinish_,] protocols = ['SFSafariViewControllerDelegate'] try: MySFSafariViewControllerDelegate = ObjCClass('MySFSafariViewControllerDelegate') except: MySFSafariViewControllerDelegate = create_objc_class('MySFSafariViewControllerDelegate', methods=methods, protocols=protocols) #@on_main_thread def MySFSafariViewController(url, w, h, mode='sheet', popover_location=None): uiview = ui.View() uiview.frame = (0,0,w,h) uiview.background_color = 'white' if mode == 'sheet': uiview.present('sheet',hide_title_bar=True) elif mode == 'popover': if popover_location: uiview.present('popover', hide_title_bar=True, popover_location=popover_location) else: return else: return SFSafariViewController = ObjCClass('SFSafariViewController').alloc().initWithURL_entersReaderIfAvailable_(url,True) # Use new delegate class: delegate = MySFSafariViewControllerDelegate.alloc().init() SFSafariViewController.delegate = delegate SFSafariViewController.setModalPresentationStyle_(3) SFSafariViewController.uiview = uiview # used by delegate objc_uiview = ObjCInstance(uiview) SUIViewController = ObjCClass('SUIViewController') vc = SUIViewController.viewControllerForView_(objc_uiview) vc.presentViewController_animated_completion_(SFSafariViewController, True, None) def main(): # demo code mv = ui.View() mv.background_color = 'white' mv.name = 'Test SFSafariViewController' mv.present() url = nsurl('https://www.nytimes.com/2019/01/29/climate/global-warming-extreme-weather.html') #MySFSafariViewController(url,600,500) MySFSafariViewController(url,600,500, mode ='popover', popover_location=(mv.width-40,60)) if __name__ == '__main__': main()
-
My code seems to have a problem with sheet mode, test it with popover mode.
I'm searching whyEdit: remove the @on_main_thread line.... ==> ok
-
I took a stab at the js code. With the code below I get the article part of the original page, but all attempts to get the cleaned version end in a non-helpful js error, which I do not have time to track right now.
import wkwebview import ui with open('safari-reader.js','r',encoding='utf-8') as f: safari_script = f.read() class Delegate: @ui.in_background def webview_did_finish_load(self, webview): w.eval_js('r = new ReaderArticleFinder(document); document.body.innerHTML = r.articleNode().innerHTML;') w = wkwebview.WKWebView(delegate=Delegate()) w.present() w.add_script(safari_script) w.load_url('http://blog.manbolo.com/2012/11/20/using-xcode-opengl-es-frame-capture')