0

I'm currently working with PyQt5 and PyQtWebEngine and I want to create a small browser.

OS and version info:

  • Windows 10
  • Python 3.9.6
  • PyQt5 5.15.6
  • PyQtWebEngine 5.15.5

I installed all these packages using pip for PyQt5 and PyQtWebEngine.

The problem I have is that when I go on Twitter for example, videos are not loaded (images are) and there is a error message on the video.

Also, I can scroll only few posts until python crashes without any error printed anywhere (not only the browser part, but python entirely: it's not the browser closing himself, that's why I can't find a solution to this).

The code of the browser is shown below:

import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWebEngineWidgets


class BrowserWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(BrowserWindow, self).__init__(*args, **kwargs)

        # ADD WINDOW ELEMENTS
        # ADD TAB WIGDETS TO DISPLAY WEB TABS
        self.tabs = QTabWidget()
        self.tabs.setDocumentMode(True)
        self.tabs.setTabsClosable(True)
        self.setCentralWidget(self.tabs)

        # ADD DOUBLE CLICK EVENT LISTENER
        self.tabs.tabBarDoubleClicked.connect(self.tab_open_doubleclick)
        # ADD TAB CLOSE EVENT LISTENER
        self.tabs.tabCloseRequested.connect(self.close_current_tab)
        # ADD ACTIVE TAB CHANGE EVENT LISTENER
        self.tabs.currentChanged.connect(self.current_tab_changed)

        # ADD NAVIGATION TOOLBAR
        navtb = QToolBar("Navigation")
        navtb.setIconSize(QtCore.QSize(16, 16))
        self.addToolBar(navtb)

        # ADD BUTTONS TO NAVIGATION TOOLBAR
        # PREVIOUS WEB PAGE BUTTON
        back_btn = QAction(QtGui.QIcon('arrow back.png'), "Back", self)
        back_btn.setStatusTip("Back to previous page")
        navtb.addAction(back_btn)
        # NAVIGATE TO PREVIOUS PAGE
        back_btn.triggered.connect(lambda: self.tabs.currentWidget().back())

        # NEXT WEB PAGE BUTTON
        next_btn = QAction(QtGui.QIcon('arrow next.png'), "Forward", self)
        next_btn.setStatusTip("Forward to next page")
        navtb.addAction(next_btn)
        # NAVIGATE TO NEXT WEB PAGE
        next_btn.triggered.connect(lambda: self.tabs.currentWidget().forward())

        # REFRESH WEB PAGE BUTTON
        reload_btn = QAction(QtGui.QIcon('refresh.png'), "Reload", self)
        reload_btn.setStatusTip("Reload page")
        navtb.addAction(reload_btn)
        # RELOAD WEB PAGE
        reload_btn.triggered.connect(lambda: self.tabs.currentWidget().reload())

        # HOME PAGE BUTTON
        home_btn = QAction(QtGui.QIcon('home.png'), "Home", self)
        home_btn.setStatusTip("Go home")
        navtb.addAction(home_btn)
        # NAVIGATE TO DEFAULT HOME PAGE
        home_btn.triggered.connect(self.navigate_home)

        # ADD SEPARATOR TO NAVIGATION BUTTONS
        navtb.addSeparator()

        # ADD LINE EDIT TO SHOW AND EDIT URLS
        self.urlbar = QLineEdit()
        navtb.addWidget(self.urlbar)
        # LOAD URL WHEN ENTER BUTTON IS PRESSED
        self.urlbar.returnPressed.connect(self.navigate_to_url)
        self.urlbar.mousePressEvent = lambda _ : self.urlbar.selectAll()

        # ADD STYLESHEET TO CUSTOMIZE YOUR WINDOWS
        self.setStyleSheet("""QWidget{
        background-color: white;
        color: rgb(48, 48, 48);
        }
        QTabWidget::pane { /* The tab widget frame */
            border-top: 2px solid rgb(255, 255, 255);
            position: absolute;

            color: rgb(90, 90, 90);
            padding: 5px;
        }

        QTabWidget::tab-bar {
            alignment: left;
        }

        /* Style the tab using the tab sub-control. Note that
            it reads QTabBar _not_ QTabWidget */
        QLabel, QToolButton {
            background: rgb(255, 255, 255);
            border: 2px solid rgb(255, 255, 255);
            /*border-bottom-color: #C2C7CB; /* same as the pane color */
            border-radius: 3px;
            min-width: 8ex;
            padding: 5px;
            margin-right: 2px;
            color: rgb(50, 50, 50);
        }

        QLabel:hover, QToolButton::hover {
            background: white;
            border: 2px solid rgb(0, 36, 36);
            background-color: white;
        }

        QTabBar::tab{
            border-radius: 3px;
            min-width: 8ex;
            padding: 5px;
            margin-right: 2px;
            color: rgb(50, 50, 50);
            background:#e0e0e0;
        }

        QTabBar::tab:selected, QTabBar::tab:hover:selected{
            background:white;
            background-color:white;
            border-bottom-width:0px;
            border-bottom-left-radius:0px;
            border-bottom-right-radius:0px;
        }
        
        QTabBar::tab:hover {
            background:#ededed;
            background-color:#ededed;
            border-color:#ededed;
        }

        QLineEdit {
            border: 2px solid rgb(0, 36, 36);
            border-radius: 3px;
            padding: 5px;
            background-color: white;
            color: rgb(50, 50, 50);
        }
        QLineEdit:hover {
            border: 2px solid rgb(0, 66, 124);
        }
        QLineEdit:focus{
            border: 2px solid rgb(0, 136, 255);
        }
        QPushButton{
            background: rgb(49, 49, 49);
            border: 2px solid rgb(0, 36, 36);
            background-color: rgb(0, 36, 36);
            padding: 5px;
            border-radius: 10px;
        }""")

        #label = Homepage
        self.add_new_tab(QtCore.QUrl('https://duckduckgo.com/'), 'Homepage')

        # SHOW MAIN WINDOW
        self.show()

    # ############################################
    # FUNCTIONS
    ##############################################
    # ADD NEW WEB TAB
    def add_new_tab(self, qurl=None, label="Blank"):
        # Check if url value is blank
        if qurl is None:
            qurl = QtCore.QUrl('')#pass empty string to url

        # Load the passed url
        browser = QtWebEngineWidgets.QWebEngineView()
        browser.setUrl(qurl)

        # ADD THE WEB PAGE TAB
        i = self.tabs.addTab(browser, label)
        self.tabs.setCurrentIndex(i)

        # ADD BROWSER EVENT LISTENERS
        # On URL change
        browser.urlChanged.connect(lambda qurl, browser=browser:
                                self.update_urlbar(qurl, browser))
        # On loadfinished
        browser.loadFinished.connect(lambda _, i=i, browser=browser:
                                    self.tabs.setTabText(i, browser.page().title()))

    # ADD NEW TAB ON DOUBLE CLICK ON TABS
    def tab_open_doubleclick(self, i):
        if i == -1:  # No tab under the click
            self.add_new_tab()

    # CLOSE TABS 
    def close_current_tab(self, i):
        if self.tabs.count() < 2: #Only close if there is more than one tab open
            return

        self.tabs.removeTab(i)

    # UPDATE URL TEXT WHEN ACTIVE TAB IS CHANGED
    def update_urlbar(self, q, browser=None):
        #q = QURL
        if browser != self.tabs.currentWidget():
            # If this signal is not from the current tab, ignore
            return

        self.urlbar.setText(q.toString())
        self.urlbar.setCursorPosition(0)

    # ACTIVE TAB CHANGE ACTIONS
    def current_tab_changed(self, i):
        # i = tab index
        # GET CURRENT TAB URL
        qurl = self.tabs.currentWidget().url()
        # UPDATE URL TEXT
        self.update_urlbar(qurl, self.tabs.currentWidget())
        # UPDATE WINDOWS TITTLE
        self.update_title(self.tabs.currentWidget())

    # UPDATE WINDOWS TITTLE
    def update_title(self, browser):
        if browser != self.tabs.currentWidget():
            # If this signal is not from the current ACTIVE tab, ignore
            return

        title = self.tabs.currentWidget().page().title()
        self.setWindowTitle(title)

    # NAVIGATE TO PASSED URL
    def navigate_to_url(self):  # Does not receive the Url
        # GET URL TEXT
        q = QtCore.QUrl(self.urlbar.text())
        if q.scheme() == "":
            q = QtCore.QUrl('https://www.google.com/search?q='+self.urlbar.text().replace(' ', '+'))

        self.tabs.currentWidget().setUrl(q)

    # NAVIGATE TO DEFAULT HOME PAGE
    def navigate_home(self):
        self.tabs.currentWidget().setUrl(QtCore.QUrl("https://duckduckgo.com/"))

app = QApplication(sys.argv)
w = BrowserWindow()
app.exec_()

EDIT : I was running it in the VSC terminal, just tried on a cmd one and I got errors :

[1436:6100:0617/142809.070:ERROR:cache_util_win.cc(21)] Unable to move the cache: AccÞs refusÚ. (0x5)
[1436:6100:0617/142809.084:ERROR:cache_util.cc(139)] Unable to move cache folder C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\GPUCache to C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\old_GPUCache_000
[1436:6100:0617/142809.096:ERROR:disk_cache.cc(184)] Unable to create cache
[1436:6100:0617/142809.096:ERROR:shader_disk_cache.cc(606)] Shader Cache Creation failed: -2
[1436:6100:0617/142812.075:ERROR:service_worker_storage.cc(1575)] Failed to delete the database: Database IO error
[1436:1208:0617/142837.652:ERROR:leveldb_factory.cc(91)] Failed to open LevelDB database from C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb,IO error: C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb/LOCK: File currently in use. (ChromeMethodBFE: 15::LockFile::2)
[1436:1208:0617/142839.674:ERROR:leveldb_factory.cc(91)] Failed to open LevelDB database from C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb,IO error: C:\Users\fabie\AppData\Local\python\QtWebEngine\Default\IndexedDB\https_twitter.com_0.indexeddb.leveldb/LOCK: File currently in use. (ChromeMethodBFE: 15::LockFile::2)

Example of a media that can't be loaded:

enter image description here

EDIT 2 :

So after some work on it, it seems that there is a problem with local storage/forage (I don't have any knowledge about that) :

I'm running another QWebEngineView for other purposes, he shows widget that I get from TradingView so I don't write the html for it. Actually this part throws js warnings or erros that you can see below.

They could be linked to the ones described before.

js: 2022-06-29T15:25:55.559Z:Common.LocalForage:IndexedDB is NOT available
js: 2022-06-29T15:25:55.816Z:ChartApi.Core:Cannot get studies_metadata, reason: Error: No available storage method found.
js: 2022-06-29T15:25:56.679Z:ChartApi.Core:Cannot update studies_metadata cache, reason: Error: No available storage method found.
5
  • Works fine for me on linux using qt-5.15.4 and pyqt-5.15.6. I only checked one twitter link, though. The videos and scrolling don't cause any problems. Commented Jun 17, 2022 at 12:13
  • Please make sure you test your script by running it in a command-window so you can see any python tracebacks or qt messages. You could also edit your question and show a url that causes problems, along with a screenshot showing the video error messages. Commented Jun 17, 2022 at 12:18
  • Thanks @ekhumoro I just tried on a CMD terminal and I got errors, see my Edit. Commented Jun 17, 2022 at 12:31
  • Please provide a proper link to a problem url that causes a crash. Also: try rebooting and testing your script without running any other browsers first. You should probably also try testing with pyqt6 to see if you get the same problems. Commented Jun 17, 2022 at 13:19
  • The url that cause crash is just Twitter homepage, it crashs only when I start scrolling, not before like at loading the page. I just tried rebooting without running any browsers first with PyQt5 and PyQt6, still same problem (the browser does not crashs with PyQt6, but I can't load videos). Commented Jun 17, 2022 at 15:17

1 Answer 1

0

The log messages look like you are launching the app twice, so the second launch found the database already locked.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your answer, what do you exactly mean by 'the app' ? The QApplication is launched only 1 time, same for the init of BrowserWindow. Actually there is 2 part of my app that uses QWebEngineView but the problem is the same if I remove one. There is clearly a problem with local storage/forage or something like that because the other QWebEngineView throw javascript warnings/errors about this.
I think you're right, after some research I feel my app is running twice. The window is shown 1 time but when the app crash for example there is in fact 2 main window. The problem is that even with checking my code I can't figure out why. Why could be the reasons for my script to be runned twice ?
@3V's you ever found out why your app was running twice? I ran into a similar problem and I still can't figure it out
@KevinM. I did not found the reason for this problem, I changed my project features just after this post so no webengine anymore, I stopped my research. I'm sorry I cannot help you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.