Note 06/01/2026 14:13:35
import requests
import re
import json
import os
import concurrent.futures
def handler(pd: "pipedream"):
# ==========================================
# ⚙️ CONFIGURATION SETTINGS
# ==========================================
CPANEL_URL = "https://cpanel.infinityfree.com"
USERNAME = "your username here" # Consider using pd.inputs or Pipedream Env Vars
PASSWORD = "your password here"
DOMAINS_TO_BACKUP = [
"mydomain.infinityfree.me",
]
DATABASES_TO_BACKUP = [
"if0_hello_world",
]
TELEGRAM_BOT_TOKEN = "bot token from botfather"
TELEGRAM_CHANNEL_ID = "-100something"
# Standard Browser Headers
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Upgrade-Insecure-Requests': '1'
}
# ==========================================
# 🚀 CORE BACKUP LOGIC
# ==========================================
def send_to_telegram(filepath, filename):
print(f"📤 Uploading {filename} to Telegram...")
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendDocument"
# Pipedream Memory Trick: Keeping the file open in 'rb' mode forces
# requests to stream the upload, keeping RAM usage near zero.
with open(filepath, 'rb') as f:
res = requests.post(
url,
data={'chat_id': TELEGRAM_CHANNEL_ID, 'caption': f"✅ Backup successful: {filename}"},
files={'document': (filename, f)}
)
if res.status_code == 200:
print(f"✅ Successfully sent {filename} to Telegram!")
else:
print(f"❌ Failed to send {filename}: {res.text}")
def backup_domain(domain, fm_url, session):
print(f"📦 Zipping and downloading domain: {domain}...")
items = json.dumps([{"name": domain, "type": "dir", "fullPath": f"/{domain}"}])
payload = {
'action': 'downloadZip',
'items': items,
'basePath': '/',
'zipName': f'{domain}.zip'
}
res = session.post(fm_url, data=payload, stream=True)
filename = f"{domain}.zip"
filepath = f"/tmp/{filename}"
# Speed Trick: Increased chunk size to 1MB (1024 * 1024)
# Reduces loop overhead and CPU time on Pipedream
with open(filepath, 'wb') as f:
for chunk in res.iter_content(chunk_size=1048576):
f.write(chunk)
send_to_telegram(filepath, filename)
os.remove(filepath) # Instantly free disk space
def backup_database(db_name, sso_url, session):
print(f"🗄️ Preparing database backup: {db_name}...")
session.get(sso_url)
export_page = f"https://php-myadmin.net/db_export.php?db={db_name}"
res = session.get(export_page)
token_match = re.search(r'name="token"\s+value="([a-f0-9]+)"', res.text)
if not token_match:
print(f"❌ Could not find CSRF token for {db_name}. Skipping.")
return
token = token_match.group(1)
tables = re.findall(r'name="table_select\[\]"\s+value="([^"]+)"', res.text, re.IGNORECASE)
payload = {
'db': db_name,
'token': token,
'export_type': 'database',
'export_method': 'quick',
'what': 'sql',
'structure_or_data_forced': '0',
'output_format': 'sendit',
'filename_template': '@DATABASE@',
'remember_template': 'on',
'charset': 'utf-8',
'compression': 'none',
'sql_compatibility': 'NONE',
'sql_structure_or_data': 'structure_and_data',
'sql_type': 'INSERT',
'sql_insert_syntax': 'both',
'sql_max_query_size': '50000',
}
if tables:
payload['table_select[]'] = tables
payload['table_structure[]'] = tables
payload['table_data[]'] = tables
print(f"⬇️ Downloading SQL for {db_name}...")
res = session.post("https://php-myadmin.net/export.php", data=payload, stream=True)
filename = f"{db_name}.sql"
filepath = f"/tmp/{filename}"
# Streaming with 1MB chunks
with open(filepath, 'wb') as f:
for chunk in res.iter_content(chunk_size=1048576):
f.write(chunk)
send_to_telegram(filepath, filename)
os.remove(filepath)
# ==========================================
# 🔐 EXECUTION SEQUENCE
# ==========================================
print("🔐 Logging into cPanel...")
# We create ONE session and pass it everywhere. This enables TCP connection pooling.
session = requests.Session()
session.headers.update(HEADERS)
res = session.get(f"{CPANEL_URL}/login.php")
csrf_match = re.search(r'name="seeesurf"\s+value="([^"]+)"', res.text)
csrf = csrf_match.group(1) if csrf_match else ""
res = session.post(f"{CPANEL_URL}/login.php", data={
'uname': USERNAME,
'passwd': PASSWORD,
'seeesurf': csrf,
'theme': 'PaperLantern',
'login': 'Login',
'language': 'English'
})
redirect_match = re.search(r"location\.href\s*=\s*['\"]([^'\"]+)['\"]", res.text)
if not redirect_match:
print("❌ Login failed. Check credentials.")
return
dashboard_url = f"{CPANEL_URL}/{redirect_match.group(1)}"
res = session.get(dashboard_url)
html_clean = res.text.replace('\\/', '/')
fm_match = re.search(r'(https?://filemanager\.ai[^"\'\s>]+)', html_clean)
fm_url = fm_match.group(1).replace('&', '&') if fm_match else None
ttt_match = re.search(r'ttt=([-0-9a-zA-Z]+)', html_clean)
ttt = ttt_match.group(1) if ttt_match else None
db_sso_links = {}
if ttt:
res_db = session.get(f"{CPANEL_URL}/panel/indexpl.php?option=pma&ttt={ttt}")
matches = re.findall(r'(https://php-myadmin\.net/login\.php\?2=[^"\'\s>]+)', res_db.text, re.IGNORECASE)
for url in matches:
url = url.replace('&', '&')
db_match = re.search(r'&db=([^&"\']+)', url)
if db_match:
db_sso_links[db_match.group(1)] = url
print("✅ Successfully authenticated! Starting high-speed parallel backups...")
# Max workers set to 5 is perfect for avoiding Pipedream CPU throttling
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
futures = []
if fm_url:
for domain in DOMAINS_TO_BACKUP:
futures.append(executor.submit(backup_domain, domain, fm_url, session))
for db in DATABASES_TO_BACKUP:
sso_url = db_sso_links.get(db)
if sso_url:
futures.append(executor.submit(backup_database, db, sso_url, session))
for future in concurrent.futures.as_completed(futures):
try:
future.result()
except Exception as e:
print(f"❌ Backup error: {e}")
print("🎉 All backup processes completed!")
return {"status": "success"}
Public Last updated: 2026-06-02 05:10:24 PM