123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- package addata
- import (
- "encoding/json"
- "fmt"
- "html"
- "io/ioutil"
- "math/rand"
- "miads/adslib"
- "miads/adslib/device"
- "miads/adslib/redis_data"
- "miads/adslib/utils"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- )
- type XiaomiAdData struct {
- DetailURL string `json:"detail_url"`
- DisplayType struct {
- Delay int64 `json:"delay"`
- Name string `json:"name"`
- RowCount int64 `json:"row_count"`
- } `json:"display_type"`
- Duration int64 `json:"duration"`
- EmcType string `json:"emc_type"`
- ID string `json:"id"`
- ImageURL string `json:"image_url"`
- Proportion string `json:"proportion"`
- Settings struct {
- ClickType string `json:"click_type"`
- HideCloseAt int64 `json:"hide_close_at"`
- LogTime string `json:"log_time"`
- ShowCloseAt int64 `json:"show_close_at"`
- } `json:"settings"`
- SkipTime int64 `json:"skip_time"`
- TagID string `json:"tag_id"`
- Target string `json:"target"`
- TargetAddition []string `json:"target_addition"`
- TargetAddition1 string `json:"target_addition1"`
- Title string `json:"title"`
- VideoURL string `json:"video_url"`
- }
- type XiaoMiAdInfoRsp struct {
- Data []XiaomiAdData `json:"data"`
- Msg string `json:"msg"`
- Result int64 `json:"result"`
- }
- type AdAction struct {
- Type string `json:"type"`
- Duration int `json:"duration"`
- Urls []string `json:"urls"`
- }
- type AdInfo struct {
- AdActions []AdAction `json:"ads_infos"`
- PercentBegin int `json:"percent_begin"`
- PercentEnd int `json:"percent_end"`
- }
- type AdData struct {
- TargetAddition []AdAction `json:"target_addition"`
- Target string
- ImageUrl string `json:"image_url"`
- Duration int64
- VideoUrl string `json:"video_url"`
- JsOrderId int64 `json:"js_order_id"`
- UserAgent string `json:"user_agent"`
- DpReport string `json:"dp_report"`
- Dp string `json:"dp"`
- OrderName string `json:"order_name"`
- Result int `json:"result"`
- Msg string `json:"msg"`
- }
- func getAdsReqUrl(dsp *utils.DspParam) string {
- reqUrl := "https://m.video.xiaomi.com/api/a3/otv_emc?"
- ref := "yilin"
- sn := "05817a33d4210ad2c67f4b869b5eedde"
- // 组装 emcp
- reqUrl = reqUrl + "_emcp=pre_play"
- // 组装 devid
- reqUrl = reqUrl + "&_devid=" + dsp.RealMd5Imei
- // 组装 ref
- reqUrl = reqUrl + "&ref=" + ref
- // 组装 sn
- reqUrl = reqUrl + "&_sn=" + sn
- // 组装 ip
- reqUrl = reqUrl + "&__ip__=" + dsp.Ip
- rad := rand.Intn(100)
- if rad < 15 {
- dsp.SendPhoneType = 1
- } else {
- dsp.SendPhoneType = 0
- }
- reqUrl = reqUrl + fmt.Sprintf("&_phonetype=%d", dsp.SendPhoneType)
- return reqUrl
- }
- // 获取广告信息
- func GetAdsInfos(dsp *utils.DspParam, advertiser string) (*AdData, error) {
- reqUrl := getAdsReqUrl(dsp)
- if dsp.SendPhoneType == 0 {
- device.SetAdsTagLog("xiaomi", dsp.ReqSource, "ADS_XIAOMI", dsp.DspCityCode)
- } else if dsp.SendPhoneType == 1 {
- device.SetAdsTagLog("xiaomi", dsp.ReqSource, "ADS_XIAOMI_1", dsp.DspCityCode)
- }
- client := &http.Client{}
- fmt.Printf("req url: %s\n", reqUrl)
- req, err := http.NewRequest("GET", reqUrl, nil)
- if err != nil {
- return nil, err
- }
- req.Header.Set(",authority", "m.video.xiaomi.com")
- req.Header.Set(",method", "GET")
- req.Header.Set(",path", reqUrl[26:])
- req.Header.Set(",scheme", "https")
- req.Header.Set("content-type", "application/json")
- req.Header.Set("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
- req.Header.Set("accept-encoding", "gzip, deflate, br")
- req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
- req.Header.Set("cache-control", "max-age=0")
- req.Header.Set("upgrade-insecure-requests", "1")
- req.Header.Set("user-agent", dsp.Ua)
- resp, err := client.Do(req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- fmt.Printf("rsp body: %s\n", body)
- if err != nil {
- return nil, err
- }
- rsp := XiaoMiAdInfoRsp{}
- err = json.Unmarshal(body, &rsp)
- if err != nil {
- return nil, err
- }
- adsDataNum := len(rsp.Data)
- xiaomiResponseAction := map[string]int{
- "xiaomi_view": 0, "xiaomi_click": 0, "xiaomi_close": 0, "xiaomi_video_finish": 0, "xiaomi_video_timer": 0,
- }
- if rsp.Result != 1 {
- return nil, nil
- }
- // bom渠道不处理
- if dsp.ReqSource != "bom" {
- rad := rand.Intn(100)
- if rad < 2 {
- dsp.ReqSource = "kk_h5"
- } else if rad < 4 {
- dsp.ReqSource = "day_09"
- } else if rad < 8 {
- dsp.ReqSource = "fu008"
- } else if rad < 9 {
- dsp.ReqSource = "yzh01"
- } else if rad < 11 {
- dsp.ReqSource = "qihuang88"
- }
- }
- if len(rsp.Data) == 0 {
- return nil, nil
- }
- ///last_infos = xiaomi_mix.xiaomi_fuse(data, dsp.req_source)
- dataInfo := rsp.Data[0]
- dsp.AllDuration = dataInfo.Duration
- dsp.VideoTimeDuration = 7
- showUrls := make([]string, 0, 100)
- clickUrls := make([]string, 0, 100)
- closeUrls := make([]string, 0, 100)
- videoFinishUrls := make([]string, 0, 100)
- videoTimerUrls := make([]string, 0, 100)
- for _, target := range rsp.Data[0].TargetAddition {
- target := html.UnescapeString(target)
- targetParseUrl, _ := url.Parse(target)
- if err != nil {
- fmt.Printf("parse url failed, url: %s, err: %s", target, err)
- continue
- }
- targetParams := targetParseUrl.Query()
- targetUrl := targetParams.Get("url")
- event := targetParams.Get("event")
- if targetUrl != "" {
- switch event {
- case "VIEW":
- showUrls = append(showUrls, targetUrl)
- xiaomiResponseAction["xiaomi_view"] = 1
- case "CLICK":
- clickUrls = append(clickUrls, targetUrl)
- xiaomiResponseAction["xiaomi_click"] = 1
- case "CLOSE":
- closeUrls = append(closeUrls, targetUrl)
- xiaomiResponseAction["xiaomi_close"] = 1
- case "VIDEO_FINISH":
- videoFinishUrls = append(videoFinishUrls, targetUrl)
- xiaomiResponseAction["xiaomi_video_finish"] = 1
- case "VIDEO_TIMER":
- videoTimerUrls = append(videoTimerUrls, targetUrl)
- }
- }
- if event == "VIDEO_TIMER" {
- timeStr := targetParams.Get("time")
- if timeStr != "" {
- videoTimeDuration, _ := strconv.Atoi(timeStr)
- dsp.VideoTimeDuration = videoTimeDuration
- xiaomiResponseAction["xiaomi_video_timer"] = 1
- }
- }
- }
- gotoUrls := make([]string, 0, 100)
- target := rsp.Data[0].Target
- if target != "" {
- targetUrlObj, _ := url.Parse(target)
- targetParams := targetUrlObj.Query()
- targetUrl := targetParams.Get("link_url")
- if targetUrl == "" {
- targetUrl = strings.ReplaceAll(targetUrl, "mv:", "")
- }
- targetUrl = html.UnescapeString(targetUrl)
- if targetUrl != "" {
- gotoUrls = append(gotoUrls, targetUrl)
- }
- }
- if dsp.ReqSource == "mh" {
- closeUrls = videoFinishUrls
- }
- videoUrls := make([]string, 0, 100)
- videoUrl := rsp.Data[0].VideoURL
- if videoUrl != "" {
- videoUrls = append(videoUrls, videoUrl)
- }
- imageUrls := make([]string, 0, 100)
- imageUrl := rsp.Data[0].ImageURL
- if imageUrl != "" {
- imageUrls = append(imageUrls, imageUrl)
- }
- fmt.Printf("%+v, addata_num: %d\n", xiaomiResponseAction, adsDataNum)
- if len(gotoUrls) == 0 {
- return nil, nil
- }
- fmt.Printf("goto urls: %+v\nshow urls: %+v\nclick_urls: %+v\nclose urls: %+v\nvideo finish urls: %+v\nimagurls: %+v\nvideo urls:%+v\n",
- gotoUrls, showUrls, clickUrls, closeUrls, videoFinishUrls, imageUrls, videoUrls)
- adsData, err := CombineLastAdsInfos(dsp, advertiser, gotoUrls, showUrls, clickUrls, closeUrls, videoFinishUrls, videoTimerUrls, imageUrls, videoUrls)
- if err != nil {
- return nil, err
- }
- fmt.Printf("addata: %+v\n", adsData)
- if dsp.SendPhoneType == 0 {
- redis_data.SetAdsRequestNum(advertiser, 0)
- } else if dsp.SendPhoneType == 1 {
- redis_data.SetAdsRequestNum(advertiser, 1)
- }
- return adsData, nil
- }
- func getActionsConf(advertiser string) []string {
- defaultActions := []string{"VIEW", "CLICK", "CLOSE", "VIDEO_FINISH", "VIDEO_TIMER"}
- svrConf := adslib.GetConf()
- actions, ok := svrConf.AdsActions[advertiser]
- if !ok || len(actions) == 0 {
- return defaultActions
- }
- return actions
- }
- func getDurationConf(advertiser string) int {
- svrConf := adslib.GetConf()
- duration, ok := svrConf.AdsDuration[advertiser]
- if !ok {
- return 0
- }
- return duration
- }
- func getCombinationActionsConf(advertiser string) []adslib.CombinationActionsConf {
- svrConf := adslib.GetConf()
- combinationActions, ok := svrConf.CombinationActions[advertiser]
- if !ok {
- return []adslib.CombinationActionsConf{}
- }
- return combinationActions
- }
- // 组装最后的广告信息
- func CombineLastAdsInfos(dsp *utils.DspParam, advertiser string, gotoUrls []string, showUrls []string,
- clickUrls []string, closeUrls []string, videoFinishUrls []string,
- videoTimerUrls []string, imageUrls []string, videoUrls []string) (*AdData, error) {
- // 判断是不是关掉所有Action
- actions := getActionsConf(advertiser)
- if len(actions) == 0 {
- return nil, nil
- }
- clickChannelFlag, err := redis_data.GetChannelFlag(dsp.ReqSource, "ads_click")
- if err != nil {
- return nil, err
- }
- fmt.Printf("click channel flag: %+v\n", clickChannelFlag)
- clickRandom := rand.Intn(100)
- needClick := false
- if clickChannelFlag.ChannelFlag == 1 && clickRandom <= clickChannelFlag.Weigth {
- needClick = true
- }
- lastInfos := make([]AdInfo, 0, 50)
- combinationActions := getCombinationActionsConf(advertiser)
- for _, combAction := range combinationActions {
- adActionDatas := make([]AdAction, 0, 20)
- percentBegin := combAction.PercentBegin
- percentEnd := combAction.PercentEnd
- actionGroup := combAction.GroupValue
- for _, action := range actionGroup {
- urls := make([]string, 0, 50)
- if dsp.ReqSource == "mh" {
- if action == "CLOSE" {
- action = "VIDEO_FINISH"
- }
- }
- switch action {
- case "VIEW":
- urls = showUrls
- case "CLICK":
- urls = clickUrls
- case "CLOSE":
- urls = closeUrls
- case "VIDEO_FINISH":
- urls = videoFinishUrls
- case "VIDEO_TIMER":
- urls = videoTimerUrls
- default:
- continue
- }
- // click的控制 控制bom
- if action == "CLICK" && dsp.RealReqSource == "bom" && dsp.SupClickFlag == 0 {
- continue
- }
- // show的控制 控制bom
- if action == "VIEW" && dsp.RealReqSource == "bom" && dsp.SupShowFlag == 0 {
- continue
- }
- if action == "CLICK" && !needClick {
- continue
- }
- if len(urls) == 0 && action == "VIDEO_TIMER" {
- continue
- }
- adActionData, err := genAdsAction(urls, advertiser, dsp, action, true)
- if err != nil {
- fmt.Printf("gen ads action data failed, err: %s\n", err)
- continue
- }
- // 没有url的就不要下发了
- if len(adActionData.Urls) == 0 {
- continue
- }
- adActionDatas = append(adActionDatas, *adActionData)
- }
- minValue := 2
- if len(videoTimerUrls) != 0 {
- minValue = 3
- }
- // 大于minValue才进行投放
- if len(adActionDatas) >= minValue {
- adInfo := AdInfo{
- AdActions: adActionDatas,
- PercentBegin: percentBegin,
- PercentEnd: percentEnd,
- }
- lastInfos = append(lastInfos, adInfo)
- }
- }
- targetUrl := ""
- if len(gotoUrls) != 0 {
- targetUrl = gotoUrls[0]
- }
- videoUrl := ""
- if len(videoUrls) != 0 {
- videoUrl = videoUrls[0]
- }
- randAdData := make([]AdAction, 0, 50)
- if len(lastInfos) != 0 {
- randIdx := rand.Intn(len(lastInfos))
- randAdData = lastInfos[randIdx].AdActions
- }
- hasClickAction := false
- for _, adData := range randAdData {
- if adData.Type == "CLICK" {
- hasClickAction = true
- break
- }
- }
- if !hasClickAction {
- targetUrl = ""
- }
- // 重新组装duration
- videoTimerUrls = make([]string, 0, 100)
- if len(randAdData) >= 3 {
- if randAdData[1].Type == "VIDEO_TIMER" {
- videoTimerUrls = randAdData[1].Urls
- }
- }
- rspAdDatas := make([]AdAction, 0, 20)
- for _, adData := range randAdData {
- if len(adData.Urls) == 0 || adData.Type == "" {
- continue
- }
- if adData.Type == "VIDEO_TIMER" && len(videoTimerUrls) > 0 {
- adData.Duration = int(dsp.AllDuration) - dsp.VideoTimeDuration
- } else if adData.Type == "VIDEO_TIMER" && len(videoTimerUrls) == 0 {
- adData.Duration = dsp.VideoTimeDuration
- } else if adData.Type == "VIEW" {
- if len(videoTimerUrls) > 0 {
- adData.Duration = dsp.VideoTimeDuration
- } else {
- adData.Duration = int(dsp.AllDuration)
- }
- }
- if adData.Type != "VIEW" {
- redis_data.SetDistributeActionNum(advertiser, adData.Type, dsp.SendPhoneType)
- }
- canReport, err := redis_data.GetDeviceIpReport(dsp.Imei, dsp.Ip)
- if err != nil {
- return nil, err
- }
- md5Imei := ""
- // 返回的曝光, 如果没有返回过秒针的,那么加入
- if adData.Type == "VIEW" && canReport {
- if dsp.ReplaceFlag == 0 {
- md5Imei = utils.Md5(dsp.Imei)
- } else {
- md5Imei = dsp.Imei
- }
- conf := adslib.GetConf()
- url := strings.ReplaceAll(conf.HostMiao, "__IMEI__", md5Imei)
- adData.Urls = append(adData.Urls, url)
- redis_data.SetDeviceIpReport(dsp.Imei, dsp.Ip)
- }
- rspAdDatas = append(rspAdDatas, adData)
- }
- adData := AdData{
- TargetAddition: rspAdDatas,
- Target: targetUrl,
- Duration: dsp.AllDuration,
- VideoUrl: videoUrl,
- }
- return &adData, nil
- }
- // 组装展示
- func genAdsAction(urls []string, advertiser string,
- dsp *utils.DspParam, action string, needControl bool) (*AdAction, error) {
- // 获取advertiser上报的总量
- allSendNum, err := redis_data.GetAdsRequestNum(advertiser, dsp.SendPhoneType)
- if err != nil {
- return nil, err
- }
- allShowNum, err := redis_data.GetAdsFeedbackNum(advertiser, action, dsp.SendPhoneType)
- if err != nil {
- return nil, err
- }
- flowControlConf := redis_data.GetFlowPercentDuration(advertiser, action)
- fmt.Printf("%+v\n", flowControlConf)
- flowPercent := 0
- duration := 0
- if flowControlConf != nil {
- flowPercent = flowControlConf.Percent
- duration = flowControlConf.Duration
- }
- lastUrls := make([]string, 0, 20)
- if !needControl || allSendNum == 0 || int(
- float32(allShowNum)/float32(allSendNum)*100) < flowPercent {
- reportUrl := getReportUrl(action, advertiser, dsp)
- lastUrls = append(urls, reportUrl)
- }
- fmt.Printf("%+v\n", lastUrls)
- if len(lastUrls) == 0 {
- duration = 0
- }
- if action == "VIDEO_TIMER" {
- duration = 7
- }
- adAction := AdAction{
- Type: action,
- Duration: duration,
- Urls: lastUrls,
- }
- return &adAction, nil
- }
- // 组装上报的url
- func getReportUrl(action string, advertiser string, dsp *utils.DspParam) string {
- urlHost := adslib.GetConf().HostIos
- url := fmt.Sprintf("%s?action=%s&advertiser=video&req_source=%s&brand=%s&city_code=%d&request_id=%s&spefial_flag=%d",
- urlHost, action, dsp.ReqSource, dsp.Brand, dsp.DspCityCode, dsp.RequestId, dsp.SendPhoneType)
- return url
- }
|