|
|
@@ -9,6 +9,7 @@ import cn.com.ctop.job.bytedance.data.utils.DateUtils;
|
|
|
import cn.com.ctop.job.bytedance.data.utils.HttpUtils;
|
|
|
import cn.com.ctop.job.bytedance.utils.BytedanceProductDocProperties;
|
|
|
import cn.com.ctop.job.bytedance.utils.FeishuRobotUtil;
|
|
|
+import cn.com.ctop.job.bytedance.utils.RateLimitUtil;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
@@ -23,6 +24,7 @@ import javax.annotation.Resource;
|
|
|
import java.io.IOException;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
+
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdateService {
|
|
|
@@ -32,7 +34,8 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
private RedisTemplate redis2Template_db5;
|
|
|
@Autowired
|
|
|
BytedanceProductDocProperties productDocProperties;
|
|
|
-
|
|
|
+ @Autowired
|
|
|
+ private RateLimitUtil rateLimitUtil;
|
|
|
|
|
|
public static final String DOUYIN_MOVIE_SOURCE_APP="ttd652a0ef496310bd01";
|
|
|
|
|
|
@@ -82,8 +85,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
log.info("付费商品库更新完成");
|
|
|
|
|
|
-
|
|
|
-
|
|
|
log.info("免费商品库更新中...");
|
|
|
List<AigcProductPlatform> iaaPlatformList = bytedanceProductUpdateMapper.getPlatformList("IAA", platformId); //商品库列表
|
|
|
if (!iaaPlatformList.isEmpty()){
|
|
|
@@ -98,7 +99,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
log.info("免费商品库更新完成");
|
|
|
|
|
|
-
|
|
|
errors.removeIf(s -> s.contains("剧目不可用"));
|
|
|
if (!Check.isNull(errors)){
|
|
|
List<String> info = new ArrayList<>();
|
|
|
@@ -123,17 +123,17 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
for (BytedanceProductDocProperties.DysDistributorLinkTable table : productDocProperties.getDysMovies()){
|
|
|
sourceCopywriteOwner.put(table.getMovieSource(), table.getCopyrightOwner());
|
|
|
}
|
|
|
- iaaPlatformList.forEach(p -> {
|
|
|
+ for (AigcProductPlatform p : iaaPlatformList){
|
|
|
p.setCopyrightOwner(sourceCopywriteOwner.get(String.valueOf(p.getSource())));
|
|
|
- });
|
|
|
+ }
|
|
|
|
|
|
List<AigcProductAlbum> iaaVideos = bytedanceProductUpdateMapper.getDysDistributorVideo("IAA");
|
|
|
- iaaVideos.forEach(v -> {
|
|
|
+ for (AigcProductAlbum v : iaaVideos){
|
|
|
v.setPlayletId(getQueryParam(v.getAlbumLink(), "playlet_id"));
|
|
|
if (StringUtils.isEmpty(v.getImg())){
|
|
|
v.setImg("https://oss.artlinkworld.cn/imgsource/20251110-144804.png");//兜底
|
|
|
}
|
|
|
- });
|
|
|
+ }
|
|
|
|
|
|
runDysProductTask(iaaPlatformList, iaaVideos, new HashMap<>(), errors, BusinessType.IAA);
|
|
|
System.out.println("端原生分销商品库更新完成");
|
|
|
@@ -170,7 +170,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
continue;
|
|
|
}
|
|
|
if (!productTypeMap.containsKey(album.getTheme())){
|
|
|
-// errors.add("上传商品:没有找到对应的产品类型:" + album.getTheme());
|
|
|
System.out.println(">>>>没有找到对应的产品类型:" + album.getTheme());
|
|
|
System.out.println("\n\n\n");
|
|
|
continue;
|
|
|
@@ -178,7 +177,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
String schemaLink = null;
|
|
|
if (platform.getIsBytedance()==1){
|
|
|
if (!albumIdToLinkMap.containsKey(album.getAlbumId())){
|
|
|
-// errors.add("上传商品:没有找到对应的推广链接,无法上传商品,剧目ID:" + album.getAlbumId() + ", 剧目名称:" + album.getName());
|
|
|
System.out.println(">>>>没有找到对应的推广链接,无法上传商品,剧目ID:" + album.getAlbumId() + ", 剧目名称:" + album.getName());
|
|
|
System.out.println("\n\n\n");
|
|
|
continue;
|
|
|
@@ -191,13 +189,11 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
private void runDysProductTask(List<AigcProductPlatform> platformList, List<AigcProductAlbum> albums, Map<String, JSONObject> productTypeMap, Set<String> errors, BusinessType businessType) throws IOException {
|
|
|
for (AigcProductPlatform platform : platformList){
|
|
|
// 拉取已上传剧目,对比,得到未上传剧目列表
|
|
|
List<AigcProductAlbum> hasUploadAlbums = hasUploadProductList(platform);
|
|
|
List<String> hasUploadPlayletIds = hasUploadAlbums.stream().map(AigcProductAlbum::getPlayletId).collect(Collectors.toList());
|
|
|
-// System.out.println("已上传剧目数: "+hasUpload.size() + ", 商品库ID: "+platform.getPlatformId()+", 来源:"+platform.getSource());
|
|
|
List<AigcProductAlbum> toUpload = albums.stream()
|
|
|
.filter(o -> !hasUploadPlayletIds.contains(o.getPlayletId()))
|
|
|
.filter(o -> Objects.equals(o.getPlatformType(), String.valueOf(platform.getPlatformType())))
|
|
|
@@ -206,9 +202,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
.collect(Collectors.toList());
|
|
|
System.out.println("待上传剧目数: "+toUpload.size() + ", 商品库ID: "+platform.getPlatformId()+", 来源:"+platform.getSource());
|
|
|
|
|
|
-// if (1==1){
|
|
|
-// return;
|
|
|
-// }
|
|
|
if (toUpload.isEmpty()){
|
|
|
continue;
|
|
|
}
|
|
|
@@ -217,9 +210,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
for (AigcProductAlbum album : toUpload){
|
|
|
JSONObject defaultTheme = JSONObject.parseObject("{\"first_type_id\":\"2038\",\"first_type_name\":\"单剧目-短剧\",\"second_type_id\":\"203807\",\"second_type_name\":\"其他剧情\",\"third_type_name\":\"其他\",\"third_type_id\":\"20380701\"}");
|
|
|
uploadProduct(platform, album, null, errors, defaultTheme, businessType);
|
|
|
-// try {
|
|
|
-// Thread.sleep(80);
|
|
|
-// }catch (InterruptedException ignored){}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -249,7 +239,12 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
if (!filtering.isEmpty()){
|
|
|
params.put("filtering", filtering);
|
|
|
}
|
|
|
- String res = HttpUtils.httpGet(url, params, headers);
|
|
|
+
|
|
|
+ String res = null;
|
|
|
+ if (rateLimitUtil.acquire(platform.getMiAppid(), url)){
|
|
|
+ res = HttpUtils.httpGet(url, params, headers);
|
|
|
+ }
|
|
|
+
|
|
|
if (res == null || res.isEmpty()) {
|
|
|
System.out.println("获取已上传商品列表失败, 广告账号ID:" + platform.getAdvertiserId() + ", 商品库ID:" + platform.getPlatformId());
|
|
|
return new ArrayList<>();
|
|
|
@@ -289,7 +284,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@Override
|
|
|
public void authMovieResource() {
|
|
|
//原片授权
|
|
|
@@ -337,7 +331,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* 初始化新的字节小程序; 新增字节用的商品库时调用
|
|
|
*/
|
|
|
@@ -387,7 +380,12 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
app_page.put("start_param", "link_id=574391");
|
|
|
requestBody.put("app_page", app_page);
|
|
|
|
|
|
- String res = HttpUtils.httpPostRequest(createLinkUrl, requestBody, headers);
|
|
|
+ String res = null;
|
|
|
+ // Rate limit for /open_api/v3.0/tools/micro_app/create/
|
|
|
+ if (rateLimitUtil.acquire(obj.getMiAppid(), createLinkUrl)){
|
|
|
+ res = HttpUtils.httpPostRequest(createLinkUrl, requestBody, headers);
|
|
|
+ }
|
|
|
+
|
|
|
if (res == null || res.isEmpty()){
|
|
|
System.out.println("创建字节小程序失败,advertiser_id:"+obj.getMiniAppAdvertiserId());
|
|
|
}else {
|
|
|
@@ -406,14 +404,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 短剧更新
|
|
|
- * @param platform 商品库信息
|
|
|
- * @param album 剧信息
|
|
|
- * @param schemaLink 小程序推广链接 schemaLink(sslocal://sxxxxx
|
|
|
- * @param errorBlanket
|
|
|
- * @param productType 商品短剧类型
|
|
|
- */
|
|
|
private void uploadProduct(AigcProductPlatform platform, AigcProductAlbum album,
|
|
|
String schemaLink, Set<String> errorBlanket, JSONObject productType,
|
|
|
BusinessType businessType){
|
|
|
@@ -475,7 +465,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
profession.put("membership_types", "5");
|
|
|
profession.put("starting_unlock_episode", String.valueOf(album.getStartingUnlockEpisode()));
|
|
|
}
|
|
|
-// String play_platform = album.getPlay_platform();
|
|
|
List<String> ad_carrier = new ArrayList<>();
|
|
|
if (platform.getIsBytedance() == 1){
|
|
|
ad_carrier.add("字节小程序");
|
|
|
@@ -497,41 +486,23 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
product_info.put("profession", profession);
|
|
|
request.put("product_info", product_info);
|
|
|
|
|
|
-
|
|
|
-// System.out.println("请求地址:" + url);
|
|
|
-// System.out.println("请求头:" + headers);
|
|
|
-// System.out.println("请求参数:" + request.toJSONString());
|
|
|
- //重试3次
|
|
|
- for (int retry = 0; retry < 3; retry++) {
|
|
|
- String res = HttpUtils.httpPostRequest(url, request, headers);
|
|
|
+ // 单次请求(已移除重试逻辑)
|
|
|
+ String res = HttpUtils.httpPostRequest(url, request, headers);
|
|
|
+ if (res == null || res.isEmpty()){
|
|
|
+ String payName = businessType==BusinessType.IAP?"付费":"免费";
|
|
|
+ errorBlanket.add("上传"+payName+"商品失败,msg: 请求失败或无响应, 关联剧目: " + album.getName());
|
|
|
+ } else {
|
|
|
JSONObject btRes = JSONObject.parseObject(res);
|
|
|
int code = btRes.getIntValue("code");
|
|
|
if (code != 0){
|
|
|
String errorMessage = btRes.getString("message");
|
|
|
- if (errorMessage.contains("系统请求频率超限") && retry < 2){
|
|
|
- try {
|
|
|
- Thread.sleep(100);
|
|
|
- }catch (InterruptedException ignored){}
|
|
|
- continue;
|
|
|
- }else {
|
|
|
- String payName = businessType==BusinessType.IAP?"付费":"免费";
|
|
|
- errorBlanket.add("上传"+payName+"商品失败,code: [" + code + "], msg: [" + errorMessage +"], 关联剧目: " + album.getName());
|
|
|
- break;
|
|
|
- }
|
|
|
- }else {
|
|
|
- break;
|
|
|
+ String payName = businessType==BusinessType.IAP?"付费":"免费";
|
|
|
+ errorBlanket.add("上传"+payName+"商品失败,code: [" + code + "], msg: [" + errorMessage +"], 关联剧目: " + album.getName());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- *
|
|
|
- * @param advertiserId 商品库主账户ID,也是创建字节小程序的ID
|
|
|
- * @param accessToken 广告账号的access_token
|
|
|
- * @param instanceId 字节小程序的实例ID
|
|
|
- * @return map key: album_id, value: 对应的字节小程序推广链接,sslocal开头
|
|
|
- */
|
|
|
private Map<String, String> getBytedancePlayletPromoteLink(String advertiserId, String accessToken, String instanceId, List<AigcProductAlbum> requests, Set<String> errorBlanket){
|
|
|
List<String> reqAlbumIds = requests.stream()
|
|
|
.map(obj -> obj.getAlbumId())
|
|
|
@@ -539,6 +510,13 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
Map<String, String> res = new HashMap<>(reqAlbumIds.size());
|
|
|
|
|
|
List<AigcProductAlbum> unfound = new ArrayList<>(requests);
|
|
|
+ /*
|
|
|
+ *
|
|
|
+ * @param advertiserId 商品库主账户ID,也是创建字节小程序的ID
|
|
|
+ * @param accessToken 广告账号的access_token
|
|
|
+ * @param instanceId 字节小程序的实例ID
|
|
|
+ * @return map key: album_id, value: 对应的字节小程序推广链接,sslocal开头
|
|
|
+ */
|
|
|
for (int page=1; page<=20; page++){
|
|
|
JSONArray playletDetailInfo = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket,page);
|
|
|
if (playletDetailInfo == null || playletDetailInfo.isEmpty()){
|
|
|
@@ -553,7 +531,7 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- unfound = requests.stream()
|
|
|
+ unfound = requests.stream()
|
|
|
.filter(obj -> !res.containsKey(obj.getAlbumId()))
|
|
|
.collect(Collectors.toList());
|
|
|
if (unfound.isEmpty()){
|
|
|
@@ -600,7 +578,12 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
requestBody.put("app_page", app_page_list);
|
|
|
requestBody.put("tag_info", "1050107001");
|
|
|
|
|
|
- String rr = HttpUtils.httpPostRequest(editLinkUrl, requestBody, headers);
|
|
|
+ String rr = null;
|
|
|
+ // Rate limit for /open_api/v3.0/tools/micro_app/update/
|
|
|
+ if (rateLimitUtil.acquire(advertiserId, editLinkUrl)){
|
|
|
+ rr = HttpUtils.httpPostRequest(editLinkUrl, requestBody, headers);
|
|
|
+ }
|
|
|
+
|
|
|
if (rr == null || rr.isEmpty()){
|
|
|
errorBlanket.add("创建字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
|
|
|
System.out.println("创建字节小程序推广链接失败");
|
|
|
@@ -647,22 +630,11 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取字节小程序中的推广链接
|
|
|
- * @param advertiserId
|
|
|
- * @param accessToken
|
|
|
- * @param instanceId
|
|
|
- * @param errorBlanket
|
|
|
- * @param pageNum 从外部调用填1
|
|
|
- * @return
|
|
|
- */
|
|
|
private JSONArray getPlayletDetail(String advertiserId, String accessToken, String instanceId, Set<String> errorBlanket, Integer pageNum) {
|
|
|
if (pageNum >60){
|
|
|
return new JSONArray();
|
|
|
}
|
|
|
String getPlayletDetailUrl = "https://api.oceanengine.com/open_api/v3.0/tools/asset_link/list/";
|
|
|
- getPlayletDetailUrl = getPlayletDetailUrl.replace("${ADVERTISER_ID}", advertiserId);
|
|
|
- getPlayletDetailUrl = getPlayletDetailUrl.replace("${INSTANCE_ID}", instanceId);
|
|
|
Map<String, String> headers = new HashMap<>();
|
|
|
headers.put("Access-Token", accessToken);
|
|
|
Map<String, Object> params = new HashMap<>();
|
|
|
@@ -670,7 +642,13 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
params.put("page", String.valueOf(pageNum));
|
|
|
params.put("page_size", "100");
|
|
|
params.put("filtering", "{\"instance_id\":" + instanceId + "}");
|
|
|
- String res = HttpUtils.httpGet(getPlayletDetailUrl, params, headers);
|
|
|
+
|
|
|
+ String res = null;
|
|
|
+ // Rate limit for /open_api/v3.0/tools/asset_link/list/
|
|
|
+ if (rateLimitUtil.acquire(advertiserId, getPlayletDetailUrl)){
|
|
|
+ res = HttpUtils.httpGet(getPlayletDetailUrl, params, headers);
|
|
|
+ }
|
|
|
+
|
|
|
if (res == null || res.isEmpty()) {
|
|
|
errorBlanket.add("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
|
|
|
System.out.println("获取字节小程序推广链接失败, 广告账号ID:" + advertiserId + ", 小程序资产ID:" + instanceId);
|
|
|
@@ -684,23 +662,15 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
return new JSONArray();
|
|
|
}else {
|
|
|
JSONArray list = jsonObject.getJSONObject("data").getJSONArray("list");
|
|
|
- if (list.size() > 0){
|
|
|
- return list;
|
|
|
+ if (list == null || list.isEmpty()){
|
|
|
+ return new JSONArray();
|
|
|
}
|
|
|
-// JSONObject page_info = jsonObject.getJSONObject("data").getJSONObject("page_info");
|
|
|
-// int total_page = page_info.getIntValue("total_page");
|
|
|
-// if (total_page > pageNum){
|
|
|
-// //递归获取下一页
|
|
|
-// JSONArray nextPage = getPlayletDetail(advertiserId, accessToken, instanceId, errorBlanket, pageNum + 1);
|
|
|
-// list.addAll(nextPage);
|
|
|
-// }
|
|
|
return list;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
-
|
|
|
public void uploadAlbum() throws IOException {
|
|
|
List<String> info = new ArrayList<>();
|
|
|
info.add("仅微小剧目上传通知");
|
|
|
@@ -762,7 +732,13 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
Map<String, Object> params = new HashMap<>();
|
|
|
params.put("album_id", al);
|
|
|
params.put("app_id", app_id);
|
|
|
- String res = HttpUtils.httpGet(url, params, headers);
|
|
|
+
|
|
|
+ String res = null;
|
|
|
+ // Rate limit for /open_api/v3.0/dpa/album_status/get/
|
|
|
+ if (rateLimitUtil.acquire(String.valueOf(app_id), url)){
|
|
|
+ res = HttpUtils.httpGet(url, params, headers);
|
|
|
+ }
|
|
|
+
|
|
|
if (res == null || res.isEmpty()){
|
|
|
System.out.println("获取短剧状态失败,albumId: " + al);
|
|
|
}else {
|
|
|
@@ -1040,7 +1016,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
headers.put("Content-Type", "application/json");
|
|
|
|
|
|
System.out.println(requestBody.toJSONString());
|
|
|
-// return null;
|
|
|
String res = HttpUtils.httpPostRequest(url, requestBody, headers);
|
|
|
System.out.println(">>> "+res);
|
|
|
if (res == null || res.isEmpty()){
|
|
|
@@ -1066,7 +1041,6 @@ public class BytedanceProductUpdateServiceImpl implements IBytedanceProductUpdat
|
|
|
.getFirst(paramName);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
private String getAppAccessToken(Long app_id, String app_secret){
|
|
|
String url = "https://open.oceanengine.com/open_api/oauth2/app_access_token/";
|
|
|
if (app_id == null || app_secret == null){
|