elements — does not call any LLM. */ final class HomepageMetaExtractor { private const array TITLE_SEPARATORS = [' | ', ' - ', ' — ', ' – ']; public function __construct( private readonly CssColorFrequencyExtractor $cssColorFrequency = new CssColorFrequencyExtractor, ) {} public function extract(string $html, string $baseUrl, string $extraCss = ''): BrandMetadata { $crawler = new Crawler($html, $baseUrl); $colors = $this->extractColors($crawler, $html, $extraCss); return new BrandMetadata( name: $this->extractName($crawler, $baseUrl), description: $this->extractDescription($crawler), language: $this->extractLanguage($crawler), logoUrl: $this->extractLogoUrl($crawler, $baseUrl), brandColor: data_get($colors, 'brand_color'), backgroundColor: data_get($colors, 'background_color'), textColor: data_get($colors, 'text_color'), ); } /** * Absolute URLs of external stylesheets referenced from the homepage. * Used to fetch CSS that the deterministic color extractor needs but isn't * inlined in