1<?php 2class ReutersBridge extends BridgeAbstract 3{ 4 const MAINTAINER = 'hollowleviathan, spraynard, csisoap'; 5 const NAME = 'Reuters Bridge'; 6 const URI = 'https://reuters.com/'; 7 const CACHE_TIMEOUT = 1800; // 30min 8 const DESCRIPTION = 'Returns news from Reuters'; 9 10 private $feedName = self::NAME; 11 12 /** 13 * Wireitem types allowed in the final story output 14 */ 15 const ALLOWED_WIREITEM_TYPES = array( 16 'story', 17 'headlines' 18 ); 19 20 /** 21 * Wireitem template types allowed in the final story output 22 */ 23 const ALLOWED_TEMPLATE_TYPES = array( 24 'story', 25 'headlines' 26 ); 27 28 const PARAMETERS = array( 29 array( 30 'feed' => array( 31 'name' => 'News Feed', 32 'type' => 'list', 33 'title' => 'Feeds from Reuters U.S/International edition', 34 'values' => array( 35 'Aerospace and Defense' => 'aerospace', 36 'Business' => 'business', 37 'China' => 'china', 38 'Energy' => 'energy', 39 'Entertainment' => 'chan:8ym8q8dl', 40 'Environment' => 'chan:6u4f0jgs', 41 'Health' => 'chan:8hw7807a', 42 'Lifestyle' => 'life', 43 'Markets' => 'markets', 44 'Politics' => 'politics', 45 'Science' => 'science', 46 'Special Reports' => 'special-reports', 47 'Sports' => 'sports', 48 'Tech' => 'tech', 49 'Top News' => 'home/topnews', 50 'UK' => 'chan:61leiu7j', 51 'USA News' => 'us', 52 'Wire' => 'wire', 53 'World' => 'world', 54 ) 55 ) 56 ) 57 ); 58 59 /** 60 * Performs an HTTP request to the Reuters API and returns decoded JSON 61 * in the form of an associative array 62 * @param string $feed_uri Parameter string to the Reuters API 63 * @return array 64 */ 65 private function getJson($feed_uri) 66 { 67 $uri = "https://wireapi.reuters.com/v8$feed_uri"; 68 $returned_data = getContents($uri); 69 return json_decode($returned_data, true); 70 } 71 72 /** 73 * Takes in data from Reuters Wire API and 74 * creates structured data in the form of a list 75 * of story information. 76 * @param array $data JSON collected from the Reuters Wire API 77 */ 78 private function processData($data) 79 { 80 /** 81 * Gets a list of wire items which are groups of templates 82 */ 83 $reuters_allowed_wireitems = array_filter( 84 $data, function ($wireitem) { 85 return in_array( 86 $wireitem['wireitem_type'], 87 self::ALLOWED_WIREITEM_TYPES 88 ); 89 } 90 ); 91 92 /* 93 * Gets a list of "Templates", which is data containing a story 94 */ 95 $reuters_wireitem_templates = array_reduce( 96 $reuters_allowed_wireitems, 97 function (array $carry, array $wireitem) { 98 $wireitem_templates = $wireitem['templates']; 99 return array_merge( 100 $carry, 101 array_filter( 102 $wireitem_templates, function ( 103 array $template_data 104 ) { 105 return in_array( 106 $template_data['type'], 107 self::ALLOWED_TEMPLATE_TYPES 108 ); 109 } 110 ) 111 ); 112 }, 113 array() 114 ); 115 116 return $reuters_wireitem_templates; 117 } 118 119 private function getArticle($feed_uri) 120 { 121 // This will make another request to API to get full detail of article and author's name. 122 $rawData = $this->getJson($feed_uri); 123 $reuters_wireitems = $rawData['wireitems']; 124 $processedData = $this->processData($reuters_wireitems); 125 126 $first = reset($processedData); 127 $article_content = $first['story']['body_items']; 128 $authorlist = $first['story']['authors']; 129 $category = $first['story']['channel']['name']; 130 $image_list = $first['story']['images']; 131 132 $content_detail = array( 133 'content' => $this->handleArticleContent($article_content), 134 'author' => $this->handleAuthorName($authorlist), 135 'category' => $category, 136 'images' => $this->handleImage($image_list), 137 ); 138 return $content_detail; 139 } 140 141 private function handleImage($images) { 142 $img_placeholder = ''; 143 144 foreach($images as $image) { // Add more image to article. 145 $image_url = $image['url']; 146 $image_caption = $image['caption']; 147 $img = "<img src=\"$image_url\">"; 148 $img_caption = "<figcaption style=\"text-align: center;\"><i>$image_caption</i></figcaption>"; 149 $figure = "<figure>$img \t $img_caption</figure>"; 150 $img_placeholder = $img_placeholder . $figure; 151 } 152 153 return $img_placeholder; 154 } 155 156 private function handleAuthorName($authors) { 157 $author = ''; 158 $counter = 0; 159 foreach ($authors as $data) { 160 //Formatting author's name. 161 $counter++; 162 $name = $data['name']; 163 if ($counter == count($authors)) { 164 $author = $author . $name; 165 } else { 166 $author = $author . "$name, "; 167 } 168 } 169 170 return $author; 171 } 172 173 private function handleArticleContent($contents) { 174 $description = ''; 175 foreach ($contents as $content) { 176 $data; 177 if(isset($content['content'])) { 178 $data = $content['content']; 179 } 180 switch($content['type']) { 181 case 'paragraph': 182 $description = $description . "<p>$data</p>"; 183 break; 184 case 'heading': 185 $description = $description . "<h3>$data</h3>"; 186 break; 187 case 'infographics': 188 $description = $description . "<img src=\"$data\">"; 189 break; 190 case 'inline_items': 191 $item_list = $content['items']; 192 $description = $description . '<p>'; 193 foreach ($item_list as $item) { 194 if($item['type'] == 'text') { 195 $description = $description . $item['content']; 196 } else { 197 $description = $description . $item['symbol']; 198 } 199 } 200 $description = $description . '</p>'; 201 break; 202 case 'p_table': 203 $description = $description . $content['content']; 204 break; 205 } 206 } 207 208 return $description; 209 } 210 211 public function getName() { 212 return $this->feedName; 213 } 214 215 public function collectData() 216 { 217 $reuters_feed_name = $this->getInput('feed'); 218 219 if(strpos($reuters_feed_name, 'chan:') !== false) { 220 // Now checking whether that feed has unique ID or not. 221 $feed_uri = "/feed/rapp/us/wirefeed/$reuters_feed_name"; 222 } else { 223 $feed_uri = "/feed/rapp/us/tabbar/feeds/$reuters_feed_name"; 224 } 225 226 $data = $this->getJson($feed_uri); 227 228 $reuters_wireitems = $data['wireitems']; 229 $this->feedName = $data['wire_name'] . ' | Reuters'; 230 $processedData = $this->processData($reuters_wireitems); 231 232 // Merge all articles from Editor's Highlight section into existing array of templates. 233 $top_section = reset($processedData); 234 if ($top_section['type'] == 'headlines') { 235 $top_section = array_shift($processedData); 236 $articles = $top_section['headlines']; 237 $processedData = array_merge($articles, $processedData); 238 } 239 240 foreach ($processedData as $story) { 241 $item['uid'] = $story['story']['usn']; 242 $article_uri = $story['template_action']['api_path']; 243 $content_detail = $this->getArticle($article_uri); 244 $description = $content_detail['content']; 245 $author = $content_detail['author']; 246 $images = $content_detail['images']; 247 $item['categories'] = array($content_detail['category']); 248 $item['author'] = $author; 249 if (!(bool) $description) { 250 $description = $story['story']['lede']; // Just in case the content doesn't have anything. 251 } else { 252 $item['content'] = "$description $images"; 253 } 254 255 $item['title'] = $story['story']['hed']; 256 $item['timestamp'] = $story['story']['updated_at']; 257 $item['uri'] = $story['template_action']['url']; 258 $this->items[] = $item; 259 } 260 } 261} 262