← back to Grassclothwallpaper

crop-xgr-6201-bottom.js

189 lines

const fetch = require('node-fetch');
const getColors = require('get-image-colors');
const axios = require('axios');
const sharp = require('sharp');

const SUPABASE_URL = 'https://fypvpcxyfmmdhtklgbrt.supabase.co';
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZ5cHZwY3h5Zm1tZGh0a2xnYnJ0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTg4MTAxMjMsImV4cCI6MjA3NDM4NjEyM30.fzDf6VE7jyrqLIbebAwI1NHXi50pI0b_FgQVO-6QcAk';

// Convert color to hex
function toHex(color) {
    const rgb = color.rgb();
    const r = Math.round(rgb[0]).toString(16).padStart(2, '0');
    const g = Math.round(rgb[1]).toString(16).padStart(2, '0');
    const b = Math.round(rgb[2]).toString(16).padStart(2, '0');
    return `#${r}${g}${b}`.toUpperCase();
}

// Extract colors EXCLUDING bottom 20% (opposite of usual top crop)
async function extractColorsExcludingBottom(imageUrl) {
    try {
        console.log(`  Downloading image: ${imageUrl}`);
        const response = await axios.get(imageUrl, {
            responseType: 'arraybuffer',
            timeout: 20000,
            maxContentLength: 15 * 1024 * 1024
        });

        const buffer = Buffer.from(response.data);
        const metadata = await sharp(buffer).metadata();

        // EXCLUDE bottom 20% from color extraction
        const cropBottom = Math.floor(metadata.height * 0.20);
        const usableHeight = metadata.height - cropBottom;

        console.log(`    Original: ${metadata.width}x${metadata.height}`);
        console.log(`    Excluding bottom ${cropBottom}px (20%)`);
        console.log(`    Using top ${usableHeight}px for colors`);

        const croppedBuffer = await sharp(buffer)
            .extract({
                left: 0,
                top: 0,  // Start from top
                width: metadata.width,
                height: usableHeight  // Use only top 80%
            })
            .jpeg()
            .toBuffer();

        const colors = await getColors(croppedBuffer, {
            count: 40,
            type: 'image/jpeg'
        });

        const hexColors = colors
            .map(c => toHex(c))
            .filter(hex => {
                const r = parseInt(hex.substr(1, 2), 16);
                const g = parseInt(hex.substr(3, 2), 16);
                const b = parseInt(hex.substr(5, 2), 16);
                const brightness = (r + g + b) / 3;
                // Filter out very bright (white text) and very dark colors
                return brightness > 15 && brightness < 240;
            });

        if (hexColors.length < 2) {
            const allHex = colors.map(c => toHex(c));
            return { primary: allHex[0] || '#808080', secondary: allHex[1] || '#A0A0A0' };
        }

        // Find most distinct colors
        let color1 = hexColors[0];
        let color2 = hexColors[1];
        let maxDist = 0;

        for (let i = 0; i < Math.min(hexColors.length, 20); i++) {
            for (let j = i + 1; j < Math.min(hexColors.length, 20); j++) {
                const r1 = parseInt(hexColors[i].substr(1, 2), 16);
                const g1 = parseInt(hexColors[i].substr(3, 2), 16);
                const b1 = parseInt(hexColors[i].substr(5, 2), 16);
                const r2 = parseInt(hexColors[j].substr(1, 2), 16);
                const g2 = parseInt(hexColors[j].substr(3, 2), 16);
                const b2 = parseInt(hexColors[j].substr(5, 2), 16);

                const dist = Math.sqrt(
                    Math.pow(r2 - r1, 2) +
                    Math.pow(g2 - g1, 2) +
                    Math.pow(b2 - b1, 2)
                );

                if (dist > maxDist) {
                    maxDist = dist;
                    color1 = hexColors[i];
                    color2 = hexColors[j];
                }
            }
        }

        return { primary: color1, secondary: color2 };

    } catch (error) {
        console.log(`    Error: ${error.message}`);
        return null;
    }
}

async function cropXGR6201Bottom() {
    console.log('🔽 CROPPING BOTTOM 20% OF XGR-6201\n');
    console.log('This product needs bottom cropping instead of top cropping');
    console.log('=' .repeat(60) + '\n');

    try {
        // Get XGR-6201 product
        const response = await fetch(
            `${SUPABASE_URL}/rest/v1/grasscloth_products?sku=eq.XGR-6201&select=*`,
            {
                headers: {
                    'apikey': SUPABASE_KEY,
                    'Authorization': `Bearer ${SUPABASE_KEY}`
                }
            }
        );

        const products = await response.json();

        if (!products || products.length === 0) {
            console.log('❌ XGR-6201 not found in database');
            return;
        }

        const product = products[0];
        console.log(`\nProcessing XGR-6201:${product.name}`);
        console.log(`  Current colors: ${product.hex_color} | ${product.hex2_color}`);

        if (!product.image_url) {
            console.log('  NO IMAGE URL');
            return;
        }

        const newColors = await extractColorsExcludingBottom(product.image_url);

        if (newColors) {
            console.log(`  New colors (excluding bottom 20%): ${newColors.primary} | ${newColors.secondary}`);

            // Check brightness
            const r = parseInt(newColors.primary.substr(1, 2), 16);
            const g = parseInt(newColors.primary.substr(3, 2), 16);
            const b = parseInt(newColors.primary.substr(5, 2), 16);
            const brightness = Math.round((r + g + b) / 3);
            console.log(`  Primary brightness: ${brightness}`);

            // Update database
            const updateResponse = await fetch(
                `${SUPABASE_URL}/rest/v1/grasscloth_products?id=eq.${product.id}`,
                {
                    method: 'PATCH',
                    headers: {
                        'apikey': SUPABASE_KEY,
                        'Authorization': `Bearer ${SUPABASE_KEY}`,
                        'Content-Type': 'application/json',
                        'Prefer': 'return=minimal'
                    },
                    body: JSON.stringify({
                        hex_color: newColors.primary,
                        hex2_color: newColors.secondary
                    })
                }
            );

            if (updateResponse.ok) {
                console.log('  ✓ UPDATED - colors now exclude bottom 20%!');
            } else {
                console.log('  ✗ Update failed');
                console.log('  Response:', await updateResponse.text());
            }
        } else {
            console.log('  ✗ Could not extract colors');
        }

        console.log('\n' + '=' .repeat(60));
        console.log('XGR-6201 BOTTOM CROP COMPLETE');
        console.log('Colors extracted from top 80% of image (excluding bottom text/elements)');

    } catch (error) {
        console.error('Fatal error:', error.message);
    }
}

// Run it
cropXGR6201Bottom();