2021-01-29 20:57:40 +03:00
|
|
|
|
<?php
|
2022-07-01 16:10:30 +03:00
|
|
|
|
|
2021-01-29 20:57:40 +03:00
|
|
|
|
class ReutersBridge extends BridgeAbstract
|
|
|
|
|
{
|
2022-07-01 16:10:30 +03:00
|
|
|
|
const MAINTAINER = 'hollowleviathan, spraynard, csisoap';
|
|
|
|
|
const NAME = 'Reuters Bridge';
|
|
|
|
|
const URI = 'https://www.reuters.com';
|
|
|
|
|
const CACHE_TIMEOUT = 1800; // 30min
|
|
|
|
|
const DESCRIPTION = 'Returns news from Reuters';
|
|
|
|
|
|
|
|
|
|
private $feedName = self::NAME;
|
|
|
|
|
private $useWireAPI = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wireitem types allowed in the final story output
|
|
|
|
|
*/
|
|
|
|
|
const ALLOWED_WIREITEM_TYPES = [
|
|
|
|
|
'story',
|
|
|
|
|
'headlines'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wireitem template types allowed in the final story output
|
|
|
|
|
*/
|
|
|
|
|
const ALLOWED_TEMPLATE_TYPES = [
|
|
|
|
|
'story',
|
|
|
|
|
'headlines'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const PARAMETERS = [
|
|
|
|
|
[
|
|
|
|
|
'feed' => [
|
|
|
|
|
'name' => 'News Feed',
|
|
|
|
|
'type' => 'list',
|
|
|
|
|
'title' => 'Feeds from Reuters U.S/International edition',
|
|
|
|
|
'values' => [
|
|
|
|
|
'Top News' => 'home/topnews',
|
|
|
|
|
'Fact Check' => 'chan:abtpk0vm',
|
|
|
|
|
'Entertainment' => 'chan:8ym8q8dl',
|
|
|
|
|
'Politics' => 'politics',
|
|
|
|
|
'Wire' => 'wire',
|
|
|
|
|
'Breakingviews' => '/breakingviews',
|
|
|
|
|
'World' => [
|
|
|
|
|
'World' => 'world',
|
|
|
|
|
'Africa' => '/world/africa',
|
|
|
|
|
'Americas' => '/world/americas',
|
|
|
|
|
'Asia-Pacific' => '/world/asia-pacific',
|
|
|
|
|
'China' => 'china',
|
|
|
|
|
'europe' => '/world/europe',
|
|
|
|
|
'India' => '/world/india',
|
|
|
|
|
'Middle East' => '/world/middle-east',
|
|
|
|
|
'UK' => 'chan:61leiu7j',
|
|
|
|
|
'USA News' => 'us',
|
|
|
|
|
'The Great Reboot' => '/world/the-great-reboot',
|
|
|
|
|
'Reuters Next' => '/world/reuters-next'
|
|
|
|
|
],
|
|
|
|
|
'Business' => [
|
|
|
|
|
'Business' => 'business',
|
|
|
|
|
'Aerospace and Defense' => 'aerospace',
|
|
|
|
|
'Autos Transportation' => '/business/autos-transportation',
|
|
|
|
|
'Energy' => 'energy',
|
|
|
|
|
'Finance' => '/business/finance',
|
|
|
|
|
'Health' => 'chan:8hw7807a',
|
|
|
|
|
'Media Telecom' => '/business/media-telecom',
|
|
|
|
|
'Retail Consumer' => '/business/retail-consumer',
|
|
|
|
|
'Sustainable Business' => '/business/sustainable-business',
|
|
|
|
|
'Change Suite' => '/business/change-suite',
|
|
|
|
|
'Future of Health' => '/business/future-of-health',
|
|
|
|
|
'Future of Money' => '/business/future-of-money',
|
|
|
|
|
'Take Five' => '/business/take-five',
|
|
|
|
|
'Reuters Impact' => '/business/reuters-impact',
|
|
|
|
|
],
|
|
|
|
|
'Legal' => [
|
|
|
|
|
'Legal' => '/legal',
|
|
|
|
|
'Government' => '/legal/government',
|
|
|
|
|
'Legal Industry' => '/legal/legalindustry',
|
|
|
|
|
'Litigation' => '/legal/litigation',
|
|
|
|
|
'Transactional' => '/legal/transactional',
|
|
|
|
|
],
|
|
|
|
|
'Markets' => [
|
|
|
|
|
'Markets' => 'markets',
|
|
|
|
|
'Asian Markets' => '/markets/asia',
|
|
|
|
|
'Commodities' => '/markets/commodities',
|
|
|
|
|
'Currencies' => '/markets/currencies',
|
|
|
|
|
'Deals' => '/markets/deals',
|
|
|
|
|
'European Markets' => '/markets/europe',
|
|
|
|
|
'Funds' => '/markets/fund',
|
|
|
|
|
'Global Market Data' => '/markets/global-market-data',
|
|
|
|
|
'Rates & Bonds' => '/markets/rates-bonds',
|
|
|
|
|
'Stocks' => '/markets/stocks',
|
|
|
|
|
'U.S Markets' => '/markets/us',
|
|
|
|
|
'Wealth' => '/markets/wealth',
|
|
|
|
|
'Macro Matters' => '/markets/macromatters',
|
|
|
|
|
],
|
|
|
|
|
'Technology' => [
|
|
|
|
|
'Technology' => 'tech',
|
|
|
|
|
'Disrupted' => '/technology/disrupted',
|
|
|
|
|
'Reuters Momentum' => '/technology/reuters-momentum',
|
|
|
|
|
],
|
|
|
|
|
'Sports' => [
|
|
|
|
|
'Sports' => 'sports',
|
|
|
|
|
'Athletics' => '/lifestyle/sports/athletics',
|
|
|
|
|
'Cricket' => '/lifestyle/sports/cricket',
|
|
|
|
|
'Cycling' => '/lifestyle/sports/cycling',
|
|
|
|
|
'Golf' => '/lifestyle/sports/golf',
|
|
|
|
|
'Motor Sports' => '/lifestyle/sports/motor-sports',
|
|
|
|
|
'Soccer' => '/lifestyle/sports/soccer',
|
|
|
|
|
'Tennis' => '/lifestyle/sports/tennis',
|
|
|
|
|
],
|
|
|
|
|
'Lifestyle' => [
|
|
|
|
|
'Lifestyle' => 'life',
|
|
|
|
|
'Oddly Enough' => '/lifestyle/oddly-enough',
|
|
|
|
|
'Science' => 'science',
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const BACKWARD_COMPATIBILITY = [
|
|
|
|
|
'world' => '/world',
|
|
|
|
|
'china' => '/world/china',
|
|
|
|
|
'chan:61leiu7j' => '/world/uk',
|
|
|
|
|
'us' => '/world/us',
|
|
|
|
|
'business' => '/business',
|
|
|
|
|
'aerospace' => '/business/aerospace-defense',
|
|
|
|
|
'energy' => '/business/energy',
|
|
|
|
|
'environment' => '/business/environment',
|
|
|
|
|
'chan:8hw7807a' => '/business/healthcare-pharmaceuticals',
|
|
|
|
|
'markets' => '/markets',
|
|
|
|
|
'tech' => '/technology',
|
|
|
|
|
'sports' => '/lifestyle/sports',
|
|
|
|
|
'life' => '/lifestyle',
|
|
|
|
|
'science' => '/lifestyle/science',
|
|
|
|
|
'home/topnews' => '/home',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const OLD_WIRE_SECTION = [
|
|
|
|
|
'home/topnews',
|
|
|
|
|
'chan:abtpk0vm',
|
|
|
|
|
'chan:8ym8q8dl',
|
|
|
|
|
'politics',
|
|
|
|
|
'wire'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Performs an HTTP request to the Reuters API and returns decoded JSON
|
|
|
|
|
* in the form of an associative array
|
|
|
|
|
* @param string $feed_uri Full API URL to fetch data
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
private function getJson($uri)
|
|
|
|
|
{
|
|
|
|
|
$returned_data = getContents($uri);
|
|
|
|
|
return json_decode($returned_data, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Takes in data from Reuters Wire API and
|
|
|
|
|
* creates structured data in the form of a list
|
|
|
|
|
* of story information.
|
|
|
|
|
* @param array $data JSON collected from the Reuters Wire API
|
|
|
|
|
*/
|
|
|
|
|
private function processData($data)
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Gets a list of wire items which are groups of templates
|
|
|
|
|
*/
|
|
|
|
|
$reuters_allowed_wireitems = array_filter(
|
|
|
|
|
$data,
|
|
|
|
|
function ($wireitem) {
|
|
|
|
|
return in_array(
|
|
|
|
|
$wireitem['wireitem_type'],
|
|
|
|
|
self::ALLOWED_WIREITEM_TYPES
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Gets a list of "Templates", which is data containing a story
|
|
|
|
|
*/
|
|
|
|
|
$reuters_wireitem_templates = array_reduce(
|
|
|
|
|
$reuters_allowed_wireitems,
|
|
|
|
|
function (array $carry, array $wireitem) {
|
|
|
|
|
$wireitem_templates = $wireitem['templates'];
|
|
|
|
|
return array_merge(
|
|
|
|
|
$carry,
|
|
|
|
|
array_filter(
|
|
|
|
|
$wireitem_templates,
|
|
|
|
|
function (
|
|
|
|
|
array $template_data
|
|
|
|
|
) {
|
|
|
|
|
return in_array(
|
|
|
|
|
$template_data['type'],
|
|
|
|
|
self::ALLOWED_TEMPLATE_TYPES
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return $reuters_wireitem_templates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getSectionEndpoint()
|
|
|
|
|
{
|
|
|
|
|
$endpoint = $this->getInput('feed');
|
|
|
|
|
if (isset(self::BACKWARD_COMPATIBILITY[$endpoint])) {
|
|
|
|
|
$endpoint = self::BACKWARD_COMPATIBILITY[$endpoint];
|
|
|
|
|
} elseif (in_array($endpoint, self::OLD_WIRE_SECTION)) {
|
|
|
|
|
$this->useWireAPI = true;
|
|
|
|
|
}
|
|
|
|
|
return $endpoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string $endpoint - A endpoint is provided could be article URI or ID.
|
|
|
|
|
* @param string $fetch_type - Provide what kind of fetch do you want? Article or Section.
|
|
|
|
|
* @param boolean $is_article_uid {true|false} - A boolean flag to determined if using UID instead of url to fetch.
|
|
|
|
|
* @return string A completed API URL to fetch data
|
|
|
|
|
*/
|
|
|
|
|
private function getAPIURL($endpoint, $fetch_type, $is_article_uid = false)
|
|
|
|
|
{
|
|
|
|
|
$base_url = self::URI . '/pf/api/v3/content/fetch/';
|
|
|
|
|
$wire_url = 'https://wireapi.reuters.com/v8';
|
|
|
|
|
switch ($fetch_type) {
|
|
|
|
|
case 'article':
|
|
|
|
|
if ($this->useWireAPI) {
|
|
|
|
|
return $wire_url . $endpoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$base_query = [
|
|
|
|
|
'website' => 'reuters',
|
|
|
|
|
];
|
|
|
|
|
$query = [];
|
|
|
|
|
|
|
|
|
|
if ($is_article_uid) {
|
|
|
|
|
$query = [
|
|
|
|
|
'id' => $endpoint
|
|
|
|
|
];
|
|
|
|
|
} else {
|
|
|
|
|
$query = [
|
|
|
|
|
'website_url' => $endpoint,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$query = array_merge($base_query, $query);
|
|
|
|
|
$json_query = json_encode($query);
|
|
|
|
|
return $base_url . 'article-by-id-or-url-v1?query=' . $json_query;
|
|
|
|
|
break;
|
|
|
|
|
case 'section':
|
|
|
|
|
if ($this->useWireAPI) {
|
|
|
|
|
if (strpos($endpoint, 'chan:') !== false) {
|
Fix coding style missed by phpbcf (#2901)
$ composer require --dev friendsofphp/php-cs-fixer
$ echo >.php-cs-fixer.dist.php "<?php
$finder = PhpCsFixer\Finder::create()
->in(__DIR__);
$rules = [
'@PSR12' => true,
// '@PSR12:risky' => true,
'@PHP74Migration' => true,
// '@PHP74Migration:risky' => true,
// buggy, duplicates existing comment sometimes
'no_break_comment' => false,
'array_syntax' => true,
'lowercase_static_reference' => true,
'visibility_required' => false,
// Too much noise
'binary_operator_spaces' => false,
'heredoc_indentation' => false,
'trailing_comma_in_multiline' => false,
];
$config = new PhpCsFixer\Config();
return $config
->setRules($rules)
// ->setRiskyAllowed(true)
->setFinder($finder);
"
$ vendor/bin/php-cs-fixer --version
PHP CS Fixer 3.8.0 BerSzcz against war! by Fabien Potencier and Dariusz Ruminski.
PHP runtime: 8.1.7
$ vendor/bin/php-cs-fixer fix
$ rm .php-cs-fixer.cache
$ vendor/bin/php-cs-fixer fix
2022-07-08 14:00:52 +03:00
|
|
|
|
// Now checking whether that feed has unique ID or not.
|
2022-07-01 16:10:30 +03:00
|
|
|
|
$feed_uri = "/feed/rapp/us/wirefeed/$endpoint";
|
|
|
|
|
} else {
|
|
|
|
|
$feed_uri = "/feed/rapp/us/tabbar/feeds/$endpoint";
|
|
|
|
|
}
|
|
|
|
|
return $wire_url . $feed_uri;
|
|
|
|
|
}
|
|
|
|
|
$query = [
|
|
|
|
|
'section_id' => $endpoint,
|
|
|
|
|
'size' => 30,
|
|
|
|
|
'website' => 'reuters'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($endpoint != '/home') {
|
|
|
|
|
$query = array_merge($query, [
|
|
|
|
|
'fetch_type' => 'section',
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$json_query = json_encode($query);
|
|
|
|
|
return $base_url . 'articles-by-section-alias-or-id-v1?query=' . $json_query;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
returnServerError('unsupported endpoint');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function addStories($title, $content, $timestamp, $author, $url, $category)
|
|
|
|
|
{
|
|
|
|
|
$item = [];
|
|
|
|
|
$item['categories'] = $category;
|
|
|
|
|
$item['author'] = $author;
|
|
|
|
|
$item['content'] = $content;
|
|
|
|
|
$item['title'] = $title;
|
|
|
|
|
$item['timestamp'] = $timestamp;
|
|
|
|
|
$item['uri'] = $url;
|
|
|
|
|
$this->items[] = $item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function getArticle($feed_uri, $is_article_uid = false)
|
|
|
|
|
{
|
|
|
|
|
// This will make another request to API to get full detail of article and author's name.
|
|
|
|
|
$url = $this->getAPIURL($feed_uri, 'article', $is_article_uid);
|
|
|
|
|
$rawData = $this->getJson($url);
|
|
|
|
|
|
|
|
|
|
$article_content = '';
|
|
|
|
|
$authorlist = '';
|
|
|
|
|
$category = [];
|
|
|
|
|
$image_list = [];
|
|
|
|
|
$published_at = '';
|
|
|
|
|
if ($this->useWireAPI) {
|
|
|
|
|
$reuters_wireitems = $rawData['wireitems'];
|
|
|
|
|
$processedData = $this->processData($reuters_wireitems);
|
|
|
|
|
|
|
|
|
|
$first = reset($processedData);
|
|
|
|
|
$article_content = $first['story']['body_items'];
|
|
|
|
|
$authorlist = $first['story']['authors'];
|
|
|
|
|
$category = [$first['story']['channel']['name']];
|
|
|
|
|
$image_list = $first['story']['images'];
|
|
|
|
|
$published_at = $first['story']['published_at'];
|
|
|
|
|
} else {
|
|
|
|
|
$article_content = $rawData['result']['content_elements'];
|
|
|
|
|
$authorlist = $rawData['result']['authors'];
|
|
|
|
|
$category = [$rawData['result']['taxonomy']['ads_primary_section']['name']];
|
|
|
|
|
$image_list = [];
|
|
|
|
|
if (!empty($rawData['result']['related_content']['galleries'])) {
|
|
|
|
|
$galleries = $rawData['result']['related_content']['galleries'];
|
|
|
|
|
foreach ($galleries as $gallery) {
|
|
|
|
|
$image_list = array_merge($image_list, $gallery['content_elements']);
|
|
|
|
|
}
|
|
|
|
|
} elseif (!empty($rawData['result']['related_content']['images'])) {
|
|
|
|
|
$image_list = $rawData['result']['related_content']['images'];
|
|
|
|
|
}
|
|
|
|
|
$published_at = $rawData['result']['published_time'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$content_detail = [
|
|
|
|
|
'content' => $this->handleArticleContent($article_content),
|
|
|
|
|
'author' => $this->handleAuthorName($authorlist),
|
|
|
|
|
'category' => $category,
|
|
|
|
|
'images' => $this->handleImage($image_list),
|
|
|
|
|
'published_at' => $published_at
|
|
|
|
|
];
|
|
|
|
|
return $content_detail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function handleImage($images)
|
|
|
|
|
{
|
|
|
|
|
$img_placeholder = '';
|
|
|
|
|
|
2023-07-03 01:39:01 +03:00
|
|
|
|
foreach ($images as $image) {
|
|
|
|
|
// Add more image to article.
|
2022-07-01 16:10:30 +03:00
|
|
|
|
$image_url = $image['url'];
|
2023-07-03 01:39:01 +03:00
|
|
|
|
$image_caption = $image['caption'] ?? $image['alt_text'] ?? $image['subtitle'] ?? '';
|
2022-07-01 16:10:30 +03:00
|
|
|
|
$image_alt_text = '';
|
2023-07-03 01:39:01 +03:00
|
|
|
|
$image_alt_text = $image['alt_text'] ?? $image_caption;
|
2022-07-01 16:10:30 +03:00
|
|
|
|
$img = "<img src=\"$image_url\" alt=\"$image_alt_text\">";
|
|
|
|
|
$img_caption = "<figcaption style=\"text-align: center;\"><i>$image_caption</i></figcaption>";
|
|
|
|
|
$figure = "<figure>$img \t $img_caption</figure>";
|
|
|
|
|
$img_placeholder = $img_placeholder . $figure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $img_placeholder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function handleAuthorName($authors)
|
|
|
|
|
{
|
|
|
|
|
$author = '';
|
|
|
|
|
$counter = 0;
|
|
|
|
|
foreach ($authors as $data) {
|
|
|
|
|
//Formatting author's name.
|
|
|
|
|
$name = $data['name'];
|
|
|
|
|
$counter++;
|
|
|
|
|
if ($counter == count($authors)) {
|
|
|
|
|
$author .= $name;
|
|
|
|
|
} else {
|
|
|
|
|
$author .= $name . ', ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $author;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function handleArticleContent($contents)
|
|
|
|
|
{
|
|
|
|
|
$description = '';
|
|
|
|
|
foreach ($contents as $content) {
|
2022-11-15 02:30:51 +03:00
|
|
|
|
$data = '';
|
2022-07-01 16:10:30 +03:00
|
|
|
|
if (isset($content['content'])) {
|
|
|
|
|
$data = $content['content'];
|
|
|
|
|
}
|
|
|
|
|
switch ($content['type']) {
|
|
|
|
|
case 'paragraph':
|
|
|
|
|
$description = $description . "<p>$data</p>";
|
|
|
|
|
break;
|
|
|
|
|
case 'heading':
|
|
|
|
|
$description = $description . "<h3>$data</h3>";
|
|
|
|
|
break;
|
|
|
|
|
case 'infographics':
|
|
|
|
|
$description = $description . "<img src=\"$data\">";
|
|
|
|
|
break;
|
|
|
|
|
case 'inline_items':
|
|
|
|
|
$item_list = $content['items'];
|
|
|
|
|
$description = $description . '<p>';
|
|
|
|
|
foreach ($item_list as $item) {
|
|
|
|
|
if ($item['type'] == 'text') {
|
|
|
|
|
$description = $description . $item['content'];
|
|
|
|
|
} else {
|
|
|
|
|
$description = $description . $item['symbol'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$description = $description . '</p>';
|
|
|
|
|
break;
|
|
|
|
|
case 'p_table':
|
|
|
|
|
$description = $description . $content['content'];
|
|
|
|
|
break;
|
|
|
|
|
case 'upstream_embed':
|
|
|
|
|
$media_type = $content['media_type'];
|
|
|
|
|
$cid = $content['cid'];
|
|
|
|
|
$embed = '';
|
|
|
|
|
switch ($media_type) {
|
|
|
|
|
case 'tweet':
|
|
|
|
|
try {
|
|
|
|
|
$tweet_url = "https://twitter.com/dummyname/statuses/$cid";
|
|
|
|
|
$get_embed_url = 'https://publish.twitter.com/oembed?url='
|
|
|
|
|
. urlencode($tweet_url) .
|
|
|
|
|
'&partner=&hide_thread=false';
|
|
|
|
|
$oembed_json = json_decode(getContents($get_embed_url), true);
|
|
|
|
|
$embed .= $oembed_json['html'];
|
|
|
|
|
} catch (Exception $e) { // In case not found any tweet.
|
|
|
|
|
$embed .= '';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'instagram':
|
|
|
|
|
$url = "https://instagram.com/p/$cid/media/?size=l";
|
|
|
|
|
$embed .= <<<EOD
|
2021-07-20 10:54:07 +03:00
|
|
|
|
<img
|
|
|
|
|
src="{$url}"
|
|
|
|
|
alt="instagram-image-$cid"
|
|
|
|
|
>
|
|
|
|
|
EOD;
|
2022-07-01 16:10:30 +03:00
|
|
|
|
break;
|
|
|
|
|
case 'youtube':
|
|
|
|
|
$url = "https://www.youtube.com/embed/$cid";
|
|
|
|
|
$embed .= <<<EOD
|
2021-07-20 10:54:07 +03:00
|
|
|
|
<iframe
|
|
|
|
|
width="560"
|
|
|
|
|
height="315"
|
|
|
|
|
src="{$url}"
|
|
|
|
|
frameborder="0"
|
|
|
|
|
allowfullscreen
|
|
|
|
|
>
|
|
|
|
|
</iframe>
|
|
|
|
|
EOD;
|
2022-07-01 16:10:30 +03:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$description .= $embed;
|
|
|
|
|
break;
|
|
|
|
|
case 'social_media':
|
|
|
|
|
if ($content['sub_type'] == 'twitter') {
|
|
|
|
|
$description .= $content['html'];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'table':
|
|
|
|
|
$table = '<table>';
|
2022-10-26 01:47:45 +03:00
|
|
|
|
$theaders = $content['header'] ?? null;
|
|
|
|
|
if ($theaders) {
|
|
|
|
|
$tr = '<tr>';
|
|
|
|
|
foreach ($theaders as $header) {
|
|
|
|
|
$tr .= '<th>' . $header . '</th>';
|
|
|
|
|
}
|
|
|
|
|
$tr .= '</tr>';
|
|
|
|
|
$table .= $tr;
|
2022-07-01 16:10:30 +03:00
|
|
|
|
}
|
|
|
|
|
$rows = $content['rows'];
|
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
|
$tr = '<tr>';
|
|
|
|
|
foreach ($row as $data) {
|
|
|
|
|
$tr .= '<td>' . $data . '</td>';
|
|
|
|
|
}
|
|
|
|
|
$tr .= '</tr>';
|
|
|
|
|
$table .= $tr;
|
|
|
|
|
}
|
|
|
|
|
$table .= '</table>';
|
|
|
|
|
$description .= $table;
|
|
|
|
|
break;
|
|
|
|
|
case 'image':
|
|
|
|
|
$description .= $this->handleImage([$content]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getName()
|
|
|
|
|
{
|
|
|
|
|
return $this->feedName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function collectData()
|
|
|
|
|
{
|
|
|
|
|
$endpoint = $this->getSectionEndpoint();
|
|
|
|
|
$url = $this->getAPIURL($endpoint, 'section');
|
|
|
|
|
$data = $this->getJson($url);
|
|
|
|
|
|
|
|
|
|
$stories = [];
|
|
|
|
|
$section_name = '';
|
|
|
|
|
if ($this->useWireAPI) {
|
|
|
|
|
$reuters_wireitems = $data['wireitems'];
|
|
|
|
|
$section_name = $data['wire_name'];
|
|
|
|
|
$processedData = $this->processData($reuters_wireitems);
|
|
|
|
|
|
|
|
|
|
// Merge all articles from Editor's Highlight section into existing array of templates.
|
|
|
|
|
$top_section = reset($processedData);
|
|
|
|
|
if ($top_section['type'] == 'headlines') {
|
|
|
|
|
$top_section = array_shift($processedData);
|
|
|
|
|
$articles = $top_section['headlines'];
|
|
|
|
|
$processedData = array_merge($articles, $processedData);
|
|
|
|
|
}
|
|
|
|
|
$stories = $processedData;
|
|
|
|
|
} else {
|
|
|
|
|
$section_name = $data['result']['section']['name'];
|
|
|
|
|
if (isset($data['arcResult']['articles'])) {
|
|
|
|
|
$stories = $data['arcResult']['articles'];
|
|
|
|
|
} else {
|
|
|
|
|
$stories = $data['result']['articles'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->feedName = $section_name . ' | Reuters';
|
|
|
|
|
|
|
|
|
|
foreach ($stories as $story) {
|
|
|
|
|
$uid = '';
|
|
|
|
|
$author = '';
|
|
|
|
|
$category = [];
|
|
|
|
|
$content = '';
|
|
|
|
|
$title = '';
|
|
|
|
|
$timestamp = '';
|
|
|
|
|
$url = '';
|
|
|
|
|
$article_uri = '';
|
|
|
|
|
$source_type = '';
|
|
|
|
|
if ($this->useWireAPI) {
|
|
|
|
|
$uid = $story['story']['usn'];
|
|
|
|
|
$article_uri = $story['template_action']['api_path'];
|
|
|
|
|
$title = $story['story']['hed'];
|
|
|
|
|
$url = $story['template_action']['url'];
|
|
|
|
|
} else {
|
|
|
|
|
$uid = $story['id'];
|
|
|
|
|
$url = self::URI . $story['canonical_url'];
|
|
|
|
|
$title = $story['title'];
|
|
|
|
|
$article_uri = $story['canonical_url'];
|
|
|
|
|
$source_type = $story['source']['name'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Some article cause unexpected behaviour like redirect to another site not API.
|
|
|
|
|
// Attempt to check article source type to avoid this.
|
|
|
|
|
if (!$this->useWireAPI && $source_type != 'Package') { // Only Reuters PF api have this, Wire don't.
|
2022-09-09 21:18:50 +03:00
|
|
|
|
$author = $this->handleAuthorName($story['authors'] ?? []);
|
2022-07-01 16:10:30 +03:00
|
|
|
|
$timestamp = $story['published_time'];
|
|
|
|
|
$image_placeholder = '';
|
|
|
|
|
if (isset($story['thumbnail'])) {
|
|
|
|
|
$image_placeholder = $this->handleImage([$story['thumbnail']]);
|
|
|
|
|
}
|
|
|
|
|
$content = $story['description'] . $image_placeholder;
|
2023-07-03 01:39:01 +03:00
|
|
|
|
if (isset($story['primary_section']['name'])) {
|
|
|
|
|
$category = [$story['primary_section']['name']];
|
|
|
|
|
} else {
|
|
|
|
|
$category = [];
|
|
|
|
|
}
|
2022-07-01 16:10:30 +03:00
|
|
|
|
} else {
|
|
|
|
|
$content_detail = $this->getArticle($article_uri);
|
|
|
|
|
$description = $content_detail['content'];
|
|
|
|
|
$description = defaultLinkTo($description, $this->getURI());
|
|
|
|
|
|
|
|
|
|
$author = $content_detail['author'];
|
|
|
|
|
$images = $content_detail['images'];
|
|
|
|
|
$category = $content_detail['category'];
|
|
|
|
|
$content = "$description $images";
|
|
|
|
|
$timestamp = $content_detail['published_at'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->addStories($title, $content, $timestamp, $author, $url, $category);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-29 20:57:40 +03:00
|
|
|
|
}
|