package service import ( "context" "fmt" "rockhu-bot/local/model" "rockhu-bot/local/repository" "rockhu-bot/local/utl/common" "strconv" "time" "github.com/gocolly/colly" "gorm.io/datatypes" ) type ConcertService struct { repository *repository.ConcertRepository } func NewConcertService(repository *repository.ConcertRepository) *ConcertService { return &ConcertService{ repository: repository, } } // GetFirst // Gets first row from Concert table. // // Args: // context.Context: Application context // Returns: // string: Application version func (as ConcertService) GetAll(ctx context.Context) *[]model.ConcertModel { return as.repository.GetAll(ctx) } func (as ConcertService) CheckAndUpdateConcerts(ctx context.Context) []model.ConcertModel { cm := as.GetAll(ctx) fmt.Printf("Currently there are %d concerts\n", len(*cm)) NewConcerts := scrapeData(ctx) fmt.Printf("There are %d new concerts\n", len(*NewConcerts)) forInsert, forDelete, _ := partitionConcerts(*cm, *NewConcerts) tx := as.repository.CreateTransaction() defer tx.Rollback() if len(forDelete) > 0 { tx.Delete(forDelete) } if len(forInsert) > 0 { tx.Create(forInsert) } tx.Commit() return forInsert } func scrapeData(ctx context.Context) *[]model.ConcertModel { c := colly.NewCollector() concerts := new([]model.ConcertModel) // Find and visit all links c.OnHTML(".event_box", func(e *colly.HTMLElement) { currentDate := time.Now() currentMonth := currentDate.Month() month, err := common.GetMonthFromLocalized(e.ChildText(".event_date>.month")) if err != nil { panic(err) } dayText := e.ChildText(".event_date>.day") day, err := strconv.Atoi(dayText) if err != nil { panic(err) } year := currentDate.Year() if month < int(currentMonth) { year = year + 1 } eventDate := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC) concert := new(model.ConcertModel) concert.Name = e.ChildText(".event_title") concert.StartDate = datatypes.Date(eventDate) *concerts = append(*concerts, *concert) }) c.OnRequest(func(r *colly.Request) { fmt.Println("Visiting", r.URL) }) c.Visit("https://jegy.rock1.hu/") return concerts } func concertKey(concert model.ConcertModel) string { cc := concert.Name + (time.Time)(concert.StartDate).Format("2006-01-02") fmt.Println(cc) return cc } func partitionConcerts(previous, current []model.ConcertModel) (newConcerts, deletedConcerts, unchangedConcerts []model.ConcertModel) { // Create a map of previous concerts for quick lookup fmt.Println("Previous concerts\n") previousMap := make(map[string]model.ConcertModel) for _, concert := range previous { previousMap[concertKey(concert)] = concert } fmt.Println("New concerts\n") // Create a map of current concerts for quick lookup currentMap := make(map[string]model.ConcertModel) for _, concert := range current { currentMap[concertKey(concert)] = concert } // Identify new and unchanged concerts for _, concert := range current { if _, exists := previousMap[concertKey(concert)]; exists { unchangedConcerts = append(unchangedConcerts, concert) } else { newConcerts = append(newConcerts, concert) fmt.Printf("New concert %s\n", concert.Name) } } // Identify deleted concerts for _, concert := range previous { if _, exists := currentMap[concertKey(concert)]; !exists { deletedConcerts = append(deletedConcerts, concert) fmt.Printf("Deleted concert %s\n", concert.Name) } } return newConcerts, deletedConcerts, unchangedConcerts }