Initial commit: RSS feed dashboard aggregating YouTube, Reddit and RT
- PHP 8 + PDO SQLite cache with on-demand TTL refresh and dedup by link hash - laminas-feed + Guzzle for RSS/Atom parsing and HTTP - Bootstrap 5 UI with source and time-range filters, AJAX load-more - User cron-free deployment under Apache/php-fpm; .htaccess hardening
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @var array<string, mixed> $app */
|
||||
$app = require dirname(__DIR__) . '/src/bootstrap.php';
|
||||
|
||||
$config = $app['config'];
|
||||
$service = $app['service'];
|
||||
|
||||
// Respect the TTL so long-lived pages stay fresh without hammering providers.
|
||||
$refresh = $service->refreshStale();
|
||||
|
||||
$sources = $service->sources();
|
||||
$source = $_GET['source'] ?? null;
|
||||
if (!is_string($source) || !in_array($source, $sources, true)) {
|
||||
$source = null;
|
||||
}
|
||||
|
||||
$ranges = $config['ranges'] ?? [];
|
||||
$range = $_GET['range'] ?? '';
|
||||
if (!is_string($range) || !array_key_exists($range, $ranges)) {
|
||||
$range = '';
|
||||
}
|
||||
$since = $range !== '' ? gmdate('c', time() - (int) $ranges[$range]) : null;
|
||||
|
||||
$pageNumber = max(1, (int) ($_GET['page'] ?? 1));
|
||||
$page = $service->page($source, $pageNumber, (int) $config['page_size'], $since);
|
||||
|
||||
$html = App\View::render('cards', ['items' => $page['items']]);
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Cache-Control: no-store');
|
||||
|
||||
echo json_encode([
|
||||
'html' => $html,
|
||||
'page' => $page['page'],
|
||||
'page_size' => $page['page_size'],
|
||||
'count' => count($page['items']),
|
||||
'total' => $page['total'],
|
||||
'has_more' => $page['has_more'],
|
||||
'range' => $range,
|
||||
'refresh' => $refresh,
|
||||
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
Reference in New Issue
Block a user