|
|
@@ -0,0 +1,395 @@
|
|
|
+package cn.com.ctop.job.bytedance.data.service.impl;
|
|
|
+
|
|
|
+import cn.com.ctop.job.bytedance.data.entity.BytedanceCdpProject;
|
|
|
+import cn.com.ctop.job.bytedance.data.mapper.BytedanceCdpProjectMapper;
|
|
|
+import cn.com.ctop.job.bytedance.data.mapper.BytedanceRefreshTokenMapper;
|
|
|
+import cn.com.ctop.job.bytedance.data.service.IBytedanceCdpProjectService;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.Check;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.DateUtils;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.HttpUtils;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.Okhttp3Utils;
|
|
|
+import cn.com.ctop.job.bytedance.data.utils.RandomStringGenerator;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.Instant;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 头条项目列Service业务层处理
|
|
|
+ * <p>
|
|
|
+ * media_api.bytedance_cdp_project_list
|
|
|
+ * media_api.bytedance_byte_app_info
|
|
|
+ * media_api.bytedance_wx_app_info
|
|
|
+ * media_api.adq_dynamic_createive_list
|
|
|
+ *
|
|
|
+ * @author ruoyi
|
|
|
+ * @date 2025-04-23
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class BytedanceCdpProjectServiceImpl implements IBytedanceCdpProjectService {
|
|
|
+ @Autowired
|
|
|
+ private BytedanceCdpProjectMapper bytedanceCdpProjectMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private BytedanceRefreshTokenMapper tokenMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Long> getAllAdverIdList(String type) {
|
|
|
+ return bytedanceCdpProjectMapper.getAllAdverIdList(type);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean delErrApps(String type) {
|
|
|
+ return bytedanceCdpProjectMapper.delErrApps(type);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Long> queryAdvertiserIds(String db, String date) {
|
|
|
+ return bytedanceCdpProjectMapper.queryAdvertiserIds(db, date);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getProjectList(Long advertiserId, String date) {
|
|
|
+ this.getProjectListVo(advertiserId, null, date, 1, 1);
|
|
|
+// this.getProjectListVo(advertiserId, "del", date, 1, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void getProjectListVo(Long advertiserId, String type, String date, Integer page, int count) {
|
|
|
+ try {
|
|
|
+ boolean nextPage = false;
|
|
|
+ String accessToken = tokenMapper.onlyGetToken(advertiserId);
|
|
|
+ if (Check.isNull(accessToken)) {
|
|
|
+ log.error("账户({})查询token失败", advertiserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("advertiser_id", advertiserId);
|
|
|
+ JSONObject filtering = new JSONObject();
|
|
|
+ if (!Check.isNull(type)) {
|
|
|
+ //不传默认返回不限(不含已删除)
|
|
|
+ filtering.put("status_first", "PROJECT_STATUS_DELETE");
|
|
|
+ }
|
|
|
+ filtering.put("project_modify_time", date);
|
|
|
+ params.put("filtering", filtering);
|
|
|
+ params.put("page", page);
|
|
|
+ params.put("page_size", 100);//最大100
|
|
|
+ String url = "https://api.oceanengine.com/open_api/v3.0/project/list/";
|
|
|
+ String results = HttpUtils.httpGet(url, params, HttpUtils.postMHeaders(accessToken));
|
|
|
+ JSONObject obj = JSONObject.parseObject(results);
|
|
|
+ if (!Check.isNull(obj)) {
|
|
|
+ Integer code = obj.getInteger("code");
|
|
|
+ if (code == 0) {
|
|
|
+ JSONObject data = obj.getJSONObject("data");
|
|
|
+ Integer totalPage = data.getJSONObject("page_info").getInteger("total_page");
|
|
|
+ if (totalPage != 0 && totalPage > data.getJSONObject("page_info").getInteger("page")) {
|
|
|
+ nextPage = true;
|
|
|
+ }
|
|
|
+ List<BytedanceCdpProject> projectList = new ArrayList<>();
|
|
|
+ JSONArray array = data.getJSONArray("list");
|
|
|
+ for (int i = 0; i < array.size(); i++) {
|
|
|
+ BytedanceCdpProject advertiserToolsSite = new BytedanceCdpProject(array.getJSONObject(i));
|
|
|
+ projectList.add(advertiserToolsSite);
|
|
|
+ }
|
|
|
+ if (!Check.isNull(projectList))
|
|
|
+ if (bytedanceCdpProjectMapper.replaceBytedanceCdpProjectList(projectList) > 0)
|
|
|
+ log.info("---账户({})项目信息更新成功", advertiserId);
|
|
|
+ } else {
|
|
|
+ //40100请求超频
|
|
|
+ if (40100 == code && count <= 5) {
|
|
|
+ Thread.sleep(800);
|
|
|
+ getProjectListVo(advertiserId, type, date, page, count + 1);
|
|
|
+ } else {
|
|
|
+ log.error("获取项目列表失败(url:{}),入参:{}\n结果:{}", url, JSONObject.toJSONString(params), obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextPage) {
|
|
|
+ getProjectListVo(advertiserId, type, date, page + 1, 1);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getByteAppInfo(Long advertiserId) {
|
|
|
+ this.getByteAppInfoVo(advertiserId, "CREATE_ONLY", 1, 1);
|
|
|
+ this.getByteAppInfoVo(advertiserId, "SHARE_ONLY", 1, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void getByteAppInfoVo(Long advertiserId, String searchType, Integer page, int count) {
|
|
|
+ try {
|
|
|
+ boolean nextPage = false;
|
|
|
+ String accessToken = tokenMapper.onlyGetToken(advertiserId);
|
|
|
+ if (Check.isNull(accessToken)) {
|
|
|
+ log.error("账户({})查询token失败", advertiserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject params = new JSONObject();
|
|
|
+ params.put("advertiser_id", advertiserId);
|
|
|
+ params.put("page", page);
|
|
|
+ //页面大小,默认值为10,最大值100
|
|
|
+ params.put("page_size", 100);
|
|
|
+ JSONObject filtering = new JSONObject();
|
|
|
+ //CREATE_ONLY本户创建,SHARE_ONLY 只查共享应用
|
|
|
+ filtering.put("search_type", searchType);
|
|
|
+// filtering.put("audit_status", "AUDIT_ACCEPTED");
|
|
|
+ params.put("filtering", filtering);
|
|
|
+ //获取微信小程序列表
|
|
|
+ String url = "https://api.oceanengine.com/open_api/v3.0/tools/micro_app/list/";
|
|
|
+ JSONObject obj = Okhttp3Utils.bytedanceGetRequest(accessToken, url, params);
|
|
|
+ if (!Check.isNull(obj)) {
|
|
|
+ Integer code = obj.getInteger("code");
|
|
|
+ if (code == 0) {
|
|
|
+ JSONObject data = obj.getJSONObject("data");
|
|
|
+ Integer totalPage = data.getJSONObject("page_info").getInteger("total_page");
|
|
|
+ if (totalPage != 0 && totalPage > data.getJSONObject("page_info").getInteger("page")) {
|
|
|
+ nextPage = true;
|
|
|
+ }
|
|
|
+ JSONArray list = data.getJSONArray("list");
|
|
|
+ if (!Check.isNull(list))
|
|
|
+ if (bytedanceCdpProjectMapper.replaceBytedanceByteAppInfo(list, advertiserId) > 0)
|
|
|
+ log.info("---账户({})抖小信息更新成功", advertiserId);
|
|
|
+ } else {
|
|
|
+ //40110请求超频 51010 内部服务超时
|
|
|
+ if ((40110 == code || 51010 == code) && count <= 3) {
|
|
|
+ Thread.sleep(700);
|
|
|
+ getByteAppInfoVo(advertiserId, searchType, page, count + 1);
|
|
|
+ } else {
|
|
|
+ log.error("账户({})获取抖小列表失败,入参:{}\n结果:{}", advertiserId, JSONObject.toJSONString(params), obj);
|
|
|
+ bytedanceCdpProjectMapper.insertErrorAdvertiserId(advertiserId, "tt");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextPage) {
|
|
|
+ getByteAppInfoVo(advertiserId, searchType, page + 1, 1);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ bytedanceCdpProjectMapper.insertErrorAdvertiserId(advertiserId, "tt");
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getWxAppInfo(Long advertiserId) {
|
|
|
+ this.getWxAppInfoVo(advertiserId, "CREATE_ONLY", 1, 1);
|
|
|
+ this.getWxAppInfoVo(advertiserId, "SHARE_ONLY", 1, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void getWxAppInfoVo(Long advertiserId, String searchType, Integer page, int count) {
|
|
|
+ try {
|
|
|
+ boolean nextPage = false;
|
|
|
+ String accessToken = tokenMapper.onlyGetToken(advertiserId);
|
|
|
+ if (Check.isNull(accessToken)) {
|
|
|
+ log.error("账户({})查询token失败", advertiserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject params = new JSONObject();
|
|
|
+ params.put("advertiser_id", advertiserId);
|
|
|
+ params.put("page", page);
|
|
|
+ //页面大小,默认值为10,最大值100
|
|
|
+ params.put("page_size", 100);
|
|
|
+ JSONObject filtering = new JSONObject();
|
|
|
+ //CREATE_ONLY本户创建,SHARE_ONLY 只查共享应用
|
|
|
+ filtering.put("search_type", searchType);
|
|
|
+ //状态 审核通过:AUDIT_ACCEPTED
|
|
|
+// filtering.put("audit_status", "AUDIT_ACCEPTED");
|
|
|
+ params.put("filtering", filtering);
|
|
|
+ //获取微信小程序列表
|
|
|
+ String url = "https://api.oceanengine.com/open_api/v3.0/tools/wechat_applet/list/";
|
|
|
+ JSONObject obj = Okhttp3Utils.bytedanceGetRequest(accessToken, url, params);
|
|
|
+ if (!Check.isNull(obj)) {
|
|
|
+ Integer code = obj.getInteger("code");
|
|
|
+ if (code == 0) {
|
|
|
+ JSONObject data = obj.getJSONObject("data");
|
|
|
+ Integer totalPage = data.getJSONObject("page_info").getInteger("total_page");
|
|
|
+ if (totalPage != 0 && totalPage > data.getJSONObject("page_info").getInteger("page")) {
|
|
|
+ nextPage = true;
|
|
|
+ }
|
|
|
+ JSONArray list = data.getJSONArray("list");
|
|
|
+ if (!Check.isNull(list))
|
|
|
+ if (bytedanceCdpProjectMapper.replaceBytedanceWxAppInfo(list, advertiserId) > 0)
|
|
|
+ log.info("---账户({})微小信息更新成功", advertiserId);
|
|
|
+ } else {
|
|
|
+ //40110请求超频
|
|
|
+ if (40110 == code && count <= 3) {
|
|
|
+ Thread.sleep(600);
|
|
|
+ getWxAppInfoVo(advertiserId, searchType, page, count + 1);
|
|
|
+ } else {
|
|
|
+ log.error("账户({})获取微小列表失败,入参:{}\n结果:{}", advertiserId, JSONObject.toJSONString(params), obj);
|
|
|
+ bytedanceCdpProjectMapper.insertErrorAdvertiserId(advertiserId, "wx");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextPage) {
|
|
|
+ getWxAppInfoVo(advertiserId, searchType, page + 1, 1);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ bytedanceCdpProjectMapper.insertErrorAdvertiserId(advertiserId, "wx");
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Long> queryMediaAdverIds(String date, String mediaType) {
|
|
|
+ return bytedanceCdpProjectMapper.queryMediaAdverIds(date, mediaType);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Long> queryADQAdverIds(String date) {
|
|
|
+ return bytedanceCdpProjectMapper.queryADQAdverIds(date);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void getAdqCreatives(Long advertiserId, String date) {
|
|
|
+ try {
|
|
|
+ String accessToken = tokenMapper.onlyGetADQToken(advertiserId);
|
|
|
+ if (Check.isNull(accessToken)) {
|
|
|
+ log.error("账户({})accessToken is null", advertiserId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.rebackadqCreativesVo(advertiserId, accessToken, date, 1, true, 1);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ log.error("账户({})获取动态创意异常", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void rebackadqCreativesVo(Long accountId, String accessToken, String date, Integer page, Boolean isDeleted, int count) throws Exception {
|
|
|
+ boolean nextPage = false;
|
|
|
+ JSONObject returnJson = new JSONObject();
|
|
|
+ Map<String, Object> param = new HashMap<>();
|
|
|
+ long timestamp = Instant.now().getEpochSecond();
|
|
|
+ param.put("timestamp", String.valueOf(timestamp));
|
|
|
+ param.put("nonce", RandomStringGenerator.generateRandomString(32));
|
|
|
+ param.put("access_token", accessToken);
|
|
|
+ param.put("account_id", accountId);
|
|
|
+ param.put("page", page);
|
|
|
+ param.put("page_size", 100);
|
|
|
+ if (!Check.isNull(date)) {
|
|
|
+ JSONArray filtering = new JSONArray();
|
|
|
+ JSONObject greObj = new JSONObject();
|
|
|
+ greObj.put("field", "created_time");
|
|
|
+ greObj.put("operator", "GREATER_EQUALS");
|
|
|
+ JSONArray startDateVls = new JSONArray();
|
|
|
+ startDateVls.add(String.valueOf(DateUtils.dt2milli(date + " 00:00:00")));
|
|
|
+ greObj.put("values", startDateVls);
|
|
|
+ filtering.add(greObj);
|
|
|
+ JSONObject lesObj = new JSONObject();
|
|
|
+ lesObj.put("field", "created_time");
|
|
|
+ lesObj.put("operator", "LESS_EQUALS");
|
|
|
+ JSONArray endDateVls = new JSONArray();
|
|
|
+ endDateVls.add(String.valueOf(DateUtils.dt2milli(date + " 23:59:59")));
|
|
|
+ lesObj.put("values", endDateVls);
|
|
|
+ filtering.add(lesObj);
|
|
|
+ param.put("filtering", filtering);
|
|
|
+ }
|
|
|
+// param.put("is_deleted", isDeleted);
|
|
|
+ JSONArray fields = new JSONArray();
|
|
|
+ fields.add("adgroup_id");
|
|
|
+ fields.add("dynamic_creative_id");
|
|
|
+ fields.add("creative_components");
|
|
|
+ param.put("fields", fields);
|
|
|
+ String result = HttpUtils.httpGet("https://api.e.qq.com/v3.0/dynamic_creatives/get", param, new HashMap<>());
|
|
|
+ JSONObject obj = JSONObject.parseObject(result);
|
|
|
+ if (!Check.isNull(obj)) {
|
|
|
+ if (0 == obj.getInteger("code")) {
|
|
|
+ JSONObject data = obj.getJSONObject("data");
|
|
|
+ if (!Check.isNull(data)) {
|
|
|
+ JSONObject pageInfo = data.getJSONObject("page_info");
|
|
|
+ Integer totalPage = pageInfo.getInteger("total_page");
|
|
|
+ if (totalPage != 0 && totalPage > pageInfo.getInteger("page")) {
|
|
|
+ nextPage = true;
|
|
|
+ }
|
|
|
+ JSONArray array = data.getJSONArray("list");
|
|
|
+ for (int i = 0; i < array.size(); i++) {
|
|
|
+ JSONObject object = array.getJSONObject(i);
|
|
|
+ getAppId(object);
|
|
|
+ }
|
|
|
+ if (!Check.isNull(array))
|
|
|
+ if (bytedanceCdpProjectMapper.replaceAdqDynamicCreateives(array, accountId) > 0)
|
|
|
+ log.info("---账户({})广点通创意更新成功", accountId);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (count <= 4) {
|
|
|
+ Thread.sleep(500);
|
|
|
+ rebackadqCreativesVo(accountId, accessToken, date, page, isDeleted, count + 1);
|
|
|
+ } else {
|
|
|
+ log.error("账户({})获取动态创意失败,入参:{}\n,结果:{}", accountId, JSONObject.toJSONString(param), obj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (nextPage) {
|
|
|
+ rebackadqCreativesVo(accountId, accessToken, date, page + 1, isDeleted, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void getAppId(JSONObject object) {
|
|
|
+ JSONObject creativeComponents = object.getJSONObject("creative_components");
|
|
|
+ if (!Check.isNull(creativeComponents)) {
|
|
|
+ JSONArray textLink = creativeComponents.getJSONArray("text_link");
|
|
|
+ if (!Check.isNull(textLink)) {
|
|
|
+ JSONObject value = textLink.getJSONObject(0).getJSONObject("value");
|
|
|
+ if (!Check.isNull(value)) {
|
|
|
+ JSONObject jumpInfo = value.getJSONObject("jump_info");
|
|
|
+ if (!Check.isNull(jumpInfo)) {
|
|
|
+ object.put("page_type", jumpInfo.getString("page_type"));
|
|
|
+ JSONObject pageSpec = jumpInfo.getJSONObject("page_spec");
|
|
|
+ if (!Check.isNull(pageSpec)) {
|
|
|
+ JSONObject wechatMiniProgramSpec = pageSpec.getJSONObject("wechat_mini_program_spec");
|
|
|
+ if (!Check.isNull(wechatMiniProgramSpec)) {
|
|
|
+ object.put("mini_program_id", wechatMiniProgramSpec.getString("mini_program_id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!Check.isNull(object.getString("mini_program_id"))) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONArray jumpInfo = creativeComponents.getJSONArray("jump_info");
|
|
|
+ if (!Check.isNull(jumpInfo)) {
|
|
|
+ JSONObject value = jumpInfo.getJSONObject(0).getJSONObject("value");
|
|
|
+ if (!Check.isNull(value)) {
|
|
|
+ object.put("page_type", value.getString("page_type"));
|
|
|
+ JSONObject pageSpec = value.getJSONObject("page_spec");
|
|
|
+ if (!Check.isNull(pageSpec)) {
|
|
|
+ JSONObject wechatMiniProgramSpec = pageSpec.getJSONObject("wechat_mini_program_spec");
|
|
|
+ if (!Check.isNull(wechatMiniProgramSpec)) {
|
|
|
+ object.put("mini_program_id", wechatMiniProgramSpec.getString("mini_program_id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!Check.isNull(object.getString("mini_program_id"))) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONArray mainJumpInfo = creativeComponents.getJSONArray("main_jump_info");
|
|
|
+ if (!Check.isNull(mainJumpInfo)) {
|
|
|
+ JSONObject value = mainJumpInfo.getJSONObject(0).getJSONObject("value");
|
|
|
+ if (!Check.isNull(value)) {
|
|
|
+ object.put("page_type", value.getString("page_type"));
|
|
|
+ JSONObject pageSpec = value.getJSONObject("page_spec");
|
|
|
+ if (!Check.isNull(pageSpec)) {
|
|
|
+ JSONObject wechatMiniProgramSpec = pageSpec.getJSONObject("wechat_mini_program_spec");
|
|
|
+ if (!Check.isNull(wechatMiniProgramSpec)) {
|
|
|
+ object.put("mini_program_id", wechatMiniProgramSpec.getString("mini_program_id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|