@@ -172,12 +172,25 @@ async function fetchBasicMetadata(url: string): Promise<{
172172
173173 // Try to extract high-quality icons in order of preference
174174 // Data URLs (base64 encoded) are now supported
175+ // Note: ICO files are deprioritized because they often contain only BMP data
176+ // which is harder to process than PNG/SVG formats
175177 const candidateIcons : string [ ] = [ ] ;
176178
179+ // Helper to check if URL points to an ICO file
180+ const isIcoFile = ( url : string ) : boolean => {
181+ try {
182+ const pathname = new URL ( url , "http://example.com" ) . pathname . toLowerCase ( ) ;
183+ return pathname . endsWith ( ".ico" ) ;
184+ } catch {
185+ return url . toLowerCase ( ) . endsWith ( ".ico" ) ;
186+ }
187+ } ;
188+
177189 // 1. Apple touch icon (usually highest quality, 180x180 or similar)
190+ // Skip if it's an ICO file - these often don't contain extractable PNG data
178191 const appleIcon =
179192 extractLinkHref ( "apple-touch-icon" ) || extractLinkHref ( "apple-touch-icon-precomposed" ) ;
180- if ( appleIcon ) candidateIcons . push ( appleIcon ) ;
193+ if ( appleIcon && ! isIcoFile ( appleIcon ) ) candidateIcons . push ( appleIcon ) ;
181194
182195 // 2. High-res icon with sizes attribute
183196 const highResIcon = headContent . match (
@@ -201,12 +214,16 @@ async function fetchBasicMetadata(url: string): Promise<{
201214 }
202215 }
203216
204- // 4. Any icon or shortcut icon
217+ // 4. Any icon or shortcut icon (prefer non-ICO)
205218 const standardIcon =
206219 extractLinkHref ( "icon" ) || extractLinkHref ( "shortcut icon" ) || extractLinkHref ( "shortcut" ) ;
207- if ( standardIcon ) candidateIcons . push ( standardIcon ) ;
220+ if ( standardIcon && ! isIcoFile ( standardIcon ) ) candidateIcons . push ( standardIcon ) ;
221+
222+ // 5. ICO files as lower priority fallback (may not have extractable PNG data)
223+ if ( appleIcon && isIcoFile ( appleIcon ) ) candidateIcons . push ( appleIcon ) ;
224+ if ( standardIcon && isIcoFile ( standardIcon ) ) candidateIcons . push ( standardIcon ) ;
208225
209- // 5 . OG image as last resort (sometimes sites use their logo as og:image)
226+ // 6 . OG image as last resort (sometimes sites use their logo as og:image)
210227 if ( ogImage && ogImage . includes ( "logo" ) ) {
211228 candidateIcons . push ( ogImage ) ;
212229 }
0 commit comments