@@ -15,6 +15,53 @@ export type OmniboxResult = {
1515 relevanceScore ?: number ;
1616} ;
1717
18+ export interface SearchEngine {
19+ name : string ;
20+ suggestUrlBuilder : ( query : string ) => string ;
21+ searchUrlBuilder : ( query : string ) => string ;
22+ suggestionParser : ( data : any ) => string [ ] ;
23+ }
24+
25+ /** Available search engines */
26+ export const AVAILABLE_SEARCH_ENGINES : Record < string , SearchEngine > = {
27+ google : {
28+ name : "Google" ,
29+ searchUrlBuilder : ( query ) =>
30+ `https://www.google.com/search?q=${ encodeURIComponent ( query ) } ` ,
31+ suggestUrlBuilder : ( query ) =>
32+ `https://suggestqueries.google.com/complete/search?client=chrome&q=${ encodeURIComponent ( query ) } ` ,
33+ suggestionParser : ( data ) => {
34+ if ( Array . isArray ( data ) && data . length > 1 && Array . isArray ( data [ 1 ] ) ) {
35+ return data [ 1 ] . map ( ( item : any ) => String ( item ) ) . filter ( Boolean ) ;
36+ }
37+ return [ ] ;
38+ } ,
39+ } ,
40+ brave : {
41+ name : "Brave" ,
42+ searchUrlBuilder : ( query ) =>
43+ `https://search.brave.com/search?q=${ encodeURIComponent ( query ) } ` ,
44+ suggestUrlBuilder : ( query ) =>
45+ `https://search.brave.com/api/suggest?q=${ encodeURIComponent ( query ) } &source=web` ,
46+ suggestionParser : ( data ) => {
47+ // Google format
48+ if ( Array . isArray ( data ) && data . length > 1 && Array . isArray ( data [ 1 ] ) ) {
49+ // biome-ignore lint/suspicious/noExplicitAny: <explanation>
50+ return data [ 1 ] . map ( ( item : any ) => String ( item ) ) . filter ( Boolean ) ;
51+ }
52+ // Brave Format
53+ if (
54+ Array . isArray ( data ) &&
55+ data . length > 0 &&
56+ typeof data [ 0 ] === "string"
57+ ) {
58+ return data . map ( ( item : string ) => String ( item ) ) . filter ( Boolean ) ;
59+ }
60+ return [ ] ;
61+ } ,
62+ } ,
63+ } ;
64+
1865function calculateRelevanceScore ( result : OmniboxResult , query : string ) : number {
1966 if ( ! query ) return 0 ;
2067
@@ -130,7 +177,9 @@ const addDirectResult = (
130177 {
131178 kind : "directsearch" ,
132179 url : new URL (
133- `https://www.google.com/search?q=${ encodeURIComponent ( query ) } `
180+ AVAILABLE_SEARCH_ENGINES [
181+ browser . settings . defaultSearchEngine
182+ ] . searchUrlBuilder ( query )
134183 ) ,
135184 title : query ,
136185 favicon : null ,
@@ -147,13 +196,20 @@ const fetchGoogleSuggestions = async (
147196
148197 try {
149198 const resp = await bare . fetch (
150- `http://suggestqueries.google.com/complete/search?client=chrome&q=${ encodeURIComponent ( query ) } `
199+ AVAILABLE_SEARCH_ENGINES [
200+ browser . settings . defaultSearchEngine
201+ ] . suggestUrlBuilder ( query )
151202 ) ;
152203
153204 const json = await resp . json ( ) ;
205+ let rawSuggestions =
206+ AVAILABLE_SEARCH_ENGINES [
207+ browser . settings . defaultSearchEngine
208+ ] . suggestionParser ( json ) ;
209+ rawSuggestions = rawSuggestions . slice ( 0 , 5 ) ;
154210 const suggestions : OmniboxResult [ ] = [ ] ;
155211
156- for ( const item of json [ 1 ] . slice ( 0 , 5 ) ) {
212+ for ( const item of rawSuggestions ) {
157213 // it's gonna be stuff like "http //fortnite.com/2fa ps5"
158214 // generally not useful
159215 if ( item . startsWith ( "http" ) ) continue ;
@@ -162,7 +218,9 @@ const fetchGoogleSuggestions = async (
162218 kind : "search" ,
163219 title : item ,
164220 url : new URL (
165- `https://www.google.com/search?q=${ encodeURIComponent ( item ) } `
221+ AVAILABLE_SEARCH_ENGINES [
222+ browser . settings . defaultSearchEngine
223+ ] . searchUrlBuilder ( query )
166224 ) ,
167225 favicon : null ,
168226 } ) ;
@@ -217,6 +275,7 @@ export type TrendingQuery = {
217275
218276export let trendingCached : TrendingQuery [ ] | null = null ;
219277export async function fetchGoogleTrending ( geo = "US" ) : Promise < void > {
278+ // TODO: make this search engine agnostic
220279 try {
221280 if ( trendingCached ) return ;
222281
0 commit comments