137 lines
4.1 KiB
PHP
137 lines
4.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
class HytaleNewsBridge extends BridgeAbstract
|
|
{
|
|
const MAINTAINER = 'Akamaru';
|
|
const NAME = 'Hytale News';
|
|
const URI = 'https://hytale.com/news';
|
|
const CACHE_TIMEOUT = 3600;
|
|
const DESCRIPTION = 'Get the latest news from Hytale!';
|
|
const PARAMETERS = [
|
|
[
|
|
'limit' => [
|
|
'name' => 'Max. Articles',
|
|
'type' => 'number',
|
|
'required' => false,
|
|
'defaultValue' => 20
|
|
]
|
|
]
|
|
];
|
|
|
|
public function getIcon()
|
|
{
|
|
return 'https://www.google.com/s2/favicons?domain=hytale.com&sz=32';
|
|
}
|
|
|
|
public function collectData()
|
|
{
|
|
$html = getContents(self::URI);
|
|
if (!$html) {
|
|
returnServerError('Could not load Hytale news page.');
|
|
}
|
|
|
|
// Find the JSON data in __INITIAL_COMPONENTS_STATE__
|
|
$marker = 'window.__INITIAL_COMPONENTS_STATE__ = ';
|
|
$startPos = strpos($html, $marker);
|
|
if ($startPos === false) {
|
|
returnServerError('Could not find initial state marker.');
|
|
}
|
|
|
|
$jsonStart = $startPos + strlen($marker);
|
|
|
|
// Find the matching closing bracket by counting brackets
|
|
$bracketCount = 0;
|
|
$jsonEnd = $jsonStart;
|
|
$len = strlen($html);
|
|
$inString = false;
|
|
$escapeNext = false;
|
|
|
|
for ($i = $jsonStart; $i < $len; $i++) {
|
|
$char = $html[$i];
|
|
|
|
if ($escapeNext) {
|
|
$escapeNext = false;
|
|
continue;
|
|
}
|
|
if ($char === '\\') {
|
|
$escapeNext = true;
|
|
continue;
|
|
}
|
|
if ($char === '"' && !$escapeNext) {
|
|
$inString = !$inString;
|
|
continue;
|
|
}
|
|
if ($inString) {
|
|
continue;
|
|
}
|
|
if ($char === '[') {
|
|
$bracketCount++;
|
|
} elseif ($char === ']') {
|
|
$bracketCount--;
|
|
if ($bracketCount === 0) {
|
|
$jsonEnd = $i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$jsonStr = substr($html, $jsonStart, $jsonEnd - $jsonStart);
|
|
$jsonData = json_decode($jsonStr, true);
|
|
|
|
if (!$jsonData || !isset($jsonData[0]['posts'])) {
|
|
returnServerError('Could not extract posts data from page.');
|
|
}
|
|
|
|
$posts = $jsonData[0]['posts'];
|
|
|
|
$limit = $this->getInput('limit') ?? 20;
|
|
$count = 0;
|
|
|
|
foreach ($posts as $post) {
|
|
if ($count >= $limit) {
|
|
break;
|
|
}
|
|
$count++;
|
|
$item = [];
|
|
|
|
$item['title'] = $post['title'] ?? 'Untitled';
|
|
$item['author'] = $post['author'] ?? 'Hytale Team';
|
|
$item['uid'] = $post['_id'] ?? '';
|
|
|
|
// Build URI from publishedAt date and slug
|
|
$publishedAt = $post['publishedAt'] ?? null;
|
|
$slug = $post['slug'] ?? '';
|
|
if ($publishedAt && $slug) {
|
|
$date = new DateTime($publishedAt);
|
|
$year = $date->format('Y');
|
|
$month = $date->format('n'); // Month without leading zero
|
|
$item['uri'] = 'https://hytale.com/news/' . $year . '/' . $month . '/' . $slug;
|
|
$item['timestamp'] = $date->getTimestamp();
|
|
} else {
|
|
$item['uri'] = self::URI;
|
|
}
|
|
|
|
// Content with image
|
|
$content = '';
|
|
$imageUrl = null;
|
|
if (isset($post['coverImage']['s3Key'])) {
|
|
$s3Key = $post['coverImage']['s3Key'];
|
|
$imageUrl = 'https://cdn.hytale.com/variants/blog_cover_' . $s3Key;
|
|
$content .= '<p><img src="' . $imageUrl . '" alt="' . htmlspecialchars($item['title']) . '"></p>';
|
|
}
|
|
|
|
$content .= '<p>' . htmlspecialchars($post['bodyExcerpt'] ?? '') . '</p>';
|
|
$item['content'] = $content;
|
|
|
|
// Enclosure for image
|
|
if ($imageUrl) {
|
|
$item['enclosures'] = [$imageUrl];
|
|
}
|
|
|
|
$this->items[] = $item;
|
|
}
|
|
}
|
|
}
|