Skip to content

Commit 1d8e04c

Browse files
committed
Better URL matching and favcoing fetching
1 parent e035c52 commit 1d8e04c

File tree

3 files changed

+128
-44
lines changed

3 files changed

+128
-44
lines changed

Public/background.js

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -574,17 +574,55 @@ async function handleScriptCreation(url, template) {
574574
// Efficient URL pattern matching
575575
function urlMatchesPattern(url, pattern) {
576576
try {
577+
const urlObj = new URL(url);
578+
579+
// Direct match
577580
if (pattern === url) return true;
581+
582+
// Extract pattern scheme, host, and path
583+
let [patternSchemeHost, ...patternPathParts] = pattern.split("://");
584+
let patternPath =
585+
patternPathParts.length > 0 ? patternPathParts.join("://") : "/*";
586+
587+
let [patternScheme, patternHost] = patternSchemeHost.includes("://")
588+
? patternSchemeHost.split("://")
589+
: ["*", patternSchemeHost];
590+
591+
// Handle wildcard subdomains (*.example.com)
578592
if (
579-
pattern.startsWith("*.") &&
580-
new URL(url).hostname.endsWith(pattern.slice(2))
581-
)
593+
patternHost.startsWith("*.") &&
594+
urlObj.hostname.endsWith(patternHost.slice(2))
595+
) {
582596
return true;
597+
}
583598

584-
return new RegExp(
585-
`^${pattern.replace(/\*/g, ".*").replace(/\./g, "\\.")}$`,
599+
// Convert scheme to regex
600+
let schemeRegex = patternScheme === "*" ? "(https?|ftp)" : patternScheme;
601+
602+
// Convert host to regex
603+
let hostRegex = patternHost
604+
.replace(/^\*\./, "(?:[^/]+\\.)?") // Handle *.example.com
605+
.replace(/\*\./g, "(?:[^/.]+\\.)") // Handle multiple wildcard subdomains
606+
.replace(/\*/g, "[^/]*") // Handle * in domain
607+
.split(".")
608+
.map((part) => part.replace(/\./g, "\\.")) // Escape dots
609+
.join("\\.");
610+
611+
// Convert path to regex
612+
let pathRegex = patternPath
613+
.split("/")
614+
.map((part) =>
615+
part === "*" ? ".*" : part.replace(/\*/g, ".*").replace(/\./g, "\\.")
616+
)
617+
.join("/");
618+
619+
// Construct full regex
620+
const finalRegex = new RegExp(
621+
`^${schemeRegex}://${hostRegex}/${pathRegex}$`,
586622
"i"
587-
).test(url);
623+
);
624+
625+
return finalRegex.test(url);
588626
} catch (error) {
589627
console.warn("URL matching error:", error);
590628
return false;

Public/dashboard.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -324,19 +324,20 @@ function createFaviconCell(script) {
324324
if (script.targetUrls && script.targetUrls.length > 0) {
325325
script.targetUrls.forEach((url) => {
326326
try {
327-
const hostname = new URL(url).hostname;
327+
let hostname;
328+
if (url.includes("://")) {
329+
hostname = new URL(url).hostname;
330+
} else {
331+
// Handle pattern-style URLs
332+
hostname = url.split("/")[0];
333+
}
334+
328335
if (!uniqueHosts.has(hostname)) {
329336
uniqueHosts.add(hostname);
330337

331-
const faviconWrapper = createFaviconWrapper(hostname);
332-
faviconContainer.appendChild(faviconWrapper);
333-
334-
// Only show first 3 favicons plus counter if more exist
335-
if (faviconContainer.children.length === 3 && uniqueHosts.size > 3) {
336-
const extraHosts = Array.from(uniqueHosts).slice(3);
337-
const counterElement = createFaviconCounter(extraHosts);
338-
faviconContainer.appendChild(counterElement);
339-
return;
338+
if (faviconContainer.children.length < 3) {
339+
const faviconWrapper = createFaviconWrapper(hostname);
340+
faviconContainer.appendChild(faviconWrapper);
340341
}
341342
}
342343
} catch (error) {
@@ -345,6 +346,13 @@ function createFaviconCell(script) {
345346
});
346347
}
347348

349+
// Show counter if there are more hosts
350+
if (uniqueHosts.size > 3) {
351+
const extraHosts = Array.from(uniqueHosts).slice(3);
352+
const counterElement = createFaviconCounter(extraHosts);
353+
faviconContainer.appendChild(counterElement);
354+
}
355+
348356
// Show fallback if no valid favicons
349357
if (faviconContainer.children.length === 0) {
350358
const fallback = document.createElement("div");
@@ -363,17 +371,24 @@ function createFaviconWrapper(hostname) {
363371
faviconWrapper.title = hostname;
364372

365373
const faviconImg = document.createElement("img");
366-
faviconImg.src = `https://${hostname}/favicon.ico`;
374+
const faviconUrl = `https://s2.googleusercontent.com/s2/favicons?domain=${hostname}`;
375+
376+
console.log(`Fetching favicon for ${hostname}:`, faviconUrl);
377+
378+
faviconImg.src = faviconUrl;
367379
faviconImg.alt = "";
368380
faviconImg.className = "favicon";
369381
faviconImg.onerror = function () {
370-
this.parentElement.innerHTML = `<div class='favicon-fallback'>${hostname[0].toUpperCase()}</div>`;
382+
console.warn(`Failed to load favicon for ${hostname}`);
383+
const fallbackText = hostname.replace(/\*\./g, "").charAt(0).toUpperCase();
384+
this.parentElement.innerHTML = `<div class='favicon-fallback'>${fallbackText}</div>`;
371385
};
372386

373387
faviconWrapper.appendChild(faviconImg);
374388
return faviconWrapper;
375389
}
376390

391+
377392
function createFaviconCounter(extraHosts) {
378393
const counter = document.createElement("div");
379394
counter.className = "favicon-counter";

Public/popup.js

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -270,44 +270,75 @@ document.addEventListener("DOMContentLoaded", async () => {
270270
function urlMatchesPattern(url, script) {
271271
if (!url || !script) return false;
272272

273-
// Support both legacy single URL and new multiple URLs format
274-
const targetUrls = script.targetUrls || [script.targetUrl];
273+
// Ensure targetUrls is an array of valid strings
274+
const targetUrls = (script.targetUrls || [script.targetUrl])
275+
.filter(Boolean)
276+
.map(String); // Convert to strings
277+
275278
return targetUrls.some((pattern) => {
276279
try {
277-
const urlObj = new URL(url);
278-
279-
if (pattern === url) {
280-
return true;
281-
}
280+
if (!pattern) return false;
282281

283-
if (pattern.startsWith("*.")) {
284-
const domain = pattern.substring(2);
285-
return (
286-
urlObj.hostname === domain || urlObj.hostname.endsWith("." + domain)
287-
);
288-
}
282+
const urlObj = new URL(url);
289283

290-
if (!pattern.includes("*") && !pattern.includes("/")) {
291-
return urlObj.hostname === pattern;
292-
}
284+
// Direct match
285+
if (pattern === url) return true;
293286

287+
// Ensure scheme exists in pattern
294288
if (!pattern.includes("://")) {
295289
pattern = "*://" + pattern + "/*";
296290
}
297291

298-
if (pattern.includes("*")) {
299-
const regexPattern = pattern
300-
.replace(/\./g, "\\.")
301-
.replace(/\*/g, ".*")
302-
.replace(/\//g, "\\/");
303-
const regex = new RegExp("^" + regexPattern + "$");
304-
return regex.test(url);
292+
// Extract scheme, host, and path from pattern
293+
let [patternSchemeHost, ...patternPathParts] = pattern.split("://");
294+
let patternPath =
295+
patternPathParts.length > 0 ? patternPathParts.join("://") : "/*";
296+
297+
let [patternScheme, patternHost] = patternSchemeHost.includes("://")
298+
? patternSchemeHost.split("://")
299+
: ["*", patternSchemeHost];
300+
301+
// Handle wildcard subdomains (*.example.com)
302+
if (
303+
patternHost.startsWith("*.") &&
304+
urlObj.hostname.endsWith(patternHost.slice(2))
305+
) {
306+
return true;
305307
}
306308

307-
return url.includes(pattern);
309+
// Convert scheme to regex
310+
let schemeRegex =
311+
patternScheme === "*" ? "(https?|ftp)" : patternScheme;
312+
313+
// Convert host to regex
314+
let hostRegex = patternHost
315+
.replace(/^\*\./, "(?:[^/]+\\.)?") // Handle *.example.com
316+
.replace(/\*\./g, "(?:[^/.]+\\.)") // Handle multiple wildcard subdomains
317+
.replace(/\*/g, "[^/]*") // Handle * in domain
318+
.split(".")
319+
.map((part) => part.replace(/\./g, "\\.")) // Escape dots
320+
.join("\\.");
321+
322+
// Convert path to regex
323+
let pathRegex = patternPath
324+
.split("/")
325+
.map((part) =>
326+
part === "*"
327+
? ".*"
328+
: part.replace(/\*/g, ".*").replace(/\./g, "\\.")
329+
)
330+
.join("/");
331+
332+
// Construct full regex
333+
const finalRegex = new RegExp(
334+
`^${schemeRegex}://${hostRegex}/${pathRegex}$`,
335+
"i"
336+
);
337+
338+
return finalRegex.test(url);
308339
} catch (error) {
309-
console.error("Error parsing URL:", error);
310-
return url.includes(pattern);
340+
console.warn("URL matching error for pattern:", pattern, error);
341+
return false;
311342
}
312343
});
313344
}

0 commit comments

Comments
 (0)