1616sys .stderr = io .TextIOWrapper (sys .stderr .buffer , encoding = 'utf-8' )
1717
1818LOGIN_URL = "https://login.alditalk-kundenbetreuung.de/signin/XUI/#login/"
19- DASHBOARD_URL = "https://www.alditalk-kundenportal.de/portal/auth/buchungsuebersicht/"
20- UBERSICHT_URL = "https://www.alditalk-kundenportal.de/portal/auth/uebersicht/"
19+ DASHBOARD_URL = "https://www.alditalk-kundenportal.de/portal/auth/uebersicht/"
2120
22- VERSION = "1.1.1 " # Deine aktuelle Version
21+ VERSION = "1.1.4 " # Deine aktuelle Version
2322
2423REMOTE_VERSION_URL = "https://raw.githubusercontent.com/Dinobeiser/AT-Extender/main/version.txt" # Link zur Version
2524REMOTE_SCRIPT_URL = "https://raw.githubusercontent.com/Dinobeiser/AT-Extender/main/at-extender.py" # Link zum neuesten Skript
2625
27- USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139 .0) Gecko/20100101 Firefox/139.0"
26+ USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137 .0) Gecko/20100101 Firefox/139.0"
2827HEADLESS = True
2928
3029
@@ -36,7 +35,7 @@ def load_config():
3635 browser = config .get ("BROWSER" , "chromium" ).lower ()
3736
3837 if browser not in valid_browsers :
39- logging .warning (f"Ungültiger Browser '{ browser } ' in config.json – fallback auf 'chromium'" )
38+ logging .warning (f"Ungültiger Browserwert '{ browser } ' in config.json - fallback auf 'chromium'" )
4039 browser = "chromium"
4140
4241 config ["BROWSER" ] = browser
@@ -69,7 +68,6 @@ def send_telegram_message(message, retries=3):
6968 logging .warning (f"Fehler beim Senden (Versuch { attempt + 1 } ): { response .text } " )
7069 except Exception as e :
7170 logging .error (f"Fehler beim Telegram-Senden (Versuch { attempt + 1 } ): { e } " )
72- time .sleep (2 )
7371 logging .error ("Telegram konnte nicht erreicht werden." )
7472 return False
7573 else :
@@ -104,7 +102,7 @@ def check_for_update():
104102 f .write (update .text )
105103 logging .info ("✅ Update erfolgreich! Starte neu..." )
106104
107- # Universeller Neustart – funktioniert mit venv & system-python
105+ # Universeller Neustart - funktioniert mit venv & system-python
108106 os .execv (sys .executable , [sys .executable ] + sys .argv )
109107
110108 else :
@@ -133,47 +131,133 @@ def login_and_check_data():
133131 with sync_playwright () as p :
134132 for attempt in range (3 ): # 3 Versuche, falls Playwright abstürzt
135133 try :
134+ COOKIE_FILE = "cookies.json"
136135 logging .info (f"Starte { BROWSER } ..." )
136+
137+ # Browser starten
137138 if BROWSER == "firefox" :
138139 browser = p .firefox .launch (headless = HEADLESS )
139140 elif BROWSER == "webkit" :
140141 browser = p .webkit .launch (headless = HEADLESS )
141142 else :
142143 browser = p .chromium .launch (headless = HEADLESS )
143- context = browser .new_context (user_agent = USER_AGENT )
144+
145+ # Cookies vorbereiten
146+ if os .path .exists (COOKIE_FILE ):
147+ logging .info ("Lade gespeicherte Cookies..." )
148+ context = browser .new_context (user_agent = USER_AGENT , storage_state = COOKIE_FILE )
149+ else :
150+ logging .info ("Keine Cookies vorhanden - neuer Kontext wird erstellt." )
151+ context = browser .new_context (user_agent = USER_AGENT )
152+
144153 page = context .new_page ()
145154
146- logging .info ("Öffne Aldi Talk Login-Seite..." )
147- page .goto (LOGIN_URL )
148- page .wait_for_load_state ("domcontentloaded" )
155+ # Hilfsfunktion: prüfen, ob eingeloggt anhand Überschrift
156+ def login_erfolgreich (p ):
157+ try :
158+ p .wait_for_selector ('one-heading[level="h1"]' , timeout = 8000 )
159+ heading = p .text_content ('one-heading[level="h1"]' )
160+ return heading and "Übersicht" in heading
161+ except :
162+ return False
163+
164+ # Dashboard aufrufen
165+ page .goto (DASHBOARD_URL , wait_until = "domcontentloaded" )
166+ time .sleep (3 )
167+
168+ # Prüfen ob auf Login-Seite umgeleitet wurde
169+ if "login" in page .url :
170+ logging .info ("Nicht eingeloggt - Login wird durchgeführt..." )
171+ page .goto (LOGIN_URL )
172+ page .wait_for_load_state ("domcontentloaded" )
173+ wait_and_click (page , 'button[data-testid="uc-deny-all-button"]' )
174+
175+ logging .info ("Fülle Login-Daten aus..." )
176+ page .fill ('#input-5' , RUFNUMMER )
177+ page .fill ('#input-6' , PASSWORT )
178+
179+ if not wait_and_click (page , '[class="button button--solid button--medium button--color-default button--has-label"]' ):
180+ raise Exception ("Login-Button konnte nicht geklickt werden." )
181+
182+ logging .info ("Warte auf Login..." )
183+ time .sleep (8 )
184+ page .wait_for_load_state ("domcontentloaded" )
185+
186+ if login_erfolgreich (page ):
187+ logging .info ("Login erfolgreich - Cookies werden gespeichert." )
188+ context .storage_state (path = COOKIE_FILE )
189+ else :
190+ raise Exception ("Login fehlgeschlagen - Übersichtsseite nicht sichtbar." )
191+ else :
192+ logging .info (" Bereits eingeloggt - Zugriff aufs Dashboard funktioniert." )
149193
150- wait_and_click (page , 'button[data-testid="uc-deny-all-button"]' )
194+ if not login_erfolgreich (page ):
195+ logging .warning ("Session scheint abgelaufen oder inkonsistent - versuche erneuten Login..." )
151196
152- logging . info ( "Fülle Login-Daten aus..." )
153- page . fill ( '#input-5' , RUFNUMMER )
154- page . fill ( '#input-6' , PASSWORT )
197+ if os . path . exists ( COOKIE_FILE ):
198+ os . remove ( COOKIE_FILE )
199+ logging . info ( "Alte Cookies wurden gelöscht, da ungültig." )
155200
156- if not wait_and_click (page , '[class="button button--solid button--medium button--color-default button--has-label"]' ):
157- raise Exception ("Login-Button konnte nicht geklickt werden." )
201+ # Versuche Login erneut
202+ page .goto (LOGIN_URL )
203+ page .wait_for_load_state ("domcontentloaded" )
204+ wait_and_click (page , 'button[data-testid="uc-deny-all-button"]' )
158205
159- logging .info ("Warte auf Login..." )
160- time .sleep (8 )
206+ logging .info ("Fülle Login-Daten aus (Fallback)..." )
207+ page .fill ('#input-5' , RUFNUMMER )
208+ page .fill ('#input-6' , PASSWORT )
161209
162- logging .info ("Öffne Datenvolumen-Übersicht..." )
163- page .goto (DASHBOARD_URL )
164- page .wait_for_load_state ("domcontentloaded" )
165- time .sleep (3 )
210+ if not wait_and_click (page , '[class="button button--solid button--medium button--color-default button--has-label"]' ):
211+ raise Exception ("Fallback-Login: Login-Button konnte nicht geklickt werden." )
166212
213+ logging .info ("Warte auf Login... (Fallback)" )
214+ time .sleep (8 )
215+ page .wait_for_load_state ("domcontentloaded" )
216+
217+ if login_erfolgreich (page ):
218+ logging .info ("Fallback-Login erfolgreich neue Cookies werden gespeichert." )
219+ context .storage_state (path = COOKIE_FILE )
220+ else :
221+ raise Exception ("Fallback-Login fehlgeschlagen Session kann nicht wiederhergestellt werden." )
222+
223+ # Session aktiv verlängern durch Aktion:
224+ try :
225+ page .hover ('one-heading[level="h1"]' )
226+ logging .info ("Session-Aktivität erfolgreich simuliert hover auf Überschrift." )
227+ except :
228+ logging .warning ("Session konnte nicht ausgeführt werden." )
229+
230+ #
231+ logging .info ("Cookies werden erneuert." )
232+ context .storage_state (path = COOKIE_FILE )
233+
234+ # Weiter mit Datenvolumen-Logik
167235 logging .info ("Lese Datenvolumen aus..." )
168236
169- GB_text_raw = page .text_content ('one-cluster[slot="help-text"]' )
237+
238+ GB_selectors = [
239+ 'one-stack.usage-meter:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)' ,
240+ 'one-stack.usage-meter:nth-child(1) > one-stack:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)'
241+ ]
242+
243+ GB_text_raw = None
244+ for sel in GB_selectors :
245+ try :
246+ element = page .query_selector (sel )
247+ if element :
248+ GB_text_raw = element .text_content ()
249+ if GB_text_raw :
250+ break
251+ except Exception as e :
252+ logging .warning (f"Selector { sel } nicht verfügbar: { e } " )
253+ continue
254+
170255 if not GB_text_raw :
171- raise Exception ("Konnte das Datenvolumen nicht auslesen." )
256+ raise Exception ("Konnte das Datenvolumen nicht auslesen - kein gültiger Selector gefunden ." )
172257
173- # Beispiel: "6,52 GB von 15 GB übrig im Inland"
174258 match = re .search (r"([\d\.,]+)\s?(GB|MB)" , GB_text_raw )
175259 if not match :
176- raise ValueError (f"Unerwartetes Format: { GB_text_raw } " )
260+ raise ValueError (f"Unerwartetes Format beim Datenvolumen : { GB_text_raw } " )
177261
178262 value , unit = match .groups ()
179263 value = value .replace ("," , "." )
@@ -185,37 +269,31 @@ def login_and_check_data():
185269
186270 logging .info (f"Aktuelles Datenvolumen: { GB :.2f} GB" )
187271
188- if GB < 1.0 :
189- message = f"{ RUFNUMMER } : ⚠️ Nur noch { GB :.2f} GB übrig! Versuche, Datenvolumen nachzubuchen..."
190- send_telegram_message (message )
191-
192- logging .info ("Öffne Nachbuchungsseite..." )
193- page .goto (UBERSICHT_URL )
194- page .wait_for_load_state ("domcontentloaded" )
195- time .sleep (2 )
196272
197- logging .info ("Klicke auf den Nachbuchungsbutton..." )
273+ if GB < 1.0 :
274+ logging .info ("Versuche, 1 GB Datenvolumen nachzubuchen..." )
198275 if wait_and_click (page , 'one-button[slot="action"]' ):
199- time .sleep (2 )
200- send_telegram_message (f"{ RUFNUMMER } : Datenvolumen erfolgreich nachgebucht! ✅" )
201- logging .info ("1 GB Datenvolumen wurde nachgebucht!" )
276+ message = f"{ RUFNUMMER } : Aktuelles Datenvolumen: { GB :.2f} GB - 1 GB wurde erfolgreich nachgebucht. ✅"
277+ logging .info ("1 GB Datenvolumen wurde erfolgreich nachgebucht." )
202278 else :
203279 raise Exception ("❌ Konnte den Nachbuchungsbutton nicht klicken!" )
204280
281+ send_telegram_message (message )
282+
205283 else :
206284 send_telegram_message (f"{ RUFNUMMER } : Noch { GB :.2f} GB übrig. Kein Nachbuchen erforderlich. ✅" )
207285
208286 return # Erfolgreicher Durchlauf, keine Wiederholung nötig
209287
210288 except Exception as e :
211289 logging .error (f"Fehler im Versuch { attempt + 1 } : { e } " )
212- send_telegram_message (f"{ RUFNUMMER } : Fehler beim Abrufen des Datenvolumens: { e } ❌ " )
290+ send_telegram_message (f"{ RUFNUMMER } : ❌ Fehler beim Abrufen des Datenvolumens: { e } " )
213291
214292 finally :
215293 browser .close ()
216294 logging .info ("Browser geschlossen." )
217295
218- time .sleep (5 ) # Kurze Pause zwischen Wiederholungen
296+ time .sleep (2 )
219297 logging .error ("Skript hat nach 3 Versuchen aufgegeben." )
220298
221299def sleep_interval (config ):
@@ -225,7 +303,7 @@ def sleep_interval(config):
225303 try :
226304 interval = int (config .get ("SLEEP_INTERVAL" , 70 )) # Sicherstellen, dass es ein int ist
227305 except ValueError :
228- logging .warning ("⚠️ Ungültiger SLEEP_INTERVAL-Wert – setze auf Standard 90 Sekunden." )
306+ logging .warning ("⚠️ Ungültiger SLEEP_INTERVAL-Wert - setze auf Standard 90 Sekunden." )
229307 interval = 90
230308
231309 if interval < 60 :
0 commit comments