Files
wevads-platform/scripts/generate-cx3-creatives.py
2026-02-26 04:53:11 +01:00

282 lines
16 KiB
Python

#!/usr/bin/env python3
"""Generate creatives for CX3 offers - with mandatory [unsub] link"""
import psycopg2, base64, hashlib, os, random
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
DB = dict(host='127.0.0.1', port=5432, dbname='adx_system', user='postgres', password='wevads2026')
MEDIA_DIR = '/opt/wevads-arsenal/public/media'
MEDIA_URL = 'http://89.167.40.150:5821/media'
# Brand configs for CX3 offers
BRANDS = {
'GlucoTrust': {'bg':'#1B5E20','fg':'#FFFFFF','accent':'#4CAF50','product':'GlucoTrust Supplement','badge':'GRATIS','lang':'de'},
'Trimology': {'bg':'#4A148C','fg':'#FFFFFF','accent':'#CE93D8','product':'Trimology Schlankheitskur','badge':'GRATIS','lang':'de'},
'Wellnee': {'bg':'#0D47A1','fg':'#FFFFFF','accent':'#42A5F5','product':'Wellnee Schmerzpflaster','badge':'GRATIS','lang':'de'},
'Lulutox': {'bg':'#E65100','fg':'#FFFFFF','accent':'#FF9800','product':'Lulutox Detox Tee','badge':'GRATIS','lang':'de'},
'Amazon Music': {'bg':'#232F3E','fg':'#FFFFFF','accent':'#FF9900','product':'Amazon Music Unlimited','badge':'KOSTENLOS','lang':'de'},
'Enence': {'bg':'#1565C0','fg':'#FFFFFF','accent':'#FFD600','product':'Enence Translator','badge':'GRATIS','lang':'de'},
'Synoshi': {'bg':'#006064','fg':'#FFFFFF','accent':'#00BCD4','product':'Synoshi Power Scrubber','badge':'FREE','lang':'en'},
'Derila': {'bg':'#311B92','fg':'#FFFFFF','accent':'#B388FF','product':'Derila Memory Pillow','badge':'FREE','lang':'en'},
'Ryoko': {'bg':'#BF360C','fg':'#FFFFFF','accent':'#FF6E40','product':'Ryoko Pro WiFi','badge':'FREE','lang':'en'},
'Irish Wins': {'bg':'#1B5E20','fg':'#FFFFFF','accent':'#FFD700','product':'Irish Wins Casino','badge':'FREE SPINS','lang':'en'},
'Doddle Car': {'bg':'#263238','fg':'#FFFFFF','accent':'#4CAF50','product':'Doddle Car Deals','badge':'FREE QUOTE','lang':'en'},
'HydroSoothe': {'bg':'#01579B','fg':'#FFFFFF','accent':'#29B6F6','product':'HydroSoothe Patches','badge':'FREE','lang':'en'},
'Akusoli': {'bg':'#3E2723','fg':'#FFFFFF','accent':'#8D6E63','product':'Akusoli Insoles','badge':'FREE','lang':'en'},
'Bonus Monster': {'bg':'#880E4F','fg':'#FFD700','accent':'#E91E63','product':'Bonus Monster Casino','badge':'FREE SPINS','lang':'en'},
'DateHotGirls': {'bg':'#B71C1C','fg':'#FFFFFF','accent':'#FF5252','product':'DateHotGirls','badge':'FREE','lang':'en'},
'MEDVi': {'bg':'#004D40','fg':'#FFFFFF','accent':'#26A69A','product':'MEDVi GLP-1','badge':'50% OFF','lang':'en'},
}
DEFAULT = {'bg':'#37474F','fg':'#FFFFFF','accent':'#FF5722','product':'Special Offer','badge':'FREE','lang':'en'}
# Email templates per language
TEMPLATES = {
'de': [
# V1: Urgency
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Arial,sans-serif;background:#f4f4f4;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;">
<div style="background:{bg};padding:20px;text-align:center;">
<h1 style="color:{fg};margin:0;font-size:24px;">⚡ Letzte Chance: {product}</h1>
</div>
<div style="text-align:center;padding:15px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<div style="padding:20px 30px;">
<p style="font-size:16px;line-height:1.6;color:#333;">Guten Tag,</p>
<p style="font-size:16px;line-height:1.6;color:#333;">Wir haben eine <strong>exklusive Einladung</strong> für Sie vorbereitet. Nur heute erhalten Sie Zugang zu unserem {product} Angebot — <strong>komplett kostenlos</strong>.</p>
<p style="font-size:16px;line-height:1.6;color:#333;">Dieses Angebot läuft in <strong>24 Stunden</strong> ab.</p>
<div style="text-align:center;padding:20px;">
<a href="[url]" style="background:{accent};color:{fg};padding:15px 40px;text-decoration:none;border-radius:5px;font-size:18px;font-weight:bold;display:inline-block;">JETZT SICHERN →</a>
</div>
<p style="font-size:12px;color:#999;text-align:center;">Werbung | <a href="[unsub]" style="color:#999;">Abmelden</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
# V2: Personal
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Georgia,serif;background:#fafafa;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;border:1px solid #e0e0e0;">
<div style="padding:25px 30px;border-bottom:3px solid {accent};">
<h2 style="color:{bg};margin:0;">Ihr persönliches Angebot</h2>
</div>
<div style="text-align:center;padding:15px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<div style="padding:20px 30px;">
<p style="font-size:16px;line-height:1.7;color:#444;">Liebe Leserin, lieber Leser,</p>
<p style="font-size:16px;line-height:1.7;color:#444;">Wir möchten Ihnen den <strong>{product}</strong> vorstellen — ein Produkt, das bereits tausende zufriedene Kunden überzeugt hat.</p>
<p style="font-size:16px;line-height:1.7;color:#444;">Bestellen Sie jetzt und erhalten Sie <strong>kostenlosen Versand</strong> als Dankeschön.</p>
<div style="text-align:center;padding:20px;">
<a href="[url]" style="background:{bg};color:{fg};padding:14px 35px;text-decoration:none;border-radius:3px;font-size:16px;display:inline-block;">Angebot ansehen</a>
</div>
<p style="font-size:11px;color:#aaa;text-align:center;border-top:1px solid #eee;padding-top:15px;">Dies ist eine Werbemitteilung. <a href="[unsub]" style="color:#aaa;">Hier abmelden</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
# V3: News-style
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Verdana,sans-serif;background:#f0f0f0;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;">
<div style="background:#ffffff;padding:15px 20px;border-bottom:2px solid {accent};">
<span style="color:{bg};font-size:12px;font-weight:bold;text-transform:uppercase;">GESUNDHEIT & WOHLBEFINDEN</span>
</div>
<div style="padding:20px;">
<h2 style="color:#222;font-size:20px;margin:0 0 15px;">{product}: Warum alle darüber sprechen</h2>
<div style="text-align:center;padding:10px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<p style="font-size:15px;line-height:1.6;color:#555;">Experten empfehlen jetzt den {product} als natürliche Lösung. Mehr als <strong>50.000 Kunden</strong> in Deutschland vertrauen bereits darauf.</p>
<p style="font-size:15px;line-height:1.6;color:#555;">Für kurze Zeit gibt es das Produkt mit einem <strong>Sonderrabatt</strong>.</p>
<div style="text-align:center;padding:15px;">
<a href="[url]" style="background:{accent};color:#ffffff;padding:12px 30px;text-decoration:none;border-radius:4px;font-size:15px;display:inline-block;">Mehr erfahren →</a>
</div>
</div>
<div style="background:#f5f5f5;padding:10px;text-align:center;">
<p style="font-size:10px;color:#999;margin:0;">Gesponsert | <a href="[unsub]" style="color:#999;">Newsletter abbestellen</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
],
'en': [
# V1: Urgency
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Arial,sans-serif;background:#f4f4f4;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;">
<div style="background:{bg};padding:20px;text-align:center;">
<h1 style="color:{fg};margin:0;font-size:24px;">⚡ Limited Time: {product}</h1>
</div>
<div style="text-align:center;padding:15px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<div style="padding:20px 30px;">
<p style="font-size:16px;line-height:1.6;color:#333;">Hi there,</p>
<p style="font-size:16px;line-height:1.6;color:#333;">We have an <strong>exclusive invitation</strong> for you. Today only, get access to our {product} deal — <strong>completely free</strong>.</p>
<p style="font-size:16px;line-height:1.6;color:#333;">This offer expires in <strong>24 hours</strong>.</p>
<div style="text-align:center;padding:20px;">
<a href="[url]" style="background:{accent};color:{fg};padding:15px 40px;text-decoration:none;border-radius:5px;font-size:18px;font-weight:bold;display:inline-block;">CLAIM NOW →</a>
</div>
<p style="font-size:12px;color:#999;text-align:center;">Ad | <a href="[unsub]" style="color:#999;">Unsubscribe</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
# V2: Personal
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Georgia,serif;background:#fafafa;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;border:1px solid #e0e0e0;">
<div style="padding:25px 30px;border-bottom:3px solid {accent};">
<h2 style="color:{bg};margin:0;">Your Personal Offer</h2>
</div>
<div style="text-align:center;padding:15px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<div style="padding:20px 30px;">
<p style="font-size:16px;line-height:1.7;color:#444;">Dear Reader,</p>
<p style="font-size:16px;line-height:1.7;color:#444;">We'd like to introduce the <strong>{product}</strong> — a product that thousands of satisfied customers already trust.</p>
<p style="font-size:16px;line-height:1.7;color:#444;">Order now and get <strong>free shipping</strong> as our thank you.</p>
<div style="text-align:center;padding:20px;">
<a href="[url]" style="background:{bg};color:{fg};padding:14px 35px;text-decoration:none;border-radius:3px;font-size:16px;display:inline-block;">View Offer</a>
</div>
<p style="font-size:11px;color:#aaa;text-align:center;border-top:1px solid #eee;padding-top:15px;">This is a promotional message. <a href="[unsub]" style="color:#aaa;">Unsubscribe here</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
# V3: News-style
"""<html><head><meta charset="utf-8"><title>{product}</title></head>
<body style="margin:0;padding:0;font-family:Verdana,sans-serif;background:#f0f0f0;">
<div style="max-width:600px;margin:0 auto;background:#ffffff;">
<div style="background:#ffffff;padding:15px 20px;border-bottom:2px solid {accent};">
<span style="color:{bg};font-size:12px;font-weight:bold;text-transform:uppercase;">HEALTH & WELLNESS</span>
</div>
<div style="padding:20px;">
<h2 style="color:#222;font-size:20px;margin:0 0 15px;">{product}: Why Everyone Is Talking About It</h2>
<div style="text-align:center;padding:10px;"><img src="{img_url}" width="250" style="max-width:250px;" alt="" /></div>
<p style="font-size:15px;line-height:1.6;color:#555;">Experts are now recommending {product} as a natural solution. Over <strong>50,000 customers</strong> already trust it.</p>
<p style="font-size:15px;line-height:1.6;color:#555;">For a limited time, get a <strong>special discount</strong>.</p>
<div style="text-align:center;padding:15px;">
<a href="[url]" style="background:{accent};color:#ffffff;padding:12px 30px;text-decoration:none;border-radius:4px;font-size:15px;display:inline-block;">Learn More →</a>
</div>
</div>
<div style="background:#f5f5f5;padding:10px;text-align:center;">
<p style="font-size:10px;color:#999;margin:0;">Sponsored | <a href="[unsub]" style="color:#999;">Unsubscribe from newsletter</a></p>
</div></div>
<img src="[open]" width="1" height="1" style="display:none;" alt="" />
</body></html>""",
]
}
SUBJECTS_DE = [
"Ihr {product} wartet auf Sie", "Exklusiv: {product} kostenlos testen", "⚡ Letzte Chance: {product}",
"Gesundheitsexperten empfehlen: {product}", "Nur heute: {product} gratis", "{product} — Sonderangebot",
"Neu für Sie: {product}", "Verpassen Sie nicht: {product}", "🎁 {product} geschenkt",
"Kostenloses {product} Angebot"
]
SUBJECTS_EN = [
"Your {product} is waiting", "Exclusive: Try {product} free", "⚡ Last chance: {product}",
"Experts recommend: {product}", "Today only: Free {product}", "{product} — Special offer",
"New for you: {product}", "Don't miss: {product}", "🎁 Free {product}",
"Complimentary {product} offer"
]
FROM_NAMES = [
"Health News", "Wellness Daily", "Special Offers", "Your Rewards", "Member Services",
"Product Alert", "Daily Deals", "Exclusive Club", "Savings Digest", "Offer Central"
]
def hex_to_rgb(h):
h = h.lstrip('#')
return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
def make_image(brand):
w, h = 580, 200
img = Image.new('RGB', (w, h), hex_to_rgb(brand['bg']))
d = ImageDraw.Draw(img)
try:
fl = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 28)
fs = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 18)
except:
fl = fs = ImageFont.load_default()
d.rectangle([0,0,w,6], fill=hex_to_rgb(brand['accent']))
bb = d.textbbox((0,0), brand['product'], font=fl)
d.text(((w-(bb[2]-bb[0]))//2, 40), brand['product'], fill=hex_to_rgb(brand['fg']), font=fl)
d.rounded_rectangle([220,125,360,165], radius=20, fill=hex_to_rgb(brand['accent']))
bb2 = d.textbbox((0,0), brand['badge'], font=fs)
d.text(((w-(bb2[2]-bb2[0]))//2, 132), brand['badge'], fill=hex_to_rgb(brand['fg']), font=fs)
d.rectangle([0,h-4,w,h], fill=hex_to_rgb(brand['accent']))
buf = BytesIO()
img.save(buf, format='PNG', optimize=True)
return buf.getvalue()
def save_img(data):
h = hashlib.md5(data).hexdigest()[:15]
fp = os.path.join(MEDIA_DIR, f"{h}.png")
if not os.path.exists(fp):
with open(fp, 'wb') as f: f.write(data)
os.chmod(fp, 0o644)
return f"{MEDIA_URL}/{h}.png"
def get_brand(name):
for k, v in BRANDS.items():
if k.lower() in name.lower():
return v
return DEFAULT
def main():
conn = psycopg2.connect(**DB)
conn.autocommit = True
cur = conn.cursor()
# Get CX3 offers needing creatives
cur.execute("""
SELECT o.id, o.name, o.countries FROM affiliate.offers o
JOIN admin.brain_offer_config bc ON bc.offer_id=o.id
WHERE bc.is_active=true AND bc.is_approved=true AND bc.link_status='live'
AND bc.good_creatives=0 AND o.affiliate_network_name='CX3 Ads'
AND o.name NOT LIKE '%Test Offer%'
ORDER BY CAST(REPLACE(REPLACE(o.payout,'$',''),'%','') AS NUMERIC) DESC
""")
offers = cur.fetchall()
cur.execute("SELECT MAX(id) FROM affiliate.creatives")
next_cid = (cur.fetchone()[0] or 0) + 1
total_created = 0
for oid, oname, ocountries in offers:
brand = get_brand(oname)
lang = brand['lang']
# Generate image
png = make_image(brand)
img_url = save_img(png)
templates = TEMPLATES[lang]
subjects = SUBJECTS_DE if lang == 'de' else SUBJECTS_EN
for i, tmpl in enumerate(templates):
html = tmpl.format(
product=brand['product'], bg=brand['bg'], fg=brand['fg'],
accent=brand['accent'], img_url=img_url
)
b64 = base64.b64encode(html.encode('utf-8')).decode('utf-8')
vname = f"{brand['product']}_v{i+1}"
subj = random.choice(subjects).format(product=brand['product'])
fname = random.choice(FROM_NAMES)
cur.execute(
"INSERT INTO affiliate.creatives(id, offer_id, name, value, status, quality_score, "
"has_tracking_placeholders, affiliate_network_id, created_by, created_date) "
"VALUES (%s, %s, %s, %s, 'Activated', 8, true, 7, 'brain', CURRENT_DATE)",
(next_cid, oid, vname, b64)
)
next_cid += 1
total_created += 1
# Update good_creatives count
cur.execute("UPDATE admin.brain_offer_config SET good_creatives=3 WHERE offer_id=%s", (oid,))
print(f" ✅ Offer #{oid} {brand['product'][:25]} ({lang}) → 3 creatives + image")
print(f"\n{'='*60}")
print(f"TOTAL: {total_created} creatives for {len(offers)} CX3 offers")
cur.execute("SELECT COUNT(*) FROM affiliate.creatives WHERE status='Activated' AND quality_score>=3 AND has_tracking_placeholders=true")
total = cur.fetchone()[0]
print(f"Total good creatives in system: {total}")
cur.close()
conn.close()
if __name__ == '__main__':
main()