This commit is contained in:
2026-07-21 03:55:57 +03:00
commit 15b428efec
39 changed files with 136724 additions and 0 deletions

343
tennis.go Normal file
View File

@@ -0,0 +1,343 @@
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
}