88import sys
99import io
1010import re
11+ try :
12+ import psutil
13+ except ImportError :
14+ import subprocess
15+ import sys
16+ subprocess .check_call ([sys .executable , "-m" , "pip" , "install" , "psutil" ])
17+ import psutil
1118from playwright .sync_api import sync_playwright , TimeoutError
1219
20+ def is_low_memory ():
21+ #Erkennt schwache Server (unter 2 GB RAM)
22+ total_ram = psutil .virtual_memory ().total / (1024 ** 3 )
23+ return total_ram <= 2.0
24+
25+ def get_launch_args (browser ):
26+ if browser == "chromium" and is_low_memory ():
27+ return ["--no-sandbox" , "--disable-dev-shm-usage" ]
28+ else :
29+ return []
30+
31+
32+
1333# Logging einrichten
1434logging .basicConfig (level = logging .INFO , format = "%(asctime)s - %(levelname)s - %(message)s" )
1535sys .stdout = io .TextIOWrapper (sys .stdout .buffer , encoding = 'utf-8' )
1838LOGIN_URL = "https://login.alditalk-kundenbetreuung.de/signin/XUI/#login/"
1939DASHBOARD_URL = "https://www.alditalk-kundenportal.de/portal/auth/uebersicht/"
2040
21- VERSION = "1.1.6 " # Deine aktuelle Version
41+ VERSION = "1.1.8 " # Deine aktuelle Version
2242
2343REMOTE_VERSION_URL = "https://raw.githubusercontent.com/Dinobeiser/AT-Extender/main/version.txt" # Link zur Version
2444REMOTE_SCRIPT_URL = "https://raw.githubusercontent.com/Dinobeiser/AT-Extender/main/at-extender.py" # Link zum neuesten Skript
2545
2646USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/139.0"
2747HEADLESS = True
28-
48+ browser = None
2949
3050def load_config ():
3151 with open ("config.json" , "r" ) as f :
@@ -73,7 +93,6 @@ def load_config():
7393 logging .error (f"Konnte 'state.json' nicht neu erstellen: { save_error } " )
7494
7595
76-
7796def send_telegram_message (message , retries = 3 ):
7897 if TELEGRAM == "1" :
7998 for attempt in range (retries ):
@@ -145,21 +164,80 @@ def wait_and_click(page, selector, timeout=5000, retries=5):
145164 logging .error (f"Konnte { selector } nicht klicken." )
146165 return False
147166
167+
168+ def get_datenvolumen (page ):
169+ logging .info ("Lese Datenvolumen aus..." )
170+
171+ try :
172+ label_selector = 'one-stack.usage-meter:nth-child(1) > one-usage-meter:nth-child(1) > one-button:nth-child(2)'
173+ label_element = page .query_selector (label_selector )
174+ label_text = label_element .text_content ().strip () if label_element else ""
175+
176+ if "Inland & EU" in label_text :
177+ logging .info ("Community+" )
178+ GB_selectors = [
179+ 'one-stack.usage-meter:nth-child(2) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)' ,
180+ 'one-stack.usage-meter:nth-child(2) > one-stack:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)'
181+ ]
182+ else :
183+ logging .info ("Kein Community+ erkannt" )
184+ GB_selectors = [
185+ 'one-stack.usage-meter:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)' ,
186+ '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)'
187+ ]
188+ except Exception as e :
189+ logging .warning (f"Fehler bei der Erkennung von Community+: { e } " )
190+ GB_selectors = [
191+ 'one-stack.usage-meter:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)' ,
192+ '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)'
193+ ]
194+
195+ GB_text_raw = None
196+ for sel in GB_selectors :
197+ try :
198+ element = page .query_selector (sel )
199+ if element :
200+ GB_text_raw = element .text_content ()
201+ if GB_text_raw :
202+ break
203+ except Exception as e :
204+ logging .warning (f"Selector { sel } nicht verfügbar: { e } " )
205+ continue
206+
207+ if not GB_text_raw :
208+ raise Exception ("Konnte das Datenvolumen nicht auslesen – kein gültiger Selector gefunden." )
209+
210+ match = re .search (r"([\d\.,]+)\s?(GB|MB)" , GB_text_raw )
211+ if not match :
212+ raise ValueError (f"Unerwartetes Format beim Datenvolumen: { GB_text_raw } " )
213+
214+ value , unit = match .groups ()
215+ value = value .replace ("," , "." )
216+
217+ if unit == "MB" :
218+ GB = float (value ) / 1024
219+ else :
220+ GB = float (value )
221+
222+ return GB
223+
224+
148225def login_and_check_data ():
149226 global LAST_GB
150227 with sync_playwright () as p :
151228 for attempt in range (3 ): # 3 Versuche, falls Playwright abstürzt
152229 try :
153230 COOKIE_FILE = "cookies.json"
154231 logging .info (f"Starte { BROWSER } ..." )
232+ LAUNCH_ARGS = get_launch_args (BROWSER )
155233
156234 # Browser starten
157235 if BROWSER == "firefox" :
158- browser = p .firefox .launch (headless = HEADLESS )
236+ browser = p .firefox .launch (headless = HEADLESS , args = LAUNCH_ARGS )
159237 elif BROWSER == "webkit" :
160- browser = p .webkit .launch (headless = HEADLESS )
238+ browser = p .webkit .launch (headless = HEADLESS , args = LAUNCH_ARGS )
161239 else :
162- browser = p .chromium .launch (headless = HEADLESS )
240+ browser = p .chromium .launch (headless = HEADLESS , args = LAUNCH_ARGS )
163241
164242 # Cookies vorbereiten
165243 if os .path .exists (COOKIE_FILE ):
@@ -250,43 +328,8 @@ def login_erfolgreich(p):
250328 logging .info ("Cookies werden erneuert." )
251329 context .storage_state (path = COOKIE_FILE )
252330
253- # Weiter mit Datenvolumen-Logik
254- logging .info ("Lese Datenvolumen aus..." )
255-
256-
257- GB_selectors = [
258- 'one-stack.usage-meter:nth-child(1) > one-usage-meter:nth-child(1) > one-group:nth-child(1) > one-heading:nth-child(2)' ,
259- '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)'
260- ]
261-
262- GB_text_raw = None
263- for sel in GB_selectors :
264- try :
265- element = page .query_selector (sel )
266- if element :
267- GB_text_raw = element .text_content ()
268- if GB_text_raw :
269- break
270- except Exception as e :
271- logging .warning (f"Selector { sel } nicht verfügbar: { e } " )
272- continue
273-
274- if not GB_text_raw :
275- raise Exception ("Konnte das Datenvolumen nicht auslesen - kein gültiger Selector gefunden." )
276-
277- match = re .search (r"([\d\.,]+)\s?(GB|MB)" , GB_text_raw )
278- if not match :
279- raise ValueError (f"Unerwartetes Format beim Datenvolumen: { GB_text_raw } " )
280-
281- value , unit = match .groups ()
282- value = value .replace ("," , "." )
283-
284- if unit == "MB" :
285- GB = float (value ) / 1024
286- else :
287- GB = float (value )
288-
289- LAST_GB = GB
331+ GB = get_datenvolumen (page )
332+ GB = LAST_GB
290333
291334 try :
292335 with open ("state.json" , "w" ) as f :
@@ -300,7 +343,7 @@ def login_erfolgreich(p):
300343 if GB < 1.0 :
301344 logging .info ("Versuche, 1 GB Datenvolumen nachzubuchen..." )
302345 if wait_and_click (page , 'one-button[slot="action"]' ):
303- message = f"{ RUFNUMMER } : Aktuelles Datenvolumen: { GB :.2f} GB - 1 GB wurde erfolgreich nachgebucht. ✅ "
346+ message = f"{ RUFNUMMER } : Aktuelles Datenvolumen: { GB :.2f} GB - 1 GB wurde erfolgreich nachgebucht. 📲 "
304347 else :
305348 raise Exception ("❌ Konnte den Nachbuchungsbutton nicht klicken!" )
306349
@@ -325,8 +368,9 @@ def login_erfolgreich(p):
325368 send_telegram_message (f"{ RUFNUMMER } : ❌ Fehler beim Abrufen des Datenvolumens: { e } " )
326369
327370 finally :
328- browser .close ()
329- logging .info ("Browser geschlossen." )
371+ if browser :
372+ browser .close ()
373+ logging .info ("Browser geschlossen." )
330374
331375 time .sleep (2 )
332376 logging .error ("Skript hat nach 3 Versuchen aufgegeben." )
@@ -373,6 +417,7 @@ def get_interval(config):
373417 else :
374418 return random .randint (300 , 500 )
375419
420+
376421if __name__ == "__main__" :
377422 while True :
378423 check_for_update ()
0 commit comments