def _chromium_version(): """Get the Chromium version for QtWebEngine.""" if QWebEngineProfile is None: # This should never happen return 'unavailable' profile = QWebEngineProfile() ua = profile.httpUserAgent() match = re.search(r' Chrome/([^ ]*) ', ua) if not match: log.misc.error("Could not get Chromium version from: {}".format(ua)) return 'unknown' return match.group(1)
def getProfile(self): profile=QWebEngineProfile("myProfile") profile.cachePath="/home/yyk/Desktop/cache" jsFile = constants.QTWEBCHANNELJS_FILE with open(jsFile, encoding="UTF-8") as file: js = file.read() script = QWebEngineScript(); script.setSourceCode(js) script.setName('qwebchannel.js') script.setInjectionPoint(QWebEngineScript.DocumentCreation) script.setWorldId(QWebEngineScript.MainWorld) script.setRunsOnSubFrames(False) profile.scripts().insert(script) return profile
def _init_profiles(): """Init the two used QWebEngineProfiles.""" global default_profile, private_profile default_profile = QWebEngineProfile.defaultProfile() default_profile.setCachePath( os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_stylesheet(default_profile) _set_user_agent(default_profile) private_profile = QWebEngineProfile() assert private_profile.isOffTheRecord() _init_stylesheet(private_profile) _set_user_agent(private_profile)
def _chromium_version(): """Get the Chromium version for QtWebEngine. This can also be checked by looking at this file with the right Qt tag: http://code.qt.io/cgit/qt/qtwebengine.git/tree/tools/scripts/version_resolver.py#n41 Quick reference: Qt 5.7: Chromium 49 49.0.2623.111 (2016-03-31) 5.7.1: Security fixes up to 54.0.2840.87 (2016-11-01) Qt 5.8: Chromium 53 53.0.2785.148 (2016-08-31) 5.8.0: Security fixes up to 55.0.2883.75 (2016-12-01) Qt 5.9: Chromium 56 (LTS) 56.0.2924.122 (2017-01-25) 5.9.7: Security fixes up to 69.0.3497.113 (2018-09-27) Qt 5.10: Chromium 61 61.0.3163.140 (2017-09-05) 5.10.1: Security fixes up to 64.0.3282.140 (2018-02-01) Qt 5.11: Chromium 65 65.0.3325.151 (.1: .230) (2018-03-06) 5.11.3: Security fixes up to 70.0.3538.102 (2018-11-09) Qt 5.12: Chromium 69 (LTS) 69.0.3497.113 (2018-09-27) 5.12.1: Security fixes up to 71.0.3578.94 (2018-12-14) 5.12.2: Security fixes up to 72.0.3626.96 (2019-02-06) Qt 5.13: (in development) Chromium 71 merged, 73 in review. Also see https://www.chromium.org/developers/calendar and https://chromereleases.googleblog.com/ """ if QWebEngineProfile is None: # This should never happen return 'unavailable' profile = QWebEngineProfile() ua = profile.httpUserAgent() match = re.search(r' Chrome/([^ ]*) ', ua) if not match: log.misc.error("Could not get Chromium version from: {}".format(ua)) return 'unknown' return match.group(1)
def _set(self, value, settings=None): utils.unused(settings) setter = getattr(QWebEngineProfile.defaultProfile(), self._setter) setter( QWebEngineProfile.AllowPersistentCookies if value else QWebEngineProfile.NoPersistentCookies )
def init(): """Initialize QtWebEngine-specific modules.""" log.init.debug("Initializing request interceptor...") host_blocker = objreg.get('host-blocker') req_interceptor = interceptor.RequestInterceptor( host_blocker, parent=QApplication.instance()) req_interceptor.install(QWebEngineProfile.defaultProfile())
def _init_profiles(): """Init the two used QWebEngineProfiles.""" global default_profile, private_profile default_profile = QWebEngineProfile.defaultProfile() default_profile.setter = ProfileSetter(default_profile) default_profile.setCachePath( os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) default_profile.setter.init_profile() default_profile.setter.set_persistent_cookie_policy() private_profile = QWebEngineProfile() private_profile.setter = ProfileSetter(private_profile) assert private_profile.isOffTheRecord() private_profile.setter.init_profile()
def _set(self, value, settings=None): if settings is not None: raise ValueError("'settings' may not be set with " "PersistentCookiePolicy!") setter = getattr(QWebEngineProfile.defaultProfile(), self._setter) setter( QWebEngineProfile.AllowPersistentCookies if value else QWebEngineProfile.NoPersistentCookies )
def _init_profiles(): """Init the two used QWebEngineProfiles.""" global default_profile, private_profile default_profile = QWebEngineProfile.defaultProfile() default_profile.setCachePath( os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_stylesheet(default_profile) _set_http_headers(default_profile) private_profile = QWebEngineProfile() assert private_profile.isOffTheRecord() _init_stylesheet(private_profile) _set_http_headers(private_profile) if qtutils.version_check('5.8'): default_profile.setSpellCheckEnabled(True) private_profile.setSpellCheckEnabled(True)
def init(args): """Initialize the global QWebSettings.""" if args.enable_webengine_inspector: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port()) profile = QWebEngineProfile.defaultProfile() profile.setCachePath(os.path.join(standarddir.cache(), 'webengine')) profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_stylesheet(profile) websettings.init_mappings(MAPPINGS) objreg.get('config').changed.connect(update_settings)
def _chromium_version(): """Get the Chromium version for QtWebEngine. This can also be checked by looking at this file with the right Qt tag: https://github.com/qt/qtwebengine/blob/dev/tools/scripts/version_resolver.py#L41 Quick reference: Qt 5.7: Chromium 49 Qt 5.8: Chromium 53 Qt 5.9: Chromium 56 Qt 5.10: Chromium 61 Qt 5.11: Chromium 63 Qt 5.12: Chromium 65 (?) """ if QWebEngineProfile is None: # This should never happen return 'unavailable' profile = QWebEngineProfile() ua = profile.httpUserAgent() match = re.search(r' Chrome/([^ ]*) ', ua) if not match: log.misc.error("Could not get Chromium version from: {}".format(ua)) return 'unknown' return match.group(1)
def init(): """Initialize QtWebEngine-specific modules.""" # For some reason we need to keep a reference, otherwise the scheme handler # won't work... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler app = QApplication.instance() profile = QWebEngineProfile.defaultProfile() log.init.debug("Initializing qute:* handler...") _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app) _qute_scheme_handler.install(profile) log.init.debug("Initializing request interceptor...") host_blocker = objreg.get('host-blocker') req_interceptor = interceptor.RequestInterceptor( host_blocker, parent=app) req_interceptor.install(profile)
def testdata_scheme(qapp): try: global _qute_scheme_handler from qutebrowser.browser.webengine import webenginequtescheme from PyQt5.QtWebEngineWidgets import QWebEngineProfile _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler( parent=qapp) _qute_scheme_handler.install(QWebEngineProfile.defaultProfile()) except ImportError: pass @qutescheme.add_handler('testdata') def handler(url): # pylint: disable=unused-variable file_abs = os.path.abspath(os.path.dirname(__file__)) filename = os.path.join(file_abs, os.pardir, 'end2end', url.path().lstrip('/')) with open(filename, 'rb') as f: data = f.read() mimetype, _encoding = mimetypes.guess_type(filename) return mimetype, data
def create_profile(): ans = getattr(create_profile, 'ans', None) if ans is None: ans = QWebEngineProfile(QApplication.instance()) ua = 'calibre-viewer ' + __version__ ans.setHttpUserAgent(ua) if is_running_from_develop: from calibre.utils.rapydscript import compile_viewer print('Compiling viewer code...') compile_viewer() js = P('viewer.js', data=True, allow_user_override=False) translations_json = get_translations_data() or b'null' js = js.replace(b'__TRANSLATIONS_DATA__', translations_json, 1) insert_scripts(ans, create_script('viewer.js', js)) url_handler = UrlSchemeHandler(ans) ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')), url_handler) s = ans.settings() s.setDefaultTextEncoding('utf-8') s.setAttribute(s.LinksIncludedInFocusChain, False) create_profile.ans = ans return ans
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.DomainCookies = {} self.setWindowTitle('微信读书助手') # 设置窗口标题 self.resize(900, 600) # 设置窗口大小 self.setWindowFlags(Qt.WindowMinimizeButtonHint) # 禁止最大化按钮 self.setFixedSize(self.width(), self.height()) # 禁止调整窗口大小 url = 'https://weread.qq.com/#login' # 目标地址 self.browser = QWebEngineView() # 实例化浏览器对象 self.profile = QWebEngineProfile.defaultProfile() self.profile.cookieStore().deleteAllCookies() # 初次运行软件时删除所有cookies self.profile.cookieStore().cookieAdded.connect( self.onCookieAdd) # cookies增加时触发self.onCookieAdd()函数 self.browser.loadFinished.connect( self.onLoadFinished) # 网页加载完毕时触发self.onLoadFinished()函数 self.browser.load(QUrl(url)) # 加载网页 self.setCentralWidget(self.browser) # 设置中心窗口
def __init__(self, uri: str, required_cookies: List[str], parent=None): """ 此工具类用于 QtWebEngine 自动化 Cookie 登录过程 Example: QtWebEngine('https://y.qq.com', ['qqmusic_key']) :param uri: 初始化登录地址 获取到的 Cookie 也会按照此地址筛选 :rtype uri: str :param required_cookies: 必需包含的 Cookie key 当全部获取到将发送 succeed 信号并自动关闭 :type required_cookies: List[str] :param parent: """ super().__init__(parent) self.set_pos() self.init_uri = uri profile = QWebEngineProfile.defaultProfile() cookie_store: QWebEngineCookieStore = profile.cookieStore() cookie_store.deleteAllCookies() cookie_store.cookieAdded.connect(self.cookie_added) cookie_store.cookieRemoved.connect(self.cookie_removed) self.saved_cookies = dict() self.required_cookies = required_cookies self.setPage(NoOutputWebPage(self)) self.load(QUrl(uri))
def init(): """Initialize QtWebEngine-specific modules.""" # For some reason we need to keep a reference, otherwise the scheme handler # won't work... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler app = QApplication.instance() profile = QWebEngineProfile.defaultProfile() log.init.debug("Initializing qute:* handler...") _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app) _qute_scheme_handler.install(profile) log.init.debug("Initializing request interceptor...") host_blocker = objreg.get('host-blocker') req_interceptor = interceptor.RequestInterceptor( host_blocker, parent=app) req_interceptor.install(profile) log.init.debug("Initializing QtWebEngine downloads...") download_manager = webenginedownloads.DownloadManager(parent=app) download_manager.install(profile) objreg.register('webengine-download-manager', download_manager)
def __init__(self, opts, log, container_root): QObject.__init__(self) self.interceptor = RequestInterceptor(self) self.has_maths = {} self.interceptor.log = self.log = log self.interceptor.container_root = os.path.normcase(os.path.abspath(container_root)) self.interceptor.resources_root = os.path.normcase(os.path.abspath(os.path.dirname(mathjax_dir()))) ans = QWebEngineProfile(QApplication.instance()) ua = 'calibre-pdf-output ' + __version__ ans.setHttpUserAgent(ua) s = ans.settings() s.setDefaultTextEncoding('utf-8') ans.setUrlRequestInterceptor(self.interceptor) self.profile = ans self.opts = opts self.workers = [] self.max_workers = detect_ncpus() if iswindows: self.original_signal_handlers = {} else: self.original_signal_handlers = setup_unix_signals(self)
def __init__(self, *args, **kwargs): # Strip out arguments we handle that are different from QMainWindow: if 'width' in kwargs: self.width = kwargs['width'] del kwargs['width'] else: self.width = 1024 if 'height' in kwargs: self.height = kwargs['height'] del kwargs['height'] else: # Short enough to fit in XGA, 768 height: self.height = 735 # Then run the default constructor. super(BrowserWindow, self).__init__(*args, **kwargs) self.browserviews = [] self.profile = QWebEngineProfile() # print("Profile initially off the record?", # self.profile.isOffTheRecord()) self.init_tab_name_len = 40 self.init_chrome() # Resize to fit on an XGA screen, allowing for window chrome. # XXX Should check the screen size and see if it can be bigger. self.resize(self.width, self.height) # Set up the listener for remote commands, the filename # and the buffer where we'll store those commands: self.cmdsockname = None self.cmdread = b'' self.set_up_listener()
def _init_default_profile(): """Init the default QWebEngineProfile.""" global default_profile default_profile = QWebEngineProfile.defaultProfile() assert parsed_user_agent is None # avoid earlier profile initialization non_ua_version = version.qtwebengine_versions(avoid_init=True) init_user_agent() ua_version = version.qtwebengine_versions() if ua_version.webengine != non_ua_version.webengine: log.init.warning( "QtWebEngine version mismatch - unexpected behavior might occur, " "please open a bug about this.\n" f" Early version: {non_ua_version}\n" f" Real version: {ua_version}") default_profile.setCachePath( os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_profile(default_profile)
def _init_profiles(): """Init the two used QWebEngineProfiles.""" global default_profile, private_profile default_profile = QWebEngineProfile.defaultProfile() default_profile.setCachePath(os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_stylesheet(default_profile) _set_http_headers(default_profile) private_profile = QWebEngineProfile() assert private_profile.isOffTheRecord() _init_stylesheet(private_profile) _set_http_headers(private_profile) if qtutils.version_check('5.8'): default_profile.setSpellCheckEnabled(True) private_profile.setSpellCheckEnabled(True)
def create_profile(): ans = getattr(create_profile, 'ans', None) if ans is None: ans = QWebEngineProfile(QApplication.instance()) osname = 'windows' if iswindows else ('macos' if isosx else 'linux') # DO NOT change the user agent as it is used to workaround # Qt bugs see workaround_qt_bug() in ajax.pyj ua = 'calibre-viewer {} {}'.format(__version__, osname) ans.setHttpUserAgent(ua) if is_running_from_develop: from calibre.utils.rapydscript import compile_viewer prints('Compiling viewer code...') compile_viewer() js = P('viewer.js', data=True, allow_user_override=False) translations_json = get_translations_data() or b'null' js = js.replace(b'__TRANSLATIONS_DATA__', translations_json, 1) insert_scripts(ans, create_script('viewer.js', js)) url_handler = UrlSchemeHandler(ans) ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')), url_handler) s = ans.settings() s.setDefaultTextEncoding('utf-8') s.setAttribute(s.LinksIncludedInFocusChain, False) create_profile.ans = ans return ans
def create_profile(): ans = getattr(create_profile, 'ans', None) if ans is None: ans = QWebEngineProfile(QApplication.instance()) ua = 'calibre-editor-preview ' + __version__ ans.setHttpUserAgent(ua) if is_running_from_develop: from calibre.utils.rapydscript import compile_editor compile_editor() js = P('editor.js', data=True, allow_user_override=False) cparser = P('csscolorparser.js', data=True, allow_user_override=False) insert_scripts(ans, create_script('csscolorparser.js', cparser), create_script('editor.js', js), ) url_handler = UrlSchemeHandler(ans) ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')), url_handler) s = ans.settings() s.setDefaultTextEncoding('utf-8') s.setAttribute(s.FullScreenSupportEnabled, False) s.setAttribute(s.LinksIncludedInFocusChain, False) create_profile.ans = ans return ans
class BrowserBuffer(Buffer): close_page = QtCore.pyqtSignal(str) get_focus_text = QtCore.pyqtSignal(str, str) open_dev_tools_tab = QtCore.pyqtSignal(object) def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path, fit_to_view): Buffer.__init__(self, buffer_id, url, arguments, emacs_var_dict, module_path, fit_to_view) self.add_widget(BrowserView(config_dir)) self.config_dir = config_dir self.history_list = [] if self.emacs_var_dict["eaf-browser-remember-history"] == "true": self.history_log_file_path = os.path.join(self.config_dir, "browser", "history", "log.txt") self.history_pattern = re.compile("^(.+)ᛝ(.+)ᛡ(.+)$") self.noprefix_url_pattern = re.compile("^(https?|file)://(.+)") self.nopostfix_url_pattern = re.compile("^[^#\?]*") self.history_close_file_path = os.path.join( self.config_dir, "browser", "history", "close.txt") touch(self.history_log_file_path) with open(self.history_log_file_path, "r") as f: raw_list = f.readlines() for raw_his in raw_list: his_line = re.match(self.history_pattern, raw_his) if his_line is None: # Obsolete Old history format old_his = re.match("(.*)\s((https?|file):[^\s]+)$", raw_his) if old_his is not None: self.history_list.append( HistoryPage(old_his.group(1), old_his.group(2), 1)) else: self.history_list.append( HistoryPage(his_line.group(1), his_line.group(2), his_line.group(3))) # Set User Agent with Firefox's one to make EAF browser can login in Google account. self.pc_user_agent = "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/72.0" self.phone_user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1" self.profile = QWebEngineProfile(self.buffer_widget) self.profile.defaultProfile().setHttpUserAgent(self.pc_user_agent) self.draw_progressbar = False self.eval_dark_js = False self.progressbar_progress = 0 self.progressbar_color = QColor(233, 129, 35, 255) self.progressbar_height = 2 self.light_mode_mask_color = QColor("#FFFFFF") self.dark_mode_mask_color = QColor("#242525") self.current_url = "" self.request_url = "" self.no_need_draw_background = False self.init_background_color() self.buffer_widget.loadStarted.connect(self.start_progress) self.buffer_widget.loadProgress.connect(self.update_progress) self.buffer_widget.urlChanged.connect(self.record_url) self.buffer_widget.web_page.windowCloseRequested.connect( self.close_buffer) self.buffer_widget.web_page.fullScreenRequested.connect( self.handle_fullscreen_request) self.buffer_widget.web_page.pdfPrintingFinished.connect( self.notify_print_message) self.profile.defaultProfile().downloadRequested.connect( self.handle_download_request) settings = QWebEngineSettings.globalSettings() try: settings.setAttribute( QWebEngineSettings.PluginsEnabled, self.emacs_var_dict["eaf-browser-enable-plugin"] == "true") settings.setAttribute( QWebEngineSettings.JavascriptEnabled, self.emacs_var_dict["eaf-browser-enable-javascript"] == "true") settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) settings.setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, False) settings.setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) except Exception: pass for method_name in [ "search_text_forward", "search_text_backward", "zoom_out", "zoom_in", "zoom_reset", "scroll_left", "scroll_right", "scroll_up", "scroll_down", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "refresh_page", "undo_action", "redo_action", "get_url", "exit_fullscreen", "set_focus_text", "clear_focus", "dark_mode", "view_source" ]: self.build_widget_method(method_name) self.build_widget_method("history_backward", "back") self.build_widget_method("history_forward", "forward") self.build_widget_method("action_quit", "search_quit") self.build_widget_method("yank_text", "yank_text", "Yank text.") self.build_widget_method("kill_text", "kill_text", "Kill text.") for method_name in [ "recover_prev_close_page", "scroll_up", "scroll_down", "scroll_left", "scroll_right", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "open_link", "open_link_new_buffer", "open_link_background_buffer", "copy_link", "history_backward", "history_forward", "new_blank_page", "open_download_manage_page", "refresh_page", "zoom_in", "zoom_out", "zoom_reset", "save_as_bookmark", "edit_url", "download_youtube_video", "download_youtube_audio", "toggle_device", "close_buffer", "save_as_pdf", "view_source", "save_as_single_file", "select_left_tab", "select_right_tab", "copy_code" ]: self.build_insert_or_do(method_name) def notify_print_message(self, file_path, success): if success: # Try to rename pdf file with title. # Use host name if title include invalid file char. title_path = os.path.join( os.path.expanduser( self.emacs_var_dict["eaf-browser-download-path"]), "{}.pdf".format(self.title)) try: os.rename(file_path, title_path) self.message_to_emacs.emit( "Successfully saved current webpage as '{}'.".format( title_path)) except Exception: self.message_to_emacs.emit( "Successfully saved current webpage as '{}'.".format( file_path)) else: self.message_to_emacs.emit( "Failed to save current webpage as '{}'.".format(file_path)) def notify_monolith_message(self, download_path, file_path, title, retcode): if retcode == 0: title_path = os.path.join(os.path.expanduser(download_path), "{}.html".format(title)) try: os.rename(file_path, title_path) self.message_to_emacs.emit( "Successfully saved current webpage as '{}'.".format( title_path)) except Exception: self.message_to_emacs.emit( "Successfully saved current webpage as '{}'.".format( file_path)) else: self.message_to_emacs.emit( "Failed to save current page as single file.") def record_url(self, url): self.request_url = url.toString() # Emacs-china forum thread don't need draw background that avoid flash. if self.dark_mode_is_enable(): current_urls = self.current_url.rsplit("/", 1) request_urls = self.request_url.rsplit("/", 1) if self.request_url == "https://emacs-china.org/": self.no_need_draw_background = False if self.current_url.startswith("https://emacs-china.org/t/" ) and self.request_url.startswith( "https://emacs-china.org/t/"): self.no_need_draw_background = current_urls[0] == request_urls[ 0] or self.request_url == current_urls[0] elif self.current_url.startswith( "https://livebook.manning.com/book/" ) and self.request_url.startswith( "https://livebook.manning.com/book/"): self.no_need_draw_background = current_urls[0] == request_urls[ 0] elif self.current_url.startswith("https://web.telegram.org" ) and self.request_url.startswith( "https://web.telegram.org"): self.no_need_draw_background = True def dark_mode_is_enable(self): module_name = self.module_path.split(".")[1] return (self.emacs_var_dict["eaf-browser-dark-mode"] == "true" or \ (self.emacs_var_dict["eaf-browser-dark-mode"] == "" and self.emacs_var_dict["eaf-emacs-theme-mode"] == "dark")) \ and module_name in ["browser", "terminal", "mindmap", "js-video-player"] \ and self.url != "devtools://devtools/bundled/devtools_app.html" def init_background_color(self): if self.dark_mode_is_enable(): self.buffer_widget.web_page.setBackgroundColor( self.dark_mode_mask_color) else: self.buffer_widget.web_page.setBackgroundColor( self.light_mode_mask_color) def drawForeground(self, painter, rect): if self.draw_progressbar: # Draw foreground over web page avoid white flash when eval dark_mode_js if self.dark_mode_is_enable() and not self.no_need_draw_background: painter.setBrush(self.dark_mode_mask_color) painter.drawRect(0, 0, rect.width(), rect.height()) # Init progress bar brush. painter.setBrush(self.progressbar_color) if self.eval_dark_js: # Draw 100% when after eval dark_mode_js, avoid flash progressbar. painter.drawRect(0, 0, rect.width(), self.progressbar_height) else: # Draw progress bar. painter.drawRect( 0, 0, rect.width() * self.progressbar_progress * 1.0 / 100, self.progressbar_height) @QtCore.pyqtSlot() def start_progress(self): self.progressbar_progress = 0 self.draw_progressbar = True self.update() @QtCore.pyqtSlot() def hide_progress(self): self.current_url = self.url self.no_need_draw_background = False self.draw_progressbar = False self.eval_dark_js = False self.update() @QtCore.pyqtSlot(int) def update_progress(self, progress): if progress < 100: # Update progres. self.progressbar_progress = progress self.update() elif progress == 100 and self.draw_progressbar: if self.dark_mode_is_enable(): if not self.eval_dark_js: self.dark_mode() self.eval_dark_js = True # We need show page some delay, avoid white flash when eval dark_mode_js QtCore.QTimer.singleShot(1000, self.hide_progress) else: # Hide progress bar immediately if not dark mode. self.hide_progress() def handle_fullscreen_request(self, request): if request.toggleOn(): self.enter_fullscreen_request.emit() else: self.exit_fullscreen_request.emit() request.accept() def handle_download_request(self, download_item): download_data = download_item.url().toString() if download_data.startswith("data:image/"): image_path = os.path.join( os.path.expanduser( self.emacs_var_dict["eaf-browser-download-path"]), "image.png") touch(image_path) with open(image_path, "wb") as f: f.write( base64.decodestring( download_data.split(",")[1].encode("utf-8"))) self.message_to_emacs.emit("Save image: " + image_path) else: self.try_start_aria2_daemon() from core.pyaria2 import Jsonrpc download_url = download_item.url().toString() jsonrpc = Jsonrpc('localhost', 6800) resp = jsonrpc.addUris(download_url) self.message_to_emacs.emit("Downloading: " + download_url) def save_as_pdf(self): self.send_input_message("Save current webpage as PDF?", "save_as_pdf", "yes-or-no") def save_as_single_file(self): import shutil if shutil.which("monolith") is None: self.message_to_emacs.emit("Executable monolith not in PATH") else: self.send_input_message( "Save current webpage as single html file?", "save_as_single_file", "yes-or-no") def destroy_buffer(self): # Record close page. self.close_page.emit(self.buffer_widget.url().toString()) # Load blank page to stop video playing, such as youtube.com. self.buffer_widget.open_url("about:blank") if self.buffer_widget is not None: # NOTE: We need delete QWebEnginePage manual, otherwise QtWebEngineProcess won't quit. self.buffer_widget.web_page.deleteLater() self.buffer_widget.deleteLater() def get_key_event_widgets(self): # We need send key event to QWebEngineView's focusProxy widget, not QWebEngineView. return [self.buffer_widget.focusProxy()] def scroll(self, scroll_direction, scroll_type): if scroll_type == "page": if scroll_direction == "up": self.scroll_up_page() else: self.scroll_down_page() else: if scroll_direction == "up": self.scroll_up() else: self.scroll_down() def handle_input_message(self, result_tag, result_content): if result_tag == "search_text_forward": self.buffer_widget._search_text(str(result_content)) elif result_tag == "search_text_backward": self.buffer_widget._search_text(str(result_content), True) elif result_tag == "jump_link": self.buffer_widget.jump_to_link(str(result_content).strip()) elif result_tag == "jump_link_new_buffer": self.buffer_widget.jump_to_link_new_buffer( str(result_content).strip()) elif result_tag == "jump_link_background_buffer": self.buffer_widget.jump_to_link_background_buffer( str(result_content).strip()) elif result_tag == "copy_link": self.buffer_widget.copy_link(str(result_content).strip()) elif result_tag == "eval_js_file": self.buffer_widget.eval_js_file(str(result_content)) elif result_tag == "eval_js": self.buffer_widget.eval_js(str(result_content)) elif result_tag == "save_as_pdf": parsed = urlparse(self.url) qd = parse_qs(parsed.query, keep_blank_values=True) pdf_path = os.path.join( os.path.expanduser( self.emacs_var_dict["eaf-browser-download-path"]), "{}.pdf".format(parsed.netloc)) self.message_to_emacs.emit("Saving as pdf...") self.buffer_widget.web_page.printToPdf(pdf_path) elif result_tag == "save_as_single_file": parsed = urlparse(self.url) qd = parse_qs(parsed.query, keep_blank_values=True) file_path = os.path.join( os.path.expanduser( self.emacs_var_dict["eaf-browser-download-path"]), "{}.html".format(parsed.netloc)) self.message_to_emacs.emit("Saving as single file...") args = ["monolith", self.url, "-o", file_path] handler = partial(self.notify_monolith_message, self.emacs_var_dict["eaf-browser-download-path"], file_path, self.title) call_and_check_code(args, handler) elif result_tag == "edit_url": self.buffer_widget.open_url(str(result_content)) elif result_tag == "copy_code": self.buffer_widget.copy_code_content(str(result_content).strip()) def cancel_input_message(self, result_tag): if result_tag == "jump_link" or \ result_tag == "jump_link_new_buffer" or \ result_tag == "jump_link_background_buffer" or \ result_tag == "copy_link" or \ result_tag == "edit_url": self.buffer_widget.cleanup_links() def clear_all_cookies(self): self.buffer_widget.clear_cookies() self.message_to_emacs.emit("Cleared all cookies.") def try_start_aria2_daemon(self): if not is_port_in_use(6800): with open(os.devnull, "w") as null_file: aria2_args = ["aria2c"] aria2_args.append("-d") # daemon aria2_args.append("-c") # continue download aria2_args.append( "--auto-file-renaming=false") # not auto rename file aria2_args.append("-d {}".format( os.path.expanduser( str(self.emacs_var_dict["eaf-browser-download-path"]))) ) aria2_proxy_host = str( self.emacs_var_dict["eaf-browser-aria2-proxy-host"]) aria2_proxy_port = str( self.emacs_var_dict["eaf-browser-aria2-proxy-port"]) if aria2_proxy_host != "" and aria2_proxy_port != "": aria2_args.append("--all-proxy") aria2_args.append("http://{0}:{1}".format( aria2_proxy_host, aria2_proxy_port)) aria2_args.append("--enable-rpc") aria2_args.append("--rpc-listen-all") subprocess.Popen(aria2_args, stdout=null_file) def open_download_manage_page(self): self.try_start_aria2_daemon() self.buffer_widget.open_download_manage_page() def copy_text(self): self.buffer_widget.copy_text() self.message_to_emacs.emit("Copy selected text.") def copy_code(self): self.buffer_widget.get_code_markers() self.send_input_message("Copy code: ", "copy_code") def open_link(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link: ", "jump_link") def open_link_new_buffer(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link in New Buffer: ", "jump_link_new_buffer") def open_link_background_buffer(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link in Background Buffer: ", "jump_link_background_buffer") def copy_link(self): self.buffer_widget.get_link_markers() self.send_input_message("Copy link: ", "copy_link") def edit_url(self): self.send_input_message("Edit link: ", "edit_url", "string", self.url) def reset_default_zoom(self): if hasattr(self, "buffer_widget"): self.buffer_widget.setZoomFactor( float(self.emacs_var_dict["eaf-browser-default-zoom"])) def edit_focus_text(self): text = self.buffer_widget.get_focus_text() if text != None: self.get_focus_text.emit(self.buffer_id, text) else: self.message_to_emacs.emit("No active input element.") def is_focus(self): return self.buffer_widget.get_focus_text( ) != None or self.url == "devtools://devtools/bundled/devtools_app.html" def record_history(self, new_title): new_url = self.buffer_widget.filter_url( self.buffer_widget.url().toString()) if self.emacs_var_dict["eaf-browser-remember-history"] == "true" and self.buffer_widget.filter_title(new_title) != "" and \ self.arguments != "temp_html_file" and new_title != "about:blank" and new_url != "about:blank": # Throw traceback info if algorithm has bug and protection of historical record is not erased. try: noprefix_new_url_match = re.match(self.noprefix_url_pattern, new_url) if noprefix_new_url_match is not None: found = False for history in self.history_list: noprefix_url_match = re.match( self.noprefix_url_pattern, history.url) if noprefix_url_match is not None: noprefix_url = noprefix_url_match.group(2) noprefix_new_url = noprefix_new_url_match.group(2) nopostfix_new_url_match = re.match( self.nopostfix_url_pattern, noprefix_new_url) if noprefix_url == noprefix_new_url: # found unique url history.title = new_title history.url = new_url history.hit += 0.5 found = True elif nopostfix_new_url_match is not None and noprefix_url == nopostfix_new_url_match.group( ): # also increment parent history.hit += 0.25 if not found: self.history_list.append( HistoryPage(new_title, new_url, 1)) self.history_list.sort(key=lambda x: x.hit, reverse=True) with open(self.history_log_file_path, "w") as f: f.writelines( map( lambda history: history.title + "ᛝ" + history.url + "ᛡ" + str(history.hit) + "\n", self.history_list)) except Exception: import traceback self.message_to_emacs.emit("Error in record_history: " + str(traceback.print_exc())) def new_blank_page(self): self.eval_in_emacs.emit( '''(eaf-open \"{0}\" \"browser\" \"\" t)''' ''.format(self.emacs_var_dict["eaf-browser-blank-page-url"])) def clear_history(self): if os.path.exists(self.history_log_file_path): os.remove(self.history_log_file_path) self.message_to_emacs.emit("Cleared browsing history.") else: self.message_to_emacs.emit("There is no browsing history.") def record_close_page(self, url): if self.emacs_var_dict["eaf-browser-remember-history"] == "true": touch(self.history_close_file_path) with open(self.history_close_file_path, "a") as f: f.write("{0}\n".format(url)) def recover_prev_close_page(self): if os.path.exists(self.history_close_file_path): with open(self.history_close_file_path, "r") as f: close_urls = f.readlines() if len(close_urls) > 0: # We need use rstrip remove \n char from url record. prev_close_url = close_urls.pop().rstrip() self.open_url_in_new_tab.emit(prev_close_url) open(self.history_close_file_path, "w").writelines(close_urls) self.message_to_emacs.emit( "Recovery {0}".format(prev_close_url)) else: self.message_to_emacs.emit("No page need recovery.") else: self.message_to_emacs.emit("No page need recovery.") def insert_or_do(func): def _do(self, *args, **kwargs): if self.is_focus(): self.fake_key_event(self.current_event_string) else: func(self, *args, **kwargs) return _do def build_insert_or_do(self, method_name): def _do(): if self.is_focus(): self.fake_key_event(self.current_event_string) else: getattr(self, method_name)() setattr(self, "insert_or_{}".format(method_name), _do) @insert_or_do def insert_or_open_url(self): self.eval_in_emacs.emit( '''(call-interactively 'eaf-open-browser-with-history)''') def select_all_or_input_text(self): if self.is_focus(): self.buffer_widget.select_input_text() else: self.buffer_widget.select_all() def eval_js_file(self): self.send_input_message("Eval JS file: ", "eval_js_file", "file") def eval_js(self): self.send_input_message("Eval JS: ", "eval_js") def open_dev_tool_page(self): self.open_dev_tools_tab.emit(self.buffer_widget.web_page) def toggle_device(self): user_agent = self.profile.defaultProfile().httpUserAgent() if user_agent == self.pc_user_agent: self.profile.defaultProfile().setHttpUserAgent( self.phone_user_agent) self.set_aspect_ratio(2.0 / 3) else: self.profile.defaultProfile().setHttpUserAgent(self.pc_user_agent) self.set_aspect_ratio(0) self.refresh_page() def download_youtube_video(self): self.download_youtube_file() def download_youtube_audio(self): self.download_youtube_file(True) def download_youtube_file(self, only_audio=False): url = self.buffer_widget.url().toString() if url.startswith("https://www.youtube.com"): import shutil if shutil.which("youtube-dl"): download_path = "{}/%(title)s-%(id)s.%(ext)s".format( os.path.expanduser( str(self.emacs_var_dict["eaf-browser-download-path"]))) youtube_dl_args = ["youtube-dl"] youtube_dl_args.append("--proxy") youtube_dl_args.append(self.proxy_string) youtube_dl_args.append(url) youtube_dl_args.append("-o") youtube_dl_args.append(download_path) file_type = "video" if only_audio: youtube_dl_args.append("-x") file_type = "audio" with open(os.devnull, "w") as null_file: popen_and_call( youtube_dl_args, lambda: self.message_to_emacs.emit( "Downloaded: {0}".format(url)), null_file) self.message_to_emacs.emit("Downloading {0}: {1}".format( file_type, url)) else: self.message_to_emacs.emit( "Please install youtube-dl to use this feature.") else: self.message_to_emacs.emit( "Only videos from YouTube can be downloaded for now.")
class ViewQt5WebEngine(View, QObject): _emit_js_signal = pyqtSignal(str, QVariant); def __init__(self, name="MyLensApp", width=640, height=480, inspector=False, start_maximized=False, *args, **kwargs): View.__init__(self, name=name, width=width,height=height, *args, **kwargs) QObject.__init__(self) self._app = QApplication([]) # prepare Qt DBus mainloop try: DBusQtMainLoop(set_as_default=True) except NameError: # TODO: validate DBus failed to import (windows) pass self._app_loaded = False self._manager = ThreadManagerQt5(app=self._app) self._inspector = inspector self._start_maximized = start_maximized self._build_app() def _build_app(self): if self._inspector: os.environ.setdefault('QTWEBENGINE_REMOTE_DEBUGGING', '8001') # build webengine container self._lensview = lv = _QWebView(inspector=self._inspector) self._page = p = _QWebPage() lv.setPage(self._page) # connect to Qt signals lv.loadFinished.connect(self._loaded_cb) self._app.lastWindowClosed.connect(self._last_window_closed_cb) # build webchannel script and inject qwebchannel_js = QFile(':/qtwebchannel/qwebchannel.js') if not qwebchannel_js.open(QIODevice.ReadOnly): raise SystemExit('Failed to load qwebchannel.js with error: %s' % qwebchannel_js.errorString()) qwebchannel_js = bytes(qwebchannel_js.readAll()).decode('utf-8') script = QWebEngineScript() script.setSourceCode(qwebchannel_js + ''' window.lens = window.lens || {}; window.lens._channel = new QWebChannel(qt.webChannelTransport, function(channel) { window.lens.emit = function() { var args = Array.prototype.slice.call(arguments); if (args.length > 0) { channel.objects.bridge._from_bridge(args); } }; channel.objects.bridge._emit_js_signal.connect(function(name, args) { window.lens.__broadcast(name, args); }); }); ''') script.setName('lens-bridge') script.setWorldId(QWebEngineScript.MainWorld) script.setInjectionPoint(QWebEngineScript.DocumentCreation) script.setRunsOnSubFrames(True) p.profile().scripts().insert(script) self._channel = QWebChannel(p) p.setWebChannel(self._channel) self._channel.registerObject('bridge', self) # set up scheme handlers for app:// and lens:// self._app_scheme_handler = AppSchemeHandler() self._lens_scheme_handler = LensSchemeHandler() self._interceptor = RequestInterceptor() self._profile = QWebEngineProfile().defaultProfile() self._profile.installUrlSchemeHandler('app'.encode(), self._app_scheme_handler) self._profile.installUrlSchemeHandler('lens'.encode(), self._lens_scheme_handler) self._profile.setRequestInterceptor(self._interceptor) # connect to Lens signals self.on('__close_app', self._close_cb) # center on screen _frame_geometry = lv.frameGeometry() _active_screen = self._app.desktop().screenNumber(self._app.desktop().cursor().pos()) _center = self._app.desktop().screenGeometry(_active_screen).center() _frame_geometry.moveCenter(_center) lv.move(_frame_geometry.topLeft()) self.set_title(self._app_name) self.set_size(self._app_width, self._app_height) def _close_cb(self): self.emit('app.close') self._app.exit() @pyqtSlot(QVariant) def _from_bridge(self, name_args): # emit our python/js bridge signal self.emit(name_args[0], *name_args[1:]) def _last_window_closed_cb(self, *args): self.emit('__close_app', *args) def _loaded_cb(self, success): # show window once some page has loaded self._lensview.show() if self._start_maximized: self.toggle_window_maximize() if not self._app_loaded: self._app_loaded = True self.emit('app.loaded') def _run(self): signal.signal(signal.SIGINT, signal.SIG_DFL) self._app.exec_() def emit_js(self, name, *args): self._emit_js_signal.emit(name, list(args)) def load_string(self, data): index_uri = pathlib.Path(self._app_scheme_handler._uri_app_base).as_uri() self._lensview.setHtml(data, QUrl(index_uri)) def load_uri(self, uri): uri_base = os.path.dirname(uri) + '/' self.set_uri_app_base(uri_base) path = uri_base + 'app.html' stream = QFile(path) if stream.open(QFile.ReadOnly): data = str(stream.readAll(), 'utf-8') index_uri = pathlib.Path(uri_base).as_uri() + os.sep logger.debug('Using {0} as index URI'.format(index_uri)) self._lensview.setHtml(data, QUrl(index_uri)) def set_inspector(self, state): self._lensview.set_inspector(state) def set_size(self, width, height): logger.debug('Setting app size: {0}x{1}'.format(width, height)) self._lensview.setMinimumSize(width, height) self._lensview.resize(width, height) def set_title(self, title): self._lensview.setWindowTitle(QString(title)) def set_uri_app_base(self, uri): self._app_scheme_handler._uri_app_base = pathlib.Path(uri).as_uri() + "/" def set_uri_lens_base(self, uri): self._lens_scheme_handler._uri_lens_base = pathlib.Path(uri).as_uri() + "/" def timer(self, interval, callback, once=False): q = QTimer(parent=self._lensview) q.timeout.connect(callback) q.start(interval) return q.timerId def toggle_window_maximize(self): if self._lensview.windowState() & Qt.WindowMaximized: self._lensview.setWindowState(self._lensview.windowState() ^ Qt.WindowMaximized) self.emit_js('window-unmaximized') else: self._lensview.setWindowState(self._lensview.windowState() | Qt.WindowMaximized) self.emit_js('window-maximized') def toggle_window_fullscreen(self): if self._lensview.windowState() & Qt.WindowFullScreen: self._lensview.setWindowState(self._lensview.windowState() ^ Qt.WindowFullScreen) self.emit_js('window-unfullscreen') else: self._lensview.setWindowState(self._lensview.windowState() | Qt.WindowFullScreen) self.emit_js('window-fullscreen')
def __init__(self, config): self.config = config super(JWebView, self).__init__() self.setAttribute(Qt.WA_DeleteOnClose, True) self.profile = QWebEngineProfile.defaultProfile() self.webpage = JWebPage(self.profile, self, config) self.setPage(self.webpage) if config["inject_JavaScript"]["JavaScript"]: from JAK.Utils import JavaScript JavaScript.inject(self.page(), config["inject_JavaScript"]) self.interceptor = Interceptor(config) if config["user_agent"]: # Set user agent self.profile.setHttpUserAgent(config["user_agent"]) if config["debug"]: self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled, True) else: self.setContextMenuPolicy(Qt.PreventContextMenu) if config["transparent"]: # Activates background transparency self.setAttribute(Qt.WA_TranslucentBackground) self.page().setBackgroundColor(Qt.transparent) self.setStyleSheet("background:transparent;") print( "Transparency detected, make sure you set [ body {background:transparent;} ]" ) # * Set Engine options if self.config["JavascriptCanPaste"]: self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste, True) else: self.settings().setAttribute(QWebEngineSettings.JavascriptCanPaste, False) if self.config["PlaybackRequiresUserGesture"]: self.settings().setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, True) else: self.settings().setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, False) if self.config["FullScreenSupportEnabled"]: self.settings().setAttribute( QWebEngineSettings.FullScreenSupportEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.FullScreenSupportEnabled, False) if self.config["AllowWindowActivationFromJavaScript"]: self.settings().setAttribute( QWebEngineSettings.AllowWindowActivationFromJavaScript, True) else: self.settings().setAttribute( QWebEngineSettings.AllowWindowActivationFromJavaScript, False) if self.config["LocalContentCanAccessRemoteUrls"]: self.settings().setAttribute( QWebEngineSettings.LocalContentCanAccessRemoteUrls, True) else: self.settings().setAttribute( QWebEngineSettings.LocalContentCanAccessRemoteUrls, False) if self.config["JavascriptCanAccessClipboard"]: self.settings().setAttribute( QWebEngineSettings.JavascriptCanAccessClipboard, True) else: self.settings().setAttribute( QWebEngineSettings.JavascriptCanAccessClipboard, False) if self.config["SpatialNavigationEnabled"]: self.settings().setAttribute( QWebEngineSettings.SpatialNavigationEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.SpatialNavigationEnabled, False) if self.config["TouchIconsEnabled"]: self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled, True) else: self.settings().setAttribute(QWebEngineSettings.TouchIconsEnabled, False) if self.config["FocusOnNavigationEnabled"]: self.settings().setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, True) else: self.settings().setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, False) if config["online"]: self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) print("Engine online (IPC) Disabled") self.page().profile().downloadRequested.connect( self._download_requested) # Set persistent cookies self.profile.setPersistentCookiesPolicy( QWebEngineProfile.ForcePersistentCookies) # set cookies on user folder if config["cookies_path"]: # allow specific path per application. _cookies_path = f"{os.getenv('HOME')}/.jak/{config['cookies_path']}" else: # use separate cookies database per application title = config["title"].lower().replace(" ", "-") _cookies_path = f"{os.getenv('HOME')}/.jak/{title}" self.profile.setPersistentStoragePath(_cookies_path) print(f"Cookies PATH:{_cookies_path}") else: self.settings().setAttribute(QWebEngineSettings.ShowScrollBars, False) print("Engine interprocess communication (IPC) up and running:") self._ipc_scheme_handler = IpcSchemeHandler() self.profile.installUrlSchemeHandler('ipc'.encode(), self._ipc_scheme_handler) if config["webChannel"]["active"]: from JAK.Utils import JavaScript if bindings() == "PyQt5": from PyQt5.QtCore import QFile, QIODevice from PyQt5.QtWebChannel import QWebChannel webchannel_js = QFile(':/qtwebchannel/qwebchannel.js') webchannel_js.open(QIODevice.ReadOnly) webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8') webchannel_js += """ var JAK; new QWebChannel(qt.webChannelTransport, function (channel) { JAK = channel.objects.Bridge; });""" JavaScript.inject(self.page(), { "JavaScript": webchannel_js, "name": "QWebChannel API" }) self.channel = QWebChannel(self.page()) if config["webChannel"]["shared_obj"]: self.bridge_obj = config["webChannel"]["shared_obj"] else: raise NotImplementedError("QWebChannel shared QObject") self.channel.registerObject("Bridge", self.bridge_obj) self.page().setWebChannel(self.channel) print("QWebChannel bridge active") self.profile.setRequestInterceptor(self.interceptor) print(self.profile.httpUserAgent()) validate_url(self, config["web_contents"])
def init_user_agent(): _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent())
def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(800, 600) QWebEngineProfile.defaultProfile().setRequestInterceptor(RequestInterceptor(self))
def __init__(self, *args, **kwargs): super(MyWebEngineView, self).__init__(*args, **kwargs) # 绑定cookie被添加的信号槽 QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect( self.onCookieAdd) self.cookies = {} # 存放cookie字典
def _build_app(self): if self._inspector: os.environ.setdefault('QTWEBENGINE_REMOTE_DEBUGGING', '8001') # build webengine container self._lensview = lv = _QWebView(inspector=self._inspector) self._page = p = _QWebPage() lv.setPage(self._page) # connect to Qt signals lv.loadFinished.connect(self._loaded_cb) self._app.lastWindowClosed.connect(self._last_window_closed_cb) # build webchannel script and inject qwebchannel_js = QFile(':/qtwebchannel/qwebchannel.js') if not qwebchannel_js.open(QIODevice.ReadOnly): raise SystemExit('Failed to load qwebchannel.js with error: %s' % qwebchannel_js.errorString()) qwebchannel_js = bytes(qwebchannel_js.readAll()).decode('utf-8') script = QWebEngineScript() script.setSourceCode(qwebchannel_js + ''' window.lens = window.lens || {}; window.lens._channel = new QWebChannel(qt.webChannelTransport, function(channel) { window.lens.emit = function() { var args = Array.prototype.slice.call(arguments); if (args.length > 0) { channel.objects.bridge._from_bridge(args); } }; channel.objects.bridge._emit_js_signal.connect(function(name, args) { window.lens.__broadcast(name, args); }); }); ''') script.setName('lens-bridge') script.setWorldId(QWebEngineScript.MainWorld) script.setInjectionPoint(QWebEngineScript.DocumentCreation) script.setRunsOnSubFrames(True) p.profile().scripts().insert(script) self._channel = QWebChannel(p) p.setWebChannel(self._channel) self._channel.registerObject('bridge', self) # set up scheme handlers for app:// and lens:// self._app_scheme_handler = AppSchemeHandler() self._lens_scheme_handler = LensSchemeHandler() self._interceptor = RequestInterceptor() self._profile = QWebEngineProfile().defaultProfile() self._profile.installUrlSchemeHandler('app'.encode(), self._app_scheme_handler) self._profile.installUrlSchemeHandler('lens'.encode(), self._lens_scheme_handler) self._profile.setRequestInterceptor(self._interceptor) # connect to Lens signals self.on('__close_app', self._close_cb) # center on screen _frame_geometry = lv.frameGeometry() _active_screen = self._app.desktop().screenNumber(self._app.desktop().cursor().pos()) _center = self._app.desktop().screenGeometry(_active_screen).center() _frame_geometry.moveCenter(_center) lv.move(_frame_geometry.topLeft()) self.set_title(self._app_name) self.set_size(self._app_width, self._app_height)
def __init__(self, config): self.config = config super(JWebView, self).__init__() self.setAttribute(Qt.WA_DeleteOnClose, True) self.profile = QWebEngineProfile.defaultProfile() self.webpage = JWebPage(self.profile, self, config) self.setPage(self.webpage) if config['webview']["injectJavaScript"]["JavaScript"]: self._inject_script(config['webview']["injectJavaScript"]) self.interceptor = Interceptor(config) if config['webview']["userAgent"]: # Set user agent self.profile.setHttpUserAgent(config['webview']["userAgent"]) if config["debug"]: self.settings().setAttribute(QWebEngineSettings.XSSAuditingEnabled, True) else: self.setContextMenuPolicy(Qt.PreventContextMenu) if config['window']["transparent"]: # Activates background transparency self.setAttribute(Qt.WA_TranslucentBackground) self.page().setBackgroundColor(Qt.transparent) print("Transparency detected") # * Set Engine options self.settings().setAttribute( self.config['webview']['disabledSettings'], False) for setting in self.config['webview']['enabledSettings']: self.settings().setAttribute(setting, True) if config['webview']["online"]: self.settings().setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) print("Engine online IPC and Bridge Disabled") self.page().profile().downloadRequested.connect( self._download_requested) # Set persistent cookies self.profile.setPersistentCookiesPolicy( QWebEngineProfile.ForcePersistentCookies) # set cookies on user folder if config['webview']["cookiesPath"]: # allow specific path per application. _cookies_path = f"{os.getenv('HOME')}/.jak/{config['webview']['cookiesPath']}" else: # use separate cookies database per application title = config['window']["title"].lower().replace(" ", "-") _cookies_path = f"{os.getenv('HOME')}/.jak/{title}" self.profile.setPersistentStoragePath(_cookies_path) print(f"Cookies PATH:{_cookies_path}") else: self.settings().setAttribute(QWebEngineSettings.ShowScrollBars, False) application_script = "const JAK = {};" if config['webview']["IPC"]: print("IPC Active:") self._ipc_scheme_handler = IpcSchemeHandler() self.profile.installUrlSchemeHandler('ipc'.encode(), self._ipc_scheme_handler) application_script += """JAK.IPC = function(backendFunction) { window.location.href = "ipc:" + backendFunction; };""" if config['webview']["webChannel"]["active"]: if bindings() == "PyQt5": from PyQt5.QtCore import QFile, QIODevice from PyQt5.QtWebChannel import QWebChannel webchannel_js = QFile(':/qtwebchannel/qwebchannel.js') webchannel_js.open(QIODevice.ReadOnly) webchannel_js = bytes(webchannel_js.readAll()).decode('utf-8') webchannel_js += """new QWebChannel(qt.webChannelTransport, function (channel) { JAK.Bridge = channel.objects.Bridge; });""" application_script += webchannel_js self._inject_script({ "JavaScript": application_script, "name": "JAK" }) channel = QWebChannel(self.page()) if config['webview']["webChannel"]["sharedOBJ"]: bridge_obj = config['webview']["webChannel"]["sharedOBJ"] else: raise NotImplementedError("QWebChannel shared QObject") channel.registerObject("Bridge", bridge_obj) self.page().setWebChannel(channel) print("WebChannel Active:") else: self._inject_script({ "JavaScript": application_script, "name": "JAK" }) self.profile.setRequestInterceptor(self.interceptor) print(self.profile.httpUserAgent()) validate_url(self, config['webview']["webContents"])
def create_profile(): ans = getattr(create_profile, 'ans', None) if ans is None: ans = QWebEngineProfile(QApplication.instance()) ua = 'calibre-editor-preview ' + __version__ ans.setHttpUserAgent(ua) if is_running_from_develop: from calibre.utils.rapydscript import compile_editor compile_editor() js = P('editor.js', data=True, allow_user_override=False) cparser = P('csscolorparser.js', data=True, allow_user_override=False) dark_mode_css = P('dark_mode.css', data=True, allow_user_override=False).decode('utf-8') insert_scripts( ans, create_script('csscolorparser.js', cparser), create_script('editor.js', js), create_script('dark-mode.js', ''' (function() { var settings = JSON.parse(navigator.userAgent.split('|')[1]); var dark_css = CSS; function apply_body_colors(event) { if (document.documentElement) { if (settings.bg) document.documentElement.style.backgroundColor = settings.bg; if (settings.fg) document.documentElement.style.color = settings.fg; } if (document.body) { if (settings.bg) document.body.style.backgroundColor = settings.bg; if (settings.fg) document.body.style.color = settings.fg; } } function apply_css() { var css = ''; if (settings.link) css += 'html > body :link, html > body :link * { color: ' + settings.link + ' !important; }'; if (settings.is_dark_theme) { css += dark_css; } var style = document.createElement('style'); style.textContent = css; document.documentElement.appendChild(style); apply_body_colors(); } apply_body_colors(); document.addEventListener("DOMContentLoaded", apply_css); })(); '''.replace('CSS', json.dumps(dark_mode_css), 1), injection_point=QWebEngineScript.InjectionPoint. DocumentCreation)) url_handler = UrlSchemeHandler(ans) ans.installUrlSchemeHandler(QByteArray(FAKE_PROTOCOL.encode('ascii')), url_handler) s = ans.settings() s.setDefaultTextEncoding('utf-8') s.setAttribute( QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, False) s.setAttribute( QWebEngineSettings.WebAttribute.LinksIncludedInFocusChain, False) create_profile.ans = ans return ans
def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, fit_to_view, background_color): Buffer.__init__(self, buffer_id, url, arguments, emacs_var_dict, fit_to_view, background_color) self.add_widget(BrowserView(config_dir)) self.config_dir = config_dir self.history_list = [] if self.emacs_var_dict["eaf-browser-remember-history"] == "true": self.history_log_file_path = os.path.join(self.config_dir, "browser", "history", "log.txt") self.history_pattern = re.compile("^(.+)ᛝ(.+)ᛡ(.+)$") self.noprefix_url_pattern = re.compile("^(https?|file)://(.+)") self.nopostfix_url_pattern = re.compile("^[^#\?]*") self.history_close_file_path = os.path.join( self.config_dir, "browser", "history", "close.txt") touch(self.history_log_file_path) with open(self.history_log_file_path, "r") as f: raw_list = f.readlines() for raw_his in raw_list: his_line = re.match(self.history_pattern, raw_his) if his_line is None: # Obsolete Old history format old_his = re.match("(.*)\s((https?|file):[^\s]+)$", raw_his) if old_his is not None: self.history_list.append( HistoryPage(old_his.group(1), old_his.group(2), 1)) else: self.history_list.append( HistoryPage(his_line.group(1), his_line.group(2), his_line.group(3))) # Set User Agent with Firefox's one to make EAF browser can login in Google account. self.profile = QWebEngineProfile(self.buffer_widget) self.profile.defaultProfile().setHttpUserAgent( "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/72.0" ) self.buffer_widget.loadStarted.connect(self.start_progress) self.buffer_widget.loadProgress.connect(self.update_progress) self.buffer_widget.loadFinished.connect(self.stop_progress) self.buffer_widget.web_page.windowCloseRequested.connect( self.request_close_buffer) self.buffer_widget.web_page.fullScreenRequested.connect( self.handle_fullscreen_request) self.profile.defaultProfile().downloadRequested.connect( self.handle_download_request) settings = QWebEngineSettings.globalSettings() try: settings.setAttribute( QWebEngineSettings.PluginsEnabled, self.emacs_var_dict["eaf-browser-enable-plugin"] == "true") settings.setAttribute( QWebEngineSettings.JavascriptEnabled, self.emacs_var_dict["eaf-browser-enable-javascript"] == "true") settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) except Exception: pass for method_name in [ "search_text_forward", "search_text_backward", "zoom_out", "zoom_in", "zoom_reset", "scroll_left", "scroll_right", "scroll_up", "scroll_down", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "refresh_page", "undo_action", "redo_action", "get_url", "exit_fullscreen", "set_focus_text", "clear_focus", "dark_mode" ]: self.build_widget_method(method_name) self.build_widget_method("history_backward", "back") self.build_widget_method("history_forward", "forward") self.build_widget_method("action_quit", "search_quit") self.build_widget_method("yank_text", "yank_text", "Yank text.") self.build_widget_method("kill_text", "kill_text", "Kill text.") for method_name in [ "recover_prev_close_page", "scroll_up", "scroll_down", "scroll_left", "scroll_right", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "open_link", "open_link_new_buffer", "open_link_background_buffer", "history_backward", "history_forward", "new_blank_page", "open_download_manage_page", "refresh_page", "zoom_in", "zoom_out", "zoom_reset", "save_as_bookmark" ]: self.build_insert_or_do(method_name)
# QWebSettings.globalSettings().setAttribute(QWebSettings.PluginsEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.DnsPrefetchEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.JavascriptEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.OfflineStorageDatabaseEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.AutoLoadImages, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.LocalStorageEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.PrivateBrowsingEnabled, True) # QWebSettings.globalSettings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True) # serverThred = Thread(start_http_server, (8067, 'localhost', HttpServerHandler)) # serverThred.start() app = QApplication(sys.argv) interceptor = WebEngineUrlRequestInterceptor() QWebEngineProfile.defaultProfile().setRequestInterceptor(interceptor) window = Page() # window.loadUrl("https://jira.orange.ro/browse/MCC-3353") # server_handler = HttpServerHandler # server_handler.set_page(window) # start_http_server(serverHandler=server_handler) # _thread.start_new_thread(start_http_server, (8067, 'localhost', HttpServerHandler)) window.showMaximized() window.loadUrl("https://www.youtube.com/watch?v=raTMa8MneTY") # view = Browser() # view.show() # # view.showMaximized() # print('show maximized')
class QTWSWebView(QWebEngineView): def __init__(self, config: QTWSConfig, window, profile_name: str = None): super().__init__() self.config = config self.window = window if profile_name is None or profile_name.lower() == 'default': self.profile = QWebEngineProfile.defaultProfile() else: self.profile = QWebEngineProfile(profile_name) maxCache = self.config.cache_mb * 1024 * 1024 self.profile.setHttpCacheMaximumSize(maxCache) self.profile.downloadRequested.connect( lambda item: self.__download(item)) QTWSPluginManager.instance().each( lambda plugin: plugin.web_profile_setup(self.profile)) self.webPage = QTWSWebPage(self.config, self.profile) self.setPage(self.webPage) self.permission_manager = QTWSPermissionManager(self.webPage) QTWSPluginManager.instance().each( lambda plugin: plugin.web_engine_setup(self)) if self.config.menu_disabled: self.setContextMenuPolicy(Qt.NoContextMenu) else: self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.__show_menu) self.__create_actions() self.urlChanged.connect(self.__url_changed) self.settings().setAttribute( QWebEngineSettings.FullScreenSupportEnabled, True) self.settings().setAttribute( QWebEngineSettings.JavascriptCanOpenWindows, True) self.settings().setAttribute(QWebEngineSettings.ScrollAnimatorEnabled, True) self.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True) self.download_windows = [] def grant_permission(self, permission): self.permission_manager.grant_permission(permission) def __create_actions(self): self.__actionBack = QAction(QIcon.fromTheme("back"), "Back") self.__actionBack.triggered.connect(lambda: self.back()) self.__actionReload = QAction(QIcon.fromTheme("reload"), "Reload") self.__actionReload.triggered.connect(lambda: self.reload()) self.__actionHome = QAction(QIcon.fromTheme("go-home"), "Home") self.__actionHome.triggered.connect( lambda: self.setUrl(self.config.home)) self.__actionShare = QAction(QIcon.fromTheme("emblem-shared"), "Share") self.__actionShare.triggered.connect(self.__share) self.__actionOpenBrowser = QAction( QIcon.fromTheme("internet-web-browser"), "Open in the browser") self.__actionOpenBrowser.triggered.connect(self.__open_in_browser) self.__actionQuit = QAction(QIcon.fromTheme("application-exit"), "Quit") self.__actionQuit.triggered.connect(self.__quit) self.__customActions = list() for menu_item in self.config.menu: if menu_item.icon: action = QAction(QIcon.fromTheme(menu_item.icon), menu_item.title) else: action = QAction(menu_item.title) action.setData(menu_item.action) if menu_item.separator: self.__customActions.append("-") self.__customActions.append(action) def __show_menu(self, position: QPoint): self.menu = QMenu() if not self.page().history().canGoBack(): self.__actionBack.setEnabled(False) self.menu.addAction(self.__actionBack) self.menu.addAction(self.__actionReload) self.menu.addAction(self.__actionHome) self.menu.addAction(self.__actionShare) self.menu.addAction(self.__actionOpenBrowser) if len(self.__customActions) > 0: self.menu.addSeparator() for action in self.__customActions: if action == '-': self.menu.addSeparator() else: self.menu.addAction(action) self.menu.addSeparator() for plugin in QTWSPluginManager.instance().plugins: plugin.add_menu_items(self.menu) self.menu.addSeparator() self.menu.addAction(self.__actionQuit) # Handles all the custom actions using the # URL stored in the action's data field self.menu.triggered.connect(self.__menu_click) self.menu.popup(self.mapToGlobal(position)) def __download(self, item): default_path = QDir(item.downloadDirectory()).filePath( item.downloadFileName()) path, _ = QFileDialog.getSaveFileName(self, "Save as", default_path) if path is None or len(path) == 0: item.cancel() return info = QFileInfo(path) item.setDownloadDirectory(info.dir().path()) item.setDownloadFileName(info.fileName()) item.accept() self.download_windows.append( DownloadProgressWindow(item, info.dir().path() + "/" + info.fileName())) def __share(self): QApplication.instance().clipboard().setText(self.url().toString()) QMessageBox().information(self, 'Shared', 'Copied to the clipboard', QMessageBox.Ok) def __open_in_browser(self): external_browser.open(self.url().toString()) def __quit(self): self.window.quit() def __menu_click(self, action: QAction): if action.data(): self.setUrl(action.data()) def __url_changed(self, status): QTWSPluginManager.instance().each( lambda plugin: plugin.on_page_loaded(self.url()))
def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, module_path, fit_to_view): Buffer.__init__(self, buffer_id, url, arguments, emacs_var_dict, module_path, fit_to_view) self.add_widget(BrowserView(config_dir)) self.config_dir = config_dir self.history_list = [] if self.emacs_var_dict["eaf-browser-remember-history"] == "true": self.history_log_file_path = os.path.join(self.config_dir, "browser", "history", "log.txt") self.history_pattern = re.compile("^(.+)ᛝ(.+)ᛡ(.+)$") self.noprefix_url_pattern = re.compile("^(https?|file)://(.+)") self.nopostfix_url_pattern = re.compile("^[^#\?]*") self.history_close_file_path = os.path.join( self.config_dir, "browser", "history", "close.txt") touch(self.history_log_file_path) with open(self.history_log_file_path, "r") as f: raw_list = f.readlines() for raw_his in raw_list: his_line = re.match(self.history_pattern, raw_his) if his_line is None: # Obsolete Old history format old_his = re.match("(.*)\s((https?|file):[^\s]+)$", raw_his) if old_his is not None: self.history_list.append( HistoryPage(old_his.group(1), old_his.group(2), 1)) else: self.history_list.append( HistoryPage(his_line.group(1), his_line.group(2), his_line.group(3))) # Set User Agent with Firefox's one to make EAF browser can login in Google account. self.pc_user_agent = "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/72.0" self.phone_user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1" self.profile = QWebEngineProfile(self.buffer_widget) self.profile.defaultProfile().setHttpUserAgent(self.pc_user_agent) self.draw_progressbar = False self.eval_dark_js = False self.progressbar_progress = 0 self.progressbar_color = QColor(233, 129, 35, 255) self.progressbar_height = 2 self.light_mode_mask_color = QColor("#FFFFFF") self.dark_mode_mask_color = QColor("#242525") self.current_url = "" self.request_url = "" self.no_need_draw_background = False self.init_background_color() self.buffer_widget.loadStarted.connect(self.start_progress) self.buffer_widget.loadProgress.connect(self.update_progress) self.buffer_widget.urlChanged.connect(self.record_url) self.buffer_widget.web_page.windowCloseRequested.connect( self.close_buffer) self.buffer_widget.web_page.fullScreenRequested.connect( self.handle_fullscreen_request) self.buffer_widget.web_page.pdfPrintingFinished.connect( self.notify_print_message) self.profile.defaultProfile().downloadRequested.connect( self.handle_download_request) settings = QWebEngineSettings.globalSettings() try: settings.setAttribute( QWebEngineSettings.PluginsEnabled, self.emacs_var_dict["eaf-browser-enable-plugin"] == "true") settings.setAttribute( QWebEngineSettings.JavascriptEnabled, self.emacs_var_dict["eaf-browser-enable-javascript"] == "true") settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) settings.setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, False) settings.setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) except Exception: pass for method_name in [ "search_text_forward", "search_text_backward", "zoom_out", "zoom_in", "zoom_reset", "scroll_left", "scroll_right", "scroll_up", "scroll_down", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "refresh_page", "undo_action", "redo_action", "get_url", "exit_fullscreen", "set_focus_text", "clear_focus", "dark_mode", "view_source" ]: self.build_widget_method(method_name) self.build_widget_method("history_backward", "back") self.build_widget_method("history_forward", "forward") self.build_widget_method("action_quit", "search_quit") self.build_widget_method("yank_text", "yank_text", "Yank text.") self.build_widget_method("kill_text", "kill_text", "Kill text.") for method_name in [ "recover_prev_close_page", "scroll_up", "scroll_down", "scroll_left", "scroll_right", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "open_link", "open_link_new_buffer", "open_link_background_buffer", "copy_link", "history_backward", "history_forward", "new_blank_page", "open_download_manage_page", "refresh_page", "zoom_in", "zoom_out", "zoom_reset", "save_as_bookmark", "edit_url", "download_youtube_video", "download_youtube_audio", "toggle_device", "close_buffer", "save_as_pdf", "view_source", "save_as_single_file", "select_left_tab", "select_right_tab", "copy_code" ]: self.build_insert_or_do(method_name)
def __init__(self): super().__init__() self.cookies = {} # 绑定cookie被添加的信号槽 QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(self.onCookieAdd)
def __init__(self): super(Browser, self).__init__() self.dbConnection = DBConnection("data.db") self.dbConnection.createdb() self.centralWidget = QWidget(self) self.grid = QGridLayout(self.centralWidget) self.urlInput = UrlInput(self) self.back = PushButton("", QIcon("Icons/NavigationBar/back.png")) self.forward = PushButton("", QIcon("Icons/NavigationBar/forward.png")) self.reload = PushButton("", QIcon("Icons/NavigationBar/reload.png")) self.bookmark = PushButton("", QIcon("Icons/NavigationBar/noFav.png")) self.home = PushButton("", QIcon("Icons/NavigationBar/home.png")) self.parameter = PushButton("", QIcon("Icons/NavigationBar/param.png")) self.tabWidget = TabWidget(self) self.tabWidget.requestsaddtab() self.back.setFlat(True) self.forward.setFlat(True) self.reload.setFlat(True) self.bookmark.setFlat(True) self.home.setFlat(True) self.parameter.setFlat(True) self.reload.clicked.connect(self.browserWidget.reload) self.back.clicked.connect(self.browserWidget.back) self.forward.clicked.connect(self.browserWidget.forward) self.bookmark.clicked.connect(self.fav) self.home.clicked.connect(lambda: self.urlInput.enterurlgiven( self.dbConnection.executewithreturn("""SELECT home FROM parameters""")[0][0])) self.parameter.clicked.connect(self.openparameter) self.grid.addWidget(self.back, 0, 0) self.grid.addWidget(self.reload, 0, 1) self.grid.addWidget(self.forward, 0, 2) self.grid.addWidget(self.urlInput, 0, 3) self.grid.addWidget(self.bookmark, 0, 4) self.grid.addWidget(self.home, 0, 5) self.grid.addWidget(self.parameter, 0, 6) self.grid.addWidget(self.tabWidget, 1, 0, 1, 7) self.grid.setContentsMargins(0, 0, 0, 0) self.grid.setSpacing(0) self.setCentralWidget(self.centralWidget) self.showMaximized() self.setWindowTitle('Browthon') QWebEngineSettings.globalSettings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) if self.dbConnection.executewithreturn("""SELECT js FROM parameters""")[0][0] == "Activé": QWebEngineSettings.globalSettings().setAttribute(QWebEngineSettings.JavascriptEnabled, True) else: QWebEngineSettings.globalSettings().setAttribute(QWebEngineSettings.JavascriptEnabled, False) self.parameterWindow = ParameterWindow(self) QWebEngineProfile.defaultProfile().\ downloadRequested.connect(self.parameterWindow.downloadPage.downloadrequested) theme = self.dbConnection.executewithreturn("""SELECT theme FROM parameters""")[0][0] if theme == "": self.applytheme("") else: if os.path.exists("Themes/"+theme+"/theme.json"): self.applytheme("Themes/"+theme) else: print("Le theme "+theme+" n'existe pas/plus.") self.applytheme("") self.show()
def __init__(self, *args, **kwargs): super(WebBrowser, self).__init__(*args, **kwargs) QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect( self.onCookieAdd) self.loadFinished.connect(self.onLoadFinished)
res = requests.get(proxy_provider_url) ip = res.text.split(":") port = ip[1] ip = ip[0] proxy = QtNetwork.QNetworkProxy() # Http访问代理 proxy.setType(QtNetwork.QNetworkProxy.HttpProxy) # 代理ip地址HttpProxy proxy.setHostName(ip) # 端口号 proxy.setPort(int(port)) QtNetwork.QNetworkProxy.setApplicationProxy(proxy) interceptor = TwitchInterceptor() profile = QWebEngineProfile() profile.clearHttpCache() profile.clearAllVisitedLinks() pCookie = profile.cookieStore() pCookie.deleteAllCookies() pCookie.deleteSessionCookies() profile.setRequestInterceptor(interceptor) profile.setPersistentCookiesPolicy(QWebEngineProfile.ForcePersistentCookies) page = QWebEnginePage(profile, view) page.loadFinished.connect(on_done) view.setPage(page) page.setUrl(QUrl(twitch_url)) view.show() sys.exit(app.exec_())
def update_settings(section, option): """Update global settings when qwebsettings changed.""" websettings.update_mappings(MAPPINGS, section, option) profile = QWebEngineProfile.defaultProfile() if section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']: _init_stylesheet(profile)
def __init__(self, *args, **kwargs): super(WebEngineView, self).__init__(*args, **kwargs) # 绑定cookie被添加的信号槽 QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect( self.onCookieAdd) self.loadFinished.connect(self.onLoadFinished)
def __init__(self, getter, setter): super().__init__() profile = QWebEngineProfile.defaultProfile() self._getter = getattr(profile, getter) self._setter = getattr(profile, setter)
class BrowserBuffer(Buffer): close_page = QtCore.pyqtSignal(str) get_focus_text = QtCore.pyqtSignal(str, str) open_dev_tools_tab = QtCore.pyqtSignal(object) enter_fullscreen_request = QtCore.pyqtSignal() exit_fullscreen_request = QtCore.pyqtSignal() def __init__(self, buffer_id, url, config_dir, arguments, emacs_var_dict, fit_to_view, background_color): Buffer.__init__(self, buffer_id, url, arguments, emacs_var_dict, fit_to_view, background_color) self.add_widget(BrowserView(config_dir)) self.config_dir = config_dir self.history_list = [] if self.emacs_var_dict["eaf-browser-remember-history"] == "true": self.history_log_file_path = os.path.join(self.config_dir, "browser", "history", "log.txt") self.history_pattern = re.compile("^(.+)ᛝ(.+)ᛡ(.+)$") self.noprefix_url_pattern = re.compile("^(https?|file)://(.+)") self.nopostfix_url_pattern = re.compile("^[^#\?]*") self.history_close_file_path = os.path.join( self.config_dir, "browser", "history", "close.txt") touch(self.history_log_file_path) with open(self.history_log_file_path, "r") as f: raw_list = f.readlines() for raw_his in raw_list: his_line = re.match(self.history_pattern, raw_his) if his_line is None: # Obsolete Old history format old_his = re.match("(.*)\s((https?|file):[^\s]+)$", raw_his) if old_his is not None: self.history_list.append( HistoryPage(old_his.group(1), old_his.group(2), 1)) else: self.history_list.append( HistoryPage(his_line.group(1), his_line.group(2), his_line.group(3))) # Set User Agent with Firefox's one to make EAF browser can login in Google account. self.profile = QWebEngineProfile(self.buffer_widget) self.profile.defaultProfile().setHttpUserAgent( "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/72.0" ) self.buffer_widget.loadStarted.connect(self.start_progress) self.buffer_widget.loadProgress.connect(self.update_progress) self.buffer_widget.loadFinished.connect(self.stop_progress) self.buffer_widget.web_page.windowCloseRequested.connect( self.request_close_buffer) self.buffer_widget.web_page.fullScreenRequested.connect( self.handle_fullscreen_request) self.profile.defaultProfile().downloadRequested.connect( self.handle_download_request) settings = QWebEngineSettings.globalSettings() try: settings.setAttribute( QWebEngineSettings.PluginsEnabled, self.emacs_var_dict["eaf-browser-enable-plugin"] == "true") settings.setAttribute( QWebEngineSettings.JavascriptEnabled, self.emacs_var_dict["eaf-browser-enable-javascript"] == "true") settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) except Exception: pass for method_name in [ "search_text_forward", "search_text_backward", "zoom_out", "zoom_in", "zoom_reset", "scroll_left", "scroll_right", "scroll_up", "scroll_down", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "refresh_page", "undo_action", "redo_action", "get_url", "exit_fullscreen", "set_focus_text", "clear_focus", "dark_mode" ]: self.build_widget_method(method_name) self.build_widget_method("history_backward", "back") self.build_widget_method("history_forward", "forward") self.build_widget_method("action_quit", "search_quit") self.build_widget_method("yank_text", "yank_text", "Yank text.") self.build_widget_method("kill_text", "kill_text", "Kill text.") for method_name in [ "recover_prev_close_page", "scroll_up", "scroll_down", "scroll_left", "scroll_right", "scroll_up_page", "scroll_down_page", "scroll_to_begin", "scroll_to_bottom", "open_link", "open_link_new_buffer", "open_link_background_buffer", "history_backward", "history_forward", "new_blank_page", "open_download_manage_page", "refresh_page", "zoom_in", "zoom_out", "zoom_reset", "save_as_bookmark" ]: self.build_insert_or_do(method_name) def handle_fullscreen_request(self, request): if request.toggleOn(): self.enter_fullscreen_request.emit() else: self.exit_fullscreen_request.emit() request.accept() def handle_download_request(self, download_item): download_data = download_item.url().toString() if download_data.startswith("data:image/"): image_path = os.path.join( os.path.expanduser( self.emacs_var_dict["eaf-browser-download-path"]), "image.png") touch(image_path) with open(image_path, "wb") as f: f.write( base64.decodestring( download_data.split(",")[1].encode("utf-8"))) self.message_to_emacs.emit("Save image: " + image_path) else: self.try_start_aria2_daemon() download_data = download_item.url().toString() with open(os.devnull, "w") as null_file: subprocess.Popen(["aria2p", "add", download_data], stdout=null_file) self.message_to_emacs.emit("Start download: " + download_data) def destroy_buffer(self): # Record close page. self.close_page.emit(self.buffer_widget.url().toString()) # Load blank page to stop video playing, such as youtube.com. self.buffer_widget.open_url("about:blank") if self.buffer_widget is not None: # NOTE: We need delete QWebEnginePage manual, otherwise QtWebEngineProcess won't quit. self.buffer_widget.web_page.deleteLater() self.buffer_widget.deleteLater() def get_key_event_widgets(self): # We need send key event to QWebEngineView's focusProxy widget, not QWebEngineView. return [self.buffer_widget.focusProxy()] def scroll(self, scroll_direction, scroll_type): if scroll_type == "page": if scroll_direction == "up": self.scroll_up_page() else: self.scroll_down_page() else: if scroll_direction == "up": self.scroll_up() else: self.scroll_down() def handle_input_message(self, result_type, result_content): if result_type == "search_text_forward": self.buffer_widget._search_text(str(result_content)) elif result_type == "search_text_backward": self.buffer_widget._search_text(str(result_content), True) elif result_type == "jump_link": self.buffer_widget.jump_to_link(str(result_content).strip()) elif result_type == "jump_link_new_buffer": self.buffer_widget.jump_to_link_new_buffer( str(result_content).strip()) elif result_type == "jump_link_background_buffer": self.buffer_widget.jump_to_link_background_buffer( str(result_content).strip()) elif result_type == "eval_js_file": self.buffer_widget.eval_js_file(str(result_content)) elif result_type == "eval_js": self.buffer_widget.eval_js(str(result_content)) def cancel_input_message(self, result_type): if result_type == "jump_link" or result_type == "jump_link_new_buffer" or result_type == "jump_link_background_buffer": self.buffer_widget.cleanup_links() def clear_all_cookies(self): self.buffer_widget.clear_cookies() self.message_to_emacs.emit("Cleared all cookies.") def try_start_aria2_daemon(self): if not is_port_in_use(6800): with open(os.devnull, "w") as null_file: aria2_args = ["aria2c"] aria2_args.append("-d") aria2_args.append( os.path.expanduser( str(self.emacs_var_dict["eaf-browser-download-path"]))) aria2_proxy_host = str( self.emacs_var_dict["eaf-browser-aria2-proxy-host"]) aria2_proxy_port = str( self.emacs_var_dict["eaf-browser-aria2-proxy-port"]) if aria2_proxy_host != "" and aria2_proxy_port != "": aria2_args.append("--all-proxy") aria2_args.append("http://{0}:{1}".format( aria2_proxy_host, aria2_proxy_port)) aria2_args.append("--enable-rpc") aria2_args.append("--rpc-listen-all") subprocess.Popen(aria2_args, stdout=null_file) def open_download_manage_page(self): self.try_start_aria2_daemon() self.buffer_widget.open_download_manage_page() def copy_text(self): self.buffer_widget.copy_text() self.message_to_emacs.emit("Copy '" + self.buffer_widget.get_selection_text() + "'") def open_link(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link: ", "jump_link") def open_link_new_buffer(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link in New Buffer: ", "jump_link_new_buffer") def open_link_background_buffer(self): self.buffer_widget.get_link_markers() self.send_input_message("Open Link in Background Buffer: ", "jump_link_background_buffer") def reset_default_zoom(self): if hasattr(self, "buffer_widget"): self.buffer_widget.setZoomFactor( float(self.emacs_var_dict["eaf-browser-default-zoom"])) def edit_focus_text(self): text = self.buffer_widget.get_focus_text() if text != None: self.get_focus_text.emit(self.buffer_id, text) else: self.message_to_emacs.emit("No active input element.") def is_focus(self): return self.buffer_widget.get_focus_text() != None def record_history(self, new_title): new_url = self.buffer_widget.filter_url( self.buffer_widget.url().toString()) if self.emacs_var_dict["eaf-browser-remember-history"] == "true" and self.buffer_widget.filter_title(new_title) != "" and \ self.arguments != "temp_html_file" and new_title != "about:blank" and new_url != "about:blank": # Throw traceback info if algorithm has bug and protection of historical record is not erased. try: noprefix_new_url_match = re.match(self.noprefix_url_pattern, new_url) if noprefix_new_url_match is not None: found = False for history in self.history_list: noprefix_url_match = re.match( self.noprefix_url_pattern, history.url) if noprefix_url_match is not None: noprefix_url = noprefix_url_match.group(2) noprefix_new_url = noprefix_new_url_match.group(2) nopostfix_new_url_match = re.match( self.nopostfix_url_pattern, noprefix_new_url) if noprefix_url == noprefix_new_url: # found unique url history.title = new_title history.url = new_url history.hit += 0.5 found = True elif nopostfix_new_url_match is not None and noprefix_url == nopostfix_new_url_match.group( ): # also increment parent history.hit += 0.25 if not found: self.history_list.append( HistoryPage(new_title, new_url, 1)) self.history_list.sort(key=lambda x: x.hit, reverse=True) with open(self.history_log_file_path, "w") as f: f.writelines( map( lambda history: history.title + "ᛝ" + history.url + "ᛡ" + str(history.hit) + "\n", self.history_list)) except Exception: import traceback self.message_to_emacs.emit("Error in record_history: " + str(traceback.print_exc())) def adjust_dark_mode(self): try: if self.emacs_var_dict["eaf-browser-dark-mode"] == "true": self.dark_mode() except Exception: pass def new_blank_page(self): self.eval_in_emacs.emit( '''(eaf-open \"{0}\" \"browser\" \"\" t)''' ''.format(self.emacs_var_dict["eaf-browser-blank-page-url"])) def clear_history(self): if os.path.exists(self.history_log_file_path): os.remove(self.history_log_file_path) self.message_to_emacs.emit("Cleared browsing history.") else: self.message_to_emacs.emit("There is no browsing history.") def record_close_page(self, url): if self.emacs_var_dict["eaf-browser-remember-history"] == "true": touch(self.history_close_file_path) with open(self.history_close_file_path, "a") as f: f.write("{0}\n".format(url)) def recover_prev_close_page(self): if os.path.exists(self.history_close_file_path): with open(self.history_close_file_path, "r") as f: close_urls = f.readlines() if len(close_urls) > 0: # We need use rstrip remove \n char from url record. prev_close_url = close_urls.pop().rstrip() self.open_url_in_new_tab.emit(prev_close_url) open(self.history_close_file_path, "w").writelines(close_urls) self.message_to_emacs.emit( "Recovery {0}".format(prev_close_url)) else: self.message_to_emacs.emit("No page need recovery.") else: self.message_to_emacs.emit("No page need recovery.") def insert_or_do(func): def _do(self, *args, **kwargs): if self.is_focus(): self.fake_key_event(self.current_event_string) else: func(self, *args, **kwargs) return _do def build_insert_or_do(self, method_name): def _do(): if self.is_focus(): self.fake_key_event(self.current_event_string) else: getattr(self, method_name)() setattr(self, "insert_or_{}".format(method_name), _do) @insert_or_do def insert_or_close_buffer(self): self.request_close_buffer() @insert_or_do def insert_or_goto_left_tab(self): self.goto_left_tab.emit() @insert_or_do def insert_or_goto_right_tab(self): self.goto_right_tab.emit() @insert_or_do def insert_or_open_url(self): self.eval_in_emacs.emit( '''(call-interactively 'eaf-open-browser-with-history)''') def select_all_or_input_text(self): if self.is_focus(): self.buffer_widget.select_input_text() else: self.buffer_widget.select_all() def eval_js_file(self): self.send_input_message("Eval JS file: ", "eval_js_file", "file") def eval_js(self): self.send_input_message("Eval JS: ", "eval_js") def open_dev_tool_page(self): self.open_dev_tools_tab.emit(self.buffer_widget.web_page)
def __init__(self): super(MainWindow, self).__init__() self._okToClose = False # systray = QSystemTrayIcon(self) # systray.setIcon(QIcon(":/icons/icon.png")) # systray.show() # def systray_activated(reason): # self.setVisible(self.isVisible() ^ True) # systray.activated.connect(systray_activated) # results self._incr_results = None self._fts_results = None self._found_items = None # status self._selection_pending = False self._loading_pending = False self._auto_fts_phrase = None # Lazy-loaded objects self._lazy = {} # Local URL scheme for name in _LOCAL_SCHEMES: scheme = QWebEngineUrlScheme(name.encode("ascii")) scheme.setFlags( QWebEngineUrlScheme.SecureScheme | QWebEngineUrlScheme.LocalScheme | QWebEngineUrlScheme.LocalAccessAllowed | QWebEngineUrlScheme.CorsEnabled ) QWebEngineUrlScheme.registerScheme(scheme) self._scheme_handler = MyUrlSchemeHandler(self) profile = QWebEngineProfile.defaultProfile() for name in _LOCAL_SCHEMES: profile.installUrlSchemeHandler(name.encode("ascii"), self._scheme_handler) # Url request interceptor profile.setUrlRequestInterceptor(UrlRequestInterceptor(self)) # Setup self._setup_ui() self._restore_from_config() # Timers def _makeSingleShotTimer(slot): timer = QTimer(self) timer.setSingleShot(True) timer.timeout.connect(slot) return timer self._timerUpdateIndex = _makeSingleShotTimer(self._updateIndex) self._timerAutoFTS = _makeSingleShotTimer(self._onTimerAutoFullSearchTimeout) self._timerAutoPron = _makeSingleShotTimer(self._onTimerAutoPronTimeout) self._timerSpellCorrection = _makeSingleShotTimer(self._onTimerSpellCorrection) self._timerSearchingLabel = _makeSingleShotTimer(self._onTimerSearchingLabel) # Clipboard clipboard = QApplication.clipboard() clipboard.dataChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Clipboard) ) clipboard.selectionChanged.connect( partial(self._onClipboardChanged, mode=QClipboard.Selection) ) # Stylesheet for the item list pane try: self._ui.listWidgetIndex.setStyleSheet( _load_static_data("styles/list.css").decode("utf-8", "ignore") ) except EnvironmentError: pass # Check index QTimer.singleShot(0, self._check_index) # Show self.show() # Click the dock icon (macOS) if objc: def applicationShouldHandleReopen_hasVisibleWindows_(s, a, f): self.show() objc.classAddMethods( Cocoa.NSApplication.sharedApplication().delegate().class__(), [applicationShouldHandleReopen_hasVisibleWindows_], )