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_())