123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- ########################################################################
- # Searx-qt - Lightweight desktop application for SearX.
- # Copyright (C) 2020 CYBERDEViL
- #
- # This file is part of Searx-qt.
- #
- # Searx-qt is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Searx-qt is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- #
- ########################################################################
- from PyQt5.QtWidgets import (
- QWidget,
- QVBoxLayout,
- QFormLayout,
- QCheckBox,
- QLabel,
- QDoubleSpinBox,
- QLineEdit,
- QComboBox,
- QHBoxLayout,
- QSizePolicy,
- QTabWidget,
- QPlainTextEdit,
- QSpacerItem
- )
- from PyQt5.QtCore import Qt, pyqtSignal
- from searxqt.widgets.buttons import Button
- from searxqt.widgets.dialogs import UrlDialog
- from searxqt.translations import _
- HAVE_SOCKS = False
- try:
- import socks
- HAVE_SOCKS = True
- del socks
- except ImportError:
- print("pysocks not installed! No socks proxy support.")
- class ProxyWidget(QWidget):
- changed = pyqtSignal(str) # self.str()
- def __init__(self, parent=None):
- QWidget.__init__(self, parent=parent)
- layout = QVBoxLayout(self)
- hLayout = QHBoxLayout()
- self._proxyType = QComboBox(self)
- self._proxyType.setSizePolicy(QSizePolicy(
- QSizePolicy.Maximum,
- QSizePolicy.Fixed))
- typeList = ['http']
- if HAVE_SOCKS:
- typeList += ['socks4', 'socks5']
- for item in typeList:
- self._proxyType.addItem(item)
- self._proxyStr = QLineEdit(self)
- self._proxyStr.setPlaceholderText("user:pass@host:port")
- hLayout.addWidget(self._proxyType)
- hLayout.addWidget(self._proxyStr)
- layout.addLayout(hLayout)
- self._proxyDns = QCheckBox(_("Proxy DNS"), self)
- layout.addWidget(self._proxyDns)
- if not HAVE_SOCKS:
- self._proxyDns.setToolTip(_("Install pysocks for socks support."))
- self._proxyDns.setEnabled(False)
- self._proxyStr.textChanged.connect(self.__changed)
- self._proxyType.currentIndexChanged.connect(self.__typeChanged)
- self._proxyDns.toggled.connect(self.__dnsChanged)
- def __changed(self):
- self.changed.emit(self.str())
- def __typeChanged(self, index):
- """ From proxy type combobox
- """
- if index == 0:
- self._proxyDns.setEnabled(False)
- self._proxyDns.setToolTip(_("Not available for http proxy."))
- else:
- self._proxyDns.setEnabled(True)
- if self.str():
- self.__changed()
- def __dnsChanged(self, state):
- """ From proxy dns checkbox
- """
- if self.str():
- self.__changed()
- def reset(self):
- self._proxyDns.setChecked(True)
- self._proxyStr.setText("")
- self._proxyType.setCurrentIndex(0)
- self.__typeChanged(0)
- def setStr(self, _str):
- self.reset()
- seq = _str.split(':')
- if len(seq) > 1:
- index = self._proxyType.findText(seq[0].rstrip('h'))
- if index != -1:
- self._proxyType.setCurrentIndex(index)
- self._proxyStr.setText(_str[len(seq[0]) + 3:])
- if seq[0] not in ['socks5h', 'socks4h']:
- self._proxyDns.setChecked(False)
- def str(self):
- if self._proxyStr.text():
- return "{0}://{1}".format(
- self.protocolStr(),
- self._proxyStr.text())
- return ""
- def protocol(self): return self._proxyType.currentText()
- def protocolStr(self):
- if (self.protocol() in ['socks4', 'socks5']
- and self._proxyDns.isChecked()):
- return "{0}h".format(self.protocol())
- return self.protocol()
- class RequestsSettings(QWidget):
- def __init__(self, model, parent=None):
- """
- @param model:
- @type model: searxqt.models.RequestSettingsModel
- """
- QWidget.__init__(self, parent=parent)
- self._model = model
- layout = QFormLayout(self)
- # Verify checkbox
- self._verifyCheck = QCheckBox(self)
- layout.addRow(QLabel(_("Verify") + " (SSL):"), self._verifyCheck)
- # Timeout double spinbox
- self._timeoutSpin = QDoubleSpinBox(self)
- self._timeoutSpin.setSuffix(" sec")
- self._timeoutSpin.setMinimum(3)
- self._timeoutSpin.setMaximum(300)
- layout.addRow(QLabel(_("Timeout") + ":"), self._timeoutSpin)
- # Proxy
- proxyLayout = QFormLayout()
- layout.addRow(QLabel(_("Proxy") + ":"), proxyLayout)
- self._httpProxy = ProxyWidget(self)
- self._httpsProxy = ProxyWidget(self)
- proxyLayout.addRow(QLabel("Http:"), self._httpProxy)
- proxyLayout.addRow(QLabel("Https:"), self._httpsProxy)
- # Headers
- # User-agent
- userAgentLayout = QFormLayout()
- layout.addRow(QLabel(_("User-agents") + ":"), userAgentLayout)
- self._userAgentStringsEdit = QPlainTextEdit(self)
- self._userAgentStringsEdit.setToolTip(
- """- One user-agent string per line.
- - Default user-agent string is the first (top) line.
- - Empty lines will be removed.
- - Leave empty to not send any user-agent string."""
- )
- userAgentLayout.addWidget(self._userAgentStringsEdit)
- self._userAgentEditButton = Button("", self)
- self._userAgentEditButton.setCheckable(True)
- userAgentLayout.addWidget(self._userAgentEditButton)
- self._randomUserAgent = QCheckBox(_("Random"), self)
- self._randomUserAgent.setToolTip(
- """When checked it will pick a random
- user-agent from the list for each request."""
- )
- userAgentLayout.addWidget(self._randomUserAgent)
- # Init values for view
- self._changed()
- # Connections
- self._timeoutSpin.valueChanged.connect(self.__timeoutEdited)
- self._verifyCheck.stateChanged.connect(self.__verifyEdited)
- self._httpProxy.changed.connect(self.__proxyEdited)
- self._httpsProxy.changed.connect(self.__proxyEdited)
- self._userAgentEditButton.toggled.connect(self._toggleUserAgentEdit)
- self._randomUserAgent.stateChanged.connect(self._randomUserAgentEdited)
- self.__unsetWidgetsEditMode()
- def _randomUserAgentEdited(self, state):
- self._model.randomUserAgent = bool(state)
- def __setWidgetsEditMode(self):
- self._userAgentEditButton.setText(_("Save"))
- self._userAgentStringsEdit.setReadOnly(False)
- self._userAgentStringsEdit.setFocus()
- def __unsetWidgetsEditMode(self):
- self._userAgentEditButton.setText(_("Edit"))
- self._userAgentStringsEdit.setReadOnly(True)
- def _toggleUserAgentEdit(self, state):
- if state:
- self.__setWidgetsEditMode()
- else:
- self.__unsetWidgetsEditMode()
- self.__UserAgentStringsEdited(
- self._userAgentStringsEdit.toPlainText()
- )
- def __UserAgentStringsEdited(self, value):
- """
- @param value: String with the ?user-agent(s)
- @type value: str
- """
- self._model.useragents = [s for s in value.split('\n') if s]
- self._userAgentListChanged()
- def __timeoutEdited(self, value):
- self._model.timeout = value
- def __verifyEdited(self, state):
- self._model.verify = bool(state)
- def __proxyEdited(self, text):
- self._model.proxies = {
- 'http': self._httpProxy.str(), 'https': self._httpsProxy.str()}
- def _userAgentListChanged(self):
- txt = ""
- for userAgentStr in self._model.useragents:
- if not txt:
- txt = userAgentStr
- else:
- txt += "\n{}".format(userAgentStr)
- self._userAgentStringsEdit.setPlainText(txt)
- def _changed(self):
- self._verifyCheck.setChecked(self._model.verify)
- self._timeoutSpin.setValue(self._model.timeout)
- self._httpProxy.setStr(self._model.proxies.get('http', 'socks5h://'))
- self._httpsProxy.setStr(self._model.proxies.get('https', 'socks5h://'))
- self._userAgentListChanged()
- self._randomUserAgent.setChecked(self._model.randomUserAgent)
- class Stats2Settings(QWidget):
- def __init__(self, model, parent=None):
- """
- @type model: SearxStats2Model
- """
- QWidget.__init__(self, parent=parent)
- self._model = model
- layout = QVBoxLayout(self)
- infoLabel = QLabel(_(
- "The searx-stats2 project lists public searx instances with"
- " statistics. The original instance is running at"
- " https://searx.space/. This is where searx-qt will request"
- " a list with instances when the update button is pressed."),
- self
- )
- infoLabel.setWordWrap(True)
- layout.addWidget(infoLabel, 0, Qt.AlignTop)
- hLayout = QHBoxLayout()
- label = QLabel("URL:", self)
- label.setSizePolicy(
- QSizePolicy(
- QSizePolicy.Maximum, QSizePolicy.Maximum
- )
- )
- self._urlLabel = QLabel(model.url, self)
- self._urlEditButton = Button(_("Edit"), self)
- self._urlResetButton = Button(_("Reset"), self)
- hLayout.addWidget(label, 0, Qt.AlignTop)
- hLayout.addWidget(self._urlLabel, 0, Qt.AlignTop)
- hLayout.addWidget(self._urlEditButton, 0, Qt.AlignTop)
- hLayout.addWidget(self._urlResetButton, 0, Qt.AlignTop)
- spacer = QSpacerItem(
- 20, 40, QSizePolicy.Minimum, QSizePolicy.MinimumExpanding
- )
- layout.addLayout(hLayout)
- layout.addItem(spacer)
- self._urlEditButton.clicked.connect(self.__urlEditClicked)
- self._urlResetButton.clicked.connect(self.__urlResetClicked)
- model.changed.connect(self.__modelChanged)
- def __modelChanged(self):
- self._urlLabel.setText(self._model.url)
- def __urlEditClicked(self):
- dialog = UrlDialog(self._model.url)
- if dialog.exec():
- self._model.url = dialog.url
- def __urlResetClicked(self):
- self._model.reset()
- class SettingsWindow(QTabWidget):
- def __init__(self, model, parent=None):
- """
- @type model: SettingsModel
- """
- QTabWidget.__init__(self, parent=parent)
- self.setWindowTitle(_("Settings"))
- self._requestsView = RequestsSettings(model.requests, self)
- self.addTab(self._requestsView, _("Connection"))
- if model.stats2:
- self._stats2View = Stats2Settings(model.stats2, self)
- self.addTab(self._stats2View, "searx-stats2")
|