Skip to content

Commit 01ad977

Browse files
authored
fix highscores by implementing pagination (#164)
1 parent 8677cf2 commit 01ad977

File tree

5 files changed

+157
-135
lines changed

5 files changed

+157
-135
lines changed

src/TibiaHighscoresV3.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,37 @@ type Highscore struct {
1919
Title string `json:"title,omitempty"` // Title column (when category: loyalty)
2020
}
2121

22+
// Child of Highscore
23+
type HighscorePage struct {
24+
CurrentPage int `json:"current_page"` // Current page
25+
TotalPages int `json:"total_pages"` // Total page count
26+
TotalHighscores int `json:"total_records"` // Total highscore records
27+
}
28+
2229
// Child of JSONData
2330
type Highscores struct {
24-
World string `json:"world"`
25-
Category string `json:"category"`
26-
Vocation string `json:"vocation"`
27-
HighscoreAge int `json:"highscore_age"`
28-
HighscoreList []Highscore `json:"highscore_list"`
31+
World string `json:"world"`
32+
Category string `json:"category"`
33+
Vocation string `json:"vocation"`
34+
HighscoreAge int `json:"highscore_age"`
35+
HighscoreList []Highscore `json:"highscore_list"`
36+
HighscorePage HighscorePage `json:"highscore_page"`
2937
}
3038

31-
//
3239
// The base includes two levels: Highscores and Information
3340
type HighscoresResponse struct {
3441
Highscores Highscores `json:"highscores"`
3542
Information Information `json:"information"`
3643
}
3744

3845
var (
39-
HighscoresAgeRegex = regexp.MustCompile(`.*<div class="Text">Highscores.*Last Update: ([0-9]+) minutes ago.*`)
40-
SevenColumnRegex = regexp.MustCompile(`<td>.*<\/td><td.*">(.*)<\/a><\/td><td.*>(.*)<\/td><td.*>(.*)<\/td><td>(.*)<\/td><td.*>(.*)<\/td><td.*>(.*)<\/td>`)
41-
SixColumnRegex = regexp.MustCompile(`<td>.*<\/td><td.*">(.*)<\/a><\/td><td.*">(.*)<\/td><td>(.*)<\/td><td.*>(.*)<\/td><td.*>(.*)<\/td>`)
46+
HighscoresAgeRegex = regexp.MustCompile(`.*<div class="Text">Highscores.*Last Update: ([0-9]+) minutes ago.*`)
47+
HighscoresPageRegex = regexp.MustCompile(`.*<b>\&raquo; Pages:\ ?(.*)<\/b>.*<b>\&raquo; Results:\ ?([0-9,]+)<\/b>.*`)
48+
SevenColumnRegex = regexp.MustCompile(`<td>(.*)<\/td><td.*">(.*)<\/a><\/td><td.*>(.*)<\/td><td.*>(.*)<\/td><td>(.*)<\/td><td.*>(.*)<\/td><td.*>(.*)<\/td>`)
49+
SixColumnRegex = regexp.MustCompile(`<td>(.*)<\/td><td.*">(.*)<\/a><\/td><td.*">(.*)<\/td><td>(.*)<\/td><td.*>(.*)<\/td><td.*>(.*)<\/td>`)
4250
)
4351

44-
func TibiaHighscoresV3Impl(world string, category HighscoreCategory, vocationName string, BoxContentHTML string) HighscoresResponse {
52+
func TibiaHighscoresV3Impl(world string, category HighscoreCategory, vocationName string, currentPage int, BoxContentHTML string) HighscoresResponse {
4553
// Loading HTML data into ReaderHTML for goquery with NewReader
4654
ReaderHTML, err := goquery.NewDocumentFromReader(strings.NewReader(BoxContentHTML))
4755
if err != nil {
@@ -50,18 +58,24 @@ func TibiaHighscoresV3Impl(world string, category HighscoreCategory, vocationNam
5058

5159
// Creating empty HighscoreData var
5260
var (
53-
HighscoreData []Highscore
54-
HighscoreDataVocation, HighscoreDataWorld, HighscoreDataTitle string
55-
HighscoreDataRank, HighscoreDataLevel, HighscoreDataValue, HighscoreAge int
61+
HighscoreData []Highscore
62+
HighscoreDataVocation, HighscoreDataWorld, HighscoreDataTitle string
63+
HighscoreDataRank, HighscoreDataLevel, HighscoreDataValue, HighscoreAge, HighscoreTotalPages, HighscoreTotalHighscores int
5664
)
5765

5866
// getting age of data
5967
subma1 := HighscoresAgeRegex.FindAllStringSubmatch(string(BoxContentHTML), 1)
60-
6168
if len(subma1) > 0 {
6269
HighscoreAge = TibiaDataStringToIntegerV3(subma1[0][1])
6370
}
6471

72+
// getting amount of pages
73+
subma1 = HighscoresPageRegex.FindAllStringSubmatch(string(BoxContentHTML), 1)
74+
if len(subma1) > 0 {
75+
HighscoreTotalPages = strings.Count(subma1[0][1], "class=\"PageLink")
76+
HighscoreTotalHighscores = TibiaDataStringToIntegerV3(subma1[0][2])
77+
}
78+
6579
// Running query over each div
6680
ReaderHTML.Find(".TableContent tr").First().NextAll().Each(func(index int, s *goquery.Selection) {
6781

@@ -101,23 +115,23 @@ func TibiaHighscoresV3Impl(world string, category HighscoreCategory, vocationNam
101115

102116
if len(subma1) > 0 {
103117

104-
HighscoreDataRank++
118+
HighscoreDataRank = TibiaDataStringToIntegerV3(subma1[0][1])
105119
if category == loyaltypoints {
106-
HighscoreDataTitle = subma1[0][2]
120+
HighscoreDataTitle = subma1[0][3]
121+
HighscoreDataVocation = subma1[0][4]
122+
HighscoreDataWorld = subma1[0][5]
123+
HighscoreDataLevel = TibiaDataStringToIntegerV3(subma1[0][6])
124+
HighscoreDataValue = TibiaDataStringToIntegerV3(subma1[0][7])
125+
} else {
107126
HighscoreDataVocation = subma1[0][3]
108127
HighscoreDataWorld = subma1[0][4]
109128
HighscoreDataLevel = TibiaDataStringToIntegerV3(subma1[0][5])
110129
HighscoreDataValue = TibiaDataStringToIntegerV3(subma1[0][6])
111-
} else {
112-
HighscoreDataVocation = subma1[0][2]
113-
HighscoreDataWorld = subma1[0][3]
114-
HighscoreDataLevel = TibiaDataStringToIntegerV3(subma1[0][4])
115-
HighscoreDataValue = TibiaDataStringToIntegerV3(subma1[0][5])
116130
}
117131

118132
HighscoreData = append(HighscoreData, Highscore{
119133
Rank: HighscoreDataRank,
120-
Name: TibiaDataSanitizeEscapedString(subma1[0][1]),
134+
Name: TibiaDataSanitizeEscapedString(subma1[0][2]),
121135
Vocation: HighscoreDataVocation,
122136
World: HighscoreDataWorld,
123137
Level: HighscoreDataLevel,
@@ -139,6 +153,11 @@ func TibiaHighscoresV3Impl(world string, category HighscoreCategory, vocationNam
139153
Vocation: vocationName,
140154
HighscoreAge: HighscoreAge,
141155
HighscoreList: HighscoreData,
156+
HighscorePage: HighscorePage{
157+
CurrentPage: currentPage,
158+
TotalPages: HighscoreTotalPages,
159+
TotalHighscores: HighscoreTotalHighscores,
160+
},
142161
},
143162
Information{
144163
APIVersion: TibiaDataAPIversion,

src/TibiaHighscoresV3_test.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,36 @@ func TestHighscoresAll(t *testing.T) {
1414
return
1515
}
1616

17-
highscoresJson := TibiaHighscoresV3Impl("", experience, "all", string(data))
17+
highscoresJson := TibiaHighscoresV3Impl("", experience, "all", 1, string(data))
1818
assert := assert.New(t)
1919

2020
assert.Equal("", highscoresJson.Highscores.World)
2121
assert.Equal("experience", highscoresJson.Highscores.Category)
2222
assert.Equal("all", highscoresJson.Highscores.Vocation)
23-
assert.Equal(30, highscoresJson.Highscores.HighscoreAge)
23+
assert.Equal(12, highscoresJson.Highscores.HighscoreAge)
2424

2525
assert.Equal(50, len(highscoresJson.Highscores.HighscoreList))
2626

27+
assert.Equal(1, highscoresJson.Highscores.HighscorePage.CurrentPage)
28+
assert.Equal(20, highscoresJson.Highscores.HighscorePage.TotalPages)
29+
assert.Equal(1000, highscoresJson.Highscores.HighscorePage.TotalHighscores)
30+
2731
firstHighscore := highscoresJson.Highscores.HighscoreList[0]
2832
assert.Equal(1, firstHighscore.Rank)
29-
assert.Equal("Bobeek", firstHighscore.Name)
30-
assert.Equal("Elder Druid", firstHighscore.Vocation)
33+
assert.Equal("Goraca", firstHighscore.Name)
34+
assert.Equal("Master Sorcerer", firstHighscore.Vocation)
3135
assert.Equal("Bona", firstHighscore.World)
32-
assert.Equal(2015, firstHighscore.Level)
33-
assert.Equal(136026206904, firstHighscore.Value)
36+
assert.Equal(2197, firstHighscore.Level)
37+
assert.Equal(176271164607, firstHighscore.Value)
3438
assert.Equal("", firstHighscore.Title)
3539

3640
lastHighscore := highscoresJson.Highscores.HighscoreList[49]
3741
assert.Equal(50, lastHighscore.Rank)
38-
assert.Equal("Kewhyx Mythus", lastHighscore.Name)
39-
assert.Equal("Royal Paladin", lastHighscore.Vocation)
40-
assert.Equal("Celebra", lastHighscore.World)
41-
assert.Equal(1575, lastHighscore.Level)
42-
assert.Equal(64869293274, lastHighscore.Value)
42+
assert.Equal("Wujo Daro", lastHighscore.Name)
43+
assert.Equal("Elite Knight", lastHighscore.Vocation)
44+
assert.Equal("Refugia", lastHighscore.World)
45+
assert.Equal(1701, lastHighscore.Level)
46+
assert.Equal(81816135617, lastHighscore.Value)
4347
assert.Equal("", lastHighscore.Title)
4448
}
4549

@@ -50,14 +54,13 @@ func TestHighscoresLoyalty(t *testing.T) {
5054
return
5155
}
5256

53-
highscoresJson := TibiaHighscoresV3Impl("Vunira", loyaltypoints, "druids", string(data))
57+
highscoresJson := TibiaHighscoresV3Impl("Vunira", loyaltypoints, "druids", 4, string(data))
5458
assert := assert.New(t)
5559

5660
assert.Equal("Vunira", highscoresJson.Highscores.World)
5761
assert.Equal("loyaltypoints", highscoresJson.Highscores.Category)
5862
assert.Equal("druids", highscoresJson.Highscores.Vocation)
59-
assert.Equal(46, highscoresJson.Highscores.HighscoreAge)
63+
assert.Equal(12, highscoresJson.Highscores.HighscoreAge)
6064

61-
// should be 50, but for some reason it can't get entries from the list..
62-
assert.Equal(0, len(highscoresJson.Highscores.HighscoreList))
65+
assert.Equal(50, len(highscoresJson.Highscores.HighscoreList))
6366
}

src/webserver.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,13 @@ func runWebServer() {
103103

104104
// Tibia highscores
105105
v3.GET("/highscores/:world", func(c *gin.Context) {
106-
c.Redirect(http.StatusMovedPermanently, v3.BasePath()+"/highscores/"+c.Param("world")+"/experience/"+TibiaDataDefaultVoc)
106+
c.Redirect(http.StatusMovedPermanently, v3.BasePath()+"/highscores/"+c.Param("world")+"/experience/"+TibiaDataDefaultVoc+"/1")
107107
})
108108
v3.GET("/highscores/:world/:category", func(c *gin.Context) {
109-
c.Redirect(http.StatusMovedPermanently, v3.BasePath()+"/highscores/"+c.Param("world")+"/"+c.Param("category")+"/"+TibiaDataDefaultVoc)
109+
c.Redirect(http.StatusMovedPermanently, v3.BasePath()+"/highscores/"+c.Param("world")+"/"+c.Param("category")+"/"+TibiaDataDefaultVoc+"/1")
110110
})
111111
v3.GET("/highscores/:world/:category/:vocation", tibiaHighscoresV3)
112+
v3.GET("/highscores/:world/:category/:vocation/:page", tibiaHighscoresV3)
112113

113114
// Tibia houses
114115
v3.GET("/house/:world/:house_id", tibiaHousesHouseV3)
@@ -361,13 +362,15 @@ func tibiaGuildsOverviewV3(c *gin.Context) {
361362
// @Param world path string true "The world" default(all) extensions(x-example=Antica)
362363
// @Param category path string true "The category" default(experience) Enums(achievements, axefighting, charmpoints, clubfighting, distancefighting, experience, fishing, fistfighting, goshnarstaint, loyaltypoints, magiclevel, shielding, swordfighting, dromescore, bosspoints) extensions(x-example=fishing)
363364
// @Param vocation path string true "The vocation" default(all) Enums(all, knights, paladins, sorcerers, druids) extensions(x-example=knights)
365+
// @Param page path int true "The current page" default(1) minimum(1) maximum(20 extensions(x-example=1)
364366
// @Success 200 {object} HighscoresResponse
365-
// @Router /v3/highscores/{world}/{category}/{vocation} [get]
367+
// @Router /v3/highscores/{world}/{category}/{vocation}/{page} [get]
366368
func tibiaHighscoresV3(c *gin.Context) {
367369
// getting params from URL
368370
world := c.Param("world")
369371
category := c.Param("category")
370372
vocation := c.Param("vocation")
373+
page := c.Param("page")
371374

372375
// maybe return error on faulty vocation value?!
373376

@@ -383,16 +386,25 @@ func tibiaHighscoresV3(c *gin.Context) {
383386
// Sanitize of vocation input
384387
vocationName, vocationid := TibiaDataVocationValidator(vocation)
385388

389+
// checking the page provided
390+
if page == "" {
391+
page = "1"
392+
}
393+
if TibiaDataStringToIntegerV3(page) < 1 || TibiaDataStringToIntegerV3(page) > 21 {
394+
TibiaDataAPIHandleResponse(c, http.StatusBadRequest, "TibiaHighscoresV3", gin.H{"error": "page needs to be from 1 to 20"})
395+
return
396+
}
397+
386398
tibiadataRequest := TibiaDataRequestStruct{
387399
Method: resty.MethodGet,
388-
URL: "https://www.tibia.com/community/?subtopic=highscores&world=" + TibiaDataQueryEscapeStringV3(world) + "&category=" + strconv.Itoa(int(highscoreCategory)) + "&profession=" + TibiaDataQueryEscapeStringV3(vocationid) + "&currentpage=400000000000000",
400+
URL: "https://www.tibia.com/community/?subtopic=highscores&world=" + TibiaDataQueryEscapeStringV3(world) + "&category=" + strconv.Itoa(int(highscoreCategory)) + "&profession=" + TibiaDataQueryEscapeStringV3(vocationid) + "&currentpage=" + TibiaDataQueryEscapeStringV3(page),
389401
}
390402

391403
tibiaDataRequestHandler(
392404
c,
393405
tibiadataRequest,
394406
func(BoxContentHTML string) (interface{}, int) {
395-
return TibiaHighscoresV3Impl(world, highscoreCategory, vocationName, BoxContentHTML), http.StatusOK
407+
return TibiaHighscoresV3Impl(world, highscoreCategory, vocationName, TibiaDataStringToIntegerV3(page), BoxContentHTML), http.StatusOK
396408
},
397409
"TibiaHighscoresV3")
398410
}
@@ -439,7 +451,7 @@ func tibiaHousesHouseV3(c *gin.Context) {
439451
// @Param town path string true "The town to show" extensions(x-example=Venore)
440452
// @Success 200 {object} HousesOverviewResponse
441453
// @Router /v3/houses/{world}/{town} [get]
442-
//TODO: This API needs to be refactored somehow to use tibiaDataRequestHandler
454+
// TODO: This API needs to be refactored somehow to use tibiaDataRequestHandler
443455
func tibiaHousesOverviewV3(c *gin.Context) {
444456
// getting params from URL
445457
world := c.Param("world")

0 commit comments

Comments
 (0)