Add manual subreddit/YouTube channel configuration (manage.php)

Browser-based feed selection layered on top of config/feeds.php:

- manage.php (password + CSRF gated, session based): add subreddits
  (name / r/name / URL) and YouTube channels (@handle / UC id / URL,
  handle resolved to channel_id once, youtube.com only); enable/disable
  toggles; remove manual feeds; config feeds are hidden, not deleted.
- New feeds are validated with one immediate fetch (bypassing the
  per-refresh host cap): HTTP 404 rejects the entry, 429 keeps it for
  a later refresh. YouTube labels adopt the real channel title.
- feeds table gains origin (config|manual) and enabled columns, with
  a guarded ALTER migration for existing databases.
- Only enabled feeds are refreshed and served: getItems/countItems
  filter by feed_url in enabled feeds, so deselected feeds' cached
  stories are hidden, not deleted; re-adding a URL re-enables it.
- Dashboard header gets a Manage link; manage page styled with the
  existing design tokens; README documents the feature.
This commit is contained in:
Harwinder Sekhon
2026-10-05 18:58:38 -04:00
parent 403fd2c604
commit 41f07b6ad8
14 changed files with 1123 additions and 28 deletions
+19 -1
View File
@@ -58,8 +58,26 @@ final class Database
label TEXT,
last_attempt_at TEXT,
last_success_at TEXT,
last_error TEXT
last_error TEXT,
origin TEXT NOT NULL DEFAULT 'config',
enabled INTEGER NOT NULL DEFAULT 1
)
SQL);
// SQLite has no "ADD COLUMN IF NOT EXISTS": migrate pre-existing tables.
self::addColumn($pdo, 'feeds', 'origin', "ALTER TABLE feeds ADD COLUMN origin TEXT NOT NULL DEFAULT 'config'");
self::addColumn($pdo, 'feeds', 'enabled', 'ALTER TABLE feeds ADD COLUMN enabled INTEGER NOT NULL DEFAULT 1');
}
private static function addColumn(PDO $pdo, string $table, string $column, string $sql): void
{
$existing = [];
foreach ($pdo->query(sprintf('PRAGMA table_info(%s)', $table)) as $row) {
$existing[strtolower((string) $row['name'])] = true;
}
if (!isset($existing[strtolower($column)])) {
$pdo->exec($sql);
}
}
}