#!/usr/bin/env python3 """ Fetch brand SVG logos from worldvectorlogo.com Saves to /var/www/sneakerpicks/public/brands/{slug}.svg Updates brands.logo_url in DB """ import requests import psycopg2 import psycopg2.extras import os import re import time import sys from urllib.parse import quote DB_URL = "postgresql://supabase_admin:HzWrn2rMMxUYWO6OT5X0PScIVEvSjQMup9YSLIrkPQ@172.18.0.5:5432/sneakerpicks" LOGO_DIR = "/var/www/sneakerpicks/public/brands" BASE_URL = "https://worldvectorlogo.com" # Alternative sources to try ALT_SOURCES = [ "https://cdn.worldvectorlogo.com/logos/{slug}.svg", "https://cdn.worldvectorlogo.com/logos/{slug}-1.svg", "https://cdn.worldvectorlogo.com/logos/{slug}-2.svg", ] HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", } # Brand name → worldvectorlogo slug overrides SLUG_OVERRIDES = { 'nike': 'nike-4', 'adidas': 'adidas-9', 'adidas originals': 'adidas-trefoil', 'new balance': 'new-balance-2', 'puma': 'puma-6', 'asics': 'asics', 'jordan': 'air-jordan', 'reebok': 'reebok-2019', 'converse': 'converse-2', 'vans': 'vans-1', 'saucony': 'saucony', 'hoka': 'hoka-one-one', 'on running': 'on-running', 'salomon': 'salomon-3', 'fila': 'fila-1', 'under armour': 'under-armour-1', 'dr. martens': 'dr-martens', 'tommy hilfiger': 'tommy-hilfiger-2', 'calvin klein': 'calvin-klein-2', 'hugo boss': 'hugo-boss', 'lacoste': 'lacoste-1', 'birkenstock': 'birkenstock', 'the north face': 'the-north-face', 'timberland': 'timberland-2', 'skechers': 'skechers-1', 'ugg': 'ugg-1', 'crocs': 'crocs-1', 'k-swiss': 'k-swiss-1', 'le coq sportif': 'le-coq-sportif', 'diadora': 'diadora-1', 'mizuno': 'mizuno-2', 'brooks': 'brooks-running', 'filling pieces': 'filling-pieces', 'golden goose': 'golden-goose', 'alexander mcqueen': 'alexander-mcqueen', 'versace': 'versace-3', 'gucci': 'gucci-4', 'balenciaga': 'balenciaga', 'off-white': 'off-white-3', 'stone island': 'stone-island', 'y-3': 'y-3', 'boss': 'boss-hugo-boss', 'ellesse': 'ellesse', 'umbro': 'umbro-1', 'clarks': 'clarks', 'ecco': 'ecco-2', 'geox': 'geox', 'camper': 'camper-1', 'superga': 'superga', 'fred perry': 'fred-perry-1', 'levi\'s': 'levis-5', 'g-star': 'g-star-raw', 'diesel': 'diesel-3', 'polo ralph lauren': 'polo-ralph-lauren', 'ralph lauren': 'ralph-lauren-2', 'michael kors': 'michael-kors', 'coach': 'coach-2', 'guess': 'guess-1', } # Minimum product count to bother fetching a logo MIN_PRODUCTS = 3 def try_download_svg(url): """Try to download an SVG from a URL. Returns content or None.""" try: r = requests.get(url, headers=HEADERS, timeout=15, allow_redirects=True) if r.status_code == 200 and ('svg' in r.headers.get('content-type', '') or r.text.strip().startswith('= %s ORDER BY COUNT(p.id) DESC """, (MIN_PRODUCTS,)) brands = cur.fetchall() print(f"Found {len(brands)} brands to process\n") fetched = 0 skipped = 0 failed = 0 for brand in brands: brand_id = brand['id'] name = brand['name'] slug = brand['slug'] existing_logo = brand['logo_url'] count = brand['product_count'] svg_path = os.path.join(LOGO_DIR, f"{slug}.svg") # Skip if already has logo and file exists (unless --force) if not force and existing_logo and os.path.exists(svg_path): skipped += 1 continue print(f" [{count:5d} products] {name} ({slug})...", end=" ", flush=True) svg_content, source_url = fetch_logo(name, slug) if svg_content: with open(svg_path, 'w', encoding='utf-8') as f: f.write(svg_content) logo_url = f"/brands/{slug}.svg" cur.execute("UPDATE brands SET logo_url = %s WHERE id = %s", (logo_url, brand_id)) print(f"✓ saved ({len(svg_content)} bytes)") fetched += 1 else: print("✗ not found") failed += 1 # Rate limit time.sleep(0.5) print(f"\n{'='*40}") print(f"Fetched: {fetched}") print(f"Skipped (already have): {skipped}") print(f"Not found: {failed}") print(f"Total brands processed: {len(brands)}") # Show brands with logos cur.execute("SELECT COUNT(*) FROM brands WHERE logo_url IS NOT NULL") print(f"Brands with logos in DB: {cur.fetchone()[0]}") cur.close() conn.close() if __name__ == "__main__": main()