Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huawei bidder updates #2832

Merged
merged 11 commits into from
Dec 15, 2023
4 changes: 4 additions & 0 deletions src/main/java/com/iab/openrtb/request/VideoObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ public class VideoObject {

List<Integer> protocols;

Integer w;

Integer h;

ObjectNode ext;
}
6 changes: 6 additions & 0 deletions src/main/java/com/iab/openrtb/response/Asset.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.iab.openrtb.response;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Builder;
import lombok.Value;
Expand All @@ -23,4 +24,9 @@ public class Asset {
Link link;

ObjectNode ext;

@JsonIgnore
public boolean isEmpty() {
return title == null && img == null && video == null && data == null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,34 @@
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.proto.openrtb.ext.request.huaweiads.ExtImpHuaweiAds;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class HuaweiAdSlotBuilder {

private static final Integer IMAGE_ASSET_TYPE_MAIN = 3;
private static final String TEST_AUTH_ENABLED = "true";

private static final BigDecimal FILL_RATIO = BigDecimal.valueOf(0.5);
private static final List<Format> POPULAR_FORMATS = List.of(
Format.of(225, 150),
Format.of(300, 250),
Format.of(640, 360),
Format.of(720, 1280),
Format.of(1080, 607),
Format.of(1080, 1620),
Format.of(1080, 1920),
Format.of(1280, 720)
);
private final JacksonMapper mapper;

public HuaweiAdSlotBuilder(JacksonMapper mapper) {
Expand Down Expand Up @@ -98,6 +114,7 @@ private AdSlot30 makeNativeAdSlot(Native xNative) {
.count();
return AdSlot30.builder()
.detailedCreativeTypeList(makeDetailedCreativeTypeList(numVideo, numImage))
.format(makeFormatListForNative(assets, numImage))
.build();
}

Expand Down Expand Up @@ -139,15 +156,76 @@ private List<Asset> parseNativeRequestAssets(Native xNative) {
}

private static List<String> makeDetailedCreativeTypeList(long numVideo, long numImage) {
final List<String> detailedCreativeTypeList = new ArrayList<>();
if (numVideo >= 1) {
return List.of("903");
} else if (numImage > 1) {
return List.of("904");
} else if (numImage == 1) {
return List.of("901");
} else {
return List.of("913", "914");
detailedCreativeTypeList.add("903");
}
if (numImage >= 1) {
detailedCreativeTypeList.addAll(List.of("901", "904", "905"));
}
return detailedCreativeTypeList;
}

private static List<Format> makeFormatListForNative(List<Asset> assets, long numImage) {
final Set<Format> formats = new HashSet<>();
formats.addAll(makeFormatListForVideo(assets));
formats.addAll(makeFormatListForImage(assets, numImage));
return formats.stream().toList();
}

private static Set<Format> makeFormatListForVideo(List<Asset> assets) {
return assets.stream()
.map(Asset::getVideo)
.filter(Objects::nonNull)
.filter(video -> HuaweiUtils.isFormatDefined(video.getW(), video.getH()))
.map(video -> Format.of(video.getW(), video.getH()))
.collect(Collectors.toSet());
}

private static Set<Format> makeFormatListForImage(List<Asset> assets, long numImage) {
final Set<Format> formats = new HashSet<>();
assets.stream()
.map(Asset::getImg)
.filter(Objects::nonNull)
.forEach(image -> {
if (numImage > 1
&& HuaweiUtils.isFormatDefined(image.getW(), image.getH())
&& HuaweiUtils.isFormatDefined(image.getWmin(), image.getHmin())) {
formats.add(Format.of(image.getW(), image.getH()));
}
if (numImage == 1
&& HuaweiUtils.isFormatDefined(image.getW(), image.getH())
&& HuaweiUtils.isFormatDefined(image.getWmin(), image.getHmin())) {
formats.addAll(filterPopularSizesByRatio(image.getW(), image.getH()));
}
if (numImage == 1
&& !HuaweiUtils.isFormatDefined(image.getW(), image.getH())
&& HuaweiUtils.isFormatDefined(image.getWmin(), image.getHmin())) {
formats.addAll(filterPopularSizesByRange(image.getWmin(), image.getHmin()));
VeryExtraordinaryUsername marked this conversation as resolved.
Show resolved Hide resolved
}
});
return formats;
}

private static List<Format> filterPopularSizesByRatio(Integer width, Integer height) {
final int precision = 5;
final BigDecimal assetWidth = BigDecimal.valueOf(width, precision);
final BigDecimal assetHeight = BigDecimal.valueOf(height, precision);
final BigDecimal assetRatio = assetWidth.divide(assetHeight, RoundingMode.UP);
return POPULAR_FORMATS.stream()
.filter(format -> {
final BigDecimal formatWidth = BigDecimal.valueOf(format.getW(), precision);
final BigDecimal formatHeight = BigDecimal.valueOf(format.getH(), precision);
final BigDecimal formatRatio = formatWidth.divide(formatHeight, RoundingMode.UP);
return assetRatio.subtract(formatRatio).abs().compareTo(FILL_RATIO) <= 0;
}
)
.toList();
}

private static List<Format> filterPopularSizesByRange(Integer width, Integer height) {
return POPULAR_FORMATS.stream()
.filter(size -> size.getW() > width && size.getH() > height)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class HuaweiAdmBuilder {
private static final Integer DATA_ASSET_CTA_TEXT_TYPE = 12;
private static final Set<Integer> DATA_ASSET_DESC_TYPES = Set.of(2, 10);
private static final int IMAGE_ASSET_TYPE_ICON = 1;
private static final int IMAGE_ASSET_TYPE_MAIN = 3;
private static final int APP_PROMOTION_INTERACTION_TYPE = 3;
private static final String DEFAULT_NATIVE_VERSION = "1.1";
private static final String DEFAULT_VIDEO_MIME_TYPE = "video/mp4";
Expand Down Expand Up @@ -364,12 +365,13 @@ public HuaweiAdm buildNative(AdsType adType, Content content, Native xNative) {
.id(asset.getId())
.build();

responseAssets.add(responseAsset);

if (isImageAsset) {
if (!HuaweiUtils.isFormatDefined(adWidth, adHeight)) {
adHeight = responseAsset.getImg().getH();
adWidth = responseAsset.getImg().getW();
if (!responseAsset.isEmpty()) {
responseAssets.add(responseAsset);
if (isImageAsset) {
if (!HuaweiUtils.isFormatDefined(adWidth, adHeight)) {
adHeight = responseAsset.getImg().getH();
adWidth = responseAsset.getImg().getW();
}
}
}
}
Expand Down Expand Up @@ -412,27 +414,31 @@ private static TitleObject buildTitleObject(MetaData metaData) {
private static ImageObject buildImageObject(Integer assetImageType,
Iterator<Icon> iconsIterators,
Iterator<ImageInfo> imageIterator) {
final ImageObject.ImageObjectBuilder imgObjectBuilder = ImageObject.builder()
.url(StringUtils.EMPTY)
.type(assetImageType);

if (Objects.equals(assetImageType, IMAGE_ASSET_TYPE_ICON)) {
if (iconsIterators.hasNext()) {
final Icon icon = iconsIterators.next();
imgObjectBuilder.url(icon.getUrl());
imgObjectBuilder.w(icon.getWidth());
imgObjectBuilder.h(icon.getHeight());
return ImageObject.builder()
.url(icon.getUrl())
.w(icon.getWidth())
.h(icon.getHeight())
.type(assetImageType)
.build();
}
} else {
if (imageIterator.hasNext()) {
final ImageInfo image = imageIterator.next();
imgObjectBuilder.url(image.getUrl());
imgObjectBuilder.w(image.getWidth());
imgObjectBuilder.h(image.getHeight());
if (Objects.equals(assetImageType, IMAGE_ASSET_TYPE_MAIN)) {
return ImageObject.builder()
.url(image.getUrl())
.w(image.getWidth())
.h(image.getHeight())
.type(assetImageType)
.build();
}
}
}

return imgObjectBuilder.build();
return null;
}

private static DataObject buildDataObject(MetaData metaData, Integer assetDataType) {
Expand Down Expand Up @@ -513,5 +519,4 @@ private static String decode(String value) {
.map(str -> URLDecoder.decode(str, StandardCharsets.UTF_8))
.orElse(StringUtils.EMPTY);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasNoImagesAndNoVideos
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("913", "914"))
.detailedCreativeTypeList(List.of())
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -410,7 +411,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneNonMainImageWith
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("913", "914"))
.detailedCreativeTypeList(List.of())
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -445,7 +447,14 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneMainImageWithFor
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("901"))
.detailedCreativeTypeList(List.of("901", "904", "905"))
.format(List.of(
org.prebid.server.bidder.huaweiads.model.request.Format.of(1080, 1920),
org.prebid.server.bidder.huaweiads.model.request.Format.of(1080, 1620),
org.prebid.server.bidder.huaweiads.model.request.Format.of(300, 250),
org.prebid.server.bidder.huaweiads.model.request.Format.of(720, 1280),
org.prebid.server.bidder.huaweiads.model.request.Format.of(225, 150)
))
.test(0)
.build();

Expand Down Expand Up @@ -479,7 +488,15 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneMainImageWithMin
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("901"))
.detailedCreativeTypeList(List.of("901", "904", "905"))
.format(List.of(
org.prebid.server.bidder.huaweiads.model.request.Format.of(1080, 1920),
org.prebid.server.bidder.huaweiads.model.request.Format.of(640, 360),
org.prebid.server.bidder.huaweiads.model.request.Format.of(1080, 607),
org.prebid.server.bidder.huaweiads.model.request.Format.of(1080, 1620),
org.prebid.server.bidder.huaweiads.model.request.Format.of(1280, 720),
org.prebid.server.bidder.huaweiads.model.request.Format.of(720, 1280)
))
.test(0)
.build();

Expand Down Expand Up @@ -508,7 +525,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneMainImageWithout
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("901"))
.detailedCreativeTypeList(List.of("901", "904", "905"))
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -539,7 +557,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasTwoMainImages()
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("904"))
.detailedCreativeTypeList(List.of("901", "904", "905"))
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -570,7 +589,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneMainAndOneNonMai
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("901"))
.detailedCreativeTypeList(List.of("901", "904", "905"))
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -601,7 +621,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasOneMainImageAndOneV
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("903"))
.detailedCreativeTypeList(List.of("903", "901", "904", "905"))
.format(List.of())
.test(0)
.build();

Expand Down Expand Up @@ -633,7 +654,8 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasTwoMainImagesAndOne
final AdSlot30 expected = AdSlot30.builder()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("903"))
.detailedCreativeTypeList(List.of("903", "901", "904", "905"))
.format(List.of())
VeryExtraordinaryUsername marked this conversation as resolved.
Show resolved Hide resolved
.test(0)
.build();

Expand Down Expand Up @@ -665,6 +687,7 @@ public void buildShouldBuildNativeAdSlotWhenImpIsNativeAndHasTwoVideos()
.adType(3)
.slotId("slotId")
.detailedCreativeTypeList(List.of("903"))
.format(List.of())
.test(0)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1555,7 +1555,6 @@ public void buildNativeShouldBuildNativeWithImagesWhenImageAreFromIconAndImageIn
+ "\"assets\":["
+ "{\"id\":12,\"img\":{\"type\":1,\"url\":\"iconUrl\"}},"
+ "{\"id\":13,\"img\":{\"type\":1,\"url\":\"\",\"w\":100,\"h\":100}},"
+ "{\"id\":24,\"img\":{\"type\":2,\"url\":\"imageInfoUrl\",\"w\":200,\"h\":0}},"
+ "{\"id\":25,\"img\":{\"type\":3,\"w\":200,\"h\":200}}"
+ "],"
+ "\"link\":{\"url\":\"clickUrl\",\"clicktrackers\":[]},"
Expand Down Expand Up @@ -1705,15 +1704,13 @@ public void buildNativeShouldBuildNativeWithTitleVideoImagesAndDataAssetsWhenMon
+ "\"assets\":["
+ "{\"id\":11,\"img\":{\"type\":1,\"url\":\"iconUrl\"}},"
+ "{\"id\":12,\"img\":{\"type\":1,\"url\":\"\",\"w\":100,\"h\":100}},"
+ "{\"id\":13,\"img\":{\"type\":2,\"url\":\"imageInfoUrl\",\"w\":200,\"h\":0}},"
+ "{\"id\":14,\"img\":{\"type\":3,\"w\":200,\"h\":200}},"
+ "{\"id\":21,\"data\":{\"value\":\"description description\"}},"
+ "{\"id\":22,\"data\":{\"value\":\"description description\"}},"
+ "{\"id\":23,\"data\":{\"value\":\"\"}},"
+ "{\"id\":24,\"data\":{\"type\":12,\"value\":\"cta cta\"}},"
+ "{\"id\":31,\"title\":{\"text\":\"title title\",\"len\":11}},"
+ "{\"id\":41,\"video\":{\"vasttag\":\"" + expectedVideoAssetAdm + "\"}},"
+ "{\"id\":51}"
+ "{\"id\":41,\"video\":{\"vasttag\":\"" + expectedVideoAssetAdm + "\"}}"
+ "],"
+ "\"link\":{\"url\":\"clickUrl\",\"clicktrackers\":[\"clickUrl1\",\"clickUrl2\",\"clickUrl3\"]},"
+ "\"eventtrackers\":["
Expand Down
Loading
Loading