[ '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 .= '
' . htmlspecialchars($post['bodyExcerpt'] ?? '') . '
'; $item['content'] = $content; // Enclosure for image if ($imageUrl) { $item['enclosures'] = [$imageUrl]; } $this->items[] = $item; } } }