dembrandt 0.12.2 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/extractors/logo.js +34 -3
- package/package.json +1 -1
package/lib/extractors/logo.js
CHANGED
|
@@ -146,6 +146,12 @@ export async function extractLogo(page, url) {
|
|
|
146
146
|
if (imgSrc.toLowerCase().includes(siteDomain) || altText.includes(siteDomain) || className.includes(siteDomain)) score += 40;
|
|
147
147
|
if (className.includes('logo') || el.id?.toLowerCase().includes('logo')) score += 30;
|
|
148
148
|
|
|
149
|
+
// SVG with aria-label="Homepage" directly in a home anchor — strong signal
|
|
150
|
+
if (el.tagName === 'svg' || el.tagName === 'SVG') {
|
|
151
|
+
const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
|
|
152
|
+
if (ariaLabel.includes('home') || ariaLabel.includes('logo')) score += 40;
|
|
153
|
+
}
|
|
154
|
+
|
|
149
155
|
if (parentLink) {
|
|
150
156
|
const href = linkHref.toLowerCase();
|
|
151
157
|
if (href === '/' || href === baseUrl || href.endsWith('://' + new URL(baseUrl).hostname + '/') || href.endsWith('://' + new URL(baseUrl).hostname)) {
|
|
@@ -156,8 +162,19 @@ export async function extractLogo(page, url) {
|
|
|
156
162
|
if (rect.top < 200) score += 10;
|
|
157
163
|
if (rect.left < 400) score += 10;
|
|
158
164
|
|
|
159
|
-
|
|
160
|
-
|
|
165
|
+
// Penalize images hosted on a different domain (CDN paths on same domain are fine)
|
|
166
|
+
if (el.tagName === 'IMG') {
|
|
167
|
+
try {
|
|
168
|
+
const srcHost = new URL(el.src).hostname.replace('www.', '')
|
|
169
|
+
const pageHost = new URL(baseUrl).hostname.replace('www.', '')
|
|
170
|
+
// If neither is a subdomain/CDN of the other, it's third-party
|
|
171
|
+
if (!srcHost.endsWith(pageHost) && !pageHost.endsWith(srcHost)) score -= 60
|
|
172
|
+
} catch {}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// For SVGs use rendered rect — baseVal reflects viewBox coordinates, not display size
|
|
176
|
+
const width = el.tagName === 'IMG' ? (el.naturalWidth || rect.width) : rect.width;
|
|
177
|
+
const height = el.tagName === 'IMG' ? (el.naturalHeight || rect.height) : rect.height;
|
|
161
178
|
if (width < 20 || height < 20) score -= 30;
|
|
162
179
|
if (width > 600 || height > 400) score -= 40;
|
|
163
180
|
if (altText.length > 50) score -= 30;
|
|
@@ -247,7 +264,18 @@ export async function extractLogo(page, url) {
|
|
|
247
264
|
if (rect.width === 0 || rect.height === 0) return;
|
|
248
265
|
|
|
249
266
|
const className = (typeof el.className === 'string' ? el.className : el.className.baseVal || '').toLowerCase();
|
|
250
|
-
const
|
|
267
|
+
const altText = (el.getAttribute('alt') || '').toLowerCase();
|
|
268
|
+
const attrs = (className + ' ' + (el.id || '') + ' ' + altText).toLowerCase();
|
|
269
|
+
|
|
270
|
+
// Disqualify third-party brand logos: alt like "Notion logo" / "Perplexity logo" / "Figma" where the brand isn't our site
|
|
271
|
+
// These appear in customer/integration/testimonial sections on marketing pages.
|
|
272
|
+
const altBrandMatch = altText.match(/^([a-z][a-z0-9\-\.]{1,30}?)(?:\s+(?:logo|icon|brand|wordmark))?$/i);
|
|
273
|
+
if (altBrandMatch) {
|
|
274
|
+
const altBrand = altBrandMatch[1].replace(/[\s\-\.]/g, '').toLowerCase();
|
|
275
|
+
if (altBrand && altBrand !== 'logo' && altBrand !== 'brand' && altBrand !== 'icon' && altBrand !== siteDomain && !altBrand.includes(siteDomain) && !siteDomain.includes(altBrand)) {
|
|
276
|
+
return; // third-party brand, skip entirely
|
|
277
|
+
}
|
|
278
|
+
}
|
|
251
279
|
|
|
252
280
|
let qualifies = attrs.includes('logo') || attrs.includes('brand');
|
|
253
281
|
|
|
@@ -257,6 +285,9 @@ export async function extractLogo(page, url) {
|
|
|
257
285
|
const href = use.getAttribute('href') || use.getAttribute('xlink:href') || '';
|
|
258
286
|
if (href.toLowerCase().includes('logo') || href.toLowerCase().includes('brand')) { qualifies = true; break; }
|
|
259
287
|
}
|
|
288
|
+
// aria-label="Homepage" or similar on the SVG itself
|
|
289
|
+
const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
|
|
290
|
+
if (ariaLabel.includes('home') || ariaLabel.includes('logo')) qualifies = true;
|
|
260
291
|
}
|
|
261
292
|
|
|
262
293
|
if (!qualifies) {
|