chore: Update translations for English and Icelandic languages, change icon colors, and add more icons
This commit is contained in:
202
app.py
202
app.py
@ -1,15 +1,67 @@
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
|
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
|
||||||
QLineEdit, QPushButton, QTextEdit, QComboBox,
|
QLineEdit, QPushButton, QTextEdit, QMessageBox,
|
||||||
QMessageBox, QSpacerItem, QSizePolicy, QLabel, QFileDialog, QDialog, QFormLayout, QTableWidget, QTableWidgetItem,
|
QSpacerItem, QSizePolicy, QLabel, QFileDialog, QDialog,
|
||||||
QHeaderView
|
QFormLayout, QTableWidget, QTableWidgetItem, QHeaderView,
|
||||||
|
QComboBox
|
||||||
)
|
)
|
||||||
from PyQt5.QtGui import QIcon
|
from PyQt5.QtGui import QIcon
|
||||||
from PyQt5.QtCore import Qt, QDateTime
|
from PyQt5.QtCore import Qt, QDateTime, QUrl
|
||||||
from PyQt5.QtSvg import QSvgWidget
|
from PyQt5.QtSvg import QSvgWidget
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
|
|
||||||
|
class URLSearch:
|
||||||
|
def __init__(self, url, search_engine_url):
|
||||||
|
self.url = url
|
||||||
|
self.search_engine_url = search_engine_url
|
||||||
|
self.filters_dir = 'filters/'
|
||||||
|
self.available_filters = self.load_filters()
|
||||||
|
|
||||||
|
def load_filters(self):
|
||||||
|
filters = {}
|
||||||
|
for file_name in os.listdir(self.filters_dir):
|
||||||
|
if file_name.endswith('.filter.py'):
|
||||||
|
domain = '.'.join(file_name.split('.')[:-2]) # Extracting domain.tld from domain.tld.filter.py
|
||||||
|
filters[domain] = os.path.join(self.filters_dir, file_name)
|
||||||
|
# print("Loaded filters:", filters) # Debug print
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def extract_terms(self):
|
||||||
|
parsed_url = QUrl(self.url)
|
||||||
|
host_parts = parsed_url.host().split('.')
|
||||||
|
domain = '.'.join(host_parts[-2:]) # Extract full domain including TLD
|
||||||
|
# print("Extracted domain:", domain) # Debug print
|
||||||
|
if domain in self.available_filters:
|
||||||
|
filter_file = self.available_filters[domain]
|
||||||
|
terms = self.apply_filter(filter_file)
|
||||||
|
if terms:
|
||||||
|
return terms
|
||||||
|
return None
|
||||||
|
|
||||||
|
def apply_filter(self, filter_file):
|
||||||
|
try:
|
||||||
|
with open(filter_file, 'r') as file:
|
||||||
|
filter_code = file.read()
|
||||||
|
local_vars = {'url': self.url, 'terms': [], 'QUrl': QUrl}
|
||||||
|
exec(filter_code, {}, local_vars)
|
||||||
|
return local_vars['terms']
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error applying filter: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def search(self):
|
||||||
|
terms = self.extract_terms()
|
||||||
|
if terms:
|
||||||
|
search_query = '+'.join(terms)
|
||||||
|
search_url = f"{self.search_engine_url}{search_query}"
|
||||||
|
QDesktopServices.openUrl(QUrl(search_url))
|
||||||
|
else:
|
||||||
|
print("No valid search term extracted, search disabled.")
|
||||||
|
|
||||||
class URLManager(QWidget):
|
class URLManager(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -49,26 +101,6 @@ class URLManager(QWidget):
|
|||||||
self.description_input.setMaximumHeight(100)
|
self.description_input.setMaximumHeight(100)
|
||||||
self.layout.addWidget(self.description_input)
|
self.layout.addWidget(self.description_input)
|
||||||
|
|
||||||
self.group_layout = QHBoxLayout()
|
|
||||||
|
|
||||||
self.group_combobox = QComboBox()
|
|
||||||
self.group_combobox.addItem(self.translations['all_categories'])
|
|
||||||
self.group_combobox.addItem(self.translations['default_category'])
|
|
||||||
self.group_combobox.currentTextChanged.connect(self.filter_urls_by_category)
|
|
||||||
self.group_layout.addWidget(self.group_combobox)
|
|
||||||
|
|
||||||
self.category_input = QLineEdit()
|
|
||||||
self.category_input.setPlaceholderText(self.translations['category_name'])
|
|
||||||
self.category_input.setFixedWidth(3 * 100) # Fixed width for the text input box, assuming "Save" button width is 100
|
|
||||||
self.group_layout.addWidget(self.category_input)
|
|
||||||
|
|
||||||
self.save_category_button = QPushButton(self.translations['save_category_button'])
|
|
||||||
self.save_category_button.setFixedWidth(100) # Fixed width for the "Save" button
|
|
||||||
self.save_category_button.clicked.connect(self.save_category)
|
|
||||||
self.group_layout.addWidget(self.save_category_button)
|
|
||||||
|
|
||||||
self.layout.addLayout(self.group_layout)
|
|
||||||
|
|
||||||
self.add_button = QPushButton(self.translations['save_url_button'])
|
self.add_button = QPushButton(self.translations['save_url_button'])
|
||||||
self.add_button.clicked.connect(self.add_url)
|
self.add_button.clicked.connect(self.add_url)
|
||||||
self.layout.addWidget(self.add_button)
|
self.layout.addWidget(self.add_button)
|
||||||
@ -86,7 +118,7 @@ class URLManager(QWidget):
|
|||||||
|
|
||||||
self.url_list = QTableWidget()
|
self.url_list = QTableWidget()
|
||||||
self.url_list.setColumnCount(3)
|
self.url_list.setColumnCount(3)
|
||||||
self.url_list.setHorizontalHeaderLabels(['URL', self.translations['column_date'], self.translations['column_actions']])
|
self.url_list.setHorizontalHeaderLabels([self.translations['url_placeholder'], self.translations['column_date'], self.translations['column_actions']])
|
||||||
self.url_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
|
self.url_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
|
||||||
self.url_list.setColumnWidth(1, 150)
|
self.url_list.setColumnWidth(1, 150)
|
||||||
self.url_list.setColumnWidth(2, 100)
|
self.url_list.setColumnWidth(2, 100)
|
||||||
@ -95,9 +127,7 @@ class URLManager(QWidget):
|
|||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
self.urls = []
|
self.urls = []
|
||||||
self.groups = set()
|
|
||||||
|
|
||||||
self.load_categories()
|
|
||||||
self.load_urls()
|
self.load_urls()
|
||||||
|
|
||||||
self.search_engines = {
|
self.search_engines = {
|
||||||
@ -122,17 +152,15 @@ class URLManager(QWidget):
|
|||||||
settings_icon_path = 'assets/cogwheel_dark.svg'
|
settings_icon_path = 'assets/cogwheel_dark.svg'
|
||||||
info_icon_path = 'assets/info_dark.svg'
|
info_icon_path = 'assets/info_dark.svg'
|
||||||
self.action_icons = {
|
self.action_icons = {
|
||||||
"edit": 'assets/edit_dark.svg',
|
"search": 'assets/search_dark.svg',
|
||||||
"delete": 'assets/delete_dark.svg',
|
"delete": 'assets/delete_dark.svg'
|
||||||
"search": 'assets/search_dark.svg'
|
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
settings_icon_path = 'assets/cogwheel_light.svg'
|
settings_icon_path = 'assets/cogwheel_light.svg'
|
||||||
info_icon_path = 'assets/info_light.svg'
|
info_icon_path = 'assets/info_light.svg'
|
||||||
self.action_icons = {
|
self.action_icons = {
|
||||||
"edit": 'assets/edit_light.svg',
|
"search": 'assets/search_light.svg',
|
||||||
"delete": 'assets/delete_light.svg',
|
"delete": 'assets/delete_light.svg'
|
||||||
"search": 'assets/search_light.svg'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.settings_button.setIcon(QIcon(settings_icon_path))
|
self.settings_button.setIcon(QIcon(settings_icon_path))
|
||||||
@ -141,10 +169,9 @@ class URLManager(QWidget):
|
|||||||
def add_url(self):
|
def add_url(self):
|
||||||
url = self.url_input.text()
|
url = self.url_input.text()
|
||||||
description = self.description_input.toPlainText()
|
description = self.description_input.toPlainText()
|
||||||
group = self.group_combobox.currentText()
|
|
||||||
if url:
|
if url:
|
||||||
date_added = QDateTime.currentDateTime().toString(Qt.ISODate)
|
date_added = QDateTime.currentDateTime().toString(Qt.ISODate)
|
||||||
url_data = {'url': url, 'description': description, 'date': date_added, 'group': group}
|
url_data = {'url': url, 'description': description, 'date': date_added}
|
||||||
self.urls.append(url_data)
|
self.urls.append(url_data)
|
||||||
self.save_url(url_data)
|
self.save_url(url_data)
|
||||||
self.update_url_list()
|
self.update_url_list()
|
||||||
@ -152,17 +179,15 @@ class URLManager(QWidget):
|
|||||||
self.description_input.clear()
|
self.description_input.clear()
|
||||||
|
|
||||||
def save_url(self, url_data):
|
def save_url(self, url_data):
|
||||||
category = url_data['group']
|
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
|
||||||
category_filename = self.get_category_filename(category)
|
if os.path.exists(url_path):
|
||||||
category_path = os.path.join(self.settings['data_directory'], category_filename)
|
with open(url_path, 'r') as file:
|
||||||
if os.path.exists(category_path):
|
url_list = json.load(file)
|
||||||
with open(category_path, 'r') as file:
|
|
||||||
category_urls = json.load(file)
|
|
||||||
else:
|
else:
|
||||||
category_urls = []
|
url_list = []
|
||||||
category_urls.append(url_data)
|
url_list.append(url_data)
|
||||||
with open(category_path, 'w') as file:
|
with open(url_path, 'w') as file:
|
||||||
json.dump(category_urls, file)
|
json.dump(url_list, file)
|
||||||
|
|
||||||
def update_url(self):
|
def update_url(self):
|
||||||
selected_item = self.url_list.currentItem()
|
selected_item = self.url_list.currentItem()
|
||||||
@ -194,14 +219,6 @@ class URLManager(QWidget):
|
|||||||
filtered_urls = [url for url in self.urls if search_term in url['url'].lower() or search_term in url['description'].lower()]
|
filtered_urls = [url for url in self.urls if search_term in url['url'].lower() or search_term in url['description'].lower()]
|
||||||
self.update_url_list(filtered_urls)
|
self.update_url_list(filtered_urls)
|
||||||
|
|
||||||
def filter_urls_by_category(self):
|
|
||||||
selected_category = self.group_combobox.currentText()
|
|
||||||
if selected_category == self.translations['all_categories']:
|
|
||||||
self.update_url_list(self.urls)
|
|
||||||
else:
|
|
||||||
filtered_urls = [url for url in self.urls if url['group'] == selected_category]
|
|
||||||
self.update_url_list(filtered_urls)
|
|
||||||
|
|
||||||
def update_url_list(self, urls=None):
|
def update_url_list(self, urls=None):
|
||||||
self.url_list.setRowCount(0)
|
self.url_list.setRowCount(0)
|
||||||
urls_to_display = urls if urls else self.urls
|
urls_to_display = urls if urls else self.urls
|
||||||
@ -213,12 +230,12 @@ class URLManager(QWidget):
|
|||||||
|
|
||||||
actions_layout = QHBoxLayout()
|
actions_layout = QHBoxLayout()
|
||||||
|
|
||||||
edit_button = QPushButton()
|
search_button = QPushButton()
|
||||||
edit_button.setIcon(QIcon(self.action_icons["edit"]))
|
search_button.setIcon(QIcon(self.action_icons["search"]))
|
||||||
edit_button.setFixedSize(18, 18)
|
search_button.setFixedSize(18, 18)
|
||||||
edit_button.setStyleSheet("border: none; padding: 0px;")
|
search_button.setStyleSheet("border: none; padding: 0px;")
|
||||||
edit_button.clicked.connect(lambda _, row=row: self.edit_url(row))
|
search_button.clicked.connect(lambda _, url=url['url']: self.search_url(url))
|
||||||
actions_layout.addWidget(edit_button)
|
actions_layout.addWidget(search_button)
|
||||||
|
|
||||||
delete_button = QPushButton()
|
delete_button = QPushButton()
|
||||||
delete_button.setIcon(QIcon(self.action_icons["delete"]))
|
delete_button.setIcon(QIcon(self.action_icons["delete"]))
|
||||||
@ -246,11 +263,10 @@ class URLManager(QWidget):
|
|||||||
else:
|
else:
|
||||||
return date_str
|
return date_str
|
||||||
|
|
||||||
def edit_url(self, row):
|
def search_url(self, url):
|
||||||
url = self.urls[row]['url']
|
search_engine_url = self.search_engines[self.settings['search_engine']]
|
||||||
description = self.urls[row]['description']
|
url_search = URLSearch(url, search_engine_url)
|
||||||
self.url_input.setText(url)
|
url_search.search()
|
||||||
self.description_input.setPlainText(description)
|
|
||||||
|
|
||||||
def load_settings(self):
|
def load_settings(self):
|
||||||
settings_path = 'data/settings.json'
|
settings_path = 'data/settings.json'
|
||||||
@ -285,59 +301,17 @@ class URLManager(QWidget):
|
|||||||
with open(settings_path, 'w') as file:
|
with open(settings_path, 'w') as file:
|
||||||
json.dump(settings, file)
|
json.dump(settings, file)
|
||||||
|
|
||||||
def load_categories(self):
|
|
||||||
self.groups = set()
|
|
||||||
categories_path = os.path.join(self.settings['data_directory'], 'categories.json')
|
|
||||||
if os.path.exists(categories_path):
|
|
||||||
with open(categories_path, 'r') as file:
|
|
||||||
self.groups = set(json.load(file))
|
|
||||||
self.update_group_combobox()
|
|
||||||
self.group_combobox.setCurrentText(self.translations['default_category'])
|
|
||||||
|
|
||||||
def save_categories(self):
|
|
||||||
categories_path = os.path.join(self.settings['data_directory'], 'categories.json')
|
|
||||||
os.makedirs(os.path.dirname(categories_path), exist_ok=True)
|
|
||||||
with open(categories_path, 'w') as file:
|
|
||||||
json.dump(list(self.groups), file)
|
|
||||||
|
|
||||||
def update_group_combobox(self):
|
|
||||||
self.group_combobox.clear()
|
|
||||||
self.group_combobox.addItem(self.translations['all_categories'])
|
|
||||||
self.group_combobox.addItem(self.translations['default_category'])
|
|
||||||
for group in sorted(self.groups):
|
|
||||||
self.group_combobox.addItem(group)
|
|
||||||
|
|
||||||
def save_category(self):
|
|
||||||
new_category = self.category_input.text().strip()
|
|
||||||
if new_category and new_category not in self.groups:
|
|
||||||
self.groups.add(new_category)
|
|
||||||
self.save_categories()
|
|
||||||
self.update_group_combobox()
|
|
||||||
self.category_input.clear()
|
|
||||||
|
|
||||||
def load_urls(self):
|
def load_urls(self):
|
||||||
self.urls = []
|
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
|
||||||
for group in self.groups:
|
if os.path.exists(url_path):
|
||||||
category_filename = self.get_category_filename(group)
|
with open(url_path, 'r') as file:
|
||||||
category_path = os.path.join(self.settings['data_directory'], category_filename)
|
self.urls = json.load(file)
|
||||||
if os.path.exists(category_path):
|
|
||||||
with open(category_path, 'r') as file:
|
|
||||||
self.urls.extend(json.load(file))
|
|
||||||
self.update_url_list()
|
self.update_url_list()
|
||||||
|
|
||||||
def save_urls(self):
|
def save_urls(self):
|
||||||
for group in self.groups:
|
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
|
||||||
group_urls = [url for url in self.urls if url['group'] == group]
|
with open(url_path, 'w') as file:
|
||||||
category_filename = self.get_category_filename(group)
|
json.dump(self.urls, file)
|
||||||
category_path = os.path.join(self.settings['data_directory'], category_filename)
|
|
||||||
with open(category_path, 'w') as file:
|
|
||||||
json.dump(group_urls, file)
|
|
||||||
|
|
||||||
def get_category_filename(self, category):
|
|
||||||
if ' ' in category:
|
|
||||||
return category.replace(' ', '_').lower() + '.json'
|
|
||||||
else:
|
|
||||||
return category.lower() + '.json'
|
|
||||||
|
|
||||||
def show_info_dialog(self):
|
def show_info_dialog(self):
|
||||||
dialog = QDialog(self)
|
dialog = QDialog(self)
|
||||||
@ -363,7 +337,7 @@ class URLManager(QWidget):
|
|||||||
def show_settings_dialog(self):
|
def show_settings_dialog(self):
|
||||||
dialog = SettingsDialog(self)
|
dialog = SettingsDialog(self)
|
||||||
if dialog.exec_() == QDialog.Accepted:
|
if dialog.exec_() == QDialog.Accepted:
|
||||||
self.load_settings()
|
self.settings = self.load_settings()
|
||||||
self.update_url_list()
|
self.update_url_list()
|
||||||
|
|
||||||
class SettingsDialog(QDialog):
|
class SettingsDialog(QDialog):
|
||||||
|
|||||||
Reference in New Issue
Block a user