From 13d3e3da84be019a216d63c1b00a907feb8d418e Mon Sep 17 00:00:00 2001 From: "N0\\A" Date: Thu, 23 Oct 2025 14:34:58 +0200 Subject: [PATCH] WEB SEARCH LET'S GO!!! --- main.py | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 208 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 3409f4f..c59ca14 100644 --- a/main.py +++ b/main.py @@ -32,6 +32,206 @@ class FileSearchResults(QtWidgets.QDialog): url = QtCore.QUrl.fromLocalFile(directory) QtGui.QDesktopServices.openUrl(url) + +class WebSearchResults(QtWidgets.QDialog): + def __init__(self, results, parent=None): + super().__init__(parent) + self.setWindowTitle(f"Web Search Results - {results['query']}") + self.setMinimumSize(800, 600) + + self.results = results + + # Main layout + layout = QtWidgets.QVBoxLayout() + + # Info label + info_text = f"Engine: {results['engine']} | Page: {results['page']}" + if results.get('cached'): + info_text += " | (Cached results)" + info_label = QtWidgets.QLabel(info_text) + info_label.setStyleSheet("color: gray; font-size: 10px; padding: 5px;") + layout.addWidget(info_label) + + # Scroll area + scroll = QtWidgets.QScrollArea() + scroll.setWidgetResizable(True) + scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # type: ignore + + # Container + container = QtWidgets.QWidget() + container_layout = QtWidgets.QVBoxLayout(container) + container_layout.setSpacing(15) + + # Add infobox + if results.get('infobox'): + infobox_widget = self._create_infobox_widget(results['infobox']) + container_layout.addWidget(infobox_widget) + + # Separator + line = QtWidgets.QFrame() + line.setFrameShape(QtWidgets.QFrame.HLine) #type: ignore + line.setFrameShadow(QtWidgets.QFrame.Sunken) #type: ignore + container_layout.addWidget(line) + + # Add news + if results.get('news'): + news_label = QtWidgets.QLabel("News") + news_label.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;") + container_layout.addWidget(news_label) + + for news_item in results['news'][:5]: # Show first 5 news items + news_widget = self._create_news_widget(news_item) + container_layout.addWidget(news_widget) + + # Separator + line = QtWidgets.QFrame() + line.setFrameShape(QtWidgets.QFrame.HLine) #type: ignore + line.setFrameShadow(QtWidgets.QFrame.Sunken) #type: ignore + container_layout.addWidget(line) + + # Add results + for result in results.get('results', []): + result_widget = self._create_result_widget(result) + container_layout.addWidget(result_widget) + + container_layout.addStretch() + scroll.setWidget(container) + layout.addWidget(scroll) + + # Navigation buttons + nav_layout = QtWidgets.QHBoxLayout() + + if results['page'] > 1: + prev_button = QtWidgets.QPushButton("← Previous Page") + prev_button.clicked.connect(lambda: self.load_page(results['page'] - 1)) + nav_layout.addWidget(prev_button) + + nav_layout.addStretch() + + if results.get('has_next_page'): + next_button = QtWidgets.QPushButton("Next Page →") + next_button.clicked.connect(lambda: self.load_page(results['page'] + 1)) + nav_layout.addWidget(next_button) + + layout.addLayout(nav_layout) + + self.setLayout(layout) + + def _create_infobox_widget(self, infobox): + """Create widget for infobox display.""" + widget = QtWidgets.QFrame() + widget.setFrameShape(QtWidgets.QFrame.StyledPanel) #type: ignore + widget.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;") + + layout = QtWidgets.QVBoxLayout(widget) + + # Title + title = QtWidgets.QLabel(infobox.get('title', '')) + title.setStyleSheet("font-weight: bold; font-size: 16px;") + title.setWordWrap(True) + layout.addWidget(title) + + # Subtitle + if infobox.get('subtitle'): + subtitle = QtWidgets.QLabel(infobox['subtitle']) + subtitle.setStyleSheet("color: gray; font-size: 12px;") + subtitle.setWordWrap(True) + layout.addWidget(subtitle) + + # URL + if infobox.get('url'): + url_label = QtWidgets.QLabel(f'{infobox["url"]}') + url_label.setOpenExternalLinks(True) + url_label.setStyleSheet("color: blue; font-size: 11px;") + layout.addWidget(url_label) + + # Description + if infobox.get('description'): + desc = QtWidgets.QLabel(infobox['description']) + desc.setWordWrap(True) + desc.setStyleSheet("margin-top: 5px;") + layout.addWidget(desc) + + return widget + + def _create_news_widget(self, news_item): + """Create widget for news item display.""" + widget = QtWidgets.QFrame() + widget.setFrameShape(QtWidgets.QFrame.Box) #type: ignore + widget.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;") + + layout = QtWidgets.QVBoxLayout(widget) + layout.setSpacing(3) + + # Source + source_label = QtWidgets.QLabel(news_item.get('source', '')) + source_label.setStyleSheet("color: green; font-size: 10px;") + layout.addWidget(source_label) + + # Title (clickable) + title = QtWidgets.QLabel(f'{news_item.get("title", "")}') + title.setOpenExternalLinks(True) + title.setWordWrap(True) + title.setStyleSheet("font-size: 12px;") + layout.addWidget(title) + + # Timestamp + if news_item.get('timestamp'): + time_label = QtWidgets.QLabel(news_item['timestamp']) + time_label.setStyleSheet("color: gray; font-size: 9px;") + layout.addWidget(time_label) + + return widget + + def _create_result_widget(self, result): + """Create widget for search result display.""" + widget = QtWidgets.QFrame() + widget.setFrameShape(QtWidgets.QFrame.NoFrame) #type: ignore + widget.setStyleSheet("padding: 5px;") + + layout = QtWidgets.QVBoxLayout(widget) + layout.setSpacing(5) + + # Display URL + if result.get('display_url'): + url_label = QtWidgets.QLabel(result['display_url']) + url_label.setStyleSheet("color: green; font-size: 11px;") + layout.addWidget(url_label) + + # Title + title = QtWidgets.QLabel(f'{result.get("title", "")}') + title.setOpenExternalLinks(True) + title.setWordWrap(True) + title.setStyleSheet("font-size: 14px; color: #1a0dab;") + layout.addWidget(title) + + # Snippet + if result.get('snippet'): + snippet = QtWidgets.QLabel(result['snippet']) + snippet.setWordWrap(True) + snippet.setStyleSheet("color: #545454; font-size: 12px;") + layout.addWidget(snippet) + + return widget + + def load_page(self, page_num): + """Load a different page of results.""" + try: + QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) # type: ignore + leta = MullvadLetaWrapper(engine=self.results['engine']) + new_results = leta.search(self.results['query'], page=page_num) + + # Close current dialog and open new one + new_dialog = WebSearchResults(new_results, self.parent()) + new_dialog.show() + self.close() + + except Exception as e: + QtWidgets.QMessageBox.critical(self, "Search Error", str(e)) + finally: + QtWidgets.QApplication.restoreOverrideCursor() + + class MainWindow(QtWidgets.QMainWindow): def __init__(self, restart=False): super().__init__() @@ -143,9 +343,15 @@ class MainWindow(QtWidgets.QMainWindow): QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) #type: ignore leta = MullvadLetaWrapper(engine="brave") results = leta.search(query) - except RuntimeError as e: + + if results and results.get('results'): + self.web_results_dialog = WebSearchResults(results, self) + self.web_results_dialog.show() + else: + QtWidgets.QMessageBox.information(self, "No Results", "No web search results found.") + + except Exception as e: QtWidgets.QMessageBox.critical(self, "Search Error", str(e)) - return finally: QtWidgets.QApplication.restoreOverrideCursor()