/
getResults.ts
147 lines (127 loc) · 4.04 KB
/
getResults.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { stringify } from 'querystring'
import { HLTVConfig } from '../config'
import { HLTVPage, HLTVScraper } from '../scraper'
import { BestOfFilter } from '../shared/BestOfFilter'
import { fromMapSlug, GameMap, toMapFilter } from '../shared/GameMap'
import { RankingFilter } from '../shared/RankingFilter'
import { fetchPage, getIdAt, notNull, sleep } from '../utils'
export enum ResultsMatchType {
LAN = 'Lan',
Online = 'Online'
}
export enum ContentFilter {
HasHighlights = 'highlights',
HasDemo = 'demo',
HadVOD = 'vod',
HasStats = 'stats'
}
export enum GameType {
CSGO = 'CSGO',
CS16 = 'CS16'
}
export interface ResultTeam {
name: string
logo: string
}
export interface FullMatchResult {
id: number
date: number
team1: ResultTeam
team2: ResultTeam
stars: number
format: string
map?: GameMap
result: {
team1: number
team2: number
}
}
export interface GetResultsArguments {
startDate?: string
endDate?: string
matchType?: ResultsMatchType
maps?: GameMap[]
bestOfX?: BestOfFilter
countries?: string[]
contentFilters?: ContentFilter[]
eventIds?: number[]
playerIds?: number[]
teamIds?: number[]
game?: GameType
stars?: 1 | 2 | 3 | 4 | 5
delayBetweenPageRequests?: number
}
export const getResults =
(config: HLTVConfig) =>
async (options: GetResultsArguments): Promise<FullMatchResult[]> => {
const query = stringify({
...(options.startDate ? { startDate: options.startDate } : {}),
...(options.endDate ? { endDate: options.endDate } : {}),
...(options.matchType ? { matchType: options.matchType } : {}),
...(options.maps ? { map: options.maps.map(toMapFilter) } : {}),
...(options.bestOfX ? { bestOfX: options.bestOfX } : {}),
...(options.countries ? { country: options.countries } : {}),
...(options.contentFilters ? { content: options.contentFilters } : {}),
...(options.eventIds ? { event: options.eventIds } : {}),
...(options.playerIds ? { player: options.playerIds } : {}),
...(options.teamIds ? { team: options.teamIds } : {}),
...(options.game ? { gameType: options.game } : {}),
...(options.stars ? { stars: options.stars } : {})
})
let page = 0
let $: HLTVPage
let results: FullMatchResult[] = []
do {
await sleep(options.delayBetweenPageRequests ?? 0)
$ = HLTVScraper(
await fetchPage(
`https://www.hltv.org/results?${query}&offset=${page * 100}`,
config.loadPage
)
)
page++
let featuredResults = $('.big-results .result-con')
.toArray()
.map((el) => el.children().first().attrThen('href', getIdAt(2)))
results.push(
...$('.result-con')
.toArray()
.map((el) => {
const id = el.children().first().attrThen('href', getIdAt(2))!
if (featuredResults.includes(id)) {
featuredResults = featuredResults.filter((x) => x !== id)
return null
}
const stars = el.find('.stars i').length
const date = el.numFromAttr('data-zonedgrouping-entry-unix')!
const format = el.find('.map-text').text()
const team1 = {
name: el.find('div.team').first().text(),
logo: el.find('img.team-logo').first().attr('src')
}
const team2 = {
name: el.find('div.team').last().text(),
logo: el.find('img.team-logo').last().attr('src')
}
const [team1Result, team2Result] = el
.find('.result-score')
.text()
.split(' - ')
.map(Number)
return {
id,
stars,
date,
team1,
team2,
result: { team1: team1Result, team2: team2Result },
...(format.includes('bo')
? { format }
: { map: fromMapSlug(format), format: 'bo1' })
}
})
.filter(notNull)
)
} while ($('.result-con').exists())
return results
}