import sys from PySide2 import QtCore, QtWidgets import gemini class GViewport(QtWidgets.QTextBrowser): hoverUrlChanged = QtCore.Signal(str) def __init__(self, address_bar): self._current_url = None self._last_redirect = (QtCore.QUrl(), {}) self.address_bar = address_bar self._hover_url = None QtWidgets.QTextBrowser.__init__(self) def mouseMoveEvent(self, event): cur = self.cursorForPosition(event.localPos().toPoint()) hover_url = cur.charFormat().anchorHref() hover_url = gemini.absolute_url(self._current_url, QtCore.QUrl(hover_url)) if hover_url != self._hover_url: self._hover_url = hover_url self.hoverUrlChanged.emit(self._hover_url.toString()) return super().mouseMoveEvent(event) def loadResource(self, type_, url): if self._last_redirect[0].toString() == url.toString(): gem = self._last_redirect[1] else: if not url.scheme(): url.setScheme(self._current_url.scheme()) if not url.host(): url.setHost(self._current_url.host()) if url.port() == -1: url.setPort(1965) if not url.path().startswith('/'): url.setPath(self._current_url.path().rsplit('/', 1)[0] + '/' + url.path()) gem = gemini.get(gemini.absolute_url(self._current_url, url)) if 'body' in gem: html = gemini.gem2html(gem['body']) else: html = '

{} {}

'.format(gem['status'], gem['meta']) self._current_url = url return html def setSource(self, url): if url.scheme() != 'gemini': return gem = gemini.get(gemini.absolute_url(self._current_url, url)) while gem['status'][0] == '3': url = QtCore.QUrl(gem['meta']) if url.port() == 1965: url.setPort(-1) print('redirect: {}'.format(url)) gem = gemini.get(gemini.absolute_url(self._current_url, url)) self._last_redirect = (url, gem) if url.port() == 1965: url.setPort(-1) print('setSource: {}'.format(url)) return super().setSource(url) def setRawSource(self): return self.setSource(QtCore.QUrl(self.address_bar.text())) class GUrlBar(QtWidgets.QLineEdit): def __init__(self): QtWidgets.QLineEdit.__init__(self) def setUrl(self, url): return self.setText(url.toDisplayString()) class GBrowser(QtWidgets.QMainWindow): def __init__(self): QtWidgets.QMainWindow.__init__(self) self.initUI() def initUI(self): self.statusBar().showMessage('Ready') back = QtWidgets.QPushButton("back") forward = QtWidgets.QPushButton("forward") address = GUrlBar() toolbar = QtWidgets.QToolBar() toolbar.addWidget(back) toolbar.addWidget(forward) toolbar.addWidget(address) browser = GViewport(address) back.clicked.connect(browser.backward) forward.clicked.connect(browser.forward) browser.sourceChanged.connect(address.setUrl) address.returnPressed.connect(browser.setRawSource) browser.hoverUrlChanged.connect(self.statusBar().showMessage) self.addToolBar(toolbar) self.setCentralWidget(browser) browser.setSource(QtCore.QUrl('gemini://gemini.circumlunar.space/')) self.setGeometry(10, 10, 1024, 750) self.setWindowTitle('Gemini Browser') self.show() app = QtWidgets.QApplication(sys.argv) ex = GBrowser() sys.exit(app.exec_())