抖音小程序

DouYinApi.php 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. <?php
  2. namespace App\Support;
  3. use App\Log;
  4. use App\Service\AccessTokenService;
  5. use App\Service\HttpService;
  6. class DouYinApi
  7. {
  8. /**
  9. * 生成签名
  10. * @param $appId string 小程序app_id
  11. * @param $method string HTTP请求方法,如:POST,GET,PUT 等。注意请使用大写。
  12. * @param $url string 获取请求的开放平台接口的绝对 URL,并去除域名部分得到参与签名的 URI。 URI 必须以斜杠字符“/”开头。
  13. * @param $body string 请求报文主体;请求方法为GET时,报文主体为空。当请求方法为POST或PUT时,请使用报文内容。
  14. * @param $timestamp string 发起请求时系统的当前时间戳,即格林威治时间 1970年01月01日 00时00分00秒(北京时间 1970年01月01日 08时00分00秒)起至现在的总秒数,作为请求时间戳。「开放平台」会拒绝处理一个小时之前发起的请求。
  15. * @param $nonce_str string 任意生成一个随机字符串(长度不限制),以保证相同时间相同参数发起的请求签名值不一样。
  16. * @return string|null
  17. */
  18. private static function makeSign($appId, $method, $url, $body, $timestamp, $nonce_str) {
  19. //method内容必须大写,如GET、POST,uri不包含域名,必须以'/'开头
  20. $text = $method . "\n" . $url . "\n" . $timestamp . "\n" . $nonce_str . "\n" . $body . "\n";
  21. if(!file_exists(public_path('key/'.$appId."_private_key.pem"))) {
  22. return null;
  23. }
  24. $priKey = file_get_contents(public_path('key/'.$appId."_private_key.pem"));
  25. $privateKey = openssl_get_privatekey($priKey, '');
  26. openssl_sign($text, $sign, $privateKey, OPENSSL_ALGO_SHA256);
  27. $sign = base64_encode($sign);
  28. openssl_free_key($privateKey);
  29. return $sign;
  30. }
  31. /**
  32. * 验签 (接收支付回调使用)
  33. * @param $appId
  34. * @param $http_body
  35. * @param $timestamp
  36. * @param $nonce_str
  37. * @param $sign
  38. * @return bool|null
  39. */
  40. private static function verify($appId, $http_body, $timestamp, $nonce_str, $sign)
  41. {
  42. $data = $timestamp . "\n" . $nonce_str . "\n" . $http_body . "\n";
  43. $publicKey = file_get_contents(public_path("key/".$appId."platform_public_key.pem"));
  44. if (!$publicKey) {
  45. return null;
  46. }
  47. $res = openssl_get_publickey($publicKey); // 注意验签时publicKey使用平台公钥而非应用公钥
  48. $result = (bool)openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
  49. openssl_free_key($res);
  50. return $result; //bool
  51. }
  52. private static function commonRequest($appId, $requestUrl, $uri, $method, $body, $header = [], $retry = 0) {
  53. $timestamp = time();
  54. $nonce_str = md5(time().rand(10000,99999));
  55. $sign = DouYinApi::makeSign($appId, $method, $uri, json_encode($body, 256), $timestamp, $nonce_str);
  56. $headers = [
  57. 'Byte-Authorization: SHA256-RSA2048 appid="'.$appId.'",nonce_str="'.$nonce_str.'",timestamp="'.$timestamp.'",key_version="1"'.',signature="'.$sign.'"'
  58. ];
  59. if(!empty($header)){
  60. $headers = array_merge($headers, $header);
  61. }
  62. switch($method) {
  63. case 'POST':
  64. $response = HttpService::httpPost($requestUrl.$uri, json_encode($body, 256), true, $headers);
  65. break;
  66. case 'GET':
  67. $response = HttpService::httpGet($requestUrl.$uri, $headers);
  68. break;
  69. default:
  70. $response = null;
  71. break;
  72. }
  73. if($response === false) {
  74. if($retry <= 3) {
  75. $retry++;
  76. return self::commonRequest($appId, $requestUrl, $uri, $method, $body, $header, $retry);
  77. } else {
  78. # 重试几次还是失败了,要报警
  79. EmailQueue::rPush('抖音小程序请求api异常', json_encode([
  80. 'app_id' => $appId,
  81. 'uri' => $uri,
  82. 'body' => $body,
  83. 'header' => $headers,
  84. 'response' => $response
  85. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  86. }
  87. }
  88. $responseData = json_decode($response, 1);
  89. Log::logInfo($uri, [
  90. 'appid' => $appId,
  91. 'body' => $body,
  92. 'header' => $headers,
  93. 'response' => $responseData
  94. ], 'douYinApi');
  95. return $responseData;
  96. }
  97. # 获取小程序接口调用凭证 access_token
  98. public static function getAccessToken($appId, $retry = 0) {
  99. $requestUrl = 'https://developer.toutiao.com';
  100. $uri = config('douyin.getAccessToken');
  101. $params = [
  102. 'app_id' => $appId,
  103. 'secret' => config('douyin.app_info')[$appId]['secret'] ?? '',
  104. 'grant_type' => 'client_credential',
  105. ];
  106. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params);
  107. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  108. if($retry <= 3) {
  109. $retry++;
  110. return self::getAccessToken($appId, $retry);
  111. } else {
  112. # 重试几次还是失败了,要报警
  113. EmailQueue::rPush('抖音小程序获取accessToken异常', json_encode([
  114. 'app_id' => $appId,
  115. 'uri' => $uri,
  116. 'body' => $params,
  117. 'response' => $responseData
  118. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  119. }
  120. }
  121. return $responseData['data'] ?? [];
  122. }
  123. public static function getClientToken($appId, $retry = 0) {
  124. $requestUrl = 'https://open.douyin.com';
  125. $uri = config('douyin.getClientToken');
  126. $params = [
  127. 'client_key' => $appId,
  128. 'client_secret' => config('douyin.app_info')[$appId]['secret'] ?? '',
  129. 'grant_type' => 'client_credential',
  130. ];
  131. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params);
  132. if(isset($responseData['data']['error_code']) && 0 != $responseData['data']['error_code']) {
  133. if($retry <= 3) {
  134. $retry++;
  135. return self::getClientToken($appId, $retry);
  136. } else {
  137. # 重试几次还是失败了,要报警
  138. EmailQueue::rPush('抖音小程序获取clientToken异常', json_encode([
  139. 'app_id' => $appId,
  140. 'uri' => $uri,
  141. 'body' => $params,
  142. 'response' => $responseData
  143. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  144. }
  145. }
  146. return $responseData['data'] ?? [];
  147. }
  148. # 根据小程序code获取用户信息
  149. public static function code2Session($appId, $code, $anonymousCode = null, $retry = 0) {
  150. $requestUrl = 'https://developer.toutiao.com';
  151. $uri = config('douyin.getSession');
  152. if(empty($code) && empty($anonymousCode)) {
  153. return 1102;
  154. }
  155. $params = [
  156. 'appid' => $appId,
  157. 'secret' => config('douyin.app_info')[$appId]['secret'] ?? '',
  158. 'code' => $code ?? '',
  159. 'anonymous_code' => $anonymousCode ?? '',
  160. ];
  161. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params);
  162. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  163. if($retry <= 3) {
  164. $retry++;
  165. return self::code2Session($appId, $code, $anonymousCode, $retry);
  166. } else {
  167. # 重试几次还是失败了,要报警
  168. EmailQueue::rPush('抖音小程序请求codeSession异常', json_encode([
  169. 'app_id' => $appId,
  170. 'code' => $code,
  171. 'anonymous_code' => $anonymousCode,
  172. 'uri' => $uri,
  173. 'body' => $params,
  174. 'response' => $responseData
  175. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  176. }
  177. }
  178. return $responseData['data'] ?? [];
  179. }
  180. # 上传图片或者视频到抖音内容库
  181. public static function uploadMedia($appId, $type, $fileUrl, $videoTitle, $videoDesc, $format, $retry = 0) {
  182. $requestUrl = 'https://open.douyin.com';
  183. $uri = config('douyin.uploadMedia');
  184. $params = [
  185. 'resource_type' => $type,
  186. 'ma_app_id' => $appId,
  187. ];
  188. switch($type) {
  189. case 1:
  190. $params['video_meta'] = [
  191. 'url' => $fileUrl,
  192. 'title' => $videoTitle,
  193. 'description' => $videoDesc,
  194. 'format' => $format
  195. ];
  196. break;
  197. case 2:
  198. $params['image_meta'] = [
  199. 'url' => $fileUrl
  200. ];
  201. }
  202. $accessToken = AccessTokenService::getAccessToken($appId);
  203. $header = [
  204. 'access-token: '.$accessToken
  205. ];
  206. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  207. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  208. if($retry <= 3) {
  209. $retry++;
  210. return self::uploadMedia($appId, $type, $fileUrl, $videoTitle, $videoDesc, $format, $retry);
  211. } else {
  212. # 重试几次还是失败了,要报警
  213. EmailQueue::rPush('抖音小程序请求上传素材异常', json_encode([
  214. 'app_id' => $appId,
  215. 'file_url' => $fileUrl,
  216. 'type' => $type,
  217. 'title' => $videoTitle,
  218. 'desc' => $videoDesc,
  219. 'uri' => $uri,
  220. 'body' => $params,
  221. 'response' => $responseData
  222. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  223. }
  224. }
  225. return $responseData['data'] ?? [];
  226. }
  227. # 查询视频状态
  228. public static function queryVideo($appId, $videoIdType, $openVideoId, $dyCloudId, $retry = 0) {
  229. $requestUrl = 'https://open.douyin.com';
  230. $uri = config('douyin.queryVideo');
  231. $accessToken = AccessTokenService::getAccessToken($appId);
  232. $header = [
  233. 'access-token: '.$accessToken
  234. ];
  235. $params = [
  236. 'video_id_type' => $videoIdType, // 1通过open_video_id 查询 2通过抖音云的视频vid查询
  237. 'ma_app_id' => $appId,
  238. 'open_video_id' => $openVideoId,
  239. 'dy_cloud_id' => $dyCloudId
  240. ];
  241. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  242. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  243. if($retry <= 3) {
  244. $retry++;
  245. return self::queryVideo($appId, $videoIdType, $openVideoId, $dyCloudId,$retry);
  246. } else {
  247. # 重试几次还是失败了,要报警
  248. EmailQueue::rPush('抖音小程序获取视频状态结果异常', json_encode([
  249. 'app_id' => $appId,
  250. 'type' => $videoIdType,
  251. 'open_video_id' => $openVideoId,
  252. 'dy_cloud_id' => $dyCloudId,
  253. 'uri' => $uri,
  254. 'body' => $params,
  255. 'response' => $responseData
  256. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  257. }
  258. }
  259. return $responseData['data'] ?? [];
  260. }
  261. # 创建短剧
  262. public static function createAlbum($appId, $title, $seqNum, $coverList, $year, $albumStatus, $recommendation
  263. , $desp, $tagList, $qualification, $recordInfo, $recordAuditInfo, $retry = 0) {
  264. $requestUrl = 'https://open.douyin.com';
  265. $uri = config('douyin.createAlbum');
  266. $accessToken = AccessTokenService::getAccessToken($appId);
  267. $header = [
  268. 'access-token: '.$accessToken
  269. ];
  270. $params = [
  271. 'ma_app_id' => $appId,
  272. 'album_info' => [
  273. 'title' => $title,
  274. 'seq_num' => $seqNum,
  275. 'cover_list' => $coverList,
  276. 'year' => $year,
  277. 'album_status' => $albumStatus,// 短剧更新状态 1未上映 2更新中 3已完结
  278. 'recommendation' => $recommendation,
  279. 'desp' => $desp,
  280. 'tag_list' => $tagList,
  281. 'qualification' => $qualification, // 资质状态 1未报审 2报审通过 3报审不通过 4不建议报审
  282. ],
  283. ];
  284. if(!empty($recordInfo)) {
  285. $params['album_info']['record_info'] = $recordInfo;// 备案信息(报审通过必填)
  286. }
  287. if(!empty($recordAuditInfo)) { # 备案审核信息
  288. $params['album_info']['record_audit_info'] = $recordAuditInfo;
  289. }
  290. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  291. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  292. if($retry <= 3) {
  293. $retry++;
  294. return self::createAlbum($appId, $title, $seqNum, $coverList, $year, $albumStatus, $recommendation, $desp
  295. , $tagList, $qualification, $recordInfo, $recordAuditInfo, $retry);
  296. } else {
  297. # 重试几次还是失败了,要报警
  298. EmailQueue::rPush('抖音小程序创建短剧结果异常', json_encode([
  299. 'app_id' => $appId, 'title' => $title, 'seq_num' => $seqNum, 'cover_list' => $coverList,
  300. 'year' => $year, 'album_status' => $albumStatus,// 短剧更新状态 1未上映 2更新中 3已完结
  301. 'recommendation' => $recommendation, 'desp' => $desp, 'tag_list' => $tagList,
  302. 'qualification' => $qualification, // 资质状态 1未报审 2报审通过 3报审不通过 4不建议报审
  303. 'record_info' => $recordInfo, 'uri' => $uri, 'body' => $params, 'response' => $responseData
  304. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  305. }
  306. }
  307. return $responseData['data'] ?? [];
  308. }
  309. public static function editAlbum($appId, $albumId, $title, $seqNum, $coverList, $year, $albumStatus, $recommendation
  310. , $desp, $tagList, $qualification, $recordInfo, $recordAuditInfo, $episodeInfoList, $retry = 0) {
  311. $requestUrl = 'https://open.douyin.com';
  312. $uri = config('douyin.editAlbum');
  313. $accessToken = AccessTokenService::getAccessToken($appId);
  314. $header = [
  315. 'access-token: '.$accessToken
  316. ];
  317. $params = [
  318. 'ma_app_id' => $appId,
  319. 'album_id' => $albumId,
  320. 'album_info' => [
  321. 'title' => $title,
  322. 'seq_num' => $seqNum,
  323. 'cover_list' => $coverList,
  324. 'year' => $year,
  325. 'album_status' => $albumStatus,// 短剧更新状态 1未上映 2更新中 3已完结
  326. 'recommendation' => $recommendation,
  327. 'desp' => $desp,
  328. 'tag_list' => $tagList,
  329. 'qualification' => $qualification, // 资质状态 1未报审 2报审通过 3报审不通过 4不建议报审
  330. ],
  331. 'episode_info_list' => $episodeInfoList
  332. ];
  333. if(!empty($recordInfo)) {
  334. $params['album_info']['record_info'] = $recordInfo;// 备案信息(报审通过必填)
  335. }
  336. if(!empty($recordAuditInfo)) { # 备案审核信息
  337. $params['album_info']['record_audit_info'] = $recordAuditInfo;
  338. }
  339. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  340. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  341. if($retry <= 3) {
  342. $retry++;
  343. return self::editAlbum($appId, $albumId, $title, $seqNum, $coverList, $year, $albumStatus, $recommendation, $desp
  344. , $tagList, $qualification, $recordInfo, $recordAuditInfo, $episodeInfoList, $retry);
  345. } else {
  346. # 重试几次还是失败了,要报警
  347. EmailQueue::rPush('抖音小程序编辑短剧结果异常', json_encode([
  348. 'app_id' => $appId, 'album_id' => $albumId, 'title' => $title, 'seq_num' => $seqNum,
  349. 'cover_list' => $coverList, 'year' => $year, 'album_status' => $albumStatus,// 短剧更新状态 1未上映 2更新中 3已完结
  350. 'recommendation' => $recommendation, 'desp' => $desp, 'tag_list' => $tagList,
  351. 'qualification' => $qualification, // 资质状态 1未报审 2报审通过 3报审不通过 4不建议报审
  352. 'record_info' => $recordInfo, 'episode_info_list' => $episodeInfoList,// 剧集信息
  353. 'record_audit_info' => $recordAuditInfo,
  354. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  355. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  356. }
  357. }
  358. return $responseData['data'] ?? [];
  359. }
  360. public static function bindPage($appId, $singleSchemaBind, $schemaBindType, $retry = 0) {
  361. $requestUrl = 'https://open.douyin.com';
  362. $uri = config('douyin.bindPage');
  363. $accessToken = AccessTokenService::getAccessToken($appId);
  364. $header = [
  365. 'access-token: '.$accessToken
  366. ];
  367. $params = [
  368. 'app_id' => $appId,
  369. 'schema_bind_type' => $schemaBindType,
  370. 'single_schema_bind' => $singleSchemaBind
  371. ];
  372. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  373. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  374. if($retry <= 3) {
  375. $retry++;
  376. return self::bindPage($appId, $singleSchemaBind, $schemaBindType, $retry);
  377. } else {
  378. # 重试几次还是失败了,要报警
  379. EmailQueue::rPush('抖音小程序短剧绑定页面结果异常', json_encode([
  380. 'app_id' => $appId, 'schema_bind_type' => $schemaBindType,
  381. 'single_schema_bind' => $singleSchemaBind,
  382. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  383. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  384. }
  385. }
  386. return $responseData['data'] ?? [];
  387. }
  388. public static function albumAuth($maAppId, $appIdList, $albumId, $increment, $retry = 0) {
  389. $requestUrl = 'https://open.douyin.com';
  390. $uri = config('douyin.albumAuth');
  391. $accessToken = AccessTokenService::getAccessToken($maAppId);
  392. $header = [
  393. 'access-token: '.$accessToken
  394. ];
  395. $params = [
  396. 'app_id' => $maAppId,
  397. 'app_id_list' => $appIdList,
  398. 'album_id' => $albumId,
  399. 'increment' => $increment
  400. ];
  401. $responseData = self::commonRequest($maAppId, $requestUrl, $uri, 'POST', $params, $header);
  402. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  403. if($retry <= 3) {
  404. $retry++;
  405. return self::albumAuth($maAppId, $appIdList, $albumId, $increment, $retry);
  406. } else {
  407. # 重试几次还是失败了,要报警
  408. EmailQueue::rPush('抖音小程序短剧授权结果异常', json_encode([
  409. 'app_id' => $maAppId, 'app_id_list' => $appIdList,
  410. 'album_id' => $albumId, 'increment' => $increment,
  411. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  412. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  413. }
  414. }
  415. return $responseData['data'] ?? [];
  416. }
  417. public static function albumToExamine($appId, $albumId, $retry = 0) {
  418. $requestUrl = 'https://open.douyin.com';
  419. $uri = config('douyin.albumExamine');
  420. $accessToken = AccessTokenService::getAccessToken($appId);
  421. $header = [
  422. 'access-token: '.$accessToken
  423. ];
  424. $params = [
  425. 'ma_app_id' => $appId,
  426. 'album_id' => $albumId,
  427. ];
  428. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  429. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  430. if($retry <= 3) {
  431. $retry++;
  432. return self::albumToExamine($appId, $albumId, $retry);
  433. } else {
  434. # 重试几次还是失败了,要报警
  435. EmailQueue::rPush('抖音小程序短剧送审结果异常', json_encode([
  436. 'app_id' => $appId, 'album_id' => $albumId,
  437. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  438. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  439. }
  440. }
  441. return $responseData['data'] ?? [];
  442. }
  443. public static function albumOnline($appId, $albumId, $operate, $version, $retry = 0) {
  444. $requestUrl = 'https://open.douyin.com';
  445. $uri = config('douyin.albumOnline');
  446. $accessToken = AccessTokenService::getAccessToken($appId);
  447. $header = [
  448. 'access-token: '.$accessToken
  449. ];
  450. $params = [
  451. 'operate' => $operate,
  452. 'album_id' => $albumId,
  453. 'version' => $version,
  454. ];
  455. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  456. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  457. if($retry <= 3) {
  458. $retry++;
  459. return self::albumOnline($appId, $albumId, $operate, $version, $retry);
  460. } else {
  461. # 重试几次还是失败了,要报警
  462. EmailQueue::rPush('抖音小程序短剧上线结果异常', json_encode([
  463. 'app_id' => $appId, 'album_id' => $albumId, 'operate' => $operate, 'version' => $version,
  464. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  465. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  466. }
  467. }
  468. return $responseData['data'] ?? [];
  469. }
  470. public static function albumFetch($appId, $queryType, $batchQuery, $singleQuery, $detailQuery, $retry = 0) {
  471. $requestUrl = 'https://open.douyin.com';
  472. $uri = config('douyin.albumFetch');
  473. $accessToken = AccessTokenService::getAccessToken($appId);
  474. $header = [
  475. 'access-token: '.$accessToken
  476. ];
  477. $params = [
  478. 'ma_app_id' => $appId,
  479. 'query_type' => $queryType,
  480. ];
  481. if($batchQuery) {
  482. $params['batch_query'] = $batchQuery;
  483. }
  484. if($singleQuery) {
  485. $params['single_query'] = $singleQuery;
  486. }
  487. if($detailQuery) {
  488. $params['detail_query'] = $detailQuery;
  489. }
  490. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  491. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  492. if($retry <= 3) {
  493. $retry++;
  494. return self::albumFetch($appId, $queryType, $batchQuery, $singleQuery, $detailQuery, $retry);
  495. } else {
  496. # 重试几次还是失败了,要报警
  497. EmailQueue::rPush('抖音小程序短剧查询果异常', json_encode([
  498. 'app_id' => $appId, 'query_type' => $queryType, 'batch_query' => $batchQuery
  499. , 'single_query' => $singleQuery, 'detail_query' => $detailQuery,
  500. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  501. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  502. }
  503. }
  504. return $responseData['data'] ?? [];
  505. }
  506. public static function getCustomerServiceList($appId, $pageNum, $pageSize, $type, $retry = 0) {
  507. $requestUrl = 'https://open.douyin.com';
  508. $uri = config('douyin.customerService');
  509. $accessToken = AccessTokenService::getAccessToken($appId);
  510. $header = [
  511. 'access-token: '.$accessToken
  512. ];
  513. $params = [
  514. 'page_num' => $pageNum,
  515. 'page_size'=> $pageSize,
  516. 'type' => $type
  517. ];
  518. $uri = $uri.'?'.http_build_query($params);
  519. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'GET', [], $header);
  520. if(isset($responseData['err_no']) && 0 != $responseData['err_no']) {
  521. if($retry <= 3) {
  522. $retry++;
  523. return self::getCustomerServiceList($appId, $pageNum, $pageSize, $type, $retry);
  524. } else {
  525. # 重试几次还是失败了,要报警
  526. EmailQueue::rPush('抖音小程序短剧绑定抖音号结果异常', json_encode([
  527. 'app_id' => $appId, 'page_num' => $pageNum, 'page_size' => $pageSize,'type' => $type,
  528. 'uri' => $uri, 'body' => $params, 'response' => $responseData
  529. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  530. }
  531. }
  532. return $responseData['data'] ?? [];
  533. }
  534. # 查询广告位列表
  535. public static function syncAdPlacement($appId, $retry = 0) {
  536. $requestUrl = 'https://open.douyin.com';
  537. $uri = config('douyin.adPlacementQuery');
  538. $accessToken = AccessTokenService::getAccessToken($appId);
  539. $header = [
  540. 'access-token: '.$accessToken
  541. ];
  542. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'GET', [], $header);
  543. if(isset($responseData['err_no']) && !in_array($responseData['err_no'], [0, 28005042])) {# 尚未开通流量主
  544. if($retry <= 3) {
  545. $retry++;
  546. return self::syncAdPlacement($appId, $retry);
  547. } else {
  548. # 重试几次还是失败了,要报警
  549. EmailQueue::rPush('抖音小程序广告位列表结果异常', json_encode([
  550. 'app_id' => $appId, 'uri' => $uri, 'response' => $responseData
  551. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  552. }
  553. }
  554. return $responseData['data'] ?? [];
  555. }
  556. # 添加广告位
  557. public static function adPlacementAdd($appId, $adType, $adName, $retry = 0) {
  558. $requestUrl = 'https://open.douyin.com';
  559. $uri = config('douyin.adPlacementAdd');
  560. $accessToken = AccessTokenService::getAccessToken($appId);
  561. $header = [
  562. 'access-token: '.$accessToken,
  563. 'content-type: application/json'
  564. ];
  565. $params = [
  566. 'ad_placement_name' => $adName,
  567. 'ad_placement_type' => $adType
  568. ];
  569. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  570. if(isset($responseData['err_no']) && !in_array($responseData['err_no'], [0, 28005042])) {# 尚未开通流量主
  571. if($retry <= 3) {
  572. $retry++;
  573. return self::adPlacementAdd($appId, $adType, $adName, $retry);
  574. } else {
  575. # 重试几次还是失败了,要报警
  576. EmailQueue::rPush('抖音小程序添加广告位结果异常', json_encode([
  577. 'app_id' => $appId, 'ad_type' => $adType, 'ad_name' => $adName, 'uri' => $uri, 'response' => $responseData
  578. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  579. }
  580. }
  581. return (0 == $responseData['err_no']);
  582. }
  583. public static function adPlacementUpdate($appId, $adPlacementId, $status, $retry = 0) {
  584. $requestUrl = 'https://open.douyin.com';
  585. $uri = config('douyin.adPlacementUpdate');
  586. $accessToken = AccessTokenService::getAccessToken($appId);
  587. $header = [
  588. 'access-token: '.$accessToken
  589. ];
  590. $params = [
  591. 'ad_placement_id' => $adPlacementId,
  592. 'status' => $status
  593. ];
  594. $responseData = self::commonRequest($appId, $requestUrl, $uri, 'POST', $params, $header);
  595. if(isset($responseData['err_no']) && !in_array($responseData['err_no'], [0, 28005042])) {# 尚未开通流量主
  596. if($retry <= 3) {
  597. $retry++;
  598. return self::adPlacementUpdate($appId, $adPlacementId, $status, $retry);
  599. } else {
  600. # 重试几次还是失败了,要报警
  601. EmailQueue::rPush('抖音小程序更新广告位状态结果异常', json_encode([
  602. 'app_id' => $appId, 'ad_placement_id' => $adPlacementId, 'status' => $status, 'uri' => $uri, 'response' => $responseData
  603. ], 1), ['song.shen@kuxuan-inc.com'], '抖音小程序');
  604. }
  605. }
  606. return (0 == $responseData['err_no']);
  607. }
  608. }