Загрузить файлы в «/»

This commit is contained in:
2026-01-11 20:56:41 +07:00
parent 9c573e52b4
commit 1d6021f304

578
main.py Normal file
View File

@@ -0,0 +1,578 @@
import sys
import json
import os
from datetime import datetime
from PyQt6.QtCore import *
from PyQt6.QtWidgets import *
from PyQt6.QtWebEngineWidgets import *
from PyQt6.QtWebEngineCore import *
from PyQt6.QtGui import *
class BrowserWindow(QMainWindow):
def __init__(self):
super().__init__()
# Настройки поисковых систем
self.search_engines = {
"Google": "https://www.google.com/search?q={}",
"DuckDuckGo": "https://duckduckgo.com/?q={}",
"Bing": "https://www.bing.com/search?q={}",
"Yandex": "https://yandex.ru/search/?text={}"
}
self.current_search_engine = "Google"
# Инициализация данных
self.bookmarks = []
self.history = []
self.load_data()
self.setup_ui()
self.apply_dark_blue_theme()
def setup_ui(self):
"""Настройка пользовательского интерфейса"""
self.setWindowTitle("Dark Blue Browser")
self.setGeometry(100, 100, 1400, 800)
# Центральный виджет
central_widget = QWidget()
self.setCentralWidget(central_widget)
# Основной макет
main_layout = QVBoxLayout(central_widget)
# Панель навигации
nav_bar = QHBoxLayout()
# Кнопка назад
self.back_btn = QPushButton("")
self.back_btn.clicked.connect(self.navigate_back)
# Кнопка вперед
self.forward_btn = QPushButton("")
self.forward_btn.clicked.connect(self.navigate_forward)
# Кнопка обновить
self.reload_btn = QPushButton("")
self.reload_btn.clicked.connect(self.reload_page)
# Адресная строка
self.url_bar = QLineEdit()
self.url_bar.returnPressed.connect(self.navigate_to_url)
# Кнопка перехода
self.go_btn = QPushButton("Go")
self.go_btn.clicked.connect(self.navigate_to_url)
# Выбор поисковой системы
self.search_combo = QComboBox()
self.search_combo.addItems(self.search_engines.keys())
self.search_combo.setCurrentText(self.current_search_engine)
self.search_combo.currentTextChanged.connect(self.change_search_engine)
# Поле поиска
self.search_bar = QLineEdit()
self.search_bar.setPlaceholderText("Поиск...")
self.search_bar.returnPressed.connect(self.perform_search)
# Кнопка закладок
self.bookmark_btn = QPushButton("")
self.bookmark_btn.clicked.connect(self.toggle_bookmark)
self.bookmark_btn.setToolTip("Добавить/удалить закладку")
# Кнопка истории
self.history_btn = QPushButton("📜")
self.history_btn.clicked.connect(self.show_history)
self.history_btn.setToolTip("Показать историю")
# Добавление элементов в панель навигации
nav_bar.addWidget(self.back_btn)
nav_bar.addWidget(self.forward_btn)
nav_bar.addWidget(self.reload_btn)
nav_bar.addWidget(QLabel("URL:"))
nav_bar.addWidget(self.url_bar, 2)
nav_bar.addWidget(self.go_btn)
nav_bar.addWidget(QLabel("Поиск:"))
nav_bar.addWidget(self.search_bar, 1)
nav_bar.addWidget(self.search_combo)
nav_bar.addWidget(self.bookmark_btn)
nav_bar.addWidget(self.history_btn)
# Веб-вью
self.browser = QWebEngineView()
self.browser.urlChanged.connect(self.update_url)
self.browser.loadFinished.connect(self.on_page_loaded)
# Принудительное включение темного режима для всех сайтов
profile = QWebEngineProfile.defaultProfile()
profile.setHttpUserAgent(profile.httpUserAgent() + " DarkMode/1.0")
# Добавление в макет
main_layout.addLayout(nav_bar)
main_layout.addWidget(self.browser)
# Загрузка домашней страницы
self.load_home_page()
def apply_dark_blue_theme(self):
"""Применение темно-голубой темы"""
dark_blue_theme = """
QMainWindow {
background-color: #0f1c2e;
}
QWidget {
background-color: #0f1c2e;
color: #e0f0ff;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 12px;
}
QPushButton {
background-color: #1e3a5f;
color: #e0f0ff;
border: 1px solid #2d4a7a;
border-radius: 4px;
padding: 5px 12px;
font-weight: bold;
}
QPushButton:hover {
background-color: #2d4a7a;
border-color: #3d5a9a;
}
QPushButton:pressed {
background-color: #1a3257;
}
QLineEdit {
background-color: #1a2b44;
color: #ffffff;
border: 1px solid #2d4a7a;
border-radius: 4px;
padding: 5px;
selection-background-color: #2d4a7a;
}
QLineEdit:focus {
border: 1px solid #4a7ac9;
}
QComboBox {
background-color: #1a2b44;
color: #ffffff;
border: 1px solid #2d4a7a;
border-radius: 4px;
padding: 5px;
min-width: 100px;
}
QComboBox::drop-down {
border: none;
}
QComboBox QAbstractItemView {
background-color: #1a2b44;
color: #ffffff;
selection-background-color: #2d4a7a;
}
QLabel {
color: #a0c8ff;
font-weight: bold;
}
QWebEngineView {
background-color: #0a1525;
border: 1px solid #1e3a5f;
border-radius: 4px;
}
QMenu {
background-color: #1a2b44;
color: #ffffff;
border: 1px solid #2d4a7a;
}
QMenu::item:selected {
background-color: #2d4a7a;
}
"""
self.setStyleSheet(dark_blue_theme)
# Также применяем темную тему для веб-контента
settings = self.browser.settings()
settings.setAttribute(QWebEngineSettings.WebAttribute.JavascriptEnabled, True)
def load_home_page(self):
"""Загрузка домашней страницы"""
self.browser.setUrl(QUrl("https://www.google.com"))
def navigate_to_url(self):
"""Переход по URL"""
url = self.url_bar.text()
# Проверка, является ли ввод поисковым запросом
if not url.startswith(('http://', 'https://')):
if ' ' in url or '.' not in url:
# Это поисковый запрос
self.perform_search_with_query(url)
return
else:
url = 'https://' + url
self.browser.setUrl(QUrl(url))
def perform_search(self):
"""Выполнение поиска"""
query = self.search_bar.text()
if query:
self.perform_search_with_query(query)
def perform_search_with_query(self, query):
"""Выполнение поиска с заданным запросом"""
search_url = self.search_engines[self.current_search_engine].format(query)
self.browser.setUrl(QUrl(search_url))
# Добавление в историю поиска
self.add_to_history(query, search_url)
def change_search_engine(self, engine):
"""Изменение поисковой системы"""
self.current_search_engine = engine
def navigate_back(self):
"""Навигация назад"""
self.browser.back()
def navigate_forward(self):
"""Навигация вперед"""
self.browser.forward()
def reload_page(self):
"""Обновление страницы"""
self.browser.reload()
def update_url(self, q):
"""Обновление URL в адресной строке"""
self.url_bar.setText(q.toString())
# Добавление в историю посещений
if q.toString() not in [h['url'] for h in self.history[-20:]]:
self.add_to_history(self.browser.page().title(), q.toString())
def on_page_loaded(self, ok):
"""Действия после загрузки страницы"""
if ok:
current_url = self.browser.url().toString()
self.url_bar.setText(current_url)
# Применение темного режима к странице через JavaScript
dark_mode_js = """
// Создаем стиль для темного режима
let darkModeStyle = document.createElement('style');
darkModeStyle.id = 'dark-mode-style';
darkModeStyle.textContent = `
body {
background-color: #0a1525 !important;
color: #e0f0ff !important;
}
* {
background-color: rgba(10, 21, 37, 0.9) !important;
color: #e0f0ff !important;
border-color: #2d4a7a !important;
}
input, textarea, select {
background-color: #1a2b44 !important;
color: #ffffff !important;
}
a {
color: #4a7ac9 !important;
}
a:visited {
color: #8a5ac9 !important;
}
button, .btn {
background-color: #1e3a5f !important;
color: #e0f0ff !important;
border-color: #2d4a7a !important;
}
`;
// Удаляем старый стиль если есть
let oldStyle = document.getElementById('dark-mode-style');
if (oldStyle) oldStyle.remove();
// Добавляем новый стиль
document.head.appendChild(darkModeStyle);
// Дополнительные настройки для популярных сайтов
if (window.location.hostname.includes('google.com')) {
// Для Google
document.body.style.backgroundColor = '#0a1525';
document.body.style.color = '#e0f0ff';
}
if (window.location.hostname.includes('youtube.com')) {
// Для YouTube
document.body.style.backgroundColor = '#0a1525';
}
"""
# Внедряем JavaScript для темного режима
self.browser.page().runJavaScript(dark_mode_js)
def toggle_bookmark(self):
"""Добавление/удаление закладки"""
current_url = self.browser.url().toString()
page_title = self.browser.page().title()
# Проверяем, есть ли уже в закладках
existing_index = -1
for i, bookmark in enumerate(self.bookmarks):
if bookmark['url'] == current_url:
existing_index = i
break
if existing_index >= 0:
# Удаляем закладку
del self.bookmarks[existing_index]
QMessageBox.information(self, "Закладка", "Закладка удалена!")
else:
# Добавляем закладку
self.bookmarks.append({
'title': page_title,
'url': current_url,
'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
QMessageBox.information(self, "Закладка", "Страница добавлена в закладки!")
self.save_data()
def show_history(self):
"""Показ истории поиска"""
history_dialog = QDialog(self)
history_dialog.setWindowTitle("История просмотров")
history_dialog.setGeometry(200, 200, 600, 400)
layout = QVBoxLayout()
# Таблица истории
table = QTableWidget()
table.setColumnCount(3)
table.setHorizontalHeaderLabels(["Дата", "Заголовок", "URL"])
table.setRowCount(len(self.history))
for i, item in enumerate(reversed(self.history[-50:])): # Последние 50 записей
table.setItem(i, 0, QTableWidgetItem(item['date']))
table.setItem(i, 1, QTableWidgetItem(item['title'][:50] + "..." if len(item['title']) > 50 else item['title']))
table.setItem(i, 2, QTableWidgetItem(item['url'][:100] + "..." if len(item['url']) > 100 else item['url']))
table.resizeColumnsToContents()
# Кнопки
button_box = QDialogButtonBox()
clear_btn = QPushButton("Очистить историю")
close_btn = QPushButton("Закрыть")
clear_btn.clicked.connect(lambda: self.clear_history(table))
close_btn.clicked.connect(history_dialog.close)
button_box.addButton(clear_btn, QDialogButtonBox.ButtonRole.ActionRole)
button_box.addButton(close_btn, QDialogButtonBox.ButtonRole.RejectRole)
layout.addWidget(table)
layout.addWidget(button_box)
history_dialog.setLayout(layout)
history_dialog.exec()
def add_to_history(self, title, url):
"""Добавление записи в историю"""
self.history.append({
'title': title,
'url': url,
'date': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
})
self.save_data()
def clear_history(self, table):
"""Очистка истории"""
reply = QMessageBox.question(self, "Очистка истории",
"Вы уверены, что хотите очистить всю историю?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
self.history.clear()
table.setRowCount(0)
self.save_data()
def save_data(self):
"""Сохранение данных в файлы"""
data_dir = "browser_data"
if not os.path.exists(data_dir):
os.makedirs(data_dir)
with open(os.path.join(data_dir, "bookmarks.json"), "w", encoding="utf-8") as f:
json.dump(self.bookmarks, f, ensure_ascii=False, indent=2)
with open(os.path.join(data_dir, "history.json"), "w", encoding="utf-8") as f:
json.dump(self.history, f, ensure_ascii=False, indent=2)
def load_data(self):
"""Загрузка данных из файлов"""
data_dir = "browser_data"
# Загрузка закладок
bookmarks_file = os.path.join(data_dir, "bookmarks.json")
if os.path.exists(bookmarks_file):
with open(bookmarks_file, "r", encoding="utf-8") as f:
self.bookmarks = json.load(f)
# Загрузка истории
history_file = os.path.join(data_dir, "history.json")
if os.path.exists(history_file):
with open(history_file, "r", encoding="utf-8") as f:
self.history = json.load(f)
def contextMenuEvent(self, event):
"""Контекстное меню"""
menu = QMenu(self)
# Добавление действий
back_action = menu.addAction("Назад")
forward_action = menu.addAction("Вперед")
reload_action = menu.addAction("Обновить")
menu.addSeparator()
bookmark_action = menu.addAction("Добавить в закладки")
show_bookmarks_action = menu.addAction("Показать закладки")
menu.addSeparator()
history_action = menu.addAction("Показать историю")
settings_action = menu.addAction("Настройки")
# Обработка выбора
action = menu.exec(self.mapToGlobal(event.pos()))
if action == back_action:
self.navigate_back()
elif action == forward_action:
self.navigate_forward()
elif action == reload_action:
self.reload_page()
elif action == bookmark_action:
self.toggle_bookmark()
elif action == show_bookmarks_action:
self.show_bookmarks()
elif action == history_action:
self.show_history()
elif action == settings_action:
self.show_settings()
def show_bookmarks(self):
"""Показ закладок"""
bookmarks_dialog = QDialog(self)
bookmarks_dialog.setWindowTitle("Закладки")
bookmarks_dialog.setGeometry(200, 200, 600, 400)
layout = QVBoxLayout()
# Список закладок
list_widget = QListWidget()
for bookmark in self.bookmarks:
item_text = f"{bookmark['title']} - {bookmark['date']}"
item = QListWidgetItem(item_text)
item.setData(Qt.ItemDataRole.UserRole, bookmark['url'])
list_widget.addItem(item)
list_widget.itemDoubleClicked.connect(
lambda item: self.browser.setUrl(QUrl(item.data(Qt.ItemDataRole.UserRole)))
)
# Кнопки
button_box = QDialogButtonBox()
open_btn = QPushButton("Открыть")
delete_btn = QPushButton("Удалить")
close_btn = QPushButton("Закрыть")
open_btn.clicked.connect(
lambda: self.open_bookmark(list_widget.currentItem())
)
delete_btn.clicked.connect(
lambda: self.delete_bookmark(list_widget)
)
close_btn.clicked.connect(bookmarks_dialog.close)
button_box.addButton(open_btn, QDialogButtonBox.ButtonRole.ActionRole)
button_box.addButton(delete_btn, QDialogButtonBox.ButtonRole.ActionRole)
button_box.addButton(close_btn, QDialogButtonBox.ButtonRole.RejectRole)
layout.addWidget(list_widget)
layout.addWidget(button_box)
bookmarks_dialog.setLayout(layout)
bookmarks_dialog.exec()
def open_bookmark(self, item):
"""Открытие закладки"""
if item:
url = item.data(Qt.ItemDataRole.UserRole)
self.browser.setUrl(QUrl(url))
def delete_bookmark(self, list_widget):
"""Удаление закладки"""
current_item = list_widget.currentItem()
if current_item:
current_row = list_widget.row(current_item)
if 0 <= current_row < len(self.bookmarks):
del self.bookmarks[current_row]
list_widget.takeItem(current_row)
self.save_data()
def show_settings(self):
"""Показ настроек"""
settings_dialog = QDialog(self)
settings_dialog.setWindowTitle("Настройки браузера")
settings_dialog.setGeometry(300, 300, 400, 300)
layout = QVBoxLayout()
# Настройки поиска
search_group = QGroupBox("Настройки поиска")
search_layout = QVBoxLayout()
search_label = QLabel("Поисковая система по умолчанию:")
self.settings_search_combo = QComboBox()
self.settings_search_combo.addItems(self.search_engines.keys())
self.settings_search_combo.setCurrentText(self.current_search_engine)
search_layout.addWidget(search_label)
search_layout.addWidget(self.settings_search_combo)
search_group.setLayout(search_layout)
# Кнопки
button_box = QDialogButtonBox()
save_btn = QPushButton("Сохранить")
cancel_btn = QPushButton("Отмена")
save_btn.clicked.connect(
lambda: self.save_settings(settings_dialog)
)
cancel_btn.clicked.connect(settings_dialog.close)
button_box.addButton(save_btn, QDialogButtonBox.ButtonRole.AcceptRole)
button_box.addButton(cancel_btn, QDialogButtonBox.ButtonRole.RejectRole)
layout.addWidget(search_group)
layout.addWidget(button_box)
settings_dialog.setLayout(layout)
settings_dialog.exec()
def save_settings(self, dialog):
"""Сохранение настроек"""
self.current_search_engine = self.settings_search_combo.currentText()
self.search_combo.setCurrentText(self.current_search_engine)
dialog.close()
QMessageBox.information(self, "Настройки", "Настройки сохранены!")
def main():
app = QApplication(sys.argv)
app.setApplicationName("Dark Blue Browser")
app.setStyle("Fusion")
window = BrowserWindow()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()