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 _set(self, value, settings=None): utils.unused(settings) setter = getattr(QWebEngineProfile.defaultProfile(), self._setter) setter( QWebEngineProfile.AllowPersistentCookies if value else QWebEngineProfile.NoPersistentCookies )
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(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: 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.8: Security fixes up to 72.0.3626.121 (2019-03-01) 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.3: Security fixes up to 73.0.3683.75 (2019-03-12) Qt 5.13: Chromium 73 73.0.3683.105 (~2019-02-28) 5.13.0: Security fixes up to 74.0.3729.131 (2019-04-30) Also see https://www.chromium.org/developers/calendar and https://chromereleases.googleblog.com/ """ if webenginesettings is None or QWebEngineProfile is None: # This should never happen return 'unavailable' ua = webenginesettings.default_user_agent if ua is None: profile = QWebEngineProfile.defaultProfile() 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_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 _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 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 _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 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 testdata_scheme(qapp): try: global _qute_scheme_handler from qutebrowser.browser.webengine import webenginequtescheme from PyQt5.QtWebEngineWidgets import QWebEngineProfile webenginequtescheme.init() _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 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, bridge_objs: BridgeObjects = None, *args, **kwargs) -> None: super().__init__(name='_web_container', bridge_objs=bridge_objs, *args, **kwargs) if self._config.debug_mode: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345' self.profile = QWebEngineProfile.defaultProfile() self.interceptor = QtUrlRequestInterceptor() self.view = QWebEngineView(parent=self._main_window.widget) self.page = self.view.page() self.channel = QWebChannel(self.page) self.bridge_initialized = False self._initialize_page(self.page) if self._config.debug_mode: self.devtools = DevTools() if not self._config.context_menu.enabled: self.view.setContextMenuPolicy(Qt.PreventContextMenu) if not self._config.allow_remote_urls: self.profile.setRequestInterceptor(self.interceptor) if self._config.entry_point.autoload: self.initialize_bridge_objects() self.load() self.view.show() self._main_window.widget.setCentralWidget(self.view)
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_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 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, getter, setter): super().__init__() profile = QWebEngineProfile.defaultProfile() self._getter = getattr(profile, getter) self._setter = getattr(profile, setter)
def init_user_agent(): _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent())
class BrowserBuffer(Buffer): get_focus_text = QtCore.pyqtSignal(str, str) 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)) # 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) 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)) 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 search_text_forward(self): self.buffer_widget.search_text_forward() def search_text_backward(self): self.buffer_widget.search_text_backward() def history_backward(self): self.buffer_widget.back() def history_forward(self): self.buffer_widget.forward() def clear_all_cookies(self): self.buffer_widget.clear_cookies() self.message_to_emacs.emit("Cleared all cookies.") def action_quit(self): self.buffer_widget.search_quit() def zoom_out(self): self.buffer_widget.zoom_out() def zoom_in(self): self.buffer_widget.zoom_in() def zoom_reset(self): self.buffer_widget.zoom_reset() def scroll_left(self): self.buffer_widget.scroll_left() def scroll_right(self): self.buffer_widget.scroll_right() def scroll_up(self): self.buffer_widget.scroll_up() def scroll_down(self): self.buffer_widget.scroll_down() def scroll_up_page(self): self.buffer_widget.scroll_up_page() def scroll_down_page(self): self.buffer_widget.scroll_down_page() def scroll_to_begin(self): self.buffer_widget.scroll_to_begin() def scroll_to_bottom(self): self.buffer_widget.scroll_to_bottom() def refresh_page(self): self.buffer_widget.refresh_page() def copy_text(self): self.buffer_widget.copy_text() self.message_to_emacs.emit("Copy selected text.") def yank_text(self): self.buffer_widget.yank_text() self.message_to_emacs.emit("Yank text.") def kill_text(self): self.buffer_widget.kill_text() self.message_to_emacs.emit("Kill text.") def undo_action(self): self.buffer_widget.undo_action() def redo_action(self): self.buffer_widget.redo_action() def get_url(self): return self.buffer_widget.get_url() 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 set_focus_text(self, new_text): self.buffer_widget.set_focus_text(new_text) def is_focus(self): return self.buffer_widget.get_focus_text() != None 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 @insert_or_do def insert_or_scroll_up(self): self.scroll_up() @insert_or_do def insert_or_scroll_down(self): self.scroll_down() @insert_or_do def insert_or_scroll_down_page(self): self.scroll_down_page() @insert_or_do def insert_or_scroll_up_page(self): self.scroll_up_page() @insert_or_do def insert_or_scroll_to_begin(self): self.scroll_to_begin() @insert_or_do def insert_or_scroll_to_bottom(self): self.scroll_to_bottom() @insert_or_do def insert_or_open_link(self): self.open_link() @insert_or_do def insert_or_open_link_new_buffer(self): self.open_link_new_buffer() @insert_or_do def insert_or_open_link_background_buffer(self): self.open_link_background_buffer() @insert_or_do def insert_or_history_backward(self): self.history_backward() @insert_or_do def insert_or_history_forward(self): self.history_forward() @insert_or_do def insert_or_scroll_left(self): self.scroll_left() @insert_or_do def insert_or_scroll_right(self): self.scroll_right() @insert_or_do def insert_or_new_blank_page(self): self.new_blank_page() @insert_or_do def insert_or_refresh_page(self): self.refresh_page() @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() def select_all_or_input_text(self): if self.is_focus(): self.buffer_widget.select_input_text() else: self.buffer_widget.select_all() def clear_focus(self): self.buffer_widget.clear_focus() def eval_js_file(self): self.send_input_message("Eval JS: ", "eval_js_file", "file") def dark_mode(self): self.buffer_widget.dark_mode()
def __init__(self, *args, **kwargs): super(WebBrowser, self).__init__(*args, **kwargs) QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect( self.onCookieAdd) self.loadFinished.connect(self.onLoadFinished)
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)
# 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')
def __init__(self): super().__init__() self.cookies = {} # 绑定cookie被添加的信号槽 QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(self.onCookieAdd)
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__(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 loadSettings(self): settings = Settings() settings.beginGroup('Themes') activeTheme = settings.value('activeTheme', const.DEFAULT_THEME_NAME) settings.endGroup() self.loadTheme(activeTheme) webSettings = self._webProfile.settings() # Web browsing settings settings.beginGroup('Web-Browser-Settings') webSettings.setAttribute(QWebEngineSettings.LocalStorageEnabled, settings.value("HTML5StorageEnabled", True)) webSettings.setAttribute(QWebEngineSettings.PluginsEnabled, settings.value("allowPlugins", True)) webSettings.setAttribute(QWebEngineSettings.JavascriptEnabled, settings.value("allowJavaScript", True)) webSettings.setAttribute( QWebEngineSettings.JavascriptCanOpenWindows, settings.value("allowJavaScriptOpenWindow", False)) webSettings.setAttribute( QWebEngineSettings.JavascriptCanAccessClipboard, settings.value("allowJavaScriptAccessClipboard", True)) webSettings.setAttribute( QWebEngineSettings.LinksIncludedInFocusChain, settings.value("IncludeLinkInFocusChain", False)) webSettings.setAttribute(QWebEngineSettings.XSSAuditingEnabled, settings.value("XSSAuditing", False)) webSettings.setAttribute( QWebEngineSettings.PrintElementBackgrounds, settings.value("PrintElementBackground", True)) webSettings.setAttribute(QWebEngineSettings.SpatialNavigationEnabled, settings.value("SpatialNavigation", False)) webSettings.setAttribute(QWebEngineSettings.ScrollAnimatorEnabled, settings.value("AnimateScrolling", True)) webSettings.setAttribute(QWebEngineSettings.HyperlinkAuditingEnabled, False) webSettings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) webSettings.setAttribute( QWebEngineSettings.LocalContentCanAccessRemoteUrls, True) webSettings.setAttribute(QWebEngineSettings.FocusOnNavigationEnabled, False) webSettings.setAttribute( QWebEngineSettings.AllowWindowActivationFromJavaScript, settings.value("allowJavaScriptActivationWindow", False)) webSettings.setAttribute(QWebEngineSettings.JavascriptCanPaste, settings.value("allowJavaScriptPaste", True)) webSettings.setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, settings.value("DisableVideoAutoPlay", False)) webSettings.setAttribute(QWebEngineSettings.WebRTCPublicInterfacesOnly, settings.value("WebRTCPublicIpOnly", True)) webSettings.setUnknownUrlSchemePolicy( QWebEngineSettings.AllowAllUnknownUrlSchemes) webSettings.setAttribute(QWebEngineSettings.DnsPrefetchEnabled, settings.value("DNSPrefetch", True)) webSettings.setDefaultTextEncoding( settings.value("DefaultEncoding", webSettings.defaultTextEncoding(), type=str)) scrollLines = settings.value("wheelScrollLines", self.wheelScrollLines()) self.setWheelScrollLines(scrollLines) userCss = settings.value("userStyleSheet", '') settings.endGroup() self.setUserStyleSheet(userCss) settings.beginGroup("Browser-Fonts") webSettings.setFontFamily( QWebEngineSettings.StandardFont, settings.value("StandardFont", webSettings.fontFamily( QWebEngineSettings.StandardFont), type=str)) webSettings.setFontFamily( QWebEngineSettings.CursiveFont, settings.value("CursiveFont", webSettings.fontFamily( QWebEngineSettings.CursiveFont), type=str)) webSettings.setFontFamily( QWebEngineSettings.FantasyFont, settings.value("FantasyFont", webSettings.fontFamily( QWebEngineSettings.FantasyFont), type=str)) webSettings.setFontFamily( QWebEngineSettings.FixedFont, settings.value("FixedFont", webSettings.fontFamily( QWebEngineSettings.FixedFont), type=str)) webSettings.setFontFamily( QWebEngineSettings.SansSerifFont, settings.value("SansSerifFont", webSettings.fontFamily( QWebEngineSettings.SansSerifFont), type=str)) webSettings.setFontFamily( QWebEngineSettings.SerifFont, settings.value("SerifFont", webSettings.fontFamily( QWebEngineSettings.SerifFont), type=str)) webSettings.setFontSize(QWebEngineSettings.DefaultFontSize, settings.value("DefaultFontSize", 15)) webSettings.setFontSize(QWebEngineSettings.DefaultFixedFontSize, settings.value("FixedFontSize", 14)) webSettings.setFontSize(QWebEngineSettings.MinimumFontSize, settings.value("MinimumFontSize", 3)) webSettings.setFontSize(QWebEngineSettings.MinimumLogicalFontSize, settings.value("MinimumLogicalFontSize", 5)) settings.endGroup() profile = QWebEngineProfile.defaultProfile() profile.setPersistentCookiesPolicy( QWebEngineProfile.AllowPersistentCookies) profile.setPersistentStoragePath(DataPaths.currentProfilePath()) defaultPath = DataPaths.path(DataPaths.Cache) if not defaultPath.startswith(DataPaths.currentProfilePath()): defaultPath += '/' + ProfileManager.currentProfile() cachePath = settings.value("Web-Browser-Settings/CachePath", defaultPath, type=str) profile.setCachePath(cachePath) allowCache = settings.value("Web-Browser-Settings/AllowLocalCache", True) profile.setHttpCacheType(allowCache and QWebEngineProfile.DiskHttpCache or QWebEngineProfile.MemoryHttpCache) cacheSize = settings.value("Web-Browser-Settings/LocalCacheSize", 50) * 1000 * 1000 profile.setHttpCacheMaximumSize(cacheSize) settings.beginGroup("SpellCheck") profile.setSpellCheckEnabled(settings.value("Enabled", False)) profile.setSpellCheckLanguages(settings.value("Languages", type=list)) settings.endGroup() if self.isPrivate(): webSettings.setAttribute(QWebEngineSettings.LocalStorageEnabled, False) self.history().setSaving(False) if self._downloadManager: self._downloadManager.loadSettings() gVar.appSettings.loadSettings() self.userAgentManager().loadSettings() self.networkManager().loadSettings()
def webengine_profile(self, qapp): profile = QWebEngineProfile.defaultProfile() profile.setParent(qapp) return profile
class BrowserBuffer(Buffer): close_page = QtCore.pyqtSignal(str) open_devtools_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(buffer_id, config_dir)) self.config_dir = config_dir self.page_closed = False self.zoom_data = ZoomSizeDb( os.path.join(os.path.dirname(config_dir), "browser", "zoom_data.db")) self.pc_user_agent = self.emacs_var_dict["eaf-browser-pc-user-agent"] self.phone_user_agent = self.emacs_var_dict[ "eaf-browser-phone-user-agent"] self.profile = QWebEngineProfile(self.buffer_widget) self.profile.defaultProfile().setHttpUserAgent(self.pc_user_agent) self.caret_js_ready = False self.caret_browsing_mode = False self.caret_browsing_exit_flag = True self.caret_browsing_mark_activated = False self.caret_browsing_search_text = "" self.light_mode_mask_color = QColor("#FFFFFF") self.dark_mode_mask_color = QColor("#242525") self.is_dark_mode_enabled = self.dark_mode_is_enabled() self.current_url = "" self.request_url = "" self.init_background_color() 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) self.settings = QWebEngineSettings.globalSettings() try: self.settings.setAttribute( QWebEngineSettings.PluginsEnabled, self.emacs_var_dict["eaf-browser-enable-plugin"] == "true") self.settings.setAttribute( QWebEngineSettings.JavascriptEnabled, self.emacs_var_dict["eaf-browser-enable-javascript"] == "true") self.settings.setAttribute( QWebEngineSettings.FullScreenSupportEnabled, True) self.settings.setAttribute( QWebEngineSettings.PlaybackRequiresUserGesture, False) self.settings.setAttribute(QWebEngineSettings.DnsPrefetchEnabled, True) self.settings.setAttribute( QWebEngineSettings.FocusOnNavigationEnabled, True) if self.emacs_var_dict[ "eaf-browser-unknown-url-scheme-policy"] == "DisallowUnknownUrlSchemes": self.settings.setUnknownUrlSchemePolicy( self.settings.DisallowUnknownUrlSchemes) elif self.emacs_var_dict[ "eaf-browser-unknown-url-scheme-policy"] == "AllowUnknownUrlSchemesFromUserInteraction": self.settings.setUnknownUrlSchemePolicy( self.settings.AllowUnknownUrlSchemesFromUserInteraction) elif self.emacs_var_dict[ "eaf-browser-unknown-url-scheme-policy"] == "AllowAllUnknownUrlSchemes": self.settings.setUnknownUrlSchemePolicy( self.settings.AllowAllUnknownUrlSchemes) font_family = self.emacs_var_dict['eaf-browser-font-family'] if font_family: for ff in ( self.settings.StandardFont, self.settings.FixedFont, self.settings.SerifFont, self.settings.SansSerifFont, # What's these font families? # self.settings.CursiveFont, # self.settings.FantasyFont, # self.settings.PictographFont ): self.settings.setFontFamily(ff, font_family) except Exception: pass self.build_all_methods(self.buffer_widget) self.build_all_methods(self) # Reset to default zoom when page init or page url changed. self.reset_default_zoom() self.buffer_widget.urlChanged.connect( lambda url: self.reset_default_zoom()) def notify_print_message(self, file_path, success): ''' Notify the print as pdf message.''' 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) message_to_emacs( "Successfully saved current webpage as '{}'.".format( title_path)) except Exception: message_to_emacs( "Successfully saved current webpage as '{}'.".format( file_path)) else: message_to_emacs( "Failed to save current webpage as '{}'.".format(file_path)) def notify_monolith_message(self, download_path, file_path, title, retcode): ''' Notify the save as html message.''' if retcode == 0: title_path = os.path.join(os.path.expanduser(download_path), "{}.html".format(title)) try: os.rename(file_path, title_path) message_to_emacs( "Successfully saved current webpage as '{}'.".format( title_path)) except Exception: message_to_emacs( "Successfully saved current webpage as '{}'.".format( file_path)) else: message_to_emacs("Failed to save current page as single file.") def dark_mode_is_enabled(self): ''' Return bool of whether dark mode is enabled.''' 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"] == "follow" 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): ''' Initialize the background colour.''' if self.dark_mode_is_enabled(): self.buffer_widget.web_page.setBackgroundColor( self.dark_mode_mask_color) else: self.buffer_widget.web_page.setBackgroundColor( self.light_mode_mask_color) def handle_fullscreen_request(self, request): ''' Handle fullscreen request.''' if request.toggleOn(): self.enter_fullscreen_request.emit() else: self.exit_fullscreen_request.emit() request.accept() def should_skip_download_item(self, download_item): return download_item.page() != self.buffer_widget.web_page def handle_download_request(self, download_item): ''' Handle download request.''' if self.should_skip_download_item(download_item): return 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"))) message_to_emacs("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) message_to_emacs("Downloading: " + download_url) def _save_as_pdf(self): 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)) message_to_emacs("Saving as pdf...") self.buffer_widget.web_page.printToPdf(pdf_path) @interactive(insert_or_do=True) def save_as_pdf(self): ''' Request to save as pdf.''' self.send_input_message("Save current webpage as PDF?", "save_as_pdf", "yes-or-no") def _save_as_single_file(self): 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)) message_to_emacs("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) @interactive(insert_or_do=True) def save_as_single_file(self): ''' Request to save current webpage as single html file.''' import shutil if shutil.which("monolith") is None: message_to_emacs("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): ''' Destroy the buffer.''' # Record close page. self.close_page.emit(self.buffer_widget.get_url()) # 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): ''' Send key event to QWebEngineView's focusProxy widget.''' # We need send key event to QWebEngineView's focusProxy widget, not QWebEngineView. return [self.buffer_widget.focusProxy()] def scroll_other_buffer(self, scroll_direction, scroll_type): ''' Scroll.''' 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_response(self, callback_tag, result_content): ''' Handle input message.''' result_content = str(result_content) if callback_tag == "search_text_forward": self.buffer_widget._search_text(result_content) elif callback_tag == "search_text_backward": self.buffer_widget._search_text(result_content, True) elif callback_tag == "caret_search_text_forward": self._caret_search_text(result_content) elif callback_tag == "caret_search_text_backward": self._caret_search_text(result_content, True) elif callback_tag == "caret_at_line": self.buffer_widget._caret_at_line(result_content.strip()) elif callback_tag == "open_link" or callback_tag == "select_marker_text": self.buffer_widget._open_link(result_content.strip()) elif callback_tag == "open_link_new_buffer": self.buffer_widget._open_link_new_buffer(result_content.strip()) elif callback_tag == "jump_link_background_buffer": self.buffer_widget._open_link_background_buffer( result_content.strip()) elif callback_tag == "copy_link": self.buffer_widget._copy_link(result_content.strip()) elif callback_tag == "eval_js_file": self.buffer_widget.eval_js_file(result_content) elif callback_tag == "eval_js": self.buffer_widget.eval_js(result_content) elif callback_tag == "save_as_pdf": self._save_as_pdf() elif callback_tag == "save_as_single_file": self._save_as_single_file() elif callback_tag == "edit_url": self.buffer_widget.open_url(result_content) elif callback_tag == "copy_code": self.buffer_widget.copy_code_content(result_content.strip()) else: return False return True def cancel_input_response(self, callback_tag): ''' Cancel input message.''' if callback_tag == "open_link" or \ callback_tag == "open_link_new_buffer" or \ callback_tag == "jump_link_background_buffer" or \ callback_tag == "select_marker_text" or \ callback_tag == "caret_at_line" or \ callback_tag == "copy_link" or \ callback_tag == "copy_code" or \ callback_tag == "edit_url": self.buffer_widget.cleanup_links_dom() def caret_toggle_browsing(self): ''' Init caret browsing.''' if self.caret_js_ready: if self.caret_browsing_mode: self.buffer_widget.eval_js("CaretBrowsing.shutdown();") message_to_emacs("Caret browsing deactivated.") self.caret_browsing_mode = False else: self.buffer_widget.eval_js("CaretBrowsing.setInitialCursor();") message_to_emacs("Caret browsing activated.") self.caret_browsing_mode = True eval_in_emacs('eaf--toggle-caret-browsing', ["'t" if self.caret_browsing_mode else "'nil"]) def caret_exit(self): ''' Exit caret browsing.''' if self.caret_browsing_mode: # Avoid popup tranlsate tips when exit caret mode. self.caret_browsing_exit_flag = True self.caret_toggle_browsing() @interactive def caret_next_sentence(self): ''' Switch to next line in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('forward', 'sentence');") @interactive def caret_previous_sentence(self): ''' Switch to previous line in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('backward', 'sentence');") @interactive def caret_next_line(self): ''' Switch to next line in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('forward', 'line');") @interactive def caret_previous_line(self): ''' Switch to previous line in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('backward', 'line');") @interactive def caret_next_character(self): ''' Switch to next character in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('forward', 'character');") @interactive def caret_previous_character(self): ''' Switch to previous character in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('backward', 'character');") @interactive def caret_next_word(self): ''' Switch to next word in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('forward', 'word');") @interactive def caret_previous_word(self): ''' Switch to previous word in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('backward', 'word');") @interactive def caret_to_bottom(self): ''' Switch to next word in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('forward', 'documentboundary');") @interactive def caret_to_top(self): ''' Switch to previous word in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js( "CaretBrowsing.move('backward', 'documentboundary');") @interactive def caret_rotate_selection(self): ''' Rotate selection.''' if self.caret_browsing_mode: if self.caret_browsing_mark_activated: self.buffer_widget.eval_js("CaretBrowsing.rotateSelection();") @interactive def caret_toggle_mark(self): ''' Toggle mark in caret browsing.''' if self.caret_browsing_mode: self.buffer_widget.eval_js("CaretBrowsing.toggleMark();") if self.buffer_widget.execute_js("CaretBrowsing.markEnabled"): self.caret_browsing_mark_activated = True message_to_emacs("Caret Mark set") else: self.caret_browsing_mark_activated = False message_to_emacs("Caret Mark deactivated") @interactive def caret_clear_search(self): ''' Clear search text in caret browsing.''' if self.caret_browsing_mode: if self.caret_browsing_mark_activated: self.caret_browsing_search_text = "" message_to_emacs("Cleared caret search text.") @interactive def caret_search_forward(self): ''' Search Text forward in caret browsing.''' if self.caret_browsing_mode: if self.caret_browsing_mark_activated: if self.caret_browsing_search_text == "": self.send_input_message("Forward Search Text and Select: ", "caret_search_text_forward") else: self._caret_search_text(self.caret_browsing_search_text) @interactive def caret_search_backward(self): ''' Search Text backward in caret browsing.''' if self.caret_browsing_mode: if self.caret_browsing_mark_activated: if self.caret_browsing_search_text == "": self.send_input_message( "Backward Search Text and Select: ", "caret_search_text_backward") else: self._caret_search_text(self.caret_browsing_search_text, True) def _caret_search_text(self, text, is_backward=False): if self.caret_browsing_search_text != text: self.caret_browsing_search_text = text if is_backward: if not self.buffer_widget.execute_js("window.find('" + text + "',false,true)"): message_to_emacs( "Unable to find more, please try forward search.") else: if not self.buffer_widget.execute_js("window.find('" + text + "')"): message_to_emacs( "Unable to find more, please try backward search.") @interactive def caret_translate_text(self): self.translate_text() @interactive(insert_or_do=True) def translate_text(self): if self.buffer_widget.selectedText().strip() != "": self.buffer_widget.translate_selected_text.emit( self.buffer_widget.selectedText()) def copy_text(self): ''' Copy selected text.''' self.buffer_widget.copy_text() message_to_emacs("Copied selected text.") @interactive def copy_code(self): ''' Copy code.''' self.buffer_widget.get_code_markers() self.send_input_message("Copy code: ", "copy_code") @interactive(insert_or_do=True) def select_text(self): ''' Select Text.''' self.buffer_widget.get_text_markers() self.send_input_message("Select Text: ", "select_marker_text") @interactive(insert_or_do=True) def caret_at_line(self): self.buffer_widget.get_text_markers() self.send_input_message("Toggle Caret Browsing at Line: ", "caret_at_line") @interactive(insert_or_do=True) def open_link(self): ''' Open Link through a marker.''' self.buffer_widget.get_link_markers() self.send_input_message("Open Link: ", "open_link") @interactive(insert_or_do=True) def open_link_new_buffer(self): ''' Open Link in New Buffer.''' self.buffer_widget.get_link_markers() self.send_input_message("Open Link in New Buffer: ", "open_link_new_buffer") @interactive(insert_or_do=True) def open_link_background_buffer(self): ''' Open Link in Background Buffer.''' self.buffer_widget.get_link_markers() self.send_input_message("Open Link in Background Buffer: ", "jump_link_background_buffer") @interactive def copy_link(self): ''' Copy link.''' self.buffer_widget.get_link_markers() self.send_input_message("Copy link: ", "copy_link") @interactive(insert_or_do=True) def edit_url(self): ''' Edit link.''' self.send_input_message("Edit link: ", "edit_url", "string", self.url) def reset_default_zoom(self): ''' Reset default magnification.''' if hasattr(self, "buffer_widget"): result = self.zoom_data.get_entry(urlparse(self.url).hostname) zoom_factor = float( self.emacs_var_dict["eaf-browser-default-zoom"]) for row in result: zoom_factor = float(row[0]) self.buffer_widget.setZoomFactor(zoom_factor) def atomic_edit(self): ''' Edit the focus text.''' text = self.buffer_widget.get_focus_text() if text != None: atomic_edit(self.buffer_id, text) else: message_to_emacs("No active input element.") def is_focus(self): ''' Return bool of whether the buffer is focused.''' return self.buffer_widget.get_focus_text( ) != None or self.url == "devtools://devtools/bundled/devtools_app.html" @interactive(insert_or_do=True) def duplicate_page(self): duplicate_page_in_new_tab(self.current_url) @interactive(insert_or_do=True) def open_browser(self): ''' Open browser.''' eval_in_emacs('call-interactively', ['\'eaf-open-browser-with-history']) def select_all_or_input_text(self): ''' Select all or input text.''' if self.is_focus(): self.buffer_widget.select_input_text() else: self.buffer_widget.select_all() @interactive() def eval_js_file(self): ''' Eval JS file.''' self.send_input_message("Eval JS file: ", "eval_js_file", "file") @interactive() def eval_js(self): ''' Eval JS interactively.''' self.send_input_message("Eval JS: ", "eval_js") @interactive() def open_devtools(self): ''' Open dev-tool page.''' self.open_devtools_tab.emit(self.buffer_widget.web_page) @interactive(insert_or_do=True) def toggle_device(self): ''' Toggle device.''' 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() @interactive def toggle_dark_mode(self): self.is_dark_mode_enabled = not self.is_dark_mode_enabled self.buffer_widget.load_dark_mode_js() if self.is_dark_mode_enabled: self.buffer_widget.enable_dark_mode() else: self.buffer_widget.disable_dark_mode() @interactive(insert_or_do=True) def history_forward(self): self.buffer_widget.history().forward() if platform.system() == "Windows": eval_in_emacs('eaf-activate-emacs-window', []) @interactive(insert_or_do=True) def history_backward(self): self.buffer_widget.history().back() if platform.system() == "Windows": eval_in_emacs('eaf-activate-emacs-window', []) @interactive(insert_or_do=True) def download_youtube_video(self): ''' Download Youtube Video.''' self.download_youtube_file() @interactive(insert_or_do=True) def download_youtube_audio(self): ''' Download Youtube Audio.''' self.download_youtube_file(True) def download_youtube_file(self, only_audio=False): ''' Download Youtube File.''' url = self.buffer_widget.get_url() 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: message_to_emacs( "Downloaded: {0}".format(url)), null_file) message_to_emacs("Downloading {0}: {1}".format(file_type, url)) else: message_to_emacs( "Please install youtube-dl to use this feature.") else: message_to_emacs( "Only videos from YouTube can be downloaded for now.") def build_js_bridge_method(self, python_method_name, js_method_name): def _do(): self.buffer_widget.execute_js('''{}()'''.format(js_method_name)) setattr(self, python_method_name, _do)
def _set(self, value, settings=None): utils.unused(settings) setter = getattr(QWebEngineProfile.defaultProfile(), self._setter) setter(value)
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_], )
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.")
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__(self, *args, **kwargs): super(MyWebEngineView, self).__init__(*args, **kwargs) # 绑定cookie被添加的信号槽 QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect( self.onCookieAdd) self.cookies = {} # 存放cookie字典
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, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(800, 600) QWebEngineProfile.defaultProfile().setRequestInterceptor(RequestInterceptor(self))
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 get(self, settings=None): utils.unused(settings) getter = getattr(QWebEngineProfile.defaultProfile(), self._getter) return getter()
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, argv): # noqa 901 super(MainApplication, self).__init__(argv) self._isPrivate = False self._isPortable = True self._isClosing = False self._isStartingAfterCrash = False self._history = None # History self._bookmarks = None # Bookmarks self._autoFill = None # AutoFill self._cookieJar = None # CookieJar self._plugins = None # PluginProxy self._browsingLibrary = None # BrowsingLibrary self._networkManager = None self._restoreManager = None self._sessionManager = None self._downloadManager = None self._userAgentManager = None self._searchEnginesManager = None self._closedWindowsManager = None self._protocolHandlerManager = None self._html5PermissionsManager = None self._desktopNotifications = None # DesktopNotificationsFactory self._webProfile = None # QWebEngineProfile self._autoSaver = None self._proxyStyle = None self._wmClass = QByteArray() self._windows = [] self._lastActiveWindow = None self._postLaunchActions = [] self.setAttribute(Qt.AA_UseHighDpiPixmaps) self.setAttribute(Qt.AA_DontCreateNativeWidgetSiblings) self.setApplicationName('demo') self.setOrganizationDomain('org.autowin') self.setWindowIcon(QIcon.fromTheme('demo', QIcon(':/icons/demo.svg'))) self.setDesktopFileName('orig.autowin.demo') self.setApplicationVersion('1.0') # Set fallback icon theme (eg. on Windows/Mac) if QIcon.fromTheme('view-refresh').isNull(): QIcon.setThemeName('breeze-fallback') # QSQLITE database plugin is required if not QSqlDatabase.isDriverAvailable('QSQLITE'): QMessageBox.Critical( None, 'Error', 'Qt SQLite database plugin is not available.' ' Please install it and restart the application.') self._isClosing = True return if const.OS_WIN: # Set default app font (needed for N'ko) fontId = QFontDatabase.addApplicationFont('font.ttf') if fontId != -1: families = QFontDatabase.applicationFontFamilies(fontId) if not families.empty(): self.setFont(QFont(families.at(0))) startUrl = QUrl() startProfile = '' messages = [] noAddons = False newInstance = False if len(argv) > 1: cmd = CommandLineOptions() for pair in cmd.getActions(): action = pair.action text = pair.text if action == const.CL_StartWithoutAddons: noAddons = True elif action == const.CL_StartWithProfile: startProfile = text elif action == const.CL_StartPortable: self._isPortable = True elif action == const.CL_NewTab: messages.append("ACTION:NewTab") self._postLaunchActions.append(self.OpenNewTab) elif action == const.CL_NewWindow: messages.append("ACTION:NewWindow") elif action == const.CL_ToggleFullScreen: messages.append("ACTION:ToggleFullScreen") self._postLaunchActions.append(self.ToggleFullScreen) elif action == const.CL_ShowDownloadManager: messages.append("ACTION:ShowDownloadManager") self._postLaunchActions.append(self.OpenDownloadManager) elif action == const.CL_StartPrivateBrowsing: self._isPrivate = True elif action == const.CL_StartNewInstance: newInstance = True elif action == const.CL_OpenUrlInCurrentTab: startUrl = QUrl.fromUserInput(text) messages.append("ACTION:OpenUrlInCurrentTab" + text) elif action == const.CL_OpenUrlInNewWindow: startUrl = QUrl.fromUserInput(text) messages.append("ACTION:OpenUrlInNewWindow" + text) elif action == const.CL_OpenUrl: startUrl = QUrl.fromUserInput(text) messages.append("URL:" + text) elif action == const.CL_ExitAction: self._isClosing = True return elif action == const.CL_WMClass: self._wmClass = text if not self.isPortable(): appConf = QSettings( pathjoin(self.applicationDirPath(), '%s.conf' % const.APPNAME), QSettings.IniFormat) appConf.value('Config/Portable') if self.isPortable(): print('%s: Running in Portable Mode.' % const.APPNAME) DataPaths.setPortableVersion() # Don't start single application in private browsing if not self.isPrivate(): appId = 'org.autowin.mc' if self.isPortable(): appId += '.Portable' if self.isTestModeEnabled(): appId += '.TestMode' if newInstance: if not startProfile or startProfile == 'default': print( 'New instance cannot be started with default profile!') else: # Generate unique appId so it is possible to start more # separate instances of the same profile. It is dangerous to # run more instance of the same profile, but if the user # wants it, we should allow it. appId += '.' + str(QDateTime.currentMSecsSinceEpoch()) self.setAppId(appId) # If there is nothing to tell other instance, we need to at least weak it if not messages: messages.append(' ') if self.isRunning(): self._isClosing = True for message in messages: self.sendMessage(message) return if const.OS_MACOS: self.setQuitOnLastWindowClosed(False) # TODO: # disable tabbing issue #2261 # extern void disableWindowTabbing(); # self.disableWindowTabbing() else: self.setQuitOnLastWindowClosed(True) QSettings.setDefaultFormat(QSettings.IniFormat) QDesktopServices.setUrlHandler('http', self.addNewTab) QDesktopServices.setUrlHandler('https', self.addNewTab) QDesktopServices.setUrlHandler('ftp', self.addNewTab) profileManager = ProfileManager() profileManager.initConfigDir() profileManager.initCurrentProfile(startProfile) Settings.createSettings( pathjoin(DataPaths.currentProfilePath(), 'settings.ini')) NetworkManager.registerSchemes() if self.isPrivate(): self._webProfile = QWebEngineProfile() else: self._webProfile = QWebEngineProfile.defaultProfile() self._webProfile.downloadRequested.connect(self.downloadRequested) self._networkManager = NetworkManager(self) self.setupUserScripts() if not self.isPrivate() and not self.isTestModeEnabled(): self._sessionManager = SessionManager(self) self._autoSaver = AutoSaver(self) self._autoSaver.save.connect( self._sessionManager.autoSaveLastSession) settings = Settings() settings.beginGroup('SessionRestore') wasRunning = settings.value('isRunning', False) wasRestoring = settings.value('isRestoring', False) settings.setValue('isRunning', True) settings.setValue('isRestoring', wasRunning) settings.endGroup() settings.sync() self._isStartingAfterCrash = bool(wasRunning and wasRestoring) if wasRunning: QTimer.singleShot( 60 * 1000, lambda: Settings().setValue( 'SessionRestore/isRestoring', False)) # we have to ask about startup session before creating main window if self._isStartingAfterCrash and self.afterLaunch( ) == self.SelectSession: self._restoreManager = RestoreManager( self.sessionManager().askSessionFromUser()) self.loadSettings() self._plugins = PluginProxy(self) self._autoFill = AutoFill(self) self.app.protocolHandlerManager() if not noAddons: self._plugins.loadPlugins() window = self.createWindow(const.BW_FirstAppWindow, startUrl) window.startingCompleted.connect(self.restoreOverrideCursor) self.focusChanged.connect(self.onFocusChanged) if not self.isPrivate() and not self.isTestModeEnabled(): # check updates settings = Settings() checkUpdates = settings.value('Web-Browser-Settings/CheckUpdates', True) if checkUpdates: Updater(window) self.sessionManager().backupSavedSessions() if self._isStartingAfterCrash or self.afterLaunch( ) == self.RestoreSession: self._restoreManager = RestoreManager( self.sessionManager().lastActiveSessionPath()) if not self._restoreManager.isValid(): self.destroyRestoreManager() if not self._isStartingAfterCrash and self._restoreManager: self.restoreSession(window, self._restoreManager.restoreData()) QSettings.setPath(QSettings.IniFormat, QSettings.UserScope, DataPaths.currentProfilePath()) self.messageReceived.connect(self.messageReceivedCb) self.aboutToQuit.connect(self.saveSettings) QTimer.singleShot(0, self.postLaunch)
def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui.actionShow.triggered.connect(self.toggle_mode) self.ui.actionSave.triggered.connect(self.save_note) self.ui.actionLoadShelf.triggered.connect(self.download_shelf) self.ui.actionLoadHot.triggered.connect(self.show_hot_note) self.ui.actionLoadNotes.triggered.connect(self.download_notes) self.ui.statusBar.hide() self.pbar = QProgressBar(self) self.pbar.setFixedWidth(500) self.ui.statusBar.addWidget(self.pbar) icon = QtGui.QIcon() icon.addPixmap( QtGui.QPixmap(os.path.join(root_path, "static/icon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.setWindowIcon(icon) self.browser = QWebEngineView(self) self.browser.setGeometry( 0, self.ui.menubar.height(), self.width(), self.height() - self.ui.menubar.height(), ) self.ui.actionback.triggered.connect(self.browser.back) self.ui.actionforward.triggered.connect(self.browser.forward) self.ui.actionShelf.triggered.connect(self.view_shelf) self.ui.actionLibrary.triggered.connect(self.view_library) # 加载外部的web页面 self.cache_path = os.path.join(root_path, "cache") if not os.path.exists(self.cache_path): os.mkdir(self.cache_path) # 设置缓存目录 default_profile = QWebEngineProfile.defaultProfile() default_profile.setCachePath(self.cache_path) default_profile.setPersistentStoragePath(self.cache_path) # 记录上次阅读位置 self.history_url_file = os.path.join(self.cache_path,"history.txt") if not os.path.exists(self.history_url_file): url = QUrl("https://weread.qq.com/") else: with open(self.history_url_file,'r') as f: url = QUrl(f.read().strip()) self.browser.urlChanged.connect(self.update_lastpage) # 每次改变都更新还是退出的时候更新 self.browser.load(url) self.model = QStringListModel(self) self.item_model = QStandardItemModel(self) self.select_model = QItemSelectionModel(self.item_model) self.ui.tableView.setModel(self.item_model) self.ui.tableView.setSelectionModel(self.select_model) self.ui.tableView.setAlternatingRowColors(True) self.ui.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.is_reading_mode = True self.note_dir = os.path.join(root_path, "notes") if not os.path.exists(self.note_dir): os.mkdir(self.note_dir) try: self.update_cookies() self.booklist = wereader.get_bookshelf(self.cookies) self.books = itertools.cycle(self.booklist) self.curBook = self.booklist[0] except Exception: self.curBook = None self.booklist = None