From 5f3d0b36a8cbd857f84e6658dbca57fe2e3dba69 Mon Sep 17 00:00:00 2001 From: Jorge Villarreal Date: Tue, 4 Jan 2022 14:17:46 -0600 Subject: [PATCH 1/3] Added Tibia Char Bazaar Auction endpoint. (#23) --- src/TibiaCharbazaarAuctionV3.go | 685 ++++++++++++++++++++++++++++++++ src/webserver.go | 3 + 2 files changed, 688 insertions(+) create mode 100644 src/TibiaCharbazaarAuctionV3.go diff --git a/src/TibiaCharbazaarAuctionV3.go b/src/TibiaCharbazaarAuctionV3.go new file mode 100644 index 00000000..19c62114 --- /dev/null +++ b/src/TibiaCharbazaarAuctionV3.go @@ -0,0 +1,685 @@ +package main + +import ( + "encoding/json" + "github.com/go-resty/resty/v2" + "log" + "strconv" + "strings" + "time" + + "github.com/PuerkitoBio/goquery" + "github.com/gin-gonic/gin" +) + +// AjaxResponseObject - child of AjaxJSONData +type AjaxResponseObject struct { + Data string `json:"Data"` + DataType string `json:"DataType"` + Target string `json:"Target"` +} + +// AjaxJSONData - base response for auction items page links +type AjaxJSONData struct { + AjaxObjects []AjaxResponseObject `json:"AjaxObjects"` +} + +// TibiaCharbazaarAuctionV3 func +func TibiaCharbazaarAuctionV3(c *gin.Context) { + + id := TibiadataStringToIntegerV3(c.Param("id")) + + // Child of Details + type Bid struct { + Type string `json:"type"` + Amount int `json:"amount"` + } + + // Child of Auction + type Details struct { + CharacterName string `json:"characterName"` + Level int `json:"level"` + Vocation string `json:"vocation"` + Gender string `json:"gender"` + World string `json:"world"` + AuctionStart string `json:"auctionStart"` + AuctionEnd string `json:"auctionEnd"` + Bid Bid `json:"bid"` + } + + // Child of Auction + type General struct { + HitPoints int `json:"hitPoints"` + Mana int `json:"mana"` + Capacity int `json:"capacity"` + Speed int `json:"speed"` + Blessings int `json:"blessings"` + Mounts int `json:"mounts"` + Outfits int `json:"outfits"` + Titles int `json:"titles"` + AxeFighting int `json:"axeFighting"` + ClubFighting int `json:"clubFighting"` + DistanceFighting int `json:"distanceFighting"` + Fishing int `json:"fishing"` + FistFighting int `json:"fistFighting"` + MagicLevel int `json:"magicLevel"` + Shielding int `json:"shielding"` + SwordFighting int `json:"swordFighting"` + CreationDate string `json:"creationDate"` + Experience int `json:"experience"` + Gold int `json:"gold"` + AchievementPoints int `json:"achievementPoints"` + RegularWorldTransfer string `json:"regularWorldTransfer"` + CharmExpansion bool `json:"charmExpansion"` + AvailableCharmPoints int `json:"availableCharmPoints"` + SpentCharmPoints int `json:"spentCharmPoints"` + DailyRewardStreak int `json:"dailyRewardStreak"` + HuntingTaskPoints int `json:"huntingTaskPoints"` + PermanentHuntingTaskSlots int `json:"permanentHuntingTaskSlots"` + PermanentPreySlots int `json:"permanentPreySlots"` + PreyWildCards int `json:"preyWildCards"` + Hirelings int `json:"hirelings"` + HirelingJobs int `json:"hirelingJobs"` + HirelingOutfits int `json:"hirelingOutfits"` + ExaltedDust int `json:"exaltedDust"` + } + + // Child of Auction + type Item struct { + Name string `json:"name"` + Amount int `json:"amount"` + } + + // Child of Auction + type Outfit struct { + Name string `json:"name"` + Addon1 bool `json:"addon1"` + Addon2 bool `json:"addon2"` + } + + // Child of Auction + type Blessings struct { + AdventurersBlessing int `json:"adventurersBlessing"` + BloodOfTheMountain int `json:"bloodOfTheMountain"` + EmbraceOfTibia int `json:"embraceOfTibia"` + FireOfTheSuns int `json:"fireOfTheSuns"` + HeartOfTheMountain int `json:"heartOfTheMountain"` + SparkOfThePhoenix int `json:"sparkOfThePhoenix"` + SpiritualShielding int `json:"spiritualShielding"` + TwistOfFate int `json:"twistOfFate"` + WisdomOfSolitude int `json:"wisdomOfSolitude"` + } + + // Child of Auction + type Charm struct { + Name string `json:"name"` + Cost int `json:"cost"` + } + + // Child of Auction + type BestiaryEntry struct { + Name string `json:"name"` + Kills int `json:"kills"` + Step int `json:"step"` + } + + // Child of JSONData + type Auction struct { + Id int `json:"id"` + Details Details `json:"details"` + General General `json:"general"` + ItemSummary []Item `json:"itemSummary"` + StoreItemSummary []Item `json:"storeItemSummary"` + Mounts []string `json:"mounts"` + StoreMounts []string `json:"storeMounts"` + Outfits []Outfit `json:"outfits"` + StoreOutfits []Outfit `json:"storeOutfits"` + Familiars []string `json:"familiars"` + Blessings Blessings `json:"blessings"` + Imbuements []string `json:"imbuements"` + Charms []Charm `json:"charms"` + CompletedCyclopediaMapAreas []string `json:"completedCyclopediaMapAreas"` + CompletedQuestLines []string `json:"completedQuestLines"` + Titles []string `json:"titles"` + Achievements []string `json:"achievements"` + BestiaryProgress []BestiaryEntry `json:"bestiaryProgress"` + } + + // The base includes two levels: Auction and Information + type JSONData struct { + Auction Auction `json:"auction"` + Information Information `json:"information"` + } + + // Getting data with TibiadataHTMLDataCollectorV3 + BoxContentHTML := TibiadataHTMLDataCollectorV3("https://www.tibia.com/charactertrade/?page=details&auctionid=" + + strconv.Itoa(id)) + + // Loading HTML data into ReaderHTML for goquery with NewReader + ReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(BoxContentHTML)) + if err != nil { + log.Fatal(err) + } + + // Extract details section + var _Details Details + ReaderHTML.Find(".Auction").Each(func(index int, s *goquery.Selection) { + detailsHeader := strings.Split(s.Find(".AuctionHeader").Text(), "Level: ") + _Details.CharacterName = detailsHeader[0] + + detailsHeader = strings.Split(detailsHeader[1], "|") + + level := TibiadataStringToIntegerV3(detailsHeader[0]) + + _Details.Level = level + _Details.Vocation = strings.TrimSpace(strings.Split(detailsHeader[1], "Vocation: ")[1]) + _Details.Gender = strings.TrimSpace(detailsHeader[2]) + _Details.World = strings.TrimSpace(strings.Split(detailsHeader[3], "World: ")[1]) + + s.Find(".ShortAuctionData").Each(func(index int, s *goquery.Selection) { + nodes := s.Children().Nodes + + lookupIndex := 0 + hasTimer := strings.EqualFold(nodes[0].Attr[0].Val, "AuctionTimer") + + // In case the auction hasn't ended yet, we need to increase the lookup index. + if hasTimer { + lookupIndex = 1 + } + + auctionStartDate := TibiaDataSanitizeNbspSpaceString(nodes[1+lookupIndex].FirstChild.Data) + auctionStartDate = strings.Split(auctionStartDate, " CET")[0] + ":00 CET" + + auctionEndDate := TibiaDataSanitizeNbspSpaceString(nodes[3+lookupIndex].FirstChild.Data) + auctionEndDate = strings.Split(auctionEndDate, " CET")[0] + ":00 CET" + + _Details.AuctionStart = TibiadataDatetimeV3(auctionStartDate) + _Details.AuctionEnd = TibiadataDatetimeV3(auctionEndDate) + + bidType := strings.Split(nodes[4+lookupIndex].FirstChild.FirstChild.Data, " Bid:")[0] + bidAmount := TibiadataStringToIntegerV3(nodes[4+lookupIndex].LastChild.FirstChild.FirstChild.Data) + + _Details.Bid = Bid{ + Type: bidType, + Amount: bidAmount, + } + }) + }) + + // Extract general section + var _General General + ReaderHTML.Find("#General").Each(func(index int, s *goquery.Selection) { + + // General + generalMap := make(map[string]string) + s.Find(".LabelV").Each(func(index int, s *goquery.Selection) { + generalMap[strings.Split(s.Nodes[0].FirstChild.Data, ":")[0]] = s.Nodes[0].NextSibling.FirstChild.Data + }) + + // Skills + skillsMap := make(map[string]int) + s.Find(".LabelColumn").Each(func(index int, s *goquery.Selection) { + skillsMap[strings.Split(s.Nodes[0].FirstChild.FirstChild.Data, ":")[0]] = + TibiadataStringToIntegerV3(s.Nodes[0].NextSibling.FirstChild.Data) + }) + + _General.HitPoints = TibiadataStringToIntegerV3(generalMap["Hit Points"]) + _General.Mana = TibiadataStringToIntegerV3(generalMap["Mana"]) + _General.Capacity = TibiadataStringToIntegerV3(generalMap["Capacity"]) + _General.Speed = TibiadataStringToIntegerV3(generalMap["Speed"]) + _General.Blessings = TibiadataStringToIntegerV3(strings.Split(generalMap["Blessings"], "/")[0]) + _General.Mounts = TibiadataStringToIntegerV3(generalMap["Mounts"]) + _General.Outfits = TibiadataStringToIntegerV3(generalMap["Outfits"]) + _General.Titles = TibiadataStringToIntegerV3(generalMap["Titles"]) + _General.AxeFighting = skillsMap["Axe Fighting"] + _General.ClubFighting = skillsMap["Club Fighting"] + _General.DistanceFighting = skillsMap["Distance Fighting"] + _General.Fishing = skillsMap["Fishing"] + _General.FistFighting = skillsMap["Fist Fighting"] + _General.MagicLevel = skillsMap["Magic Level"] + _General.Shielding = skillsMap["Shielding"] + _General.SwordFighting = skillsMap["Sword Fighting"] + _General.CreationDate = TibiadataDatetimeV3(generalMap["Creation Date"]) + _General.Experience = TibiadataStringToIntegerV3(generalMap["Experience"]) + _General.Gold = TibiadataStringToIntegerV3(generalMap["Gold"]) + _General.AchievementPoints = TibiadataStringToIntegerV3(generalMap["Achievement Points"]) + _General.RegularWorldTransfer = generalMap["Regular World Transfer"] + _General.CharmExpansion = strings.EqualFold(generalMap["Charm Expansion"], "yes") + _General.AvailableCharmPoints = TibiadataStringToIntegerV3(generalMap["Available Charm Points"]) + _General.SpentCharmPoints = TibiadataStringToIntegerV3(generalMap["Spent Charm Points"]) + _General.DailyRewardStreak = TibiadataStringToIntegerV3(generalMap["Daily Reward Streak"]) + _General.HuntingTaskPoints = TibiadataStringToIntegerV3(generalMap["Hunting Task Points"]) + _General.PermanentHuntingTaskSlots = TibiadataStringToIntegerV3(generalMap["Permanent Hunting Task Slots"]) + _General.PermanentPreySlots = TibiadataStringToIntegerV3(generalMap["Permanent Prey Slots"]) + _General.PreyWildCards = TibiadataStringToIntegerV3(generalMap["Prey Wildcards"]) + _General.Hirelings = TibiadataStringToIntegerV3(generalMap["Hirelings"]) + _General.HirelingJobs = TibiadataStringToIntegerV3(generalMap["Hireling Jobs"]) + _General.HirelingOutfits = TibiadataStringToIntegerV3(generalMap["Hireling Outfits"]) + _General.ExaltedDust = TibiadataStringToIntegerV3(strings.Split(generalMap["Exalted Dust"], "/")[0]) + }) + + // Extract items summary + var _ItemSummary []Item + ReaderHTML.Find("#ItemSummary").Each(func(index int, s *goquery.Selection) { + + for k, v := range ParseItems(s) { + _ItemSummary = append(_ItemSummary, Item{Name: k, Amount: v}) + } + + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + itemPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=0¤tpage=" + strconv.Itoa(i)) + ItemPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(itemPage)) + if err != nil { + log.Fatal(err) + } + for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { + _ItemSummary = append(_ItemSummary, Item{Name: k, Amount: v}) + } + } + } + }) + + // Extract store items summary + var _StoreItemSummary []Item + ReaderHTML.Find("#StoreItemSummary").Each(func(index int, s *goquery.Selection) { + + for k, v := range ParseItems(s) { + _StoreItemSummary = append(_StoreItemSummary, Item{Name: k, Amount: v}) + } + + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + itemPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=1¤tpage=" + strconv.Itoa(i)) + ItemPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(itemPage)) + if err != nil { + log.Fatal(err) + } + for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { + _StoreItemSummary = append(_StoreItemSummary, Item{Name: k, Amount: v}) + } + } + } + }) + + // Extract mounts + var _Mounts []string + ReaderHTML.Find("#Mounts").Each(func(index int, s *goquery.Selection) { + + _Mounts = append(_Mounts, ParseMounts(s)...) + + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + mountsPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=2¤tpage=" + strconv.Itoa(i)) + MountsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(mountsPage)) + if err != nil { + log.Fatal(err) + } + _Mounts = append(_Mounts, ParseMounts(MountsPageReaderHTML.Contents())...) + } + } + }) + + // Extract store mounts + var _StoreMounts []string + ReaderHTML.Find("#StoreMounts").Each(func(index int, s *goquery.Selection) { + + _StoreMounts = append(_StoreMounts, ParseMounts(s)...) + + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + mountsPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=3¤tpage=" + strconv.Itoa(i)) + MountsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(mountsPage)) + if err != nil { + log.Fatal(err) + } + _StoreMounts = append(_StoreMounts, ParseMounts(MountsPageReaderHTML.Contents())...) + } + } + }) + + // Extract outfits + var _Outfits []Outfit + ReaderHTML.Find("#Outfits").Each(func(index int, s *goquery.Selection) { + for k, v := range ParseOutfits(s) { + _Outfits = append(_Outfits, Outfit{ + Name: k, + Addon1: v[0], + Addon2: v[1], + }) + } + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + outfitsPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=4¤tpage=" + strconv.Itoa(i)) + OutfitsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(outfitsPage)) + if err != nil { + log.Fatal(err) + } + for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { + _Outfits = append(_Outfits, Outfit{ + Name: k, + Addon1: v[0], + Addon2: v[1], + }) + } + } + } + }) + + // Extract store outfits + var _StoreOutfits []Outfit + ReaderHTML.Find("#StoreOutfits").Each(func(index int, s *goquery.Selection) { + for k, v := range ParseOutfits(s) { + _Outfits = append(_Outfits, Outfit{ + Name: k, + Addon1: v[0], + Addon2: v[1], + }) + } + totalPages := s.Find(".PageLink").Size() + if totalPages > 1 { + // Fetch missing pages using links + for i := 2; i <= totalPages; i++ { + outfitsPage := AjaxJSONDataCollectorV3( + "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + + "&type=5¤tpage=" + strconv.Itoa(i)) + OutfitsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(outfitsPage)) + if err != nil { + log.Fatal(err) + } + for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { + _Outfits = append(_Outfits, Outfit{ + Name: k, + Addon1: v[0], + Addon2: v[1], + }) + } + } + } + }) + + // Extract familiars + var _Familiars []string + ReaderHTML.Find("#Familiars").Each(func(index int, s *goquery.Selection) { + s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + familiarName, exists := s.Attr("title") + if exists { + _Familiars = append(_Familiars, familiarName) + } + }) + }) + + // Extract blessings + var _Blessings Blessings + ReaderHTML.Find("#Blessings").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + blessingsAmount := TibiadataStringToIntegerV3(strings.Split(node.FirstChild.Data, " x")[0]) + switch blessingName := node.NextSibling.FirstChild.Data; blessingName { + case "Adventurer's Blessing": + _Blessings.AdventurersBlessing = blessingsAmount + case "Blood of the Mountain": + _Blessings.BloodOfTheMountain = blessingsAmount + case "Embrace of Tibia": + _Blessings.EmbraceOfTibia = blessingsAmount + case "Fire of the Suns": + _Blessings.FireOfTheSuns = blessingsAmount + case "Heart of the Mountain": + _Blessings.HeartOfTheMountain = blessingsAmount + case "Spark of the Phoenix": + _Blessings.SparkOfThePhoenix = blessingsAmount + case "Spiritual Shielding": + _Blessings.SpiritualShielding = blessingsAmount + case "Twist of Fate": + _Blessings.TwistOfFate = blessingsAmount + case "Wisdom of Solitude": + _Blessings.WisdomOfSolitude = blessingsAmount + } + }) + }) + + // Extract Imbuements + var _Imbuements []string + ReaderHTML.Find("#Imbuements").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if strings.Contains(node.FirstChild.Data, "No imbuements.") { + return + } + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _Imbuements = append(_Imbuements, strings.TrimSpace(node.FirstChild.Data)) + } + }) + }) + + // Extract Charms + var _Charms []Charm + ReaderHTML.Find("#Charms").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if strings.Contains(node.FirstChild.Data, "No charms.") { + return + } + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _Charms = append(_Charms, Charm{ + Cost: TibiadataStringToIntegerV3(node.FirstChild.Data), + Name: node.NextSibling.FirstChild.Data, + }) + } + }) + }) + + // Extract Completed Cyclopedia Map Areas + var _CompletedCyclopediaMapAreas []string + ReaderHTML.Find("#CompletedCyclopediaMapAreas").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if strings.Contains(node.FirstChild.Data, "No areas explored.") { + return + } + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _CompletedCyclopediaMapAreas = append(_CompletedCyclopediaMapAreas, strings.TrimSpace(node.FirstChild.Data)) + } + }) + }) + + // Extract Completed Quest Lines + var _CompletedQuestLines []string + ReaderHTML.Find("#CompletedQuestLines").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _CompletedQuestLines = append(_CompletedQuestLines, strings.TrimSpace(node.FirstChild.Data)) + } + }) + }) + + // Extract Titles + var _Titles []string + ReaderHTML.Find("#Titles").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _Titles = append(_Titles, strings.TrimSpace(node.FirstChild.Data)) + } + }) + }) + + // Extract Achievements + var _Achievements []string + ReaderHTML.Find("#Achievements").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _Achievements = append(_Achievements, strings.TrimSpace(node.FirstChild.Data)) + } + }) + }) + + // Extract Bestiary Progress + var _BestiaryProgress []BestiaryEntry + ReaderHTML.Find("#BestiaryProgress").Each(func(index int, s *goquery.Selection) { + s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + node := s.Nodes[0].FirstChild + if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { + _BestiaryProgress = append(_BestiaryProgress, BestiaryEntry{ + Step: TibiadataStringToIntegerV3(node.FirstChild.Data), + Kills: TibiadataStringToIntegerV3(strings.Split(node.NextSibling.FirstChild.Data, " x")[0]), + Name: node.NextSibling.NextSibling.FirstChild.Data, + }) + } + }) + }) + + jsonData := JSONData{ + Auction: Auction{ + Id: id, + Details: _Details, + General: _General, + ItemSummary: _ItemSummary, + StoreItemSummary: _StoreItemSummary, + Mounts: _Mounts, + StoreMounts: _StoreMounts, + Outfits: _Outfits, + StoreOutfits: _StoreOutfits, + Familiars: _Familiars, + Blessings: _Blessings, + Imbuements: _Imbuements, + Charms: _Charms, + CompletedCyclopediaMapAreas: _CompletedCyclopediaMapAreas, + CompletedQuestLines: _CompletedQuestLines, + Titles: _Titles, + Achievements: _Achievements, + BestiaryProgress: _BestiaryProgress, + }, + Information: Information{ + APIVersion: TibiadataAPIversion, + Timestamp: TibiadataDatetimeV3(""), + }, + } + + // return jsonData + TibiaDataAPIHandleSuccessResponse(c, "TibiaCharbazaarAuctionV3", jsonData) +} + +func ParseItems(s *goquery.Selection) map[string]int { + m := make(map[string]int) + s.Find(".CVIconObject").Each(func(index int, s *goquery.Selection) { + + itemTitle, exists := s.Attr("title") + + if exists { + var itemAmount int + var itemName string + + nodes := s.Find(".ObjectAmount").First().Nodes + if nodes == nil { + itemName = strings.Split(itemTitle, "\n")[0] + itemAmount = 1 + } else { + temp := strings.SplitN(itemTitle, "x ", 2) + itemName = strings.Split(temp[1], "\n")[0] + itemAmount = TibiadataStringToIntegerV3(temp[0]) + } + m[itemName] = itemAmount + } + }) + return m +} + +func ParseOutfits(s *goquery.Selection) map[string][]bool { + m := make(map[string][]bool) + s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + outfitTitle, exists := s.Attr("title") + if exists { + outfitName := strings.Split(outfitTitle, " (")[0] + hasAddon1 := strings.Contains(outfitTitle, "addon 1") + hasAddon2 := strings.Contains(outfitTitle, "addon 2") + m[outfitName] = []bool{hasAddon1, hasAddon2} + } + }) + return m +} + +func ParseMounts(s *goquery.Selection) []string { + var mountsList []string + s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + mountTitle, exists := s.Attr("title") + if exists { + mountsList = append(mountsList, mountTitle) + } + }) + return mountsList +} + +func AjaxJSONDataCollectorV3(TibiaURL string) string { + + // Setting up resty client + client := resty.New() + + // Set Debug if enabled by TibiadataDebug var + if TibiadataDebug { + client.SetDebug(true) + } + + // Set client timeout and retry + client.SetTimeout(5 * time.Second) + client.SetRetryCount(2) + + // Set headers for all requests + client.SetHeaders(map[string]string{ + "X-Requested-With": "XMLHttpRequest", + "Content-Type": "application/json", + "User-Agent": TibiadataUserAgent, + }) + + // Enabling Content length value for all request + client.SetContentLength(true) + + // Disable redirection of client (so we skip parsing maintenance page) + client.SetRedirectPolicy(resty.NoRedirectPolicy()) + + res, err := client.R().Get(TibiaURL) + if err != nil { + log.Printf("[error] AjaxJSONDataCollectorV3 (URL: %s) in resp1: %s", TibiaURL, err) + } + + // Checking if status is something else than 200 + if res.StatusCode() != 200 { + log.Printf("[warni] AjaxJSONDataCollectorV3 (URL: %s) status code: %s", TibiaURL, res.Status()) + + // Check if page is in maintenance mode + if res.StatusCode() == 302 { + log.Printf("[info] AjaxJSONDataCollectorV3 (URL: %s): Page tibia.com returns 302, probably maintenance mode enabled?", TibiaURL) + } + } + + var result AjaxJSONData + err = json.Unmarshal(res.Body(), &result) + if err != nil { + log.Printf("[error] AjaxJSONDataCollectorV3 (URL: %s) in deserialization process: %s", TibiaURL, err) + } + + // Return of extracted html to functions + return result.AjaxObjects[0].Data +} diff --git a/src/webserver.go b/src/webserver.go index 8c987fda..faf00e5d 100644 --- a/src/webserver.go +++ b/src/webserver.go @@ -118,6 +118,9 @@ func runWebServer() { // Tibia worlds v3.GET("/worlds", tibiaWorldsOverviewV3) v3.GET("/worlds/world/:world", tibiaWorldsWorldV3) + + // TibiaBazaarAuctionV3 + v3.GET("/charbazaar/auction/:id", TibiaCharbazaarAuctionV3) } // container version details endpoint From fc254ee50c106cb59c6b783d22d235ff1a44d1a2 Mon Sep 17 00:00:00 2001 From: Jorge Villarreal Date: Tue, 4 Jan 2022 18:21:40 -0600 Subject: [PATCH 2/3] Variable renaming and use of constants. (#28) --- src/TibiaCharbazaarAuctionV3.go | 318 ++++++++++++++++---------------- 1 file changed, 160 insertions(+), 158 deletions(-) diff --git a/src/TibiaCharbazaarAuctionV3.go b/src/TibiaCharbazaarAuctionV3.go index 19c62114..b6b931c7 100644 --- a/src/TibiaCharbazaarAuctionV3.go +++ b/src/TibiaCharbazaarAuctionV3.go @@ -12,18 +12,6 @@ import ( "github.com/gin-gonic/gin" ) -// AjaxResponseObject - child of AjaxJSONData -type AjaxResponseObject struct { - Data string `json:"Data"` - DataType string `json:"DataType"` - Target string `json:"Target"` -} - -// AjaxJSONData - base response for auction items page links -type AjaxJSONData struct { - AjaxObjects []AjaxResponseObject `json:"AjaxObjects"` -} - // TibiaCharbazaarAuctionV3 func func TibiaCharbazaarAuctionV3(c *gin.Context) { @@ -162,19 +150,19 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { } // Extract details section - var _Details Details + var details Details ReaderHTML.Find(".Auction").Each(func(index int, s *goquery.Selection) { detailsHeader := strings.Split(s.Find(".AuctionHeader").Text(), "Level: ") - _Details.CharacterName = detailsHeader[0] + details.CharacterName = detailsHeader[0] detailsHeader = strings.Split(detailsHeader[1], "|") level := TibiadataStringToIntegerV3(detailsHeader[0]) - _Details.Level = level - _Details.Vocation = strings.TrimSpace(strings.Split(detailsHeader[1], "Vocation: ")[1]) - _Details.Gender = strings.TrimSpace(detailsHeader[2]) - _Details.World = strings.TrimSpace(strings.Split(detailsHeader[3], "World: ")[1]) + details.Level = level + details.Vocation = strings.TrimSpace(strings.Split(detailsHeader[1], "Vocation: ")[1]) + details.Gender = strings.TrimSpace(detailsHeader[2]) + details.World = strings.TrimSpace(strings.Split(detailsHeader[3], "World: ")[1]) s.Find(".ShortAuctionData").Each(func(index int, s *goquery.Selection) { nodes := s.Children().Nodes @@ -193,13 +181,13 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { auctionEndDate := TibiaDataSanitizeNbspSpaceString(nodes[3+lookupIndex].FirstChild.Data) auctionEndDate = strings.Split(auctionEndDate, " CET")[0] + ":00 CET" - _Details.AuctionStart = TibiadataDatetimeV3(auctionStartDate) - _Details.AuctionEnd = TibiadataDatetimeV3(auctionEndDate) + details.AuctionStart = TibiadataDatetimeV3(auctionStartDate) + details.AuctionEnd = TibiadataDatetimeV3(auctionEndDate) bidType := strings.Split(nodes[4+lookupIndex].FirstChild.FirstChild.Data, " Bid:")[0] bidAmount := TibiadataStringToIntegerV3(nodes[4+lookupIndex].LastChild.FirstChild.FirstChild.Data) - _Details.Bid = Bid{ + details.Bid = Bid{ Type: bidType, Amount: bidAmount, } @@ -207,7 +195,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract general section - var _General General + var general General ReaderHTML.Find("#General").Each(func(index int, s *goquery.Selection) { // General @@ -223,160 +211,150 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { TibiadataStringToIntegerV3(s.Nodes[0].NextSibling.FirstChild.Data) }) - _General.HitPoints = TibiadataStringToIntegerV3(generalMap["Hit Points"]) - _General.Mana = TibiadataStringToIntegerV3(generalMap["Mana"]) - _General.Capacity = TibiadataStringToIntegerV3(generalMap["Capacity"]) - _General.Speed = TibiadataStringToIntegerV3(generalMap["Speed"]) - _General.Blessings = TibiadataStringToIntegerV3(strings.Split(generalMap["Blessings"], "/")[0]) - _General.Mounts = TibiadataStringToIntegerV3(generalMap["Mounts"]) - _General.Outfits = TibiadataStringToIntegerV3(generalMap["Outfits"]) - _General.Titles = TibiadataStringToIntegerV3(generalMap["Titles"]) - _General.AxeFighting = skillsMap["Axe Fighting"] - _General.ClubFighting = skillsMap["Club Fighting"] - _General.DistanceFighting = skillsMap["Distance Fighting"] - _General.Fishing = skillsMap["Fishing"] - _General.FistFighting = skillsMap["Fist Fighting"] - _General.MagicLevel = skillsMap["Magic Level"] - _General.Shielding = skillsMap["Shielding"] - _General.SwordFighting = skillsMap["Sword Fighting"] - _General.CreationDate = TibiadataDatetimeV3(generalMap["Creation Date"]) - _General.Experience = TibiadataStringToIntegerV3(generalMap["Experience"]) - _General.Gold = TibiadataStringToIntegerV3(generalMap["Gold"]) - _General.AchievementPoints = TibiadataStringToIntegerV3(generalMap["Achievement Points"]) - _General.RegularWorldTransfer = generalMap["Regular World Transfer"] - _General.CharmExpansion = strings.EqualFold(generalMap["Charm Expansion"], "yes") - _General.AvailableCharmPoints = TibiadataStringToIntegerV3(generalMap["Available Charm Points"]) - _General.SpentCharmPoints = TibiadataStringToIntegerV3(generalMap["Spent Charm Points"]) - _General.DailyRewardStreak = TibiadataStringToIntegerV3(generalMap["Daily Reward Streak"]) - _General.HuntingTaskPoints = TibiadataStringToIntegerV3(generalMap["Hunting Task Points"]) - _General.PermanentHuntingTaskSlots = TibiadataStringToIntegerV3(generalMap["Permanent Hunting Task Slots"]) - _General.PermanentPreySlots = TibiadataStringToIntegerV3(generalMap["Permanent Prey Slots"]) - _General.PreyWildCards = TibiadataStringToIntegerV3(generalMap["Prey Wildcards"]) - _General.Hirelings = TibiadataStringToIntegerV3(generalMap["Hirelings"]) - _General.HirelingJobs = TibiadataStringToIntegerV3(generalMap["Hireling Jobs"]) - _General.HirelingOutfits = TibiadataStringToIntegerV3(generalMap["Hireling Outfits"]) - _General.ExaltedDust = TibiadataStringToIntegerV3(strings.Split(generalMap["Exalted Dust"], "/")[0]) + general.HitPoints = TibiadataStringToIntegerV3(generalMap["Hit Points"]) + general.Mana = TibiadataStringToIntegerV3(generalMap["Mana"]) + general.Capacity = TibiadataStringToIntegerV3(generalMap["Capacity"]) + general.Speed = TibiadataStringToIntegerV3(generalMap["Speed"]) + general.Blessings = TibiadataStringToIntegerV3(strings.Split(generalMap["Blessings"], "/")[0]) + general.Mounts = TibiadataStringToIntegerV3(generalMap["Mounts"]) + general.Outfits = TibiadataStringToIntegerV3(generalMap["Outfits"]) + general.Titles = TibiadataStringToIntegerV3(generalMap["Titles"]) + general.AxeFighting = skillsMap["Axe Fighting"] + general.ClubFighting = skillsMap["Club Fighting"] + general.DistanceFighting = skillsMap["Distance Fighting"] + general.Fishing = skillsMap["Fishing"] + general.FistFighting = skillsMap["Fist Fighting"] + general.MagicLevel = skillsMap["Magic Level"] + general.Shielding = skillsMap["Shielding"] + general.SwordFighting = skillsMap["Sword Fighting"] + general.CreationDate = TibiadataDatetimeV3(generalMap["Creation Date"]) + general.Experience = TibiadataStringToIntegerV3(generalMap["Experience"]) + general.Gold = TibiadataStringToIntegerV3(generalMap["Gold"]) + general.AchievementPoints = TibiadataStringToIntegerV3(generalMap["Achievement Points"]) + general.RegularWorldTransfer = generalMap["Regular World Transfer"] + general.CharmExpansion = strings.EqualFold(generalMap["Charm Expansion"], "yes") + general.AvailableCharmPoints = TibiadataStringToIntegerV3(generalMap["Available Charm Points"]) + general.SpentCharmPoints = TibiadataStringToIntegerV3(generalMap["Spent Charm Points"]) + general.DailyRewardStreak = TibiadataStringToIntegerV3(generalMap["Daily Reward Streak"]) + general.HuntingTaskPoints = TibiadataStringToIntegerV3(generalMap["Hunting Task Points"]) + general.PermanentHuntingTaskSlots = TibiadataStringToIntegerV3(generalMap["Permanent Hunting Task Slots"]) + general.PermanentPreySlots = TibiadataStringToIntegerV3(generalMap["Permanent Prey Slots"]) + general.PreyWildCards = TibiadataStringToIntegerV3(generalMap["Prey Wildcards"]) + general.Hirelings = TibiadataStringToIntegerV3(generalMap["Hirelings"]) + general.HirelingJobs = TibiadataStringToIntegerV3(generalMap["Hireling Jobs"]) + general.HirelingOutfits = TibiadataStringToIntegerV3(generalMap["Hireling Outfits"]) + general.ExaltedDust = TibiadataStringToIntegerV3(strings.Split(generalMap["Exalted Dust"], "/")[0]) }) // Extract items summary - var _ItemSummary []Item + var itemSummary []Item ReaderHTML.Find("#ItemSummary").Each(func(index int, s *goquery.Selection) { for k, v := range ParseItems(s) { - _ItemSummary = append(_ItemSummary, Item{Name: k, Amount: v}) + itemSummary = append(itemSummary, Item{Name: k, Amount: v}) } - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - itemPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=0¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + itemPage := AjaxJSONDataCollectorV3(id, ItemSummarySection, pageIndex) ItemPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(itemPage)) if err != nil { log.Fatal(err) } for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { - _ItemSummary = append(_ItemSummary, Item{Name: k, Amount: v}) + itemSummary = append(itemSummary, Item{Name: k, Amount: v}) } } } }) // Extract store items summary - var _StoreItemSummary []Item + var storeItemSummary []Item ReaderHTML.Find("#StoreItemSummary").Each(func(index int, s *goquery.Selection) { for k, v := range ParseItems(s) { - _StoreItemSummary = append(_StoreItemSummary, Item{Name: k, Amount: v}) + storeItemSummary = append(storeItemSummary, Item{Name: k, Amount: v}) } - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - itemPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=1¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + itemPage := AjaxJSONDataCollectorV3(id, StoreItemSummarySection, pageIndex) ItemPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(itemPage)) if err != nil { log.Fatal(err) } for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { - _StoreItemSummary = append(_StoreItemSummary, Item{Name: k, Amount: v}) + storeItemSummary = append(storeItemSummary, Item{Name: k, Amount: v}) } } } }) // Extract mounts - var _Mounts []string + var mounts []string ReaderHTML.Find("#Mounts").Each(func(index int, s *goquery.Selection) { - _Mounts = append(_Mounts, ParseMounts(s)...) + mounts = append(mounts, ParseMounts(s)...) - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - mountsPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=2¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + mountsPage := AjaxJSONDataCollectorV3(id, MountsSection, pageIndex) MountsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(mountsPage)) if err != nil { log.Fatal(err) } - _Mounts = append(_Mounts, ParseMounts(MountsPageReaderHTML.Contents())...) + mounts = append(mounts, ParseMounts(MountsPageReaderHTML.Contents())...) } } }) // Extract store mounts - var _StoreMounts []string + var storeMounts []string ReaderHTML.Find("#StoreMounts").Each(func(index int, s *goquery.Selection) { - _StoreMounts = append(_StoreMounts, ParseMounts(s)...) + storeMounts = append(storeMounts, ParseMounts(s)...) - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - mountsPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=3¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + mountsPage := AjaxJSONDataCollectorV3(id, StoreMountsSection, pageIndex) MountsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(mountsPage)) if err != nil { log.Fatal(err) } - _StoreMounts = append(_StoreMounts, ParseMounts(MountsPageReaderHTML.Contents())...) + storeMounts = append(storeMounts, ParseMounts(MountsPageReaderHTML.Contents())...) } } }) // Extract outfits - var _Outfits []Outfit + var outfits []Outfit ReaderHTML.Find("#Outfits").Each(func(index int, s *goquery.Selection) { for k, v := range ParseOutfits(s) { - _Outfits = append(_Outfits, Outfit{ + outfits = append(outfits, Outfit{ Name: k, Addon1: v[0], Addon2: v[1], }) } - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - outfitsPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=4¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + outfitsPage := AjaxJSONDataCollectorV3(id, OutfitsSection, pageIndex) OutfitsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(outfitsPage)) if err != nil { log.Fatal(err) } for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { - _Outfits = append(_Outfits, Outfit{ + outfits = append(outfits, Outfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -387,28 +365,26 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract store outfits - var _StoreOutfits []Outfit + var storeOutfits []Outfit ReaderHTML.Find("#StoreOutfits").Each(func(index int, s *goquery.Selection) { for k, v := range ParseOutfits(s) { - _Outfits = append(_Outfits, Outfit{ + outfits = append(outfits, Outfit{ Name: k, Addon1: v[0], Addon2: v[1], }) } - totalPages := s.Find(".PageLink").Size() + totalPages := s.Find(PageLinkSelector).Size() if totalPages > 1 { // Fetch missing pages using links - for i := 2; i <= totalPages; i++ { - outfitsPage := AjaxJSONDataCollectorV3( - "https://www.tibia.com/websiteservices/handle_charactertrades.php?auctionid=" + strconv.Itoa(id) + - "&type=5¤tpage=" + strconv.Itoa(i)) + for pageIndex := 2; pageIndex <= totalPages; pageIndex++ { + outfitsPage := AjaxJSONDataCollectorV3(id, StoreOutfitsSection, pageIndex) OutfitsPageReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(outfitsPage)) if err != nil { log.Fatal(err) } for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { - _Outfits = append(_Outfits, Outfit{ + outfits = append(outfits, Outfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -419,69 +395,69 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract familiars - var _Familiars []string + var familiars []string ReaderHTML.Find("#Familiars").Each(func(index int, s *goquery.Selection) { - s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + s.Find(CVIconSelector).Each(func(index int, s *goquery.Selection) { familiarName, exists := s.Attr("title") if exists { - _Familiars = append(_Familiars, familiarName) + familiars = append(familiars, familiarName) } }) }) // Extract blessings - var _Blessings Blessings + var blessings Blessings ReaderHTML.Find("#Blessings").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild blessingsAmount := TibiadataStringToIntegerV3(strings.Split(node.FirstChild.Data, " x")[0]) switch blessingName := node.NextSibling.FirstChild.Data; blessingName { case "Adventurer's Blessing": - _Blessings.AdventurersBlessing = blessingsAmount + blessings.AdventurersBlessing = blessingsAmount case "Blood of the Mountain": - _Blessings.BloodOfTheMountain = blessingsAmount + blessings.BloodOfTheMountain = blessingsAmount case "Embrace of Tibia": - _Blessings.EmbraceOfTibia = blessingsAmount + blessings.EmbraceOfTibia = blessingsAmount case "Fire of the Suns": - _Blessings.FireOfTheSuns = blessingsAmount + blessings.FireOfTheSuns = blessingsAmount case "Heart of the Mountain": - _Blessings.HeartOfTheMountain = blessingsAmount + blessings.HeartOfTheMountain = blessingsAmount case "Spark of the Phoenix": - _Blessings.SparkOfThePhoenix = blessingsAmount + blessings.SparkOfThePhoenix = blessingsAmount case "Spiritual Shielding": - _Blessings.SpiritualShielding = blessingsAmount + blessings.SpiritualShielding = blessingsAmount case "Twist of Fate": - _Blessings.TwistOfFate = blessingsAmount + blessings.TwistOfFate = blessingsAmount case "Wisdom of Solitude": - _Blessings.WisdomOfSolitude = blessingsAmount + blessings.WisdomOfSolitude = blessingsAmount } }) }) // Extract Imbuements - var _Imbuements []string + var imbuements []string ReaderHTML.Find("#Imbuements").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if strings.Contains(node.FirstChild.Data, "No imbuements.") { return } if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _Imbuements = append(_Imbuements, strings.TrimSpace(node.FirstChild.Data)) + imbuements = append(imbuements, strings.TrimSpace(node.FirstChild.Data)) } }) }) // Extract Charms - var _Charms []Charm + var charms []Charm ReaderHTML.Find("#Charms").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if strings.Contains(node.FirstChild.Data, "No charms.") { return } if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _Charms = append(_Charms, Charm{ + charms = append(charms, Charm{ Cost: TibiadataStringToIntegerV3(node.FirstChild.Data), Name: node.NextSibling.FirstChild.Data, }) @@ -490,59 +466,59 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract Completed Cyclopedia Map Areas - var _CompletedCyclopediaMapAreas []string + var completedCyclopediaMapAreas []string ReaderHTML.Find("#CompletedCyclopediaMapAreas").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if strings.Contains(node.FirstChild.Data, "No areas explored.") { return } if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _CompletedCyclopediaMapAreas = append(_CompletedCyclopediaMapAreas, strings.TrimSpace(node.FirstChild.Data)) + completedCyclopediaMapAreas = append(completedCyclopediaMapAreas, strings.TrimSpace(node.FirstChild.Data)) } }) }) // Extract Completed Quest Lines - var _CompletedQuestLines []string + var completedQuestLines []string ReaderHTML.Find("#CompletedQuestLines").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _CompletedQuestLines = append(_CompletedQuestLines, strings.TrimSpace(node.FirstChild.Data)) + completedQuestLines = append(completedQuestLines, strings.TrimSpace(node.FirstChild.Data)) } }) }) // Extract Titles - var _Titles []string + var titles []string ReaderHTML.Find("#Titles").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _Titles = append(_Titles, strings.TrimSpace(node.FirstChild.Data)) + titles = append(titles, strings.TrimSpace(node.FirstChild.Data)) } }) }) // Extract Achievements - var _Achievements []string + var achievements []string ReaderHTML.Find("#Achievements").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _Achievements = append(_Achievements, strings.TrimSpace(node.FirstChild.Data)) + achievements = append(achievements, strings.TrimSpace(node.FirstChild.Data)) } }) }) // Extract Bestiary Progress - var _BestiaryProgress []BestiaryEntry + var bestiaryProgress []BestiaryEntry ReaderHTML.Find("#BestiaryProgress").Each(func(index int, s *goquery.Selection) { - s.Find(".Odd,.Even").Each(func(index int, s *goquery.Selection) { + s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - _BestiaryProgress = append(_BestiaryProgress, BestiaryEntry{ + bestiaryProgress = append(bestiaryProgress, BestiaryEntry{ Step: TibiadataStringToIntegerV3(node.FirstChild.Data), Kills: TibiadataStringToIntegerV3(strings.Split(node.NextSibling.FirstChild.Data, " x")[0]), Name: node.NextSibling.NextSibling.FirstChild.Data, @@ -554,23 +530,23 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { jsonData := JSONData{ Auction: Auction{ Id: id, - Details: _Details, - General: _General, - ItemSummary: _ItemSummary, - StoreItemSummary: _StoreItemSummary, - Mounts: _Mounts, - StoreMounts: _StoreMounts, - Outfits: _Outfits, - StoreOutfits: _StoreOutfits, - Familiars: _Familiars, - Blessings: _Blessings, - Imbuements: _Imbuements, - Charms: _Charms, - CompletedCyclopediaMapAreas: _CompletedCyclopediaMapAreas, - CompletedQuestLines: _CompletedQuestLines, - Titles: _Titles, - Achievements: _Achievements, - BestiaryProgress: _BestiaryProgress, + Details: details, + General: general, + ItemSummary: itemSummary, + StoreItemSummary: storeItemSummary, + Mounts: mounts, + StoreMounts: storeMounts, + Outfits: outfits, + StoreOutfits: storeOutfits, + Familiars: familiars, + Blessings: blessings, + Imbuements: imbuements, + Charms: charms, + CompletedCyclopediaMapAreas: completedCyclopediaMapAreas, + CompletedQuestLines: completedQuestLines, + Titles: titles, + Achievements: achievements, + BestiaryProgress: bestiaryProgress, }, Information: Information{ APIVersion: TibiadataAPIversion, @@ -609,7 +585,7 @@ func ParseItems(s *goquery.Selection) map[string]int { func ParseOutfits(s *goquery.Selection) map[string][]bool { m := make(map[string][]bool) - s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + s.Find(CVIconSelector).Each(func(index int, s *goquery.Selection) { outfitTitle, exists := s.Attr("title") if exists { outfitName := strings.Split(outfitTitle, " (")[0] @@ -623,7 +599,7 @@ func ParseOutfits(s *goquery.Selection) map[string][]bool { func ParseMounts(s *goquery.Selection) []string { var mountsList []string - s.Find(".CVIcon").Each(func(index int, s *goquery.Selection) { + s.Find(CVIconSelector).Each(func(index int, s *goquery.Selection) { mountTitle, exists := s.Attr("title") if exists { mountsList = append(mountsList, mountTitle) @@ -632,7 +608,11 @@ func ParseMounts(s *goquery.Selection) []string { return mountsList } -func AjaxJSONDataCollectorV3(TibiaURL string) string { +func AjaxJSONDataCollectorV3(AuctionId int, SectionType int, PageIndex int) string { + TibiaURL := "https://www.tibia.com/websiteservices/handle_charactertrades.php?" + + "auctionid=" + strconv.Itoa(AuctionId) + + "&type=" + strconv.Itoa(SectionType) + + "¤tpage=" + strconv.Itoa(PageIndex) // Setting up resty client client := resty.New() @@ -683,3 +663,25 @@ func AjaxJSONDataCollectorV3(TibiaURL string) string { // Return of extracted html to functions return result.AjaxObjects[0].Data } + +// AjaxResponseObject - child of AjaxJSONData +type AjaxResponseObject struct { + Data string `json:"Data"` + DataType string `json:"DataType"` + Target string `json:"Target"` +} + +// AjaxJSONData - base response for auction items page links +type AjaxJSONData struct { + AjaxObjects []AjaxResponseObject `json:"AjaxObjects"` +} + +const OddEvenSelector = ".Odd,.Even" +const PageLinkSelector = ".PageLink" +const CVIconSelector = ".CVIcon" +const ItemSummarySection = 0 +const StoreItemSummarySection = 1 +const MountsSection = 2 +const StoreMountsSection = 3 +const OutfitsSection = 4 +const StoreOutfitsSection = 5 From be534bca3a1002cc267ea2250ce9aaf426f92581 Mon Sep 17 00:00:00 2001 From: Tobias Lindberg Date: Wed, 19 Jan 2022 22:40:15 +0100 Subject: [PATCH 3/3] rebasing and rewriting a couple of things --- ...arAuctionV3.go => TibiaBazaarAuctionV3.go} | 322 +++++++++--------- src/webserver.go | 33 +- 2 files changed, 193 insertions(+), 162 deletions(-) rename src/{TibiaCharbazaarAuctionV3.go => TibiaBazaarAuctionV3.go} (71%) diff --git a/src/TibiaCharbazaarAuctionV3.go b/src/TibiaBazaarAuctionV3.go similarity index 71% rename from src/TibiaCharbazaarAuctionV3.go rename to src/TibiaBazaarAuctionV3.go index b6b931c7..227ff332 100644 --- a/src/TibiaCharbazaarAuctionV3.go +++ b/src/TibiaBazaarAuctionV3.go @@ -2,146 +2,152 @@ package main import ( "encoding/json" - "github.com/go-resty/resty/v2" "log" "strconv" "strings" "time" + "github.com/go-resty/resty/v2" + "github.com/PuerkitoBio/goquery" - "github.com/gin-gonic/gin" ) -// TibiaCharbazaarAuctionV3 func -func TibiaCharbazaarAuctionV3(c *gin.Context) { - - id := TibiadataStringToIntegerV3(c.Param("id")) +// Child of BazaarAuction +type BazaarAuctionBid struct { + Type string `json:"type"` + Amount int `json:"amount"` +} - // Child of Details - type Bid struct { - Type string `json:"type"` - Amount int `json:"amount"` - } +// Child of BazaarAuction +type BazaarAuctionDetails struct { + CharacterName string `json:"character_name"` + Level int `json:"level"` + Vocation string `json:"vocation"` + Gender string `json:"gender"` + World string `json:"world"` + AuctionStart string `json:"auction_start"` + AuctionEnd string `json:"auction_end"` + Bid BazaarAuctionBid `json:"bid"` +} - // Child of Auction - type Details struct { - CharacterName string `json:"characterName"` - Level int `json:"level"` - Vocation string `json:"vocation"` - Gender string `json:"gender"` - World string `json:"world"` - AuctionStart string `json:"auctionStart"` - AuctionEnd string `json:"auctionEnd"` - Bid Bid `json:"bid"` - } +// Child of BazaarAuction +type General struct { + HitPoints int `json:"hitPoints"` + Mana int `json:"mana"` + Capacity int `json:"capacity"` + Speed int `json:"speed"` + Blessings int `json:"blessings"` + Mounts int `json:"mounts"` + Outfits int `json:"outfits"` + Titles int `json:"titles"` + AxeFighting int `json:"axe_fighting"` + ClubFighting int `json:"club_fighting"` + DistanceFighting int `json:"distance_fighting"` + Fishing int `json:"fishing"` + FistFighting int `json:"fist_fighting"` + MagicLevel int `json:"magic_level"` + Shielding int `json:"shielding"` + SwordFighting int `json:"sword_fighting"` + CreationDate string `json:"creation_date"` + Experience int `json:"experience"` + Gold int `json:"gold"` + AchievementPoints int `json:"achievement_points"` + RegularWorldTransfer string `json:"regular_world_transfer"` // woot + CharmExpansion bool `json:"charm_expansion"` + AvailableCharmPoints int `json:"available_charm_points"` + SpentCharmPoints int `json:"spent_charm_points"` + DailyRewardStreak int `json:"daily_reward_streak"` + HuntingTaskPoints int `json:"hunting_task_points"` + PermanentHuntingTaskSlots int `json:"permanent_hunting_task_slots"` + PermanentPreySlots int `json:"permanent_prey_slots"` + PreyWildCards int `json:"prey_wild_cards"` + Hirelings int `json:"hirelings"` + HirelingJobs int `json:"hireling_jobs"` + HirelingOutfits int `json:"hireling_outfits"` + ExaltedDust int `json:"exalted_dust"` +} - // Child of Auction - type General struct { - HitPoints int `json:"hitPoints"` - Mana int `json:"mana"` - Capacity int `json:"capacity"` - Speed int `json:"speed"` - Blessings int `json:"blessings"` - Mounts int `json:"mounts"` - Outfits int `json:"outfits"` - Titles int `json:"titles"` - AxeFighting int `json:"axeFighting"` - ClubFighting int `json:"clubFighting"` - DistanceFighting int `json:"distanceFighting"` - Fishing int `json:"fishing"` - FistFighting int `json:"fistFighting"` - MagicLevel int `json:"magicLevel"` - Shielding int `json:"shielding"` - SwordFighting int `json:"swordFighting"` - CreationDate string `json:"creationDate"` - Experience int `json:"experience"` - Gold int `json:"gold"` - AchievementPoints int `json:"achievementPoints"` - RegularWorldTransfer string `json:"regularWorldTransfer"` - CharmExpansion bool `json:"charmExpansion"` - AvailableCharmPoints int `json:"availableCharmPoints"` - SpentCharmPoints int `json:"spentCharmPoints"` - DailyRewardStreak int `json:"dailyRewardStreak"` - HuntingTaskPoints int `json:"huntingTaskPoints"` - PermanentHuntingTaskSlots int `json:"permanentHuntingTaskSlots"` - PermanentPreySlots int `json:"permanentPreySlots"` - PreyWildCards int `json:"preyWildCards"` - Hirelings int `json:"hirelings"` - HirelingJobs int `json:"hirelingJobs"` - HirelingOutfits int `json:"hirelingOutfits"` - ExaltedDust int `json:"exaltedDust"` - } +// Child of BazaarAuction +type BazaarAuctionItem struct { + Name string `json:"name"` + Amount int `json:"amount"` +} - // Child of Auction - type Item struct { - Name string `json:"name"` - Amount int `json:"amount"` - } +// Child of BazaarAuction +type BazaarAuctionOutfit struct { + Name string `json:"name"` + Addon1 bool `json:"addon_1"` + Addon2 bool `json:"addon_2"` +} - // Child of Auction - type Outfit struct { - Name string `json:"name"` - Addon1 bool `json:"addon1"` - Addon2 bool `json:"addon2"` - } +// Child of BazaarAuction +type BazaarAuctionBlessings struct { + AdventurersBlessing int `json:"adventurers_blessing"` + BloodOfTheMountain int `json:"blood_of_the_mountain"` + EmbraceOfTibia int `json:"embrace_of_tibia"` + FireOfTheSuns int `json:"fire_of_the_suns"` + HeartOfTheMountain int `json:"heart_of_the_mountain"` + SparkOfThePhoenix int `json:"spark_of_the_phoenix"` + SpiritualShielding int `json:"spiritual_shielding"` + TwistOfFate int `json:"twist_of_fate"` + WisdomOfSolitude int `json:"wisdom_of_solitude"` +} - // Child of Auction - type Blessings struct { - AdventurersBlessing int `json:"adventurersBlessing"` - BloodOfTheMountain int `json:"bloodOfTheMountain"` - EmbraceOfTibia int `json:"embraceOfTibia"` - FireOfTheSuns int `json:"fireOfTheSuns"` - HeartOfTheMountain int `json:"heartOfTheMountain"` - SparkOfThePhoenix int `json:"sparkOfThePhoenix"` - SpiritualShielding int `json:"spiritualShielding"` - TwistOfFate int `json:"twistOfFate"` - WisdomOfSolitude int `json:"wisdomOfSolitude"` - } +// Child of BazaarAuction +type BazaarAuctionCharm struct { + Name string `json:"name"` + Cost int `json:"cost"` +} - // Child of Auction - type Charm struct { - Name string `json:"name"` - Cost int `json:"cost"` - } +// Child of BazaarAuction +type BazaarAuctionBestiaryEntry struct { + Name string `json:"name"` + Kills int `json:"kills"` + Step int `json:"step"` +} - // Child of Auction - type BestiaryEntry struct { - Name string `json:"name"` - Kills int `json:"kills"` - Step int `json:"step"` - } +// Child of BazaarAuctionResponse +type BazaarAuction struct { + Id int `json:"id"` + Details BazaarAuctionDetails `json:"details"` + General General `json:"general"` + ItemSummary []BazaarAuctionItem `json:"item_summary"` + StoreItemSummary []BazaarAuctionItem `json:"store_item_summary"` + Mounts []string `json:"mounts"` + StoreMounts []string `json:"store_mounts"` + Outfits []BazaarAuctionOutfit `json:"outfits"` + StoreOutfits []BazaarAuctionOutfit `json:"store_outfits"` + Familiars []string `json:"familiars"` + Blessings BazaarAuctionBlessings `json:"blessings"` + Imbuements []string `json:"imbuements"` + Charms []BazaarAuctionCharm `json:"charms"` + CompletedCyclopediaMapAreas []string `json:"completed_cyclopedia_map_areas"` + CompletedQuestLines []string `json:"completed_quest_lines"` + Titles []string `json:"titles"` + Achievements []string `json:"achievements"` + BestiaryProgress []BazaarAuctionBestiaryEntry `json:"bestiary_progress"` +} - // Child of JSONData - type Auction struct { - Id int `json:"id"` - Details Details `json:"details"` - General General `json:"general"` - ItemSummary []Item `json:"itemSummary"` - StoreItemSummary []Item `json:"storeItemSummary"` - Mounts []string `json:"mounts"` - StoreMounts []string `json:"storeMounts"` - Outfits []Outfit `json:"outfits"` - StoreOutfits []Outfit `json:"storeOutfits"` - Familiars []string `json:"familiars"` - Blessings Blessings `json:"blessings"` - Imbuements []string `json:"imbuements"` - Charms []Charm `json:"charms"` - CompletedCyclopediaMapAreas []string `json:"completedCyclopediaMapAreas"` - CompletedQuestLines []string `json:"completedQuestLines"` - Titles []string `json:"titles"` - Achievements []string `json:"achievements"` - BestiaryProgress []BestiaryEntry `json:"bestiaryProgress"` - } +// The base includes two levels: Auction and Information +type BazaarAuctionResponse struct { + Auction BazaarAuction `json:"auction"` + Information Information `json:"information"` +} - // The base includes two levels: Auction and Information - type JSONData struct { - Auction Auction `json:"auction"` - Information Information `json:"information"` - } +const ( + OddEvenSelector = ".Odd,.Even" + PageLinkSelector = ".PageLink" + CVIconSelector = ".CVIcon" + ItemSummarySection = 0 + StoreItemSummarySection = 1 + MountsSection = 2 + StoreMountsSection = 3 + OutfitsSection = 4 + StoreOutfitsSection = 5 +) - // Getting data with TibiadataHTMLDataCollectorV3 - BoxContentHTML := TibiadataHTMLDataCollectorV3("https://www.tibia.com/charactertrade/?page=details&auctionid=" + - strconv.Itoa(id)) +// TibiaBazaarAuctionV3Impl func +func TibiaBazaarAuctionV3Impl(BoxContentHTML string) BazaarAuctionResponse { // Loading HTML data into ReaderHTML for goquery with NewReader ReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(BoxContentHTML)) @@ -149,15 +155,21 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { log.Fatal(err) } + var id int + ReaderHTML.Find("input[name=auctionid]").Each(func(i int, selection *goquery.Selection) { + // collect the auction ID + id = TibiadataStringToIntegerV3(selection.AttrOr("value", "")) + }) + // Extract details section - var details Details + var details BazaarAuctionDetails ReaderHTML.Find(".Auction").Each(func(index int, s *goquery.Selection) { detailsHeader := strings.Split(s.Find(".AuctionHeader").Text(), "Level: ") details.CharacterName = detailsHeader[0] detailsHeader = strings.Split(detailsHeader[1], "|") - level := TibiadataStringToIntegerV3(detailsHeader[0]) + level := TibiadataStringToIntegerV3(strings.TrimSpace(detailsHeader[0])) details.Level = level details.Vocation = strings.TrimSpace(strings.Split(detailsHeader[1], "Vocation: ")[1]) @@ -177,9 +189,11 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { auctionStartDate := TibiaDataSanitizeNbspSpaceString(nodes[1+lookupIndex].FirstChild.Data) auctionStartDate = strings.Split(auctionStartDate, " CET")[0] + ":00 CET" + auctionStartDate = strings.Split(auctionStartDate, " CEST")[0] + ":00 CEST" auctionEndDate := TibiaDataSanitizeNbspSpaceString(nodes[3+lookupIndex].FirstChild.Data) auctionEndDate = strings.Split(auctionEndDate, " CET")[0] + ":00 CET" + auctionEndDate = strings.Split(auctionEndDate, " CEST")[0] + ":00 CEST" details.AuctionStart = TibiadataDatetimeV3(auctionStartDate) details.AuctionEnd = TibiadataDatetimeV3(auctionEndDate) @@ -187,7 +201,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { bidType := strings.Split(nodes[4+lookupIndex].FirstChild.FirstChild.Data, " Bid:")[0] bidAmount := TibiadataStringToIntegerV3(nodes[4+lookupIndex].LastChild.FirstChild.FirstChild.Data) - details.Bid = Bid{ + details.Bid = BazaarAuctionBid{ Type: bidType, Amount: bidAmount, } @@ -247,11 +261,11 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract items summary - var itemSummary []Item + var itemSummary []BazaarAuctionItem ReaderHTML.Find("#ItemSummary").Each(func(index int, s *goquery.Selection) { for k, v := range ParseItems(s) { - itemSummary = append(itemSummary, Item{Name: k, Amount: v}) + itemSummary = append(itemSummary, BazaarAuctionItem{Name: k, Amount: v}) } totalPages := s.Find(PageLinkSelector).Size() @@ -264,18 +278,18 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { log.Fatal(err) } for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { - itemSummary = append(itemSummary, Item{Name: k, Amount: v}) + itemSummary = append(itemSummary, BazaarAuctionItem{Name: k, Amount: v}) } } } }) // Extract store items summary - var storeItemSummary []Item + var storeItemSummary []BazaarAuctionItem ReaderHTML.Find("#StoreItemSummary").Each(func(index int, s *goquery.Selection) { for k, v := range ParseItems(s) { - storeItemSummary = append(storeItemSummary, Item{Name: k, Amount: v}) + storeItemSummary = append(storeItemSummary, BazaarAuctionItem{Name: k, Amount: v}) } totalPages := s.Find(PageLinkSelector).Size() @@ -288,7 +302,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { log.Fatal(err) } for k, v := range ParseItems(ItemPageReaderHTML.Contents()) { - storeItemSummary = append(storeItemSummary, Item{Name: k, Amount: v}) + storeItemSummary = append(storeItemSummary, BazaarAuctionItem{Name: k, Amount: v}) } } } @@ -335,10 +349,10 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract outfits - var outfits []Outfit + var outfits []BazaarAuctionOutfit ReaderHTML.Find("#Outfits").Each(func(index int, s *goquery.Selection) { for k, v := range ParseOutfits(s) { - outfits = append(outfits, Outfit{ + outfits = append(outfits, BazaarAuctionOutfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -354,7 +368,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { log.Fatal(err) } for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { - outfits = append(outfits, Outfit{ + outfits = append(outfits, BazaarAuctionOutfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -365,10 +379,10 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract store outfits - var storeOutfits []Outfit + var storeOutfits []BazaarAuctionOutfit ReaderHTML.Find("#StoreOutfits").Each(func(index int, s *goquery.Selection) { for k, v := range ParseOutfits(s) { - outfits = append(outfits, Outfit{ + outfits = append(outfits, BazaarAuctionOutfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -384,7 +398,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { log.Fatal(err) } for k, v := range ParseOutfits(OutfitsPageReaderHTML.Contents()) { - outfits = append(outfits, Outfit{ + outfits = append(outfits, BazaarAuctionOutfit{ Name: k, Addon1: v[0], Addon2: v[1], @@ -406,7 +420,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract blessings - var blessings Blessings + var blessings BazaarAuctionBlessings ReaderHTML.Find("#Blessings").Each(func(index int, s *goquery.Selection) { s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild @@ -449,7 +463,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract Charms - var charms []Charm + var charms []BazaarAuctionCharm ReaderHTML.Find("#Charms").Each(func(index int, s *goquery.Selection) { s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild @@ -457,7 +471,7 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { return } if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - charms = append(charms, Charm{ + charms = append(charms, BazaarAuctionCharm{ Cost: TibiadataStringToIntegerV3(node.FirstChild.Data), Name: node.NextSibling.FirstChild.Data, }) @@ -513,12 +527,12 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) // Extract Bestiary Progress - var bestiaryProgress []BestiaryEntry + var bestiaryProgress []BazaarAuctionBestiaryEntry ReaderHTML.Find("#BestiaryProgress").Each(func(index int, s *goquery.Selection) { s.Find(OddEvenSelector).Each(func(index int, s *goquery.Selection) { node := s.Nodes[0].FirstChild if !strings.Contains(node.Parent.Attr[0].Val, "IndicateMoreEntries") { - bestiaryProgress = append(bestiaryProgress, BestiaryEntry{ + bestiaryProgress = append(bestiaryProgress, BazaarAuctionBestiaryEntry{ Step: TibiadataStringToIntegerV3(node.FirstChild.Data), Kills: TibiadataStringToIntegerV3(strings.Split(node.NextSibling.FirstChild.Data, " x")[0]), Name: node.NextSibling.NextSibling.FirstChild.Data, @@ -527,8 +541,9 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { }) }) - jsonData := JSONData{ - Auction: Auction{ + // Build the data-blob + return BazaarAuctionResponse{ + BazaarAuction{ Id: id, Details: details, General: general, @@ -548,14 +563,11 @@ func TibiaCharbazaarAuctionV3(c *gin.Context) { Achievements: achievements, BestiaryProgress: bestiaryProgress, }, - Information: Information{ + Information{ APIVersion: TibiadataAPIversion, Timestamp: TibiadataDatetimeV3(""), }, } - - // return jsonData - TibiaDataAPIHandleSuccessResponse(c, "TibiaCharbazaarAuctionV3", jsonData) } func ParseItems(s *goquery.Selection) map[string]int { @@ -565,8 +577,10 @@ func ParseItems(s *goquery.Selection) map[string]int { itemTitle, exists := s.Attr("title") if exists { - var itemAmount int - var itemName string + var ( + itemAmount int + itemName string + ) nodes := s.Find(".ObjectAmount").First().Nodes if nodes == nil { @@ -675,13 +689,3 @@ type AjaxResponseObject struct { type AjaxJSONData struct { AjaxObjects []AjaxResponseObject `json:"AjaxObjects"` } - -const OddEvenSelector = ".Odd,.Even" -const PageLinkSelector = ".PageLink" -const CVIconSelector = ".CVIcon" -const ItemSummarySection = 0 -const StoreItemSummarySection = 1 -const MountsSection = 2 -const StoreMountsSection = 3 -const OutfitsSection = 4 -const StoreOutfitsSection = 5 diff --git a/src/webserver.go b/src/webserver.go index faf00e5d..adc5572d 100644 --- a/src/webserver.go +++ b/src/webserver.go @@ -71,6 +71,9 @@ func runWebServer() { // TibiaData API version 3 v3 := router.Group("/v3") { + // Tibia bazaar + v3.GET("/bazaar/auction/:id", tibiaBazaarAuctionV3) + // Tibia characters v3.GET("/characters/character/:character", tibiaCharactersCharacterV3) @@ -118,9 +121,6 @@ func runWebServer() { // Tibia worlds v3.GET("/worlds", tibiaWorldsOverviewV3) v3.GET("/worlds/world/:world", tibiaWorldsWorldV3) - - // TibiaBazaarAuctionV3 - v3.GET("/charbazaar/auction/:id", TibiaCharbazaarAuctionV3) } // container version details endpoint @@ -137,6 +137,33 @@ func runWebServer() { _ = router.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080") } +// Bazaar auction godoc +// @Summary Show one bazaar auction +// @Description Show all information about one bazaar auction +// @Tags bazaar +// @Accept json +// @Produce json +// @Param id path int true "The ID of auction" +// @Success 200 {object} BazaarAuctionResponse +// @Router /v3/bazaar/auction/{id} [get] +func tibiaBazaarAuctionV3(c *gin.Context) { + // getting params from URL + id := c.Param("id") + + tibiadataRequest := TibiadataRequestStruct{ + Method: resty.MethodGet, + URL: "https://www.tibia.com/charactertrade/?page=details&auctionid=" + id, + } + + tibiaDataRequestHandler( + c, + tibiadataRequest, + func(BoxContentHTML string) (interface{}, int) { + return TibiaBazaarAuctionV3Impl(BoxContentHTML), http.StatusOK + }, + "TibiaBazaarAuctionV3") +} + // Character godoc // @Summary Show one character // @Description Show all information about one character available pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy