85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
package scheduler
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"veola/internal/apify"
|
|
)
|
|
|
|
// ShouldAlert returns true if the result should trigger an alert.
|
|
//
|
|
// - Result must not already be in DB (caller checks that first).
|
|
// - If targetPrice is nil, alert on every new result.
|
|
// - If targetPrice is non-nil, alert only when price <= targetPrice.
|
|
//
|
|
// price=0 is treated as "unknown" and never alerts under a target.
|
|
func ShouldAlert(targetPrice *float64, price float64) bool {
|
|
if targetPrice == nil {
|
|
return true
|
|
}
|
|
if price <= 0 {
|
|
return false
|
|
}
|
|
return price <= *targetPrice
|
|
}
|
|
|
|
// FilterResults applies match-confidence and out-of-stock filtering. Returns
|
|
// a fresh slice; the input is not mutated.
|
|
func FilterResults(in []apify.UnifiedResult, minConfidence float64, includeOOS bool) []apify.UnifiedResult {
|
|
out := make([]apify.UnifiedResult, 0, len(in))
|
|
for _, r := range in {
|
|
if !includeOOS && r.OutOfStock {
|
|
continue
|
|
}
|
|
if r.MatchConfidence != 0 && r.MatchConfidence < minConfidence {
|
|
continue
|
|
}
|
|
if r.URL == "" || r.Price <= 0 {
|
|
continue
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ApplyItemFilters drops results below minPrice (when set) and any whose title
|
|
// contains one of excludeKeywords (case-insensitive substring match). Pass nil
|
|
// or empty for either to skip that filter. Returns a fresh slice.
|
|
func ApplyItemFilters(in []apify.UnifiedResult, minPrice *float64, excludeKeywords []string) []apify.UnifiedResult {
|
|
lowered := make([]string, 0, len(excludeKeywords))
|
|
for _, k := range excludeKeywords {
|
|
k = strings.ToLower(strings.TrimSpace(k))
|
|
if k != "" {
|
|
lowered = append(lowered, k)
|
|
}
|
|
}
|
|
out := make([]apify.UnifiedResult, 0, len(in))
|
|
outer:
|
|
for _, r := range in {
|
|
if minPrice != nil && r.Price < *minPrice {
|
|
continue
|
|
}
|
|
if len(lowered) > 0 {
|
|
title := strings.ToLower(r.Title)
|
|
for _, k := range lowered {
|
|
if strings.Contains(title, k) {
|
|
continue outer
|
|
}
|
|
}
|
|
}
|
|
out = append(out, r)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// PickBest returns the index of the lowest-priced result, or -1 if none.
|
|
func PickBest(rs []apify.UnifiedResult) int {
|
|
best := -1
|
|
for i, r := range rs {
|
|
if best == -1 || r.Price < rs[best].Price {
|
|
best = i
|
|
}
|
|
}
|
|
return best
|
|
}
|