Skip to content

Commit

Permalink
* feat(.env.example): add support for SERVICE environment variable
Browse files Browse the repository at this point in the history
* feat(README.md): update tool description to support both SIM24 and 1&1 Unlimited-Demand tariffs
* feat(docker-entrypoint.sh): add SERVICE variable to .env file creation
* feat(main.py): add logging filter for different services and update main function to support multiple services
  • Loading branch information
DanielWTE committed Jan 11, 2025
1 parent 535493f commit 599200d
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 81 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
SERVICE="" # 1und1, sim24
USERNAME=""
PASSWORD=""
CHECK_INTERVAL=300
47 changes: 25 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# SIM24 Auto Extender
# Unlimited OnDemand Auto Extender

Dieses Tool automatisiert das Nachbuchen von Datenvolumen bei SIM24-Unlimited-Tarifen. Bei diesen Tarifen muss nach Verbrauch der ersten 50GB das Datenvolumen manuell in 2GB-Schritten nachgebucht werden. Dieser Prozess wird durch dieses Script vollautomatisch erledigt.
Dieses Tool automatisiert das Nachbuchen von Datenvolumen bei SIM24- und 1&1-Unlimited-Demand-Tarifen. Bei diesen Tarifen muss nach Verbrauch der ersten 50GB das Datenvolumen manuell in Schritten nachgebucht werden. Dieser Prozess wird durch dieses Script vollautomatisch erledigt.

## Features

- Automatische Anmeldung im SIM24-Portal
- Automatische Anmeldung im SIM24- oder 1&1-Portal
- Kontinuierliche Überwachung des Datenvolumens
- Automatisches Nachbuchen bei Bedarf
- Ausführliche Logging-Funktionen
Expand All @@ -13,54 +13,56 @@ Dieses Tool automatisiert das Nachbuchen von Datenvolumen bei SIM24-Unlimited-Ta
## Voraussetzungen

- Docker auf dem System installiert
- SIM24 Account-Zugangsdaten
- Ein aktiver SIM24-Unlimited-Tarif
- SIM24 oder 1&1 Account-Zugangsdaten
- Ein aktiver Unlimited-Demand-Tarif bei einem der unterstützten Anbieter

## Installation & Einrichtung

1. Image herunterladen:
```bash
docker pull ghcr.io/danielwte/sim24-auto-extender:latest
docker pull ghcr.io/danielwte/unlimited-ondemand-auto-extender:latest
```

2. Container starten:
```bash
docker run -d \
-e USERNAME="sim24-username" \
-e PASSWORD="sim24-password" \
-e USERNAME="service-username" \
-e PASSWORD="service-password" \
-e SERVICE="service" \
-e CHECK_INTERVAL=300 \
--name sim24-auto-extender \
ghcr.io/danielwte/sim24-auto-extender:latest
--name unlimited-ondemand-auto-extender \
ghcr.io/danielwte/unlimited-ondemand-auto-extender:latest
```

### Umgebungsvariablen

- `USERNAME`: Der SIM24 Benutzername
- `PASSWORD`: Das SIM24 Passwort
- `USERNAME`: Der Benutzername für das entsprechende Portal
- `PASSWORD`: Das Passwort für das entsprechende Portal
- `CHECK_INTERVAL`: Prüfintervall in Sekunden (Standard: 300)
- `SERVICE`: Der zu überwachende Service (Standard: sim24, Optionen: sim24, 1und1)

## Logs einsehen

Die Logs können wie folgt eingesehen werden:
```bash
docker logs sim24-auto-extender
docker logs unlimited-ondemand-auto-extender
```

## Container-Verwaltung

Container neustarten:
```bash
docker restart sim24-auto-extender
docker restart unlimited-ondemand-auto-extender
```

Container stoppen:
```bash
docker stop sim24-auto-extender
docker stop unlimited-ondemand-auto-extender
```

Container entfernen:
```bash
docker rm sim24-auto-extender
docker rm unlimited-ondemand-auto-extender
```

## Automatischer Start nach Systemneustart
Expand All @@ -69,19 +71,20 @@ Für einen automatischen Start nach einem Systemneustart:
```bash
docker run -d \
--restart unless-stopped \
-e USERNAME="sim24-username" \
-e PASSWORD="sim24-password" \
-e USERNAME="service-username" \
-e PASSWORD="service-password" \
-e SERVICE="service" \
-e CHECK_INTERVAL=300 \
--name sim24-auto-extender \
ghcr.io/danielwte/sim24-auto-extender:latest
--name unlimited-ondemand-auto-extender \
ghcr.io/danielwte/unlimited-ondemand-auto-extender:latest
```

## Sicherheit

- Die Zugangsdaten werden nur innerhalb des Containers verwendet
- Es werden keine Daten persistent gespeichert
- Die Kommunikation erfolgt direkt mit dem SIM24-Portal
- Die Kommunikation erfolgt direkt mit dem Portal des entsprechenden Anbieters

## Disclaimer

Dieses Tool ist ein inoffizielles Hilfsprogramm und steht in keiner Verbindung zu SIM24. Die Nutzung erfolgt auf eigene Verantwortung.
Dieses Tool ist ein inoffizielles Hilfsprogramm und steht in keiner Verbindung zu SIM24 oder 1&1. Die Nutzung erfolgt auf eigene Verantwortung.
63 changes: 63 additions & 0 deletions checker/oneandone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import time
from playwright.sync_api import sync_playwright
import logging

def check_1und1(username, password):
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")

try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()

logging.info("Öffne Login-Seite...")
page.goto('https://account.1und1.de/')

logging.info("Führe Login durch...")
page.fill('#login-form-user', username)
page.fill('#login-form-password', password)

page.click('#login-button')
logging.info("Login erfolgreich")

logging.info("Cookies ablehnen...")
try:
page.click('#consent_wall_optout')
except:
logging.info("Cookie-Banner nicht vorhanden oder bereits geschlossen.")

logging.info("Weiterleitung zu Verbrauchsübersicht...")
page.goto('https://control-center.1und1.de/usages.html')

time.sleep(3)

page.wait_for_selector('div[data-testid="usage-volume-used"] strong')
used_data = page.locator('div[data-testid="usage-volume-used"] strong').nth(-1).text_content()
if used_data:
logging.info(f"Verbrauchte Daten: {used_data}")
else:
logging.warning("Verbrauchsdaten nicht gefunden.")

button = page.locator('button:has-text("+1 GB")')
if button:
is_disabled = button.get_attribute('disabled') is not None
if is_disabled:
logging.info("Button gefunden, aber er ist deaktiviert.")
else:
logging.info("Button gefunden und aktiv. Versuche zu klicken...")
button.click()
logging.info("Button erfolgreich geklickt.")
time.sleep(3)
confirm_button = page.locator('button:has-text("Ok")')
if confirm_button:
confirm_button.click()
logging.info("Bestätigungsdialog erfolgreich geschlossen.")

else:
logging.warning("Button '+1 GB' nicht gefunden.")

logging.info("Schließe Browser.")
browser.close()

except Exception as e:
logging.error(f"Fehler bei der Ausführung: {str(e)}")
60 changes: 60 additions & 0 deletions checker/sim24.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from playwright.sync_api import sync_playwright
import logging

def check_sim24(username, password):
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()

logging.info("Öffne Login-Seite...")
page.goto('https://service.sim24.de/mytariff/invoice/showGprsDataUsage')

logging.info("Führe Login durch...")
page.fill('input[name="UserLoginType[alias]"]', username)
page.fill('input[name="UserLoginType[password]"]', password)

page.click('a.c-button.submitOnEnter[title="Login"]')

logging.info("Deny Cookies...")
consent_button = page.query_selector('#consent_wall_optout')
if consent_button and consent_button.is_visible():
consent_button.click()
else:
logging.info("Consent button not visible, skipping...")

logging.info("Suche nach Button...")
try:
button = page.wait_for_selector('#ButtonBuchen-ChangeServiceType-showGprsDataUsage-0V5I3', timeout=10000)
stats = page.wait_for_selector('.dataUsageBar-info-numbers', timeout=10000)

if stats:
used_data = stats.query_selector('.font-weight-bold').inner_text()
total_data = stats.query_selector('.l-txt-small').inner_text().replace('von', '').strip()
logging.info(f"Verbrauchte Daten: {used_data} von {total_data}")

if button:
is_disabled = button.get_attribute('disabled') is not None

if is_disabled:
logging.info("Button gefunden, aber deaktiviert")
else:
logging.info("Button gefunden und aktiv - Klicke...")
button.click()
logging.info("Button erfolgreich geklickt")

page.click('#ButtonAktivieren-ChangeServiceType-getChangeServiceInfo-1V5I3')

logging.info("Prozess erfolgreich beendet")
return
else:
logging.warning("Button nicht gefunden")

except Exception as e:
logging.warning(f"Button nicht gefunden oder nicht klickbar: {str(e)}")

logging.info("Schließe Browser")
browser.close()

except Exception as e:
logging.error(f"Fehler bei der Ausführung: {str(e)}")
4 changes: 3 additions & 1 deletion docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ set -e
create_env_file() {
if [ ! -f .env ]; then
echo "Creating .env file from environment variables..."
: ${SERVICE:=""}
: ${USERNAME:=""}
: ${PASSWORD:=""}
: ${CHECK_INTERVAL:=300}

echo "USERNAME=\"$USERNAME\"" > .env
echo "SERVICE=\"$SERVICE\"" > .env
echo "USERNAME=\"$USERNAME\"" >> .env
echo "PASSWORD=\"$PASSWORD\"" >> .env
echo "CHECK_INTERVAL=$CHECK_INTERVAL" >> .env
fi
Expand Down
77 changes: 19 additions & 58 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,35 @@
import logging
from dotenv import load_dotenv
import os
from checker.sim24 import check_sim24
from checker.oneandone import check_1und1

load_dotenv()

SERVICE = os.getenv("SERVICE")
USERNAME = os.getenv("USERNAME")
PASSWORD = os.getenv("PASSWORD")
CHECK_INTERVAL = int(os.getenv("CHECK_INTERVAL"))

logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
format='%(asctime)s - %(levelname)s - [%(prefix)s] %(message)s',
handlers=[
logging.FileHandler('automation.log'),
logging.StreamHandler()
]
)

def check_sim24():
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
class PrefixFilter(logging.Filter):
def __init__(self, prefix=""):
self.prefix = prefix
super().__init__()

logging.info("Öffne Login-Seite...")
page.goto('https://service.sim24.de/mytariff/invoice/showGprsDataUsage')

logging.info("Führe Login durch...")
page.fill('input[name="UserLoginType[alias]"]', USERNAME)
page.fill('input[name="UserLoginType[password]"]', PASSWORD)

page.click('a.c-button.submitOnEnter[title="Login"]')

logging.info("Deny Cookies...")
consent_button = page.query_selector('#consent_wall_optout')
if consent_button and consent_button.is_visible():
consent_button.click()
else:
logging.info("Consent button not visible, skipping...")

logging.info("Suche nach Button...")
try:
button = page.wait_for_selector('#ButtonBuchen-ChangeServiceType-showGprsDataUsage-0V5I3', timeout=10000)
stats = page.wait_for_selector('.dataUsageBar-info-numbers', timeout=10000)

if stats:
used_data = stats.query_selector('.font-weight-bold').inner_text()
total_data = stats.query_selector('.l-txt-small').inner_text().replace('von', '').strip()
logging.info(f"Verbrauchte Daten: {used_data} von {total_data}")

if button:
is_disabled = button.get_attribute('disabled') is not None

if is_disabled:
logging.info("Button gefunden, aber deaktiviert")
else:
logging.info("Button gefunden und aktiv - Klicke...")
button.click()
logging.info("Button erfolgreich geklickt")

page.click('#ButtonAktivieren-ChangeServiceType-getChangeServiceInfo-1V5I3')

logging.info("Prozess erfolgreich beendet")
return
else:
logging.warning("Button nicht gefunden")

except Exception as e:
logging.warning(f"Button nicht gefunden oder nicht klickbar: {str(e)}")

logging.info("Schließe Browser")
browser.close()

except Exception as e:
logging.error(f"Fehler bei der Ausführung: {str(e)}")
def filter(self, record):
record.prefix = self.prefix
return True

logging.getLogger().addFilter(PrefixFilter(SERVICE))

def main():
logging.info("Starte Automatisierung...")
Expand All @@ -86,7 +42,12 @@ def main():
logging.info(f"Starte neue Überprüfung um {current_time}")

try:
check_sim24()
if SERVICE == "sim24":
check_sim24(USERNAME, PASSWORD)
elif SERVICE == "1und1":
check_1und1(USERNAME, PASSWORD)
else:
logging.error(f"Unbekannte Service-ID: {SERVICE}")
except Exception as e:
logging.error(f"Fehler im Hauptprozess: {str(e)}")

Expand Down

0 comments on commit 599200d

Please sign in to comment.