|
| 1 | +#!/usr/bin/env php |
| 2 | +<?php |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +const SHOPEE_API_URL = 'https://open.shopee.com/opservice/api/v1'; |
| 6 | + |
| 7 | +// get shopee openapi updates list |
| 8 | +$shopee_openapi_updates = curl_get(SHOPEE_API_URL.'/content/list?SPC_CDS_VER=2&category_id=55&page_size=10&page_index=1'); |
| 9 | +$shopee_openapi_updates = json_decode($shopee_openapi_updates, true); |
| 10 | + |
| 11 | +// latest announcement |
| 12 | +$latest_announcement = $shopee_openapi_updates['data'][0] ?? null; |
| 13 | + |
| 14 | +if (!$latest_announcement) { |
| 15 | + die("No announcement found."); |
| 16 | +} |
| 17 | + |
| 18 | +$announcement_id = $latest_announcement['id']; |
| 19 | +$announcement_title = $latest_announcement['title']; |
| 20 | +$repo = getenv('GITHUB_REPOSITORY'); |
| 21 | +$unique_flag = "[Shopee-ID:{$announcement_id}]"; |
| 22 | + |
| 23 | +echo "Checking Issue for announcement ID: {$announcement_id}\n\n"; |
| 24 | +$search_query = urlencode("\"{$unique_flag}\" repo:{$repo} is:issue"); |
| 25 | +$api_url = "https://api.github.com/search/issues?q={$search_query}"; |
| 26 | + |
| 27 | +$search_result = curl_get($api_url, getenv('GITHUB_TOKEN')); |
| 28 | + |
| 29 | +// checking if issue already exists |
| 30 | +if (isset($searchResult['total_count']) && $searchResult['total_count'] > 0) { |
| 31 | + echo "Issue already exists for announcement ID: {$announcement_id}\n\n"; |
| 32 | + exit; |
| 33 | +} |
| 34 | + |
| 35 | +// get announcement content |
| 36 | +$latest_announcement_data = curl_get(SHOPEE_API_URL.'/content/detail?SPC_CDS_VER=2&id='.$latest_announcement['id']); |
| 37 | +$latest_announcement_data = json_decode($latest_announcement_data, true); |
| 38 | + |
| 39 | +// announcement content |
| 40 | +$blocks = json_decode($latest_announcement_data['detail'], true); |
| 41 | +$markdownOutput = convertShopeeJsonToEnglishMarkdown($blocks); |
| 42 | + |
| 43 | +echo "No Issue found. Creating new Issue for announcement ID: {$announcement_id}\n\n"; |
| 44 | +$issue_title = "{$announcement_title} {$unique_flag}"; |
| 45 | +$issue_body = <<<MARKDOWN |
| 46 | +## New Shopee's Openapi Announcement (ID: {$announcement_id}) |
| 47 | +
|
| 48 | +{$markdownOutput} |
| 49 | +
|
| 50 | +--- |
| 51 | +@junie-agent Please check the changes for this endpoint in Shopee's Openapi Announcement, update the corresponding PHP source code in the repo, and create a new Pull Request for review. |
| 52 | +MARKDOWN; |
| 53 | + |
| 54 | +echo $markdownOutput;exit; |
| 55 | + |
| 56 | +function curl_get($url, $github_token = null) |
| 57 | +{ |
| 58 | + $ch = curl_init(); |
| 59 | + curl_setopt($ch, CURLOPT_URL, $url); |
| 60 | + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
| 61 | + curl_setopt($ch, CURLOPT_USERAGENT, 'Shopee-Automation-Script'); |
| 62 | + |
| 63 | + if ($github_token) { |
| 64 | + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer {$github_token}"]); |
| 65 | + } |
| 66 | + |
| 67 | + $output = curl_exec($ch); |
| 68 | + curl_close($ch); |
| 69 | + |
| 70 | + return json_decode($output, true); |
| 71 | +} |
| 72 | + |
| 73 | +function parseHtmlTableToMarkdown(string $htmlTable): string |
| 74 | +{ |
| 75 | + // Extract all table rows. |
| 76 | + if (!preg_match_all('/<tr[^>]*>(.*?)<\/tr>/is', $htmlTable, $rows)) { |
| 77 | + return ''; |
| 78 | + } |
| 79 | + |
| 80 | + $markdownRows = []; |
| 81 | + $isHeader = true; |
| 82 | + $lineBreaks = ['<br />', '<br>', "\n", "\r"]; |
| 83 | + |
| 84 | + foreach ($rows[1] as $rowHtml) { |
| 85 | + // Extract all th/td cells from the current row. |
| 86 | + if (!preg_match_all('/<(th|td)[^>]*>(.*?)<\/\1>/is', $rowHtml, $cells)) { |
| 87 | + continue; |
| 88 | + } |
| 89 | + |
| 90 | + $cleanCells = []; |
| 91 | + foreach ($cells[2] as $cell) { |
| 92 | + // Remove nested tags, normalize whitespace and keep <code> tags. |
| 93 | + $cell = strip_tags($cell, '<code>'); |
| 94 | + $cell = str_replace($lineBreaks, ' ', $cell); |
| 95 | + $cleanCells[] = trim((string) preg_replace('/\s+/', ' ', $cell)); |
| 96 | + } |
| 97 | + |
| 98 | + if ($cleanCells === []) { |
| 99 | + continue; |
| 100 | + } |
| 101 | + |
| 102 | + $markdownRows[] = '| ' . implode(' | ', $cleanCells) . ' |'; |
| 103 | + |
| 104 | + // For the first row (header), append markdown separator. |
| 105 | + if ($isHeader) { |
| 106 | + $alignments = array_fill(0, count($cleanCells), '---'); |
| 107 | + $markdownRows[] = '| ' . implode(' | ', $alignments) . ' |'; |
| 108 | + $isHeader = false; |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + return implode("\n", $markdownRows) . "\n"; |
| 113 | +} |
| 114 | + |
| 115 | +/** |
| 116 | + * Convert Shopee JSON blocks into English markdown. |
| 117 | + */ |
| 118 | +function convertShopeeJsonToEnglishMarkdown(array $blocks): string |
| 119 | +{ |
| 120 | + $markdown = ""; |
| 121 | + $containsChinesePattern = '/[\x{4e00}-\x{9fa5}]+/u'; |
| 122 | + |
| 123 | + foreach ($blocks as $block) { |
| 124 | + $type = $block['type'] ?? ''; |
| 125 | + $html = $block['html'] ?? ''; |
| 126 | + |
| 127 | + // --- LANGUAGE FILTERING STEP --- |
| 128 | + // Stop once Chinese translation blocks start, to keep only English content. |
| 129 | + if (strpos($html, '尊敬的开发者') || preg_match($containsChinesePattern, $html) === 1) { |
| 130 | + break; |
| 131 | + } |
| 132 | + |
| 133 | + // --- HTML TO MARKDOWN CONVERSION --- |
| 134 | + switch ($type) { |
| 135 | + case 'heading': |
| 136 | + // Convert heading tags to markdown heading syntax. |
| 137 | + $cleanText = strip_tags($html); |
| 138 | + $markdown .= "## " . trim($cleanText) . "\n\n"; |
| 139 | + break; |
| 140 | + |
| 141 | + case 'table': |
| 142 | + $markdown .= parseHtmlTableToMarkdown($html) . "\n"; |
| 143 | + break; |
| 144 | + |
| 145 | + case 'text': |
| 146 | + // Handle ordered lists (<ol><li>). |
| 147 | + if (strpos($html, '<ol>')) { |
| 148 | + preg_match_all('/<li>(.*?)<\/li>/is', $html, $lis); |
| 149 | + foreach ($lis[1] as $index => $li) { |
| 150 | + $cleanLi = strip_tags($li, '<a><code>'); |
| 151 | + // Convert <a> tags to markdown links. |
| 152 | + $cleanLi = preg_replace('/<a href="([^"]+)">([^<]+)<\/a>/i', '[$2]($1)', $cleanLi); |
| 153 | + $markdown .= ($index + 1) . ". " . trim($cleanLi) . "\n"; |
| 154 | + } |
| 155 | + $markdown .= "\n"; |
| 156 | + } else { |
| 157 | + // Handle normal text paragraphs and break lines. |
| 158 | + $html = str_replace(['<br />', '<br>'], "\n", $html); |
| 159 | + |
| 160 | + // Convert inline <a> links. |
| 161 | + $html = preg_replace('/<a href="([^"]+)"[^>]*>([^<]+)<\/a>/i', '[$2]($1)', $html); |
| 162 | + |
| 163 | + // Convert bold/italic tags to markdown markers, keep <code>. |
| 164 | + $html = preg_replace('/<\/?b[^>]*>/i', '**', $html); |
| 165 | + $html = preg_replace('/<\/?i[^>]*>/i', '*', $html); |
| 166 | + |
| 167 | + // Remove remaining HTML tags except <code>. |
| 168 | + $cleanText = strip_tags($html, '<code>'); |
| 169 | + |
| 170 | + // Normalize HTML entities (for example, & to &). |
| 171 | + $cleanText = html_entity_decode($cleanText); |
| 172 | + |
| 173 | + if (trim($cleanText) !== '') { |
| 174 | + $markdown .= trim($cleanText) . "\n\n"; |
| 175 | + } |
| 176 | + } |
| 177 | + break; |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + // Remove excessive blank lines. |
| 182 | + return trim(preg_replace("/\n{3,}/", "\n\n", $markdown)); |
| 183 | +} |
| 184 | + |
| 185 | +?> |
0 commit comments