From 2aea7e9a5b7054d2b0dfa9502e9d6692308b8b02 Mon Sep 17 00:00:00 2001 From: ChuishenX Date: Sat, 22 Jun 2024 20:55:10 +0800 Subject: [PATCH] GUI --- .gitignore | 157 ++++++++++++++++++++++++++ pse.py | 60 ++++++++++ requirements.txt | 1 + ui.py | 191 ++++++++++++++++++++++++++++++++ ui.ui | 283 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 692 insertions(+) create mode 100644 .gitignore create mode 100644 pse.py create mode 100644 requirements.txt create mode 100644 ui.py create mode 100644 ui.ui diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58f427f --- /dev/null +++ b/.gitignore @@ -0,0 +1,157 @@ +.vscode/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# CMake +CMakeFiles/ +CMakeCache.txt +CMakeLists.txt +CTestTestfile.cmake +cmake_install.cmake +compile_commands.json +testing/ + +# Poetry +# Virtual environment +/.venv/ + +# .env file +.env + +# Mac OS +.DS_Store + +# Windows +Thumbs.db +ehthumbs.db +ehthumbs_vista.db +*.stackdump \ No newline at end of file diff --git a/pse.py b/pse.py new file mode 100644 index 0000000..a2294ae --- /dev/null +++ b/pse.py @@ -0,0 +1,60 @@ +from plugin.engine.minebbs import Minebbs +from plugin.engine.klpbbs import Klpbbs +from plugin.engine.spigotmc import Spigot +from plugin.engine.tinksp import Tinksp +from concurrent.futures import ThreadPoolExecutor, wait +from PySide6.QtWidgets import QMainWindow, QApplication, QMessageBox, QTreeWidgetItem +from PySide6 import QtCore +import sys +import multiprocessing as m +from multiprocessing import Process as P +from ui import Ui_MainWindow +import pyperclip + +QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) + +def get_result(keyword, q): + engine = [Spigot, Tinksp, Minebbs, Klpbbs] + results = [] + with ThreadPoolExecutor(max_workers=6) as executor: + future_list = [] + for e in engine: + future = executor.submit(e().search, keyword) + print(0) + future_list.append(future) + wait(future_list) + for future in future_list: + for result in future.result(): + results.append(result) + print(1) + q.put(results) + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + self.ui.searchButton.clicked.connect(self.search) + self.ui.outputTreeWidget.itemDoubleClicked.connect(self.copyUrl) + + def search(self): + self.ui.outputTreeWidget.clear() + keyword = self.ui.searchLine.text() + q = m.Queue() + p = P(target=get_result, args=(keyword, q)) + p.start(); p.join(); results = q.get() + for result in results: + num = results.index(result) + title = QTreeWidgetItem(self.ui.outputTreeWidget, [result.title, result.url, result.summary]) + + def copyUrl(self, item): + # copy a text to the clipboard. + pyperclip.copy(item.text(1)) + QMessageBox.information(self, "Copied!", "已将该插件链接复制到剪贴板。") + +if __name__ == "__main__": + m.freeze_support() + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec()) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..07d7add --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +cn_bing_translator \ No newline at end of file diff --git a/ui.py b/ui.py new file mode 100644 index 0000000..f774ab4 --- /dev/null +++ b/ui.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'ui.ui' +## +## Created by: Qt User Interface Compiler version 6.5.3 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient, + QCursor, QFont, QFontDatabase, QGradient, + QIcon, QImage, QKeySequence, QLinearGradient, + QPainter, QPalette, QPixmap, QRadialGradient, + QTransform) +from PySide6.QtWidgets import (QAbstractScrollArea, QApplication, QFrame, QGridLayout, + QGroupBox, QHBoxLayout, QHeaderView, QLineEdit, + QMainWindow, QPushButton, QSizePolicy, QTreeWidget, + QTreeWidgetItem, QVBoxLayout, QWidget) + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + if not MainWindow.objectName(): + MainWindow.setObjectName(u"MainWindow") + MainWindow.resize(779, 594) + icon = QIcon() + icon.addFile(u"icons/icon.png", QSize(), QIcon.Normal, QIcon.Off) + MainWindow.setWindowIcon(icon) + MainWindow.setStyleSheet(u"QTreeView {\n" +" border:none\n" +"}\n" +"") + self.actionAbout = QAction(MainWindow) + self.actionAbout.setObjectName(u"actionAbout") + self.actionHelp = QAction(MainWindow) + self.actionHelp.setObjectName(u"actionHelp") + self.actionSearchType = QAction(MainWindow) + self.actionSearchType.setObjectName(u"actionSearchType") + icon1 = QIcon() + icon1.addFile(u"icons/radio-circle-marked.png", QSize(), QIcon.Normal, QIcon.Off) + self.actionSearchType.setIcon(icon1) + self.actionSearchName = QAction(MainWindow) + self.actionSearchName.setObjectName(u"actionSearchName") + icon2 = QIcon() + icon2.addFile(u"icons/radio-circle.png", QSize(), QIcon.Normal, QIcon.Off) + self.actionSearchName.setIcon(icon2) + self.actionTextViewer = QAction(MainWindow) + self.actionTextViewer.setObjectName(u"actionTextViewer") + self.actionPlayerViewer = QAction(MainWindow) + self.actionPlayerViewer.setObjectName(u"actionPlayerViewer") + self.actionImageViewer = QAction(MainWindow) + self.actionImageViewer.setObjectName(u"actionImageViewer") + self.actionSearchWeb = QAction(MainWindow) + self.actionSearchWeb.setObjectName(u"actionSearchWeb") + self.actionSearchWeb.setIcon(icon2) + self.actionSearchKey = QAction(MainWindow) + self.actionSearchKey.setObjectName(u"actionSearchKey") + self.actionSearchKey.setIcon(icon2) + self.centralwidget = QWidget(MainWindow) + self.centralwidget.setObjectName(u"centralwidget") + self.verticalLayout_3 = QVBoxLayout(self.centralwidget) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2 = QVBoxLayout() + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.groupBox = QGroupBox(self.centralwidget) + self.groupBox.setObjectName(u"groupBox") + self.groupBox.setEnabled(True) + font = QFont() + font.setStyleStrategy(QFont.PreferDefault) + self.groupBox.setFont(font) + self.groupBox.setMouseTracking(False) + self.groupBox.setTabletTracking(False) + self.groupBox.setContextMenuPolicy(Qt.DefaultContextMenu) + self.groupBox.setLayoutDirection(Qt.LeftToRight) + self.groupBox.setAutoFillBackground(False) + self.groupBox.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop) + self.groupBox.setFlat(False) + self.verticalLayout = QVBoxLayout(self.groupBox) + self.verticalLayout.setObjectName(u"verticalLayout") + self.gridLayout = QGridLayout() + self.gridLayout.setObjectName(u"gridLayout") + self.searchButton = QPushButton(self.groupBox) + self.searchButton.setObjectName(u"searchButton") + + self.gridLayout.addWidget(self.searchButton, 0, 1, 1, 1) + + self.searchLine = QLineEdit(self.groupBox) + self.searchLine.setObjectName(u"searchLine") + sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.searchLine.sizePolicy().hasHeightForWidth()) + self.searchLine.setSizePolicy(sizePolicy) + + self.gridLayout.addWidget(self.searchLine, 0, 0, 1, 1) + + + self.verticalLayout.addLayout(self.gridLayout) + + + self.horizontalLayout.addWidget(self.groupBox) + + + self.verticalLayout_2.addLayout(self.horizontalLayout) + + self.line = QFrame(self.centralwidget) + self.line.setObjectName(u"line") + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + + self.verticalLayout_2.addWidget(self.line) + + self.outputTreeWidget = QTreeWidget(self.centralwidget) + __qtreewidgetitem = QTreeWidgetItem() + __qtreewidgetitem.setTextAlignment(2, Qt.AlignCenter); + __qtreewidgetitem.setTextAlignment(1, Qt.AlignTrailing|Qt.AlignVCenter); + __qtreewidgetitem.setTextAlignment(0, Qt.AlignLeading|Qt.AlignVCenter); + self.outputTreeWidget.setHeaderItem(__qtreewidgetitem) + self.outputTreeWidget.setObjectName(u"outputTreeWidget") + self.outputTreeWidget.setEnabled(True) + sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.outputTreeWidget.sizePolicy().hasHeightForWidth()) + self.outputTreeWidget.setSizePolicy(sizePolicy1) + self.outputTreeWidget.setSizeAdjustPolicy(QAbstractScrollArea.AdjustIgnored) + self.outputTreeWidget.setProperty("showDropIndicator", True) + self.outputTreeWidget.setIndentation(20) + self.outputTreeWidget.setRootIsDecorated(False) + self.outputTreeWidget.setUniformRowHeights(False) + self.outputTreeWidget.setItemsExpandable(True) + self.outputTreeWidget.setSortingEnabled(False) + self.outputTreeWidget.setAnimated(False) + self.outputTreeWidget.setAllColumnsShowFocus(False) + self.outputTreeWidget.setHeaderHidden(False) + self.outputTreeWidget.setExpandsOnDoubleClick(True) + self.outputTreeWidget.setColumnCount(3) + self.outputTreeWidget.header().setVisible(True) + self.outputTreeWidget.header().setCascadingSectionResizes(False) + self.outputTreeWidget.header().setMinimumSectionSize(25) + self.outputTreeWidget.header().setDefaultSectionSize(100) + self.outputTreeWidget.header().setHighlightSections(False) + + self.verticalLayout_2.addWidget(self.outputTreeWidget) + + + self.verticalLayout_3.addLayout(self.verticalLayout_2) + + MainWindow.setCentralWidget(self.centralwidget) + + self.retranslateUi(MainWindow) + + QMetaObject.connectSlotsByName(MainWindow) + # setupUi + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"PluginSearchEngine", None)) + self.actionAbout.setText(QCoreApplication.translate("MainWindow", u"\u5173\u4e8e\u4f5c\u8005", None)) +#if QT_CONFIG(shortcut) + self.actionAbout.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Shift+A", None)) +#endif // QT_CONFIG(shortcut) + self.actionHelp.setText(QCoreApplication.translate("MainWindow", u"\u67e5\u770b\u7528\u6cd5", None)) +#if QT_CONFIG(shortcut) + self.actionHelp.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+H", None)) +#endif // QT_CONFIG(shortcut) + self.actionSearchType.setText(QCoreApplication.translate("MainWindow", u"\u7c7b\u578b\u641c\u7d22", None)) + self.actionSearchName.setText(QCoreApplication.translate("MainWindow", u"\u540d\u79f0\u641c\u7d22", None)) + self.actionTextViewer.setText(QCoreApplication.translate("MainWindow", u"\u6587\u672c\u67e5\u770b\u5668", None)) + self.actionPlayerViewer.setText(QCoreApplication.translate("MainWindow", u"\u97f3\u9891\u64ad\u653e\u5668", None)) + self.actionImageViewer.setText(QCoreApplication.translate("MainWindow", u"\u56fe\u50cf\u67e5\u770b\u5668", None)) + self.actionSearchWeb.setText(QCoreApplication.translate("MainWindow", u"Web\u641c\u7d22", None)) + self.actionSearchKey.setText(QCoreApplication.translate("MainWindow", u"\u6587\u4ef6\u5173\u952e\u5b57\u641c\u7d22", None)) +#if QT_CONFIG(accessibility) + self.groupBox.setAccessibleName("") +#endif // QT_CONFIG(accessibility) + self.groupBox.setTitle("") + self.searchButton.setText(QCoreApplication.translate("MainWindow", u"\u641c\u7d22", None)) + self.searchLine.setPlaceholderText(QCoreApplication.translate("MainWindow", u"\u8bf7\u8f93\u5165\u4f60\u60f3\u67e5\u8be2\u7684\u63d2\u4ef6", None)) + ___qtreewidgetitem = self.outputTreeWidget.headerItem() + ___qtreewidgetitem.setText(2, QCoreApplication.translate("MainWindow", u"\u7b80\u4ecb", None)); + ___qtreewidgetitem.setText(1, QCoreApplication.translate("MainWindow", u"URL", None)); + ___qtreewidgetitem.setText(0, QCoreApplication.translate("MainWindow", u"\u540d\u79f0", None)); + # retranslateUi + diff --git a/ui.ui b/ui.ui new file mode 100644 index 0000000..6f950d1 --- /dev/null +++ b/ui.ui @@ -0,0 +1,283 @@ + + + MainWindow + + + + 0 + 0 + 779 + 594 + + + + PluginSearchEngine + + + + icons/icon.pngicons/icon.png + + + QTreeView { + border:none +} + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + true + + + + PreferDefault + + + + false + + + false + + + Qt::DefaultContextMenu + + + + + + Qt::LeftToRight + + + false + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + false + + + + + + + + 搜索 + + + + + + + + 0 + 0 + + + + 请输入你想查询的插件 + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + true + + + + 0 + 0 + + + + QAbstractScrollArea::AdjustIgnored + + + true + + + 20 + + + false + + + false + + + true + + + false + + + false + + + false + + + false + + + true + + + 3 + + + true + + + false + + + 25 + + + 100 + + + false + + + + 名称 + + + AlignLeading|AlignVCenter + + + + + URL + + + AlignTrailing|AlignVCenter + + + + + 简介 + + + AlignCenter + + + + + + + + + + + 关于作者 + + + Ctrl+Shift+A + + + + + 查看用法 + + + Ctrl+H + + + + + + icons/radio-circle-marked.pngicons/radio-circle-marked.png + + + 类型搜索 + + + + + + icons/radio-circle.pngicons/radio-circle.png + + + 名称搜索 + + + + + 文本查看器 + + + + + 音频播放器 + + + + + 图像查看器 + + + + + + icons/radio-circle.pngicons/radio-circle.png + + + Web搜索 + + + + + + icons/radio-circle.pngicons/radio-circle.png + + + 文件关键字搜索 + + + + + +