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

344 lines
7.2 KiB
Go
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 (
"encoding/json"
"fmt"
"strings"
webspider "gordenko.dev/dima/spider"
"gordenko.dev/dima/flashscore"
)
var (
// проверка на Contains
bannedTennisChamps = []string{
"Setka Cup",
"Russia. Masters",
"Russia. League Pro",
"Daily Aqua Tour",
"UTR Pro Tennis Series",
"VS OPEN",
"Daily Pro Tour",
"Mountain Bay Open",
"Russian River Cup",
}
bannedTennisPrefixes = []string{}
)
func TennisChampFilter(champName string) (_ bool) {
for _, bannedChampName := range bannedHandballChamps {
if strings.Contains(champName, bannedChampName) {
return
}
}
for _, bannedPrefix := range bannedHandballPrefixes {
if strings.HasPrefix(champName, bannedPrefix) {
return
}
}
if flashscore.IsTennisDoublesChamp(champName) {
return
}
fmt.Printf("CHAMP NAME IS OK: %s\n", champName)
return true
}
/*
// Поля P и St - топ поля документа
// Tennis match status
// Подтверждено точно
"St": 2,
// Tennis Match Stat
// Счет по сетам
"P": [
{
"A": 7,
"CSPP": [],
"H": 5,
"T": 11,
"TI": "000000000000000000000000"
},
{
"A": 4,
"CSPP": [],
"H": 6,
"T": 12,
"TI": "000000000000000000000000"
},
{
"A": 4,
"CSPP": [],
"H": 6,
"T": 13,
"TI": "000000000000000000000000"
},
{
"A": 6,
"CSPP": [],
"H": 4,
"T": 14,
"TI": "000000000000000000000000"
},
{
"A": 6,
"CSPP": [],
"H": 2,
"T": 15,
"TI": "000000000000000000000000"
}
],
*/
type matchResult struct {
Periods []periodResult `json:"P"`
Status int `json:"St"`
}
// Можно добавить поле T (код сета) для контроля.
// Коды сетов: 1й - 11, 2й - 12, 3й - 13, 4й - 14, 5й - 15
type periodResult struct {
Code int `json:"T"`
HomePoints int `json:"H"`
AwayPoints int `json:"A"`
}
// Для футбола и гандбола
var periodCode2PeriodNumberMapping = map[int]int{
1: 1,
3: 2,
}
var setCode2SetNumberMapping = map[int]int{
11: 1,
12: 2,
13: 3,
14: 4,
15: 5,
}
func GetTennisMatchResult(statsMatchID string) (result TeamMatchResult, err error) {
url := fmt.Sprintf(matchStatsURLPattern, statsMatchID)
spider, err := webspider.NewSpider(nil)
if err != nil {
panic(err)
}
buf, err := spider.Get(url, nil)
if err != nil {
return
}
//fmt.Printf("%s\n", buf)
var tmp matchResult
err = json.Unmarshal(buf, &tmp)
if err != nil {
return
}
result.Status = tmp.Status
result.ScoreByPeriods = make(map[int]PeriodScore)
for _, set := range tmp.Periods {
setNumber := setCode2SetNumberMapping[set.Code]
if setNumber == 0 {
continue
}
result.ScoreByPeriods[setNumber] = PeriodScore{
HomePoints: set.HomePoints,
AwayPoints: set.AwayPoints,
}
}
return
}
///////////
// Все структуры с маленькой буквы - это служебные структуры для парсинга
// служебная структура для парсинга данных live матча
type tennisLiveMatchDataEnvelope struct {
Error string
ErrorCode int64
Success bool // false, если матч закончен
Value tennisLiveMatchData
}
// поле BIG со списком matchID для других периодов встречается в JSON документах
// других периодов. То есть если запросить данные для 2-го сета по специальному ID,
// то в поле BIG будет список ID. Если же запросить документ для Regular Time, то
// поля BIG не будет, а будет SG (с коэффициентами для других периодов)
type tennisLiveMatchData struct {
Markets []rawMarket `json:"GE"` // рынки
// текущий счет, в том числе по геймам (только в Regular Time документе)
Stats statAndScore `json:"SC"`
Sets []tennisSet `json:"SG"`
StatsMatchID string `json:"SGI"`
}
type tennisSet struct {
SetNumber int `json:"P"`
Markets []rawMarket `json:"GE"`
}
/*
type tennisStatsAndScore struct {
CurrentSetNumber int `json:"CP"`
SetScore scoreStruct `json:"FS"` // счет по сетам
GameScore []periodScore `json:"PS"`
}
*/
type statAndScore struct {
Score scoreStruct `json:"FS"`
ScoreByPeriods []periodScore `json:"PS"`
CurrentPeriod int `json:"CP"`
}
// public
func LoadTennisLiveMatchData(matchID string) (_ TeamLiveMatchData, isMatchFinished bool, err error) {
url := fmt.Sprintf(liveMatchURLPattern, matchID)
spider, err := webspider.NewSpider(nil)
if err != nil {
panic(err)
}
buf, err := spider.Get(url, nil)
if err != nil {
return
}
//fmt.Printf("buf: %s\n\n", buf)
var env tennisLiveMatchDataEnvelope
err = json.Unmarshal(buf, &env)
if err != nil {
err = fmt.Errorf("json.Unmarshal liveMatchDataEnvelope: %s", err)
return
}
if !env.Success {
isMatchFinished = true
return
}
data := TeamLiveMatchData{
MatchID: matchID,
ScoreByPeriods: make(map[int]Score),
Periods: make(map[int]Period),
}
// FULL TIME
for _, market := range env.Value.Markets {
switch market.MarketType {
case tennisMarketWinner:
winner := &Winner2Way{}
for _, offers := range market.OffersList {
if len(offers) > 0 {
offer := offers[0]
if offer.IsBlocked {
continue
}
if offer.Side == 1 {
// T=1
winner.HasHome = true
winner.Home = offer.Price
} else if offer.Side == 3 {
// T=3
winner.HasAway = true
winner.Away = offer.Price
}
}
}
data.Winner2Way = winner
case tennisMarketTotal:
data.Total, err = getTotal(market)
if err != nil {
err = fmt.Errorf("FT getTotal (tennis): %s", err)
return
}
case tennisMarketHandicap:
data.Handicap, err = getHandicap(market)
if err != nil {
err = fmt.Errorf("FT getHandicap (tennis): %s", err)
return
}
}
}
// BY SETS
for _, p := range env.Value.Sets {
set := Period{
PeriodNumber: p.SetNumber,
}
for _, market := range p.Markets {
switch market.MarketType {
case tennisMarketTotal:
set.Total, err = getTotal(market)
if err != nil {
err = fmt.Errorf("SET %d getTotal (tennis): %s", p.SetNumber, err)
return
}
case tennisMarketHandicap:
set.Handicap, err = getHandicap(market)
if err != nil {
err = fmt.Errorf("SET %d getHandicap (tennis): %s", p.SetNumber, err)
return
}
}
}
data.Periods[p.SetNumber] = set
}
// SCORE
stat := env.Value.Stats
if stat.CurrentPeriod == 0 {
// ВАЖНО!
// Если период не указан - поля нет в JSON, счета нет
err = fmt.Errorf("Current score not found")
return
}
data.CurrentPeriod = stat.CurrentPeriod
data.Score.Home = stat.Score.HomeScore
data.Score.Away = stat.Score.AwayScore
for _, p := range stat.ScoreByPeriods {
data.ScoreByPeriods[p.Period] = Score{
Home: p.Score.HomeScore,
Away: p.Score.AwayScore,
}
}
//fmt.Printf("%s\n\n", buf)
return data, false, nil
}