Ejemplo n.º 1
0
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())
Ejemplo n.º 2
0
 def _set(self, value, settings=None):
     utils.unused(settings)
     setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
     setter(
         QWebEngineProfile.AllowPersistentCookies if value else
         QWebEngineProfile.NoPersistentCookies
     )
Ejemplo n.º 3
0
 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
     )
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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)  # 设置中心窗口
Ejemplo n.º 15
0
    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)
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
 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())
Ejemplo n.º 20
0
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()
Ejemplo n.º 21
0
    def __init__(self, *args, **kwargs):
        super(WebBrowser, self).__init__(*args, **kwargs)

        QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(
            self.onCookieAdd)
        self.loadFinished.connect(self.onLoadFinished)
Ejemplo n.º 22
0
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)
Ejemplo n.º 23
0
    # 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')
Ejemplo n.º 24
0
 def __init__(self):
     super().__init__()
     self.cookies = {}
     # 绑定cookie被添加的信号槽
     QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(self.onCookieAdd)
Ejemplo n.º 25
0
 def _set(self, value, settings=None):
     utils.unused(settings)
     setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
     setter(QWebEngineProfile.AllowPersistentCookies
            if value else QWebEngineProfile.NoPersistentCookies)
Ejemplo n.º 26
0
    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"])
Ejemplo n.º 27
0
    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()
Ejemplo n.º 28
0
 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)
Ejemplo n.º 30
0
 def _set(self, value, settings=None):
     utils.unused(settings)
     setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
     setter(value)
Ejemplo n.º 31
0
    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.")
Ejemplo n.º 33
0
    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"])
Ejemplo n.º 34
0
 def __init__(self, *args, **kwargs):
     super(MyWebEngineView, self).__init__(*args, **kwargs)
     # 绑定cookie被添加的信号槽
     QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(
         self.onCookieAdd)
     self.cookies = {}  # 存放cookie字典
Ejemplo n.º 35
0
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)
Ejemplo n.º 36
0
 def __init__(self, *args, **kwargs):
     super(Window, self).__init__(*args, **kwargs)
     self.resize(800, 600)
     QWebEngineProfile.defaultProfile().setRequestInterceptor(RequestInterceptor(self))
Ejemplo n.º 37
0
    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()
Ejemplo n.º 38
0
 def get(self, settings=None):
     utils.unused(settings)
     getter = getattr(QWebEngineProfile.defaultProfile(), self._getter)
     return getter()
Ejemplo n.º 39
0
 def __init__(self, *args, **kwargs):
     super(WebEngineView, self).__init__(*args, **kwargs)
     # 绑定cookie被添加的信号槽
     QWebEngineProfile.defaultProfile().cookieStore().cookieAdded.connect(
         self.onCookieAdd)
     self.loadFinished.connect(self.onLoadFinished)
Ejemplo n.º 40
0
    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)
Ejemplo n.º 41
0
    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