2026-06-26 08:37:04 +00:00
|
|
|
package placement
|
|
|
|
|
|
|
|
|
|
import "time"
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
MaxPostAgeDays = 30
|
|
|
|
|
IdealMaxPostAgeDays = 7
|
|
|
|
|
WebSearchMaxAgeDays = 14
|
2026-07-06 06:13:14 +00:00
|
|
|
|
|
|
|
|
// MinRecencyCandidatesPerTag triggers wider recency windows when a keyword finds fewer posts.
|
|
|
|
|
MinRecencyCandidatesPerTag = 1
|
|
|
|
|
// MaxRecencyCascadeQueries caps extra Search API calls per patrol run.
|
|
|
|
|
MaxRecencyCascadeQueries = 10
|
2026-06-26 08:37:04 +00:00
|
|
|
)
|
|
|
|
|
|
2026-07-06 06:13:14 +00:00
|
|
|
// RecencyCascadeDays is the patrol recency ladder: nearest window first, then shift older.
|
|
|
|
|
func RecencyCascadeDays() []int {
|
|
|
|
|
return []int{IdealMaxPostAgeDays, WebSearchMaxAgeDays, MaxPostAgeDays}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-26 08:37:04 +00:00
|
|
|
func FormatAfterDate(maxAgeDays int, now time.Time) string {
|
|
|
|
|
if now.IsZero() {
|
|
|
|
|
now = time.Now()
|
|
|
|
|
}
|
|
|
|
|
date := now.AddDate(0, 0, -maxAgeDays).UTC()
|
|
|
|
|
return date.Format("2006-01-02")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FormatPublishedAfterISO(maxAgeDays int, now time.Time) string {
|
|
|
|
|
if now.IsZero() {
|
|
|
|
|
now = time.Now()
|
|
|
|
|
}
|
|
|
|
|
date := now.AddDate(0, 0, -maxAgeDays).UTC()
|
|
|
|
|
return date.Format("2006-01-02T15:04:05.000Z")
|
|
|
|
|
}
|