package api import ( "encoding/json" "fmt" "io" "log/slog" "net/http" "strings" "time" ) type EpicStruct struct { url string baseUrl string idPrefix string headers map[string]string deals DealsMap logger *slog.Logger } func NewEpicApi(logger *slog.Logger) EpicStruct { epic := EpicStruct{ url: "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions", baseUrl: "https://store.epicgames.com/p/", idPrefix: "epic-", headers: make(map[string]string), deals: make(map[string]Deal), logger: logger, } epic.headers["Accept-Language"] = "en" epic.headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0" return epic } type epicApiBody struct { Data struct { Catalog struct { SearchStore struct { Elements []struct { Title string `json:"title"` Id string `json:"id"` Description string `json:"description"` OfferType string `json:"offerType"` IsCodeRedemptionOnly bool `json:"isCodeRedemptionOnly"` KeyImages []struct { Type string `json:"type"` Url string `json:"url"` } `json:"keyImages"` ProductSlug string `json:"productSlug"` OfferMappings []struct { PageSlug string `json:"pageSlug"` PageType string `json:"pageType"` } `json:"offerMappings"` Price struct { TotalPrice struct { DiscountPrice int `json:"discountPrice"` OriginalPrice int `json:"originalPrice"` Discount int `json:"discount"` CurrencyCode string `json:"currencyCode"` } `json:"totalPrice"` } `json:"price"` Promotions *struct { PromotionalOffers []struct { PromotionalOffers []struct { StartDate time.Time `json:"startDate"` EndDate time.Time `json:"endDate"` DiscountSetting struct { DiscountType string `json:"discountType"` DiscountPercentage int `json:"discountPercentage"` } `json:"discountSetting"` } `json:"promotionalOffers"` } `json:"promotionalOffers"` } `json:"promotions"` } `json:"elements"` Paging struct { Count int `json:"count"` Total int `json:"total"` } `json:"paging"` } `json:"searchStore"` } `json:"Catalog"` } `json:"data"` } func (e EpicStruct) Load() error { client := &http.Client{} req, err := http.NewRequest("GET", e.url, nil) if err != nil { return err } for key, value := range e.headers { req.Header.Set(key, value) } res, err := client.Do(req) if err != nil { return err } body, err := io.ReadAll(res.Body) if err != nil { return err } var data epicApiBody err = json.Unmarshal(body, &data) if err != nil { return err } for _, element := range data.Data.Catalog.SearchStore.Elements { if element.Promotions == nil || len(element.Promotions.PromotionalOffers) == 0 || len(element.Promotions.PromotionalOffers[0].PromotionalOffers) == 0 || element.Promotions.PromotionalOffers[0].PromotionalOffers[0].DiscountSetting.DiscountPercentage != 0 { // no deal continue } productSlug := element.ProductSlug if len(element.OfferMappings) != 0 && productSlug == "" { productSlug = element.OfferMappings[0].PageSlug } if productSlug == "" { e.logger.Error("product slug not found", slog.String("title", element.Title)) continue } image := "" for _, keyImage := range element.KeyImages { if keyImage.Type == "OfferImageWide" { image = keyImage.Url } } id := fmt.Sprintf("%v%v", e.idPrefix, element.Id) title := strings.TrimSpace(element.Title) url := fmt.Sprintf("%v%v", e.baseUrl, productSlug) e.deals[id] = Deal{ Id: id, Title: title, Url: url, Image: image, } } return nil } func (e EpicStruct) Get() []Deal { var deals []Deal for _, deal := range e.deals { deals = append(deals, deal) } return deals }