← back to Corkwallcovering

scripts/crop_cork_headers.py

80 lines

#!/usr/bin/env python3
"""
Batch: for every CORK product in data/products.json, download its image, detect
the PHILLIPE ROMANO logo-header banner, and (if found) crop it off. Cropped
files are saved into public/cropped/<sku>.jpg. Originals are downloaded to a
cache dir. Remote-image, so re-hosting/replacing the live Shopify URL is a
SEPARATE GATED prod step — this only produces local cropped files + a manifest.

Usage:
  python3 scripts/crop_cork_headers.py [--vendor "Phillipe Romano"] [--limit N]
"""
import os, sys, json, urllib.request, ssl
from crop_logo_header import detect_band, crop

ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA = os.path.join(ROOT, 'data', 'products.json')
CACHE = os.path.join(ROOT, '.image-cache')          # gitignored originals
OUTDIR = os.path.join(ROOT, 'public', 'cropped')    # cropped results (served)
MANIFEST = os.path.join(ROOT, 'data', 'cropped-manifest.json')

vendor_filter = None
limit = None
args = sys.argv[1:]
for i,a in enumerate(args):
    if a == '--vendor': vendor_filter = args[i+1]
    if a == '--limit': limit = int(args[i+1])

def is_cork(p):
    s = (str(p.get('handle',''))+' '+str(p.get('sku',''))+' '+str(p.get('title',''))).lower()
    return 'cork' in s

def main():
    os.makedirs(CACHE, exist_ok=True)
    os.makedirs(OUTDIR, exist_ok=True)
    d = json.load(open(DATA))
    cork = [p for p in d if is_cork(p)]
    if vendor_filter:
        cork = [p for p in cork if p.get('vendor') == vendor_filter]
    if limit: cork = cork[:limit]

    ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
    manifest = []
    cropped = downloaded = errors = nobanner = 0
    for i, p in enumerate(cork):
        sku = p.get('sku') or p.get('handle')
        url = p.get('image_url')
        if not url: continue
        cachefile = os.path.join(CACHE, sku + '.jpg')
        try:
            if not os.path.exists(cachefile):
                req = urllib.request.Request(url, headers={'User-Agent':'Mozilla/5.0'})
                with urllib.request.urlopen(req, context=ctx, timeout=30) as r, open(cachefile,'wb') as f:
                    f.write(r.read())
                downloaded += 1
        except Exception as e:
            errors += 1
            print(f'[{i}] ERR download {sku}: {e}')
            continue
        try:
            b, info = detect_band(cachefile)
        except Exception as e:
            errors += 1; print(f'[{i}] ERR detect {sku}: {e}'); continue
        if b:
            out = os.path.join(OUTDIR, sku + '.jpg')
            crop(cachefile, out, b)
            cropped += 1
            manifest.append(dict(sku=sku, handle=p.get('handle'), vendor=p.get('vendor'),
                                 band_row=b, frac=info.get('frac'),
                                 image_url=url, cropped_file=f'cropped/{sku}.jpg'))
            print(f'[{i}] CROP {sku} band@{b} ({info.get("frac")})')
        else:
            nobanner += 1
    json.dump(manifest, open(MANIFEST,'w'), indent=2)
    print(f'\n=== DONE === scanned={len(cork)} downloaded={downloaded} '
          f'CROPPED={cropped} no-banner={nobanner} errors={errors}')
    print('manifest ->', MANIFEST, '| cropped files ->', OUTDIR)

if __name__ == '__main__':
    main()