mirror of
https://github.com/karust/openserp.git
synced 2026-08-12 11:53:29 +08:00
Add google uule query param support for regional search
This commit is contained in:
@@ -133,6 +133,68 @@ func TestBuildSearchURL(t *testing.T) {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "curated city region resolves to canonical google uule without country market",
|
||||
query: core.Query{
|
||||
Text: "weather",
|
||||
Region: "New York",
|
||||
Filter: true,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.google.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
// "New York" resolves to the exact Google canonical name
|
||||
// "New York,New York,United States", which is what Google
|
||||
// actually honors (a bare city name is ignored).
|
||||
if got := params.Get("uule"); got != "w+CAIQICIfTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw==" {
|
||||
t.Fatalf("unexpected uule value: %q", got)
|
||||
}
|
||||
if got := params.Get("gl"); got != "" {
|
||||
t.Fatalf("city region should not set gl, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bare city Berlin resolves to canonical google uule",
|
||||
query: core.Query{
|
||||
Text: "weather",
|
||||
Region: "Berlin",
|
||||
Filter: true,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
// region=Berlin -> "Berlin,Berlin,Germany" canonical, which is
|
||||
// the form Google honors. A bare "Berlin" UULE is ignored.
|
||||
if got := params.Get("uule"); got != "w+CAIQICIVQmVybGluLEJlcmxpbixHZXJtYW55" {
|
||||
t.Fatalf("unexpected uule value: %q", got)
|
||||
}
|
||||
if got := params.Get("gl"); got != "" {
|
||||
t.Fatalf("city region should not set gl, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "numeric yandex region does not set google market",
|
||||
query: core.Query{
|
||||
Text: "weather",
|
||||
Region: "213",
|
||||
Filter: true,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.google.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("gl"); got != "" {
|
||||
t.Fatalf("numeric region should not set gl, got %q", got)
|
||||
}
|
||||
if got := params.Get("uule"); got != "" {
|
||||
t.Fatalf("numeric region should not set uule, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "site and filetype without text",
|
||||
query: core.Query{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
@@ -225,6 +226,10 @@ var googleDefaultCountryByLanguage = map[string]string{
|
||||
"ko": "kr",
|
||||
}
|
||||
|
||||
const googleUULEPrefix = "w+CAIQICI"
|
||||
|
||||
var googleUULELengthAlphabet = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
|
||||
|
||||
// BuildURL builds a Google web search URL from Query fields.
|
||||
// It returns an error when the resulting query text is empty or invalid.
|
||||
func BuildURL(q core.Query) (string, error) {
|
||||
@@ -289,6 +294,9 @@ func BuildURL(q core.Query) (string, error) {
|
||||
if locale.country != "" {
|
||||
params.Add("gl", locale.country)
|
||||
}
|
||||
if uule := googleUULE(q.Region); uule != "" {
|
||||
params.Add("uule", uule)
|
||||
}
|
||||
if locale.language != "" {
|
||||
params.Add("hl", locale.language)
|
||||
params.Add("lr", "lang_"+locale.language)
|
||||
@@ -355,6 +363,9 @@ func BuildImageURL(q core.Query) (string, error) {
|
||||
if locale.country != "" {
|
||||
params.Add("gl", locale.country)
|
||||
}
|
||||
if uule := googleUULE(q.Region); uule != "" {
|
||||
params.Add("uule", uule)
|
||||
}
|
||||
if locale.language != "" {
|
||||
params.Add("hl", locale.language)
|
||||
params.Add("lr", "lang_"+locale.language)
|
||||
@@ -420,6 +431,43 @@ func googleDomain(locale googleLocaleParams) string {
|
||||
return GoogleDomains[""]
|
||||
}
|
||||
|
||||
// googleUULE builds a Google UULE v1 value for a region hint.
|
||||
//
|
||||
// UULE only takes effect when the encoded string is an exact Google geotargets
|
||||
// canonical name; a bare free-text city is silently ignored by Google. We
|
||||
// therefore resolve the region first (core.ResolveRegion) and encode the
|
||||
// resolved canonical name when one is found. Country-level hints intentionally
|
||||
// produce no UULE — those are conveyed via gl= instead.
|
||||
func googleUULE(region string) string {
|
||||
target := core.ResolveRegion(region)
|
||||
canonical := target.GoogleCanonical
|
||||
if canonical == "" {
|
||||
// No resolved canonical name. A bare country code (e.g. "DE") or a
|
||||
// numeric Yandex lr ID must not become a UULE; both are handled
|
||||
// elsewhere (gl=) or are not applicable to Google.
|
||||
if target.Country != "" || target.YandexLR != "" {
|
||||
return ""
|
||||
}
|
||||
// Best-effort: encode the raw free-text region. This may be ignored by
|
||||
// Google if it isn't a canonical name, matching prior behavior.
|
||||
canonical = strings.TrimSpace(region)
|
||||
}
|
||||
if canonical == "" {
|
||||
return ""
|
||||
}
|
||||
return encodeGoogleUULE(canonical)
|
||||
}
|
||||
|
||||
// encodeGoogleUULE encodes a canonical location name into a UULE v1 value:
|
||||
// a fixed prefix, a single length-tag character, then base64(name).
|
||||
func encodeGoogleUULE(canonical string) string {
|
||||
length := len([]rune(canonical))
|
||||
if length <= 0 || length >= len(googleUULELengthAlphabet) {
|
||||
return ""
|
||||
}
|
||||
return googleUULEPrefix + string(googleUULELengthAlphabet[length]) + base64.StdEncoding.EncodeToString([]byte(canonical))
|
||||
}
|
||||
|
||||
// SourceImage contains parsed Google image metadata extracted from result links.
|
||||
type SourceImage struct {
|
||||
PageURL string
|
||||
|
||||
Reference in New Issue
Block a user