package ebay import ( "strings" "time" ) // SearchParams is the input to a single Browse API item_summary/search call. // It is provider-specific and is carried as the opaque input payload of a // scheduler plan, mirroring how Apify actor inputs are carried. type SearchParams struct { // MarketplaceID is an eBay marketplace identifier such as EBAY_US. MarketplaceID string // Query is the keyword search string. Required; the Browse API rejects // an empty q. Query string // ListingType is Veola's vocabulary ("all", "bin"/"buy_it_now", // "auction"); it is mapped to a buyingOptions filter. ListingType string // Condition is Veola's condition vocabulary ("new", "used", // "refurbished", "parts"); it is mapped to a conditionIds filter. Empty // means no condition filter. Condition string // Region is an ISO 3166-1 alpha-2 country code constraining item // location (mapped to the itemLocationCountry filter). Empty means no // location filter. Region string // Limit caps the number of results requested (Browse API max is 200). Limit int } // Listing is one normalized active eBay listing. The scheduler converts these // into the shared apify.UnifiedResult shape so the rest of the pipeline // (dedup, filter, alert) is provider-agnostic. type Listing struct { Title string Price float64 Currency string URL string Store string ImageURL string // EndsAt is the auction end time as reported by the Browse API // (itemEndDate). Nil for fixed-price ("Buy It Now") listings, which // don't have one. EndsAt *time.Time } // MarketplaceID maps a Veola marketplace string (e.g. "ebay.com", // "ebay.co.uk") to an eBay Browse API marketplace identifier. Unknown or // bare "ebay" values fall back to EBAY_US. func MarketplaceID(marketplace string) string { m := strings.ToLower(strings.TrimSpace(marketplace)) switch { case strings.Contains(m, "ebay.co.uk"): return "EBAY_GB" case strings.Contains(m, "ebay.de"): return "EBAY_DE" case strings.Contains(m, "ebay.com.au"): return "EBAY_AU" case strings.Contains(m, "ebay.ca"): return "EBAY_CA" case strings.Contains(m, "ebay.fr"): return "EBAY_FR" case strings.Contains(m, "ebay.it"): return "EBAY_IT" case strings.Contains(m, "ebay.es"): return "EBAY_ES" case strings.Contains(m, "ebay.at"): return "EBAY_AT" case strings.Contains(m, "ebay.ch"): return "EBAY_CH" case strings.Contains(m, "ebay.ie"): return "EBAY_IE" case strings.Contains(m, "ebay.nl"): return "EBAY_NL" case strings.Contains(m, "ebay.com.hk"): return "EBAY_HK" case strings.Contains(m, "ebay.com.sg"): return "EBAY_SG" case strings.Contains(m, "ebay.com.my"): return "EBAY_MY" case strings.Contains(m, "ebay.ph"): return "EBAY_PH" case strings.Contains(m, "ebay.pl"): return "EBAY_PL" default: // "ebay.com" and any bare/unknown eBay marketplace. return "EBAY_US" } } // IsEbayMarketplace reports whether a Veola marketplace string should be // polled through the official eBay Browse API. func IsEbayMarketplace(marketplace string) bool { return strings.Contains(strings.ToLower(marketplace), "ebay") } // buyingOptionsFilter maps Veola's listing-type vocabulary to the Browse API // "filter" query parameter. An empty string means no filter ("all"). func buyingOptionsFilter(listingType string) string { switch strings.ToLower(strings.TrimSpace(listingType)) { case "bin", "buy_it_now", "fixed_price": return "buyingOptions:{FIXED_PRICE}" case "auction": return "buyingOptions:{AUCTION}" default: return "" } } // conditionIDsFilter maps Veola's condition vocabulary to a Browse API // "conditionIds" filter clause. Each Veola value expands to the set of eBay // condition IDs that belong to it (e.g. "new" covers both brand-new and // new-other). An empty or unknown value yields no filter. func conditionIDsFilter(condition string) string { var ids string switch strings.ToLower(strings.TrimSpace(condition)) { case "new": ids = "1000|1500" case "used": ids = "3000" case "refurbished": ids = "2000|2010|2020|2030|2500" case "parts": ids = "7000" default: return "" } return "conditionIds:{" + ids + "}" } // itemLocationFilter maps an ISO 3166-1 alpha-2 country code to a Browse API // "itemLocationCountry" filter clause. An empty value yields no filter. func itemLocationFilter(region string) string { r := strings.ToUpper(strings.TrimSpace(region)) if r == "" { return "" } return "itemLocationCountry:" + r }