mirror of
https://github.com/Xevion/banner.git
synced 2025-12-06 03:14:24 -06:00
Improve CalculateExpiry with Slope-based duration calculation
- Remove ICS NewCalendar() func - TODO IsViewOnlyTerm
This commit is contained in:
31
helpers.go
31
helpers.go
@@ -13,7 +13,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ics "github.com/arran4/golang-ical"
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
log "github.com/rs/zerolog/log"
|
log "github.com/rs/zerolog/log"
|
||||||
@@ -321,16 +320,6 @@ func GetFooter(time time.Time) *discordgo.MessageEmbedFooter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCalendar() *ics.Calendar {
|
|
||||||
c := &ics.Calendar{
|
|
||||||
Components: []ics.Component{},
|
|
||||||
CalendarProperties: []ics.CalendarProperty{},
|
|
||||||
}
|
|
||||||
c.SetVersion("2.0")
|
|
||||||
c.SetProductId("-//xevion//Banner Discord Bot//EN")
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUser returns the user from the interaction.
|
// GetUser returns the user from the interaction.
|
||||||
// This helper method is useful as depending on where the message was sent (guild or DM), the user is in a different field.
|
// This helper method is useful as depending on where the message was sent (guild or DM), the user is in a different field.
|
||||||
func GetUser(interaction *discordgo.InteractionCreate) *discordgo.User {
|
func GetUser(interaction *discordgo.InteractionCreate) *discordgo.User {
|
||||||
@@ -345,7 +334,7 @@ func GetUser(interaction *discordgo.InteractionCreate) *discordgo.User {
|
|||||||
|
|
||||||
// Encode encodes the values into “URL encoded” form
|
// Encode encodes the values into “URL encoded” form
|
||||||
// ("bar=baz&foo=quux") sorted by key.
|
// ("bar=baz&foo=quux") sorted by key.
|
||||||
func EncodeParams(params map[string][]string) string {
|
func EncodeParams(params map[string]*[]string) string {
|
||||||
// Escape hatch for nil
|
// Escape hatch for nil
|
||||||
if params == nil {
|
if params == nil {
|
||||||
return ""
|
return ""
|
||||||
@@ -364,7 +353,7 @@ func EncodeParams(params map[string][]string) string {
|
|||||||
values := params[k]
|
values := params[k]
|
||||||
keyEscaped := url.QueryEscape(k)
|
keyEscaped := url.QueryEscape(k)
|
||||||
|
|
||||||
for _, v := range values {
|
for _, v := range *values {
|
||||||
// If any parameters have been written, add the ampersand
|
// If any parameters have been written, add the ampersand
|
||||||
if buf.Len() > 0 {
|
if buf.Len() > 0 {
|
||||||
buf.WriteByte('&')
|
buf.WriteByte('&')
|
||||||
@@ -379,3 +368,19 @@ func EncodeParams(params map[string][]string) string {
|
|||||||
|
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add a function to check if a term is view-only
|
||||||
|
func IsViewOnlyTerm(term string) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point represents a point in 2D space
|
||||||
|
type Point struct {
|
||||||
|
X, Y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func Slope(p1 Point, p2 Point, x float64) Point {
|
||||||
|
slope := (p2.Y - p1.Y) / (p2.X - p1.X)
|
||||||
|
newY := slope*(x-p1.X) + p1.Y
|
||||||
|
return Point{X: x, Y: newY}
|
||||||
|
}
|
||||||
|
|||||||
49
scrape.go
49
scrape.go
@@ -144,16 +144,17 @@ func ScrapeMajor(subject string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term := Default(time.Now()).ToString()
|
||||||
|
|
||||||
// Calculate the expiry time for the scrape (1 hour for every 200 classes, random +-15%) with a minimum of 1 hour
|
// Calculate the expiry time for the scrape (1 hour for every 200 classes, random +-15%) with a minimum of 1 hour
|
||||||
var scrapeExpiry time.Duration
|
var scrapeExpiry time.Duration
|
||||||
if totalClassCount == 0 {
|
if totalClassCount == 0 {
|
||||||
scrapeExpiry = time.Hour * 12
|
scrapeExpiry = time.Hour * 12
|
||||||
} else {
|
} else {
|
||||||
scrapeExpiry = CalculateExpiry(totalClassCount, lo.Contains(PriorityMajors, subject))
|
scrapeExpiry = CalculateExpiry(term, totalClassCount, lo.Contains(PriorityMajors, subject))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the major as scraped
|
// Mark the major as scraped
|
||||||
term := Default(time.Now()).ToString()
|
|
||||||
if totalClassCount == 0 {
|
if totalClassCount == 0 {
|
||||||
totalClassCount = -1
|
totalClassCount = -1
|
||||||
}
|
}
|
||||||
@@ -166,27 +167,45 @@ func ScrapeMajor(subject string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CalculateExpiry calculates the expiry time until the next scrape for a major.
|
// CalculateExpiry calculates the expiry time until the next scrape for a major.
|
||||||
func CalculateExpiry(count int, priority bool) time.Duration {
|
// term is the term for which the relevant course is occurring within.
|
||||||
scrapeExpiry := time.Hour * time.Duration(count/100)
|
// count is the number of courses that were scraped.
|
||||||
partial := scrapeExpiry.Seconds() * (rand.Float64() * 0.15) // Between 0 and 15% of the total
|
// priority is a boolean indicating whether the major is a priority major.
|
||||||
|
func CalculateExpiry(term string, count int, priority bool) time.Duration {
|
||||||
|
// Subjects with less than 50 classes have a reversed expiry (less classes, longer interval)
|
||||||
|
// 1 class => 12 hours, 49 classes => 1 hour
|
||||||
|
if count < 50 {
|
||||||
|
hours := Slope(Point{1, 12}, Point{49, 1}, float64(count)).Y
|
||||||
|
return time.Duration(hours * float64(time.Hour))
|
||||||
|
}
|
||||||
|
|
||||||
// Randomly add or subtract the partial (delta between -15% and 15%)
|
// An hour for every 100 classes
|
||||||
|
baseExpiry := time.Hour * time.Duration(count/100)
|
||||||
|
|
||||||
|
// If the subject is a priority, then the expiry is halved without variance
|
||||||
|
if priority {
|
||||||
|
return baseExpiry / 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the term is considered "view only", then the expiry is multipled by 5
|
||||||
|
var expiry = baseExpiry
|
||||||
|
if IsViewOnlyTerm(term) {
|
||||||
|
expiry *= 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add minor variance to the expiry
|
||||||
|
expiryVariance := baseExpiry.Seconds() * (rand.Float64() * 0.15) // Between 0 and 15% of the total
|
||||||
if rand.Intn(2) == 0 {
|
if rand.Intn(2) == 0 {
|
||||||
scrapeExpiry -= time.Duration(partial) * time.Second
|
expiry -= time.Duration(expiryVariance) * time.Second
|
||||||
} else {
|
} else {
|
||||||
scrapeExpiry += time.Duration(partial) * time.Second
|
expiry += time.Duration(expiryVariance) * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the expiry is at least 1 hour with up to 15 extra minutes
|
// Ensure the expiry is at least 1 hour with up to 15 extra minutes
|
||||||
if scrapeExpiry < time.Hour {
|
if expiry < time.Hour {
|
||||||
scrapeExpiry = time.Hour + time.Duration(rand.Intn(60*15))*time.Second
|
baseExpiry = time.Hour + time.Duration(rand.Intn(60*15))*time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the subject is a priority, then the expiry is halved
|
return baseExpiry
|
||||||
if priority {
|
|
||||||
return scrapeExpiry / 3
|
|
||||||
}
|
|
||||||
return scrapeExpiry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntakeCourse stores a course in Redis.
|
// IntakeCourse stores a course in Redis.
|
||||||
|
|||||||
Reference in New Issue
Block a user