Dieser Commit ist enthalten in:
Claude Project Manager
2025-07-03 21:11:05 +02:00
Commit 08ed938105
239 geänderte Dateien mit 21554 neuen und 0 gelöschten Zeilen

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

207
views/tabs/accounts_tab.py Normale Datei
Datei anzeigen

@ -0,0 +1,207 @@
"""
Tab zur Verwaltung der erstellten Social-Media-Accounts.
"""
import logging
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QTableWidget,
QTableWidgetItem, QPushButton, QHeaderView, QMessageBox
)
from PyQt5.QtCore import pyqtSignal, Qt
logger = logging.getLogger("accounts_tab")
class AccountsTab(QWidget):
"""Widget für den Konten-Tab."""
# Signale
refresh_requested = pyqtSignal()
export_requested = pyqtSignal()
delete_requested = pyqtSignal(int) # account_id
def __init__(self, platform_name=None, db_manager=None, language_manager=None):
super().__init__()
self.platform_name = platform_name
self.db_manager = db_manager
self.language_manager = language_manager
self.init_ui()
if self.language_manager:
self.language_manager.language_changed.connect(self.update_texts)
self.update_texts()
# Konten laden, falls db_manager vorhanden
if self.db_manager:
self.load_accounts()
def init_ui(self):
"""Initialisiert die Benutzeroberfläche."""
layout = QVBoxLayout(self)
# Konten-Tabelle
self.accounts_table = QTableWidget()
self.accounts_table.setColumnCount(8)
self.accounts_table.setHorizontalHeaderLabels([
"ID",
"Benutzername",
"Passwort",
"E-Mail",
"Handynummer",
"Name",
"Plattform",
"Erstellt am",
])
self.accounts_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# ID-Spalte verstecken
self.accounts_table.setColumnHidden(0, True)
layout.addWidget(self.accounts_table)
# Button-Leiste
button_layout = QHBoxLayout()
self.refresh_button = QPushButton("Aktualisieren")
self.refresh_button.clicked.connect(self.on_refresh_clicked)
self.export_button = QPushButton("Exportieren")
self.export_button.clicked.connect(self.on_export_clicked)
self.delete_button = QPushButton("Löschen")
self.delete_button.clicked.connect(self.on_delete_clicked)
button_layout.addWidget(self.refresh_button)
button_layout.addWidget(self.export_button)
button_layout.addWidget(self.delete_button)
layout.addLayout(button_layout)
def load_accounts(self):
"""Lädt Konten aus der Datenbank und zeigt sie in der Tabelle an."""
try:
if (self.platform_name and str(self.platform_name).lower() not in ["all", ""]
and hasattr(self.db_manager, "get_accounts_by_platform")):
accounts = self.db_manager.get_accounts_by_platform(self.platform_name.lower())
else:
accounts = self.db_manager.get_all_accounts()
if self.platform_name and str(self.platform_name).lower() not in ["all", ""]:
accounts = [
acc for acc in accounts
if acc.get("platform", "").lower() == str(self.platform_name).lower()
]
self.display_accounts(accounts)
except Exception as e:
logger.error(f"Fehler beim Laden der Konten: {e}")
QMessageBox.critical(self, "Fehler", f"Fehler beim Laden der Konten:\n{str(e)}")
def display_accounts(self, accounts):
"""Zeigt die Konten in der Tabelle an."""
self.accounts_table.setRowCount(len(accounts))
for row, account in enumerate(accounts):
self.accounts_table.setItem(row, 0, QTableWidgetItem(str(account.get("id", ""))))
self.accounts_table.setItem(row, 1, QTableWidgetItem(account.get("username", "")))
self.accounts_table.setItem(row, 2, QTableWidgetItem(account.get("password", "")))
self.accounts_table.setItem(row, 3, QTableWidgetItem(account.get("email", "")))
self.accounts_table.setItem(row, 4, QTableWidgetItem(account.get("phone", "")))
self.accounts_table.setItem(row, 5, QTableWidgetItem(account.get("full_name", "")))
self.accounts_table.setItem(row, 6, QTableWidgetItem(account.get("platform", "")))
self.accounts_table.setItem(row, 7, QTableWidgetItem(account.get("created_at", "")))
def on_refresh_clicked(self):
"""Wird aufgerufen, wenn der Aktualisieren-Button geklickt wird."""
self.refresh_requested.emit()
# Direkt aktualisieren, falls db_manager vorhanden
if self.db_manager:
self.load_accounts()
def on_export_clicked(self):
"""Wird aufgerufen, wenn der Exportieren-Button geklickt wird."""
self.export_requested.emit()
def on_delete_clicked(self):
"""Wird aufgerufen, wenn der Löschen-Button geklickt wird."""
selected_rows = self.accounts_table.selectionModel().selectedRows()
if not selected_rows:
title = "Kein Konto ausgewählt"
text = "Bitte wählen Sie ein Konto zum Löschen aus."
if self.language_manager:
title = self.language_manager.get_text(
"accounts_tab.no_selection_title", title
)
text = self.language_manager.get_text(
"accounts_tab.no_selection_text", text
)
QMessageBox.warning(self, title, text)
return
account_id = int(self.accounts_table.item(selected_rows[0].row(), 0).text())
username = self.accounts_table.item(selected_rows[0].row(), 1).text()
q_title = "Konto löschen"
q_text = f"Möchten Sie das Konto '{username}' wirklich löschen?"
if self.language_manager:
q_title = self.language_manager.get_text("accounts_tab.delete_title", q_title)
q_text = self.language_manager.get_text(
"accounts_tab.delete_text", q_text
).format(username=username)
reply = QMessageBox.question(
self,
q_title,
q_text,
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No,
)
if reply == QMessageBox.Yes:
self.delete_requested.emit(account_id)
# Direkt aktualisieren, falls db_manager vorhanden
if self.db_manager:
success = self.db_manager.delete_account(account_id)
if success:
self.load_accounts()
suc_title = "Erfolg"
suc_text = f"Konto '{username}' wurde gelöscht."
if self.language_manager:
suc_title = self.language_manager.get_text(
"accounts_tab.delete_success_title", suc_title
)
suc_text = self.language_manager.get_text(
"accounts_tab.delete_success_text", suc_text
).format(username=username)
QMessageBox.information(self, suc_title, suc_text)
else:
err_title = "Fehler"
err_text = f"Konto '{username}' konnte nicht gelöscht werden."
if self.language_manager:
err_title = self.language_manager.get_text(
"accounts_tab.delete_error_title", err_title
)
err_text = self.language_manager.get_text(
"accounts_tab.delete_error_text", err_text
).format(username=username)
QMessageBox.critical(self, err_title, err_text)
def update_texts(self):
"""Aktualisiert UI-Texte gemäß aktueller Sprache."""
if not self.language_manager:
return
lm = self.language_manager
self.refresh_button.setText(lm.get_text("buttons.refresh", "Aktualisieren"))
self.export_button.setText(lm.get_text("buttons.export", "Exportieren"))
self.delete_button.setText(lm.get_text("buttons.delete", "Löschen"))
headers = lm.get_text(
"accounts_tab.headers",
[
"ID",
"Benutzername",
"Passwort",
"E-Mail",
"Handynummer",
"Name",
"Plattform",
"Erstellt am",
],
)
self.accounts_table.setHorizontalHeaderLabels(headers)

500
views/tabs/generator_tab.py Normale Datei
Datei anzeigen

@ -0,0 +1,500 @@
# Pfad: views/tabs/generator_tab.py
"""
Tab zur Erstellung von Social-Media-Accounts.
"""
import logging
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
QGroupBox, QLabel, QLineEdit, QSpinBox, QRadioButton,
QCheckBox, QComboBox, QPushButton, QTextEdit, QProgressBar,
QMessageBox
)
from PyQt5.QtCore import Qt, pyqtSignal
from utils.logger import add_gui_handler
logger = logging.getLogger("generator_tab")
class GeneratorTab(QWidget):
"""Widget für den Account-Generator-Tab."""
# Signale
start_requested = pyqtSignal(dict)
stop_requested = pyqtSignal()
account_created = pyqtSignal(str, dict) # (platform, account_data)
def __init__(self, platform_name, language_manager=None):
super().__init__()
self.platform_name = platform_name
self.language_manager = language_manager
self.init_ui()
if self.language_manager:
self.language_manager.language_changed.connect(self.update_texts)
self.update_texts()
def init_ui(self):
"""Initialisiert die Benutzeroberfläche."""
layout = QVBoxLayout(self)
# Formularbereich
self.form_group = QGroupBox()
form_layout = QFormLayout()
self.form_group.setLayout(form_layout)
# Vorname und Nachname statt vollständigem Namen
self.first_name_label = QLabel()
self.first_name_input = QLineEdit()
form_layout.addRow(self.first_name_label, self.first_name_input)
self.last_name_label = QLabel()
self.last_name_input = QLineEdit()
form_layout.addRow(self.last_name_label, self.last_name_input)
# Alter (jetzt mit QLineEdit statt QSpinBox)
self.age_label = QLabel()
self.age_input = QLineEdit()
form_layout.addRow(self.age_label, self.age_input)
# Registrierungsmethode
self.reg_method_group = QWidget()
reg_method_layout = QHBoxLayout(self.reg_method_group)
reg_method_layout.setContentsMargins(0, 0, 0, 0)
self.email_radio = QRadioButton()
self.phone_radio = QRadioButton()
self.email_radio.setChecked(True)
reg_method_layout.addWidget(self.email_radio)
reg_method_layout.addWidget(self.phone_radio)
self.reg_method_label = QLabel()
form_layout.addRow(self.reg_method_label, self.reg_method_group)
# Telefonnummer (nur sichtbar, wenn Telefon ausgewählt)
self.phone_label = QLabel()
self.phone_input = QLineEdit()
self.phone_input.setEnabled(False)
form_layout.addRow(self.phone_label, self.phone_input)
# E-Mail-Domain
self.email_domain_label = QLabel()
self.email_domain_input = QLineEdit("z5m7q9dk3ah2v1plx6ju.com")
form_layout.addRow(self.email_domain_label, self.email_domain_input)
# Proxy verwenden
self.use_proxy_check = QCheckBox()
self.use_proxy_check.setChecked(True)
# Proxy-Typ
self.proxy_type_combo = QComboBox()
proxy_widget = QWidget()
proxy_layout = QHBoxLayout(proxy_widget)
proxy_layout.setContentsMargins(0, 0, 0, 0)
proxy_layout.addWidget(self.use_proxy_check)
self.proxy_type_label = QLabel()
proxy_layout.addWidget(self.proxy_type_label)
proxy_layout.addWidget(self.proxy_type_combo)
proxy_layout.addStretch()
self.proxy_label = QLabel()
form_layout.addRow(self.proxy_label, proxy_widget)
# Headless-Modus
self.headless_check = QCheckBox()
form_layout.addRow("", self.headless_check)
# Debug-Modus
self.debug_check = QCheckBox()
form_layout.addRow("", self.debug_check)
# Plattformspezifische Parameter hinzufügen
self.add_platform_specific_fields(form_layout)
# Formular zum Layout hinzufügen
layout.addWidget(self.form_group)
# Fortschrittsanzeige
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
layout.addWidget(self.progress_bar)
# Log-Bereich
self.log_group = QGroupBox()
log_layout = QVBoxLayout(self.log_group)
self.log_text = QTextEdit()
self.log_text.setReadOnly(True)
log_layout.addWidget(self.log_text)
# Log-Handler für das TextEdit
add_gui_handler(logger, self.log_text)
layout.addWidget(self.log_group)
# Buttons
button_layout = QHBoxLayout()
self.start_button = QPushButton()
self.start_button.clicked.connect(self.on_start_clicked)
self.stop_button = QPushButton()
self.stop_button.clicked.connect(self.on_stop_clicked)
self.stop_button.setEnabled(False)
button_layout.addWidget(self.start_button)
button_layout.addWidget(self.stop_button)
layout.addLayout(button_layout)
# Event-Verbindungen
self.email_radio.toggled.connect(self.toggle_phone_input)
self.phone_radio.toggled.connect(self.toggle_phone_input)
self.use_proxy_check.toggled.connect(self.toggle_proxy_combo)
def add_platform_specific_fields(self, form_layout):
"""
Fügt plattformspezifische Felder hinzu.
Diese Methode kann in abgeleiteten Klassen überschrieben werden.
Args:
form_layout: Das Formular-Layout, zu dem die Felder hinzugefügt werden sollen
"""
# In plattformspezifischen Unterklassen überschreiben
platform = self.platform_name.lower()
if platform == "tiktok":
# Beispiel: Kategorie/Nische für TikTok
self.category_label = QLabel()
self.category_combo = QComboBox()
categories = [
"Allgemein",
"Gaming",
"Mode",
"Fitness",
"Reisen",
"Kochen",
"Technologie",
"Bildung",
]
if self.language_manager:
categories = [
self.language_manager.get_text(
"generator_tab.tiktok_category_general", "Allgemein"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_gaming", "Gaming"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_fashion", "Mode"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_fitness", "Fitness"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_travel", "Reisen"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_cooking", "Kochen"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_technology", "Technologie"
),
self.language_manager.get_text(
"generator_tab.tiktok_category_education", "Bildung"
),
]
self.category_label.setText(
self.language_manager.get_text(
"generator_tab.tiktok_category_label", "Kategorie/Nische:"
)
)
else:
self.category_label.setText("Kategorie/Nische:")
self.category_combo.addItems(categories)
form_layout.addRow(self.category_label, self.category_combo)
elif platform == "twitter":
# Beispiel: Interessen für Twitter
self.interests_combo = QComboBox()
interests = ["Allgemein", "Politik", "Technologie", "Wirtschaft", "Sport", "Unterhaltung", "Wissenschaft"]
self.interests_combo.addItems(interests)
form_layout.addRow("Interessen:", self.interests_combo)
elif platform == "facebook":
# Beispiel: Datenschutzeinstellungen für Facebook
self.privacy_combo = QComboBox()
privacy_options = ["Öffentlich", "Nur Freunde", "Freunde außer...", "Nur ich"]
self.privacy_combo.addItems(privacy_options)
form_layout.addRow("Datenschutz:", self.privacy_combo)
def toggle_phone_input(self):
"""Aktiviert/Deaktiviert das Telefoneingabefeld basierend auf der Radiobutton-Auswahl."""
self.phone_input.setEnabled(self.phone_radio.isChecked())
def toggle_proxy_combo(self):
"""Aktiviert/Deaktiviert die Proxy-Typ-Combobox basierend auf der Checkbox."""
self.proxy_type_combo.setEnabled(self.use_proxy_check.isChecked())
def on_start_clicked(self):
"""Wird aufgerufen, wenn der Start-Button geklickt wird."""
# Parameter sammeln
params = self.get_params()
# Eingaben validieren
valid, error_msg = self.validate_inputs(params)
if not valid:
self.show_error(error_msg)
return
# Signal auslösen
self.start_requested.emit(params)
def on_stop_clicked(self):
"""Wird aufgerufen, wenn der Stop-Button geklickt wird."""
self.stop_requested.emit()
def get_params(self):
"""Sammelt alle Parameter für die Account-Erstellung."""
# Vorname und Nachname kombinieren für den vollständigen Namen
first_name = self.first_name_input.text().strip()
last_name = self.last_name_input.text().strip()
full_name = f"{first_name} {last_name}"
params = {
"first_name": first_name,
"last_name": last_name,
"full_name": full_name,
"age_text": self.age_input.text().strip(), # Speichere den Rohtext
"registration_method": "email" if self.email_radio.isChecked() else "phone",
"headless": self.headless_check.isChecked(),
"debug": self.debug_check.isChecked(),
"email_domain": self.email_domain_input.text().strip()
}
# Telefonnummer (wenn ausgewählt)
if self.phone_radio.isChecked():
params["phone_number"] = self.phone_input.text().strip()
# Proxy (wenn aktiviert)
if self.use_proxy_check.isChecked():
proxy_type = self.proxy_type_combo.currentText().lower()
params["use_proxy"] = True
params["proxy_type"] = proxy_type
else:
params["use_proxy"] = False
# Plattformspezifische Parameter
additional_params = self.get_platform_specific_params()
if additional_params:
params["additional_params"] = additional_params
return params
def validate_inputs(self, params):
"""
Validiert die Eingaben für die Account-Erstellung.
Args:
params: Die gesammelten Parameter
Returns:
tuple: (gültig, Fehlermeldung)
"""
# Namen prüfen
if not params.get("first_name"):
msg = "Bitte geben Sie einen Vornamen ein."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.first_name_error",
"Bitte geben Sie einen Vornamen ein.",
)
return False, msg
if not params.get("last_name"):
msg = "Bitte geben Sie einen Nachnamen ein."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.last_name_error",
"Bitte geben Sie einen Nachnamen ein.",
)
return False, msg
# Alter prüfen
age_text = params.get("age_text", "")
if not age_text:
msg = "Bitte geben Sie ein Alter ein."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.age_empty_error",
"Bitte geben Sie ein Alter ein.",
)
return False, msg
# Alter muss eine Zahl sein
try:
age = int(age_text)
params["age"] = age # Füge das konvertierte Alter zu den Parametern hinzu
except ValueError:
msg = "Das Alter muss eine ganze Zahl sein."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.age_int_error",
"Das Alter muss eine ganze Zahl sein.",
)
return False, msg
# Alter-Bereich prüfen - hier ist die allgemeine Prüfung für 13-99
# Die plattformspezifische Validierung kann später in den Controllern erfolgen
if age < 13 or age > 99:
msg = "Das Alter muss zwischen 13 und 99 liegen."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.age_range_error",
"Das Alter muss zwischen 13 und 99 liegen.",
)
return False, msg
# Telefonnummer prüfen, falls erforderlich
if params.get("registration_method") == "phone" and not params.get("phone_number"):
msg = "Bitte geben Sie eine Telefonnummer ein."
if self.language_manager:
msg = self.language_manager.get_text(
"generator_tab.phone_error",
"Bitte geben Sie eine Telefonnummer ein.",
)
return False, msg
return True, ""
def get_platform_specific_params(self):
"""
Gibt plattformspezifische Parameter zurück.
Diese Methode kann in abgeleiteten Klassen überschrieben werden.
Returns:
dict: Plattformspezifische Parameter
"""
# In plattformspezifischen Unterklassen überschreiben
platform = self.platform_name.lower()
additional_params = {}
if platform == "tiktok" and hasattr(self, "category_combo"):
additional_params["category"] = self.category_combo.currentText()
elif platform == "twitter" and hasattr(self, "interests_combo"):
additional_params["interests"] = self.interests_combo.currentText()
elif platform == "facebook" and hasattr(self, "privacy_combo"):
additional_params["privacy"] = self.privacy_combo.currentText()
return additional_params
def set_running(self, running: bool):
"""Setzt den Status auf 'Wird ausgeführt' oder 'Bereit'."""
self.start_button.setEnabled(not running)
self.stop_button.setEnabled(running)
def clear_log(self):
"""Löscht den Log-Bereich."""
self.log_text.clear()
def add_log(self, message: str):
"""Fügt eine Nachricht zum Log-Bereich hinzu."""
self.log_text.append(message)
# Scrolle nach unten
# Korrigierter Code für die Qt-Version
try:
self.log_text.moveCursor(Qt.MoveOperation.MoveEnd)
except AttributeError:
# Fallback für ältere Qt-Versionen
try:
self.log_text.moveCursor(Qt.MoveEnd)
except AttributeError:
# Weitere Fallbacks
try:
from PyQt5.QtGui import QTextCursor
self.log_text.moveCursor(QTextCursor.End)
except:
pass # Im Notfall einfach ignorieren
def set_progress(self, value: int):
"""Setzt den Fortschritt der Fortschrittsanzeige."""
self.progress_bar.setValue(value)
def set_status(self, message: str):
"""Setzt die Statusnachricht."""
# Diese Methode könnte später um eine Statusleiste erweitert werden
self.add_log(message)
def show_error(self, message: str):
"""Zeigt eine Fehlermeldung an."""
title = "Fehler"
if self.language_manager:
title = self.language_manager.get_text(
"generator_tab.error_title", "Fehler"
)
QMessageBox.critical(self, title, message)
def update_texts(self):
"""Aktualisiert UI-Texte gemäß der aktuellen Sprache."""
if not self.language_manager:
return
lm = self.language_manager
self.form_group.setTitle(lm.get_text("generator_tab.form_title", "Account-Informationen"))
self.first_name_label.setText(lm.get_text("generator_tab.first_name_label", "Vorname:"))
self.first_name_input.setPlaceholderText(lm.get_text("generator_tab.first_name_placeholder", "z.B. Max"))
self.last_name_label.setText(lm.get_text("generator_tab.last_name_label", "Nachname:"))
self.last_name_input.setPlaceholderText(lm.get_text("generator_tab.last_name_placeholder", "z.B. Mustermann"))
self.age_label.setText(lm.get_text("generator_tab.age_label", "Alter:"))
self.age_input.setPlaceholderText(lm.get_text("generator_tab.age_placeholder", "Alter zwischen 13 und 99"))
self.reg_method_label.setText(lm.get_text("generator_tab.registration_method_label", "Registrierungsmethode:"))
self.email_radio.setText(lm.get_text("generator_tab.email_radio", "E-Mail"))
self.phone_radio.setText(lm.get_text("generator_tab.phone_radio", "Telefon"))
self.phone_label.setText(lm.get_text("generator_tab.phone_label", "Telefonnummer:"))
self.phone_input.setPlaceholderText(lm.get_text("generator_tab.phone_placeholder", "z.B. +49123456789"))
self.email_domain_label.setText(lm.get_text("generator_tab.email_domain_label", "E-Mail-Domain:"))
self.use_proxy_check.setText(lm.get_text("generator_tab.proxy_use", "Proxy verwenden"))
self.proxy_type_label.setText(lm.get_text("generator_tab.proxy_type_label", "Typ:"))
self.proxy_type_combo.clear()
self.proxy_type_combo.addItems([
lm.get_text("generator_tab.proxy_type_ipv4", "IPv4"),
lm.get_text("generator_tab.proxy_type_ipv6", "IPv6"),
lm.get_text("generator_tab.proxy_type_mobile", "Mobile"),
])
self.proxy_label.setText(lm.get_text("generator_tab.proxy_label", "Proxy:"))
self.headless_check.setText(lm.get_text("generator_tab.headless", "Browser im Hintergrund ausführen"))
self.debug_check.setText(lm.get_text("generator_tab.debug", "Debug-Modus (detaillierte Protokollierung)"))
platform = self.platform_name.lower()
if platform == "tiktok" and hasattr(self, "category_combo"):
self.category_label.setText(
lm.get_text("generator_tab.tiktok_category_label", "Kategorie/Nische:")
)
categories = [
lm.get_text("generator_tab.tiktok_category_general", "Allgemein"),
lm.get_text("generator_tab.tiktok_category_gaming", "Gaming"),
lm.get_text("generator_tab.tiktok_category_fashion", "Mode"),
lm.get_text("generator_tab.tiktok_category_fitness", "Fitness"),
lm.get_text("generator_tab.tiktok_category_travel", "Reisen"),
lm.get_text("generator_tab.tiktok_category_cooking", "Kochen"),
lm.get_text("generator_tab.tiktok_category_technology", "Technologie"),
lm.get_text("generator_tab.tiktok_category_education", "Bildung"),
]
current = self.category_combo.currentText()
self.category_combo.clear()
self.category_combo.addItems(categories)
if current in categories:
self.category_combo.setCurrentIndex(categories.index(current))
self.log_group.setTitle(lm.get_text("generator_tab.log_title", "Log"))
self.start_button.setText(lm.get_text("buttons.create", "Account erstellen"))
self.stop_button.setText(lm.get_text("buttons.cancel", "Abbrechen"))

315
views/tabs/settings_tab.py Normale Datei
Datei anzeigen

@ -0,0 +1,315 @@
"""
Tab für die Einstellungen der Anwendung.
"""
import logging
from PyQt5.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QFormLayout,
QGroupBox, QLabel, QLineEdit, QSpinBox, QTextEdit,
QPushButton, QCheckBox, QComboBox
)
from PyQt5.QtCore import pyqtSignal, Qt
logger = logging.getLogger("settings_tab")
class SettingsTab(QWidget):
"""Widget für den Einstellungen-Tab."""
# Signale
proxy_settings_saved = pyqtSignal(dict)
proxy_tested = pyqtSignal(str) # proxy_type
email_settings_saved = pyqtSignal(dict)
email_tested = pyqtSignal(dict) # email_settings
license_activated = pyqtSignal(str) # license_key
def __init__(self, platform_name, proxy_rotator=None, email_handler=None, license_manager=None, language_manager=None):
super().__init__()
self.platform_name = platform_name
self.proxy_rotator = proxy_rotator
self.email_handler = email_handler
self.license_manager = license_manager
self.language_manager = language_manager
self.init_ui()
if self.language_manager:
self.language_manager.language_changed.connect(self.update_texts)
self.update_texts()
# Einstellungen laden, falls Handler vorhanden
self.load_settings()
def init_ui(self):
"""Initialisiert die Benutzeroberfläche."""
layout = QVBoxLayout(self)
# Proxy-Einstellungen
proxy_group = QGroupBox("Proxy-Einstellungen")
proxy_layout = QVBoxLayout(proxy_group)
# IPv4 Proxies
ipv4_form = QFormLayout()
self.ipv4_proxy_input = QTextEdit()
self.ipv4_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
ipv4_form.addRow("IPv4 Proxies:", self.ipv4_proxy_input)
proxy_layout.addLayout(ipv4_form)
# IPv6 Proxies
ipv6_form = QFormLayout()
self.ipv6_proxy_input = QTextEdit()
self.ipv6_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
ipv6_form.addRow("IPv6 Proxies:", self.ipv6_proxy_input)
proxy_layout.addLayout(ipv6_form)
# Mobile Proxies
mobile_form = QFormLayout()
self.mobile_proxy_input = QTextEdit()
self.mobile_proxy_input.setPlaceholderText("Ein Proxy pro Zeile im Format: host:port:username:password")
mobile_form.addRow("Mobile Proxies:", self.mobile_proxy_input)
proxy_layout.addLayout(mobile_form)
# Mobile Proxy API Keys
api_key_layout = QFormLayout()
self.marsproxy_api_input = QLineEdit()
api_key_layout.addRow("MarsProxies API Key:", self.marsproxy_api_input)
self.iproyal_api_input = QLineEdit()
api_key_layout.addRow("IPRoyal API Key:", self.iproyal_api_input)
proxy_layout.addLayout(api_key_layout)
# Test-Button
proxy_button_layout = QHBoxLayout()
self.test_proxy_button = QPushButton("Proxy testen")
self.test_proxy_button.clicked.connect(self.on_test_proxy_clicked)
self.save_proxy_button = QPushButton("Proxy-Einstellungen speichern")
self.save_proxy_button.clicked.connect(self.on_save_proxy_clicked)
proxy_button_layout.addWidget(self.test_proxy_button)
proxy_button_layout.addWidget(self.save_proxy_button)
proxy_layout.addLayout(proxy_button_layout)
layout.addWidget(proxy_group)
# E-Mail-Einstellungen
email_group = QGroupBox("E-Mail-Einstellungen")
email_layout = QFormLayout(email_group)
self.imap_server_input = QLineEdit("imap.ionos.de")
email_layout.addRow("IMAP-Server:", self.imap_server_input)
self.imap_port_input = QSpinBox()
self.imap_port_input.setRange(1, 65535)
self.imap_port_input.setValue(993)
email_layout.addRow("IMAP-Port:", self.imap_port_input)
self.imap_user_input = QLineEdit()
email_layout.addRow("IMAP-Benutzername:", self.imap_user_input)
self.imap_pass_input = QLineEdit()
self.imap_pass_input.setEchoMode(QLineEdit.Password)
email_layout.addRow("IMAP-Passwort:", self.imap_pass_input)
email_button_layout = QHBoxLayout()
self.test_email_button = QPushButton("E-Mail testen")
self.test_email_button.clicked.connect(self.on_test_email_clicked)
self.save_email_button = QPushButton("E-Mail-Einstellungen speichern")
self.save_email_button.clicked.connect(self.on_save_email_clicked)
email_button_layout.addWidget(self.test_email_button)
email_button_layout.addWidget(self.save_email_button)
email_layout.addRow("", email_button_layout)
layout.addWidget(email_group)
# Plattformspezifische Einstellungen
if self.platform_name.lower() != "instagram":
self.add_platform_specific_settings(layout)
# Lizenz-Gruppe
license_group = QGroupBox("Lizenz")
license_layout = QFormLayout(license_group)
self.license_key_input = QLineEdit()
license_layout.addRow("Lizenzschlüssel:", self.license_key_input)
self.activate_license_button = QPushButton("Lizenz aktivieren")
self.activate_license_button.clicked.connect(self.on_activate_license_clicked)
license_layout.addRow("", self.activate_license_button)
layout.addWidget(license_group)
# Stretch am Ende hinzufügen
layout.addStretch(1)
def add_platform_specific_settings(self, layout):
"""
Fügt plattformspezifische Einstellungen hinzu.
Diese Methode kann in abgeleiteten Klassen überschrieben werden.
Args:
layout: Das Layout, zu dem die Einstellungen hinzugefügt werden sollen
"""
platform = self.platform_name.lower()
platform_settings_group = QGroupBox(f"{self.platform_name}-spezifische Einstellungen")
platform_settings_layout = QFormLayout(platform_settings_group)
# Je nach Plattform unterschiedliche Einstellungen
if platform == "twitter":
self.twitter_api_key = QLineEdit()
platform_settings_layout.addRow("Twitter API Key:", self.twitter_api_key)
self.twitter_api_secret = QLineEdit()
platform_settings_layout.addRow("Twitter API Secret:", self.twitter_api_secret)
elif platform == "tiktok":
self.video_upload = QCheckBox("Video automatisch hochladen")
platform_settings_layout.addRow("", self.video_upload)
self.follower_action = QCheckBox("Automatisch anderen Nutzern folgen")
platform_settings_layout.addRow("", self.follower_action)
elif platform == "facebook":
self.page_creation = QCheckBox("Seite automatisch erstellen")
platform_settings_layout.addRow("", self.page_creation)
self.privacy_level = QComboBox()
self.privacy_level.addItems(["Öffentlich", "Freunde", "Nur ich"])
platform_settings_layout.addRow("Datenschutzeinstellung:", self.privacy_level)
# Speichern-Button für plattformspezifische Einstellungen
self.platform_save_button = QPushButton(f"{self.platform_name}-Einstellungen speichern")
self.platform_save_button.clicked.connect(self.on_save_platform_settings_clicked)
platform_settings_layout.addRow("", self.platform_save_button)
layout.addWidget(platform_settings_group)
def load_settings(self):
"""Lädt die Einstellungen aus den Handlern."""
# Proxy-Einstellungen laden
if self.proxy_rotator:
try:
proxy_config = self.proxy_rotator.get_config() or {}
# IPv4 Proxies
ipv4_proxies = proxy_config.get("ipv4", [])
self.ipv4_proxy_input.setPlainText("\n".join(ipv4_proxies))
# IPv6 Proxies
ipv6_proxies = proxy_config.get("ipv6", [])
self.ipv6_proxy_input.setPlainText("\n".join(ipv6_proxies))
# Mobile Proxies
mobile_proxies = proxy_config.get("mobile", [])
self.mobile_proxy_input.setPlainText("\n".join(mobile_proxies))
# API Keys
mobile_api = proxy_config.get("mobile_api", {})
self.marsproxy_api_input.setText(mobile_api.get("marsproxies", ""))
self.iproyal_api_input.setText(mobile_api.get("iproyal", ""))
except Exception as e:
logger.error(f"Fehler beim Laden der Proxy-Einstellungen: {e}")
# E-Mail-Einstellungen laden
if self.email_handler:
try:
email_config = self.email_handler.get_config() or {}
self.imap_server_input.setText(email_config.get("imap_server", "imap.ionos.de"))
self.imap_port_input.setValue(email_config.get("imap_port", 993))
self.imap_user_input.setText(email_config.get("imap_user", ""))
self.imap_pass_input.setText(email_config.get("imap_pass", ""))
except Exception as e:
logger.error(f"Fehler beim Laden der E-Mail-Einstellungen: {e}")
# Lizenzeinstellungen laden
if self.license_manager:
try:
license_info = self.license_manager.get_license_info()
self.license_key_input.setText(license_info.get("key", ""))
except Exception as e:
logger.error(f"Fehler beim Laden der Lizenzeinstellungen: {e}")
def on_save_proxy_clicked(self):
"""Wird aufgerufen, wenn der Proxy-Speichern-Button geklickt wird."""
# Proxy-Einstellungen sammeln
settings = {
"ipv4_proxies": self.ipv4_proxy_input.toPlainText(),
"ipv6_proxies": self.ipv6_proxy_input.toPlainText(),
"mobile_proxies": self.mobile_proxy_input.toPlainText(),
"mobile_api": {
"marsproxies": self.marsproxy_api_input.text().strip(),
"iproyal": self.iproyal_api_input.text().strip()
}
}
# Signal auslösen
self.proxy_settings_saved.emit(settings)
def on_test_proxy_clicked(self):
"""Wird aufgerufen, wenn der Proxy-Test-Button geklickt wird."""
# Proxy-Typ aus der Combobox in der Generator-Tab holen
# Da wir keine direkte Referenz haben, nehmen wir den ersten Eintrag
proxy_type = "ipv4"
# Signal auslösen
self.proxy_tested.emit(proxy_type)
def on_save_email_clicked(self):
"""Wird aufgerufen, wenn der E-Mail-Speichern-Button geklickt wird."""
# E-Mail-Einstellungen sammeln
settings = {
"imap_server": self.imap_server_input.text().strip(),
"imap_port": self.imap_port_input.value(),
"imap_user": self.imap_user_input.text().strip(),
"imap_pass": self.imap_pass_input.text()
}
# Signal auslösen
self.email_settings_saved.emit(settings)
def on_test_email_clicked(self):
"""Wird aufgerufen, wenn der E-Mail-Test-Button geklickt wird."""
# E-Mail-Einstellungen sammeln
settings = {
"imap_server": self.imap_server_input.text().strip(),
"imap_port": self.imap_port_input.value(),
"imap_user": self.imap_user_input.text().strip(),
"imap_pass": self.imap_pass_input.text()
}
# Signal auslösen
self.email_tested.emit(settings)
def on_save_platform_settings_clicked(self):
"""Wird aufgerufen, wenn der Plattform-Einstellungen-Speichern-Button geklickt wird."""
# Hier könnte ein plattformspezifisches Signal ausgelöst werden
logger.info(f"{self.platform_name}-Einstellungen gespeichert")
def on_activate_license_clicked(self):
"""Wird aufgerufen, wenn der Lizenz-Aktivieren-Button geklickt wird."""
license_key = self.license_key_input.text().strip()
if not license_key:
return
# Signal auslösen
self.license_activated.emit(license_key)
def update_texts(self):
"""Aktualisiert UI-Texte gemäß aktueller Sprache."""
if not self.language_manager:
return
self.test_proxy_button.setText(self.language_manager.get_text("buttons.test_proxy", "Proxy testen"))
self.save_proxy_button.setText(self.language_manager.get_text("buttons.save_proxy", "Proxy-Einstellungen speichern"))
self.test_email_button.setText(self.language_manager.get_text("buttons.test_email", "E-Mail testen"))
self.save_email_button.setText(self.language_manager.get_text("buttons.save_email", "E-Mail-Einstellungen speichern"))
self.activate_license_button.setText(self.language_manager.get_text("buttons.activate_license", "Lizenz aktivieren"))