501 Zeilen
20 KiB
Python
501 Zeilen
20 KiB
Python
# 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"))
|