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

475
team.go Normal file
View File

@@ -0,0 +1,475 @@
package onexbet
import (
"encoding/json"
"fmt"
"strconv"
"strings"
webspider "gordenko.dev/dima/spider"
)
// ListLiveMatchesBySport - букмекер возвращает много мусора, типа киберспорта, поэтому метод
// champFilter фильтрует разный мусор
func ListLiveMatchesBySport(sportID OnexbetSport) (list []LiveMatch, err error) {
url := fmt.Sprintf(liveSportURLPattern, sportID)
spider, err := webspider.NewSpider(nil)
if err != nil {
panic(err)
}
buf, err := spider.Get(url, nil)
if err != nil {
return
}
var rawList liveList
err = json.Unmarshal(buf, &rawList)
if err != nil {
return
}
var champFilter func(string) bool
switch sportID {
case Football:
champFilter = FootballChampFilter
case Handball:
champFilter = HandballChampFilter
case Tennis:
champFilter = TennisChampFilter
}
for _, m := range rawList.Value {
m.ChampName = strings.TrimSpace(m.ChampName)
if champFilter != nil {
if !champFilter(m.ChampName) {
continue
}
}
scoreByPeriods := make(map[int]Score)
stat := m.Stat
for _, p := range stat.ScoreByPeriods {
scoreByPeriods[p.Period] = Score{
Home: p.Score.HomeScore,
Away: p.Score.AwayScore,
}
}
list = append(list, LiveMatch{
MatchID: fmt.Sprintf("%d", m.MatchID),
Home: m.Home,
Away: m.Away,
StartTime: m.StartTime,
ChampName: m.ChampName,
SportName: m.SportName,
StatsMatchID: m.StatsMatchID,
CurrentPeriod: stat.CurrentPeriod,
Score: Score{
Home: stat.Score.HomeScore,
Away: stat.Score.AwayScore,
},
ScoreByPeriods: scoreByPeriods,
})
}
return
}
func LoadTeamLiveMatchData(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 teamLiveMatchDataEnvelope
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,
}
// FULL TIME
for _, market := range env.Value.GE {
switch market.MarketType {
case teamMarketWinner3Way:
if len(market.OffersList) != 3 {
// ВАЖНО!
// Встречается такая херня, что принимают ставки только на 1 или 2 исхода.
fmt.Printf("1x2 market must have 3 arrays of offers (1, x, 2), not %d", len(market.OffersList))
break
}
// [
// {
// "C": 1.48,
// "G": 1,
// "T": 1 // 1
// }
// ],
// [
// {
// "C": 6.11,
// "G": 1,
// "T": 2 // DRAW
// }
// ],
// [
// {
// "C": 4.38,
// "G": 1,
// "T": 3 // 2
// }
// ]
winner := &Winner3Way{}
homeList := market.OffersList[0]
if len(homeList) == 1 {
winner.Home = homeList[0].Price
}
drawList := market.OffersList[1]
if len(drawList) == 1 {
winner.Draw = drawList[0].Price
}
awayList := market.OffersList[2]
if len(awayList) == 1 {
winner.Away = awayList[0].Price
}
data.Winner = winner
case teamMarketTotal:
data.Total, err = getTotal(market)
if err != nil {
err = fmt.Errorf("Full Time total football getTotal: %s", err)
return
}
case teamMarketIndividualTotal1:
data.IndividualTotalHome, err = getTotal(market)
if err != nil {
err = fmt.Errorf("Full Time individual total 1 football getTotal: %s", err)
return
}
case teamMarketIndividualTotal2:
data.IndividualTotalAway, err = getTotal(market)
if err != nil {
err = fmt.Errorf("Full Time individual total 2 football getTotal: %s", err)
return
}
}
}
// Статистика
stats := env.Value.SC
// Текущее время матча в секундах
data.CurrentTime = stats.CurrentTime
data.HomeGoals = stats.FullTimeScore.HomeScore
data.AwayGoals = stats.FullTimeScore.AwayScore
for _, pair := range stats.Stats {
switch pair.Key {
case "Attacks1":
data.HomeAttacks, _ = strconv.Atoi(pair.Value)
case "Attacks2":
data.AwayAttacks, _ = strconv.Atoi(pair.Value)
case "DanAttacks1":
data.HomeDangerousAttacks, _ = strconv.Atoi(pair.Value)
case "DanAttacks2":
data.AwayDangerousAttacks, _ = strconv.Atoi(pair.Value)
case "ShotsOn1":
data.HomeShotsOnTarget, _ = strconv.Atoi(pair.Value)
case "ShotsOn2":
data.AwayShotsOnTarget, _ = strconv.Atoi(pair.Value)
case "ShotsOff1":
data.HomeShotsOffTarget, _ = strconv.Atoi(pair.Value)
case "ShotsOff2":
data.AwayShotsOffTarget, _ = strconv.Atoi(pair.Value)
}
}
// SubMatchID первого и второго тайма
//type teamSubMatchIDs struct {
// H1 string
// H2 string
//}
var h1MatchID string
//var h2MatchID string
//var subMatchIDs teamSubMatchIDs
if len(env.Value.BIG) > 0 {
//fmt.Printf("\n\nBIG: %v\n\n", env.Value.BIG)
// Парсим 1st HALF
for _, item := range env.Value.BIG {
period := strings.ToLower(strings.TrimSpace(item.PeriodName))
switch period {
case "1 half":
if item.SubCategory == "" {
h1MatchID = strconv.Itoa(item.SubMatchID)
}
//case "2 half":
// if item.SubCategory == "" {
// h2MatchID = strconv.Itoa(item.SubMatchID)
// }
}
}
} else {
//fmt.Printf("\n\nSG: %v\n\n", env.Value.SG)
// Парсим 1st HALF
for _, item := range env.Value.SG {
period := strings.ToLower(strings.TrimSpace(item.PeriodName))
switch period {
case "1 half":
if item.SubCategory == "" {
h1MatchID = strconv.Itoa(item.SubMatchID)
}
//case "2 half":
// if item.SubCategory == "" {
// h2MatchID = strconv.Itoa(item.SubMatchID)
// }
}
}
}
//fmt.Printf("\n\nsubMatchIDs: %v\n\n", subMatchIDs)
if h1MatchID != "" {
url = fmt.Sprintf(liveMatchURLPattern, h1MatchID)
//fmt.Printf("Load sub url: %s", url)
buf, err = spider.Get(url, nil)
if err != nil {
// Не загрузился 1й тайм - ну и хер с ним. Просто логгируем
fmt.Printf("Load sub: %s", err)
return
}
var env teamLiveMatchDataEnvelope
err = json.Unmarshal(buf, &env)
if err != nil {
err = fmt.Errorf("json.Unmarshal liveMatchDataEnvelope: %s", err)
return
}
if !env.Success {
return
}
var half Half
//
for _, market := range env.Value.GE {
switch market.MarketType {
case teamMarketTotal:
//fmt.Printf("h1 total: %v\n\n", market)
half.Total, err = getTotal(market)
if err != nil {
err = fmt.Errorf("1st Half total football getTotal: %s", err)
return
}
case teamMarketIndividualTotal1:
//fmt.Printf("h1 total 1: %v\n\n", market)
half.IndividualTotalHome, err = getTotal(market)
if err != nil {
err = fmt.Errorf("1st Half individual total 1 football getTotal: %s", err)
return
}
case teamMarketIndividualTotal2:
//fmt.Printf("h1 total 2: %v\n\n", market)
half.IndividualTotalAway, err = getTotal(market)
if err != nil {
err = fmt.Errorf("1st Half individual total 2 football getTotal: %s", err)
return
}
}
}
data.H1 = half
}
//fmt.Printf("%s\n\n", buf)
return data, false, nil
}
/*
type matchPeriod struct {
// Football, Handball: 1 - half 1, 3 - half 2
// Tennis: 11 - 1st set, 12 - 2nd set, 13 - 3rd set
Type int
Score1 int
Score2 int
}
// Можно получить и доп. статистику, атак, ударов, где periodType - это
// 1 - тайм 1, 3 - тайм 2, 100 - весь матч
type matchStats struct {
Score1 int
Score2 int
Status int // 1 - line, 2 - inplay, 3 - end
//Winner int // в inplay не 0?
Periods []matchPeriod
}
const (
// для гандбола тоже справедливо
footballH1 = 1
footballH2 = 3
)
// GetTeamMatchResult - возвращает счет матча, счет по таймам. Подходит для футбола
// и гандбола.
func GetTeamMatchResult(statsMatchID string) (stats 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("Response: %s\n", buf)
var raw matchStats
err = json.Unmarshal(buf, &raw)
if err != nil {
return
}
//stats.Winner = raw.Winner
stats.Status = raw.Status
stats.HomeGoals = raw.Score1
stats.AwayGoals = raw.Score2
// tennis
stats.Score.Home = raw.Score1
stats.Score.Away = raw.Score2
stats.ScoreByPeriods = make(map[int]Score)
for _, period := range raw.Periods {
switch period.Type {
case footballH1:
// fix - позже удалить H1 и H2
stats.H1 = &HalfStats{
HomeGoals: period.Score1,
AwayGoals: period.Score2,
}
stats.ScoreByPeriods[1] = Score{
Home: period.Score1,
Away: period.Score2,
}
case footballH2:
// fix - позже удалить H1 и H2
stats.H2 = &HalfStats{
HomeGoals: period.Score1,
AwayGoals: period.Score2,
}
stats.ScoreByPeriods[2] = Score{
Home: period.Score1,
Away: period.Score2,
}
}
}
return
}
*/
func GetTeamMatchResult(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 _, p := range tmp.Periods {
periodNumber := periodCode2PeriodNumberMapping[p.Code]
if periodNumber == 0 {
continue
}
result.ScoreByPeriods[periodNumber] = PeriodScore{
HomePoints: p.HomePoints,
AwayPoints: p.AwayPoints,
}
result.HomePoints += p.HomePoints
result.AwayPoints += p.AwayPoints
}
return
}