476 lines
10 KiB
Go
476 lines
10 KiB
Go
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
|
||
}
|