diff --git a/adapters/jwplayer/jwplayer.go b/adapters/jwplayer/jwplayer.go new file mode 100644 index 00000000000..38439f00ad0 --- /dev/null +++ b/adapters/jwplayer/jwplayer.go @@ -0,0 +1,99 @@ +package jwplayer + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/mxmCherry/openrtb/v15/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the JWPlayer adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{err} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + requestData := &adapters.RequestData{ + Method: "GET", + Uri: a.endpoint, + Body: requestJSON, + Headers: headers, + } + + return []*adapters.RequestData{requestData}, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if responseData.StatusCode == http.StatusNoContent { + return nil, nil + } + + if responseData.StatusCode == http.StatusBadRequest { + err := &errortypes.BadInput{ + Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", + } + return nil, []error{err} + } + + if responseData.StatusCode != http.StatusOK { + err := &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + } + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + response.ID = request.ID + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + for _, seatBid := range response.SeatBid { + for i, _ := range seatBid.Bid { + bid := &seatBid.Bid[i] + if matchingImpId := getImpId(i, *request); matchingImpId != "" { + bid.ImpID = matchingImpId + } + + b := &adapters.TypedBid{ + Bid: bid, + BidType: openrtb_ext.BidTypeVideo, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getImpId(impIdx int, request openrtb2.BidRequest) string { + impressions := request.Imp + if impIdx >= len(impressions) { + return "" + } + + return impressions[impIdx].ID +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index af5507bb4d6..2c064898556 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -68,6 +68,7 @@ import ( "github.com/prebid/prebid-server/adapters/iqzone" "github.com/prebid/prebid-server/adapters/ix" "github.com/prebid/prebid-server/adapters/jixie" + "github.com/prebid/prebid-server/adapters/jwplayer" "github.com/prebid/prebid-server/adapters/kayzen" "github.com/prebid/prebid-server/adapters/kidoz" "github.com/prebid/prebid-server/adapters/krushmedia" @@ -201,6 +202,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderIQZone: iqzone.Builder, openrtb_ext.BidderIx: ix.Builder, openrtb_ext.BidderJixie: jixie.Builder, + openrtb_ext.BidderJWPlayer: jwplayer.Builder, openrtb_ext.BidderKayzen: kayzen.Builder, openrtb_ext.BidderKidoz: kidoz.Builder, openrtb_ext.BidderKrushmedia: krushmedia.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1d189c66a5d..f1c29063b83 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -139,6 +139,7 @@ const ( BidderIQZone BidderName = "iqzone" BidderIx BidderName = "ix" BidderJixie BidderName = "jixie" + BidderJWPlayer BidderName = "jwplayer" BidderKayzen BidderName = "kayzen" BidderKidoz BidderName = "kidoz" BidderKrushmedia BidderName = "krushmedia" @@ -274,6 +275,7 @@ func CoreBidderNames() []BidderName { BidderIQZone, BidderIx, BidderJixie, + BidderJWPlayer, BidderKayzen, BidderKidoz, BidderKrushmedia, diff --git a/static/bidder-info/jwplayer.yaml b/static/bidder-info/jwplayer.yaml new file mode 100644 index 00000000000..e9157cd8381 --- /dev/null +++ b/static/bidder-info/jwplayer.yaml @@ -0,0 +1,10 @@ +maintainer: + email: boost-engineering@jwplayer.com +gvlVendorID: 1046 +capabilities: + app: + mediaTypes: + - video + site: + mediaTypes: + - video diff --git a/static/bidder-params/jwplayer.json b/static/bidder-params/jwplayer.json new file mode 100644 index 00000000000..07ea718919d --- /dev/null +++ b/static/bidder-params/jwplayer.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "JWPlayer Adapter Params", + "description": "A schema which validates params accepted by the JWPlayer adapter", + + "type": "object", + "properties": { + "placementId": { + "type": "string" + }, + "publisherId": { + "type": "string" + } + }, + "required": [ + "placementId" + ] +}