Files
onexbet/parser.go
2026-07-21 03:55:57 +03:00

249 lines
6.7 KiB
Go
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package onexbet
import (
"fmt"
"strings"
)
type organizer struct {
Name string `json:"name"`
Sport string `json:"sport"`
}
type teamName struct {
Name string `json:"name"`
}
// служебная структура для парсинга списка live матчей
type liveMatch struct {
StartDate string `json:"startDate"`
URL string `json:"url"`
Organizer organizer `json:"organizer"`
HomeTeam teamName `json:"homeTeam"`
AwayTeam teamName `json:"awayTeam"`
}
// служебная структура для статистики: удары, угловые, атаки...
type keyValue struct {
Key string
Value string
}
// служебная структура для коэффициентов/параметров
type rawMarket struct {
OffersList [][]rawOffer `json:"E"` // Массив массивов!
MarketType int `json:"G"`
}
type rawOffer struct {
Price float64 `json:"C"`
Param float64 `json:"P"` // 2.5
Side int `json:"T"` // 1 X 2, over/under
IsBlocked bool `json:"B"` // означает что цена заблокирована (иконка замка)
}
func getMatchIDFromURL(url string) string {
// формат ссылки live/Football/2084034-FIFA-20-Italian-Cup/240767941-Fiorentina-Paulo-Milan-Arta/
// matchID - 240767941
// Алгоритм:
// - разбиваем ссылки на секции по символу '/'
// - разбиваем последнюю НЕпустую секцию на части по символу '-'
// - первый элемент и будет matchID
url = strings.TrimSpace(url)
url = strings.TrimSuffix(url, "/")
sections := strings.Split(url, "/")
last := sections[len(sections)-1]
parts := strings.Split(last, "-")
return parts[0]
}
type rawMatchCandidate struct {
Sport string `json:"SN"`
ChampName string `json:"L"`
Home string `json:"O1"`
Away string `json:"O2"`
StartTime int64 `json:"S"`
MatchID string `json:"SGI"`
}
// служебная структура для парсинга данных live матча
type searchResponse struct {
Error string
ErrorCode int64
Success bool // false, если матч закончен
Value []rawMatchCandidate
}
// Список live матчей
/*
Live матч. Коэффициенты и т.д.
https://1x-bet-ua.com/LiveFeed/GetGameZip?id=240704765&lng=en&cfview=0&isSubGames=true&GroupEvents=true&allEventsGroupSubGames=true&countevents=250&partner=25&marketType=1
Live матч завершен. Ответ:
{"Error":null,"ErrorCode":0,"Guid":"","Id":0,"Success":false,"Value":null}
<a href="live/Football/2084034-FIFA-20-Italian-Cup/240767941-Fiorentina-Paulo-Milan-Arta/" class="c-events__name">
*/
// https://ua-1x-bet.com/en/live/Football/88637-England-Premier-League/242638344-Leicester-City-Brighton--Hove-Albion/
type liveItem struct {
SportName string `json:"SN"`
Home string `json:"O1"`
Away string `json:"O2"`
MatchID int64 `json:"I"`
StartTime int64 `json:"S"`
ChampName string `json:"L"` // вместе с зоной
ZoneName string `json:"CN"`
StatsMatchID string `json:"SGI"` // вида 5d02144c286ef2e7bff3015b
Stat statAndScore `json:"SC"`
}
type liveList struct {
Success bool
Value []liveItem
}
func getTotal(market rawMarket) (_ Total, err error) {
if len(market.OffersList) != 2 {
err = fmt.Errorf("Total market must have 2 arrays of offers (Over and Under), not %d", len(market.OffersList))
return
}
// OVER
var over []ParamOffer
for _, offer := range market.OffersList[0] {
if offer.IsBlocked {
continue
}
over = append(over, ParamOffer{
Price: offer.Price,
Param: fmt.Sprintf("%.1f", offer.Param),
ParamFloat: offer.Param,
})
}
// UNDER
var under []ParamOffer
for _, offer := range market.OffersList[1] {
if offer.IsBlocked {
continue
}
under = append(under, ParamOffer{
Price: offer.Price,
Param: fmt.Sprintf("%.1f", offer.Param),
ParamFloat: offer.Param,
})
}
return Total{
Over: over,
Under: under,
}, nil
}
func getHandicap(market rawMarket) (_ Handicap, err error) {
if len(market.OffersList) != 2 {
err = fmt.Errorf("Handicap market must have 2 arrays of offers (Home and Away), not %d", len(market.OffersList))
return
}
// home
var home []ParamOffer
for _, offer := range market.OffersList[0] {
if offer.IsBlocked {
continue
}
home = append(home, ParamOffer{
Price: offer.Price,
Param: fmt.Sprintf("%.1f", offer.Param),
ParamFloat: offer.Param,
})
}
// away
var away []ParamOffer
for _, offer := range market.OffersList[1] {
if offer.IsBlocked {
continue
}
away = append(away, ParamOffer{
Price: offer.Price,
Param: fmt.Sprintf("%.1f", offer.Param),
ParamFloat: offer.Param,
})
}
return Handicap{
Home: home,
Away: away,
}, nil
}
/// live match data
// служебная структура для парсинга данных live матча
type teamLiveMatchDataEnvelope struct {
Error string
ErrorCode int64
Success bool // false, если матч закончен
Value teamLiveMatchData
}
// half 1, half 2
type teamSG struct {
SubMatchID int `json:"I"`
Period int `json:"P"`
PeriodName string `json:"PN"`
// Опциональное поле (у тенниса нет)
SubCategory string `json:"TG"` // yellow cards, etc...
// В "Austria. Erste Liga" у матчей half 1 кодируется в нижеуказанных полях
// Требует уточнения.
// EC int
// EGC int
// GE []rawMarket
}
type teamLiveMatchData struct {
// список subMatchID для half 1, half 2...
// поле есть до лайва вместо SG?
BIG []teamSG
GE []rawMarket // рынки
// периоды и голы; текущее время матча; статистика по ударам, атакам...
SC teamStatsAndScore
// список subMatchID для half 1, half 2...
// коэффициенты можно получить отдельным HTTP-запросом
SG []teamSG
//StatsMatchID string `json:""SGI`
}
type teamStatsAndScore struct {
CurrentPeriod int `json:"CP"`
FullTimeScore scoreStruct `json:"FS"`
ScoreByPeriods []periodScore `json:"PS"`
CurrentTime int `json:"TS"` // в секундах с начала матча!
Stats []keyValue `json:"S"` // статистика удары, угловые, атаки и т.д.
}
type scoreStruct struct {
HomeScore int `json:"S1"`
AwayScore int `json:"S2"`
}
type periodScore struct {
Period int `json:"Key"`
Score scoreStruct `json:"Value"`
}