- Descriptions now render Markdown or sanitized HTML via [includes/db.php](/Users/tyemeclifford/Documents/GH/mediaplayer/includes/db.php).
Public player descriptions render formatted HTML on the homepage. Catalogue cards, embed meta tags, and social metadata use safe plain-text excerpts. Add/edit admin pages now use a rich description editor that preserves pasted HTML styling, with a textarea fallback for no-JS. External/YouTube-imported descriptions are sanitized before storage. README now documents Markdown/HTML description support.
This commit is contained in:
+106
@@ -27,6 +27,10 @@ function cli_main(array $argv): int {
|
||||
$command = 'help';
|
||||
}
|
||||
|
||||
if (cli_command_requires_database_write($command)) {
|
||||
cli_assert_database_writable();
|
||||
}
|
||||
|
||||
return match ($command) {
|
||||
'help' => cli_help(),
|
||||
'site:status', 'status' => cli_site_status(),
|
||||
@@ -51,6 +55,7 @@ function cli_main(array $argv): int {
|
||||
'maintenance:external-views' => cli_maintenance_external_views($parsed),
|
||||
'maintenance:all' => cli_maintenance_all($parsed),
|
||||
'db:path' => cli_db_path(),
|
||||
'db:doctor' => cli_db_doctor(),
|
||||
'db:backup' => cli_db_backup($parsed),
|
||||
'db:vacuum' => cli_db_vacuum(),
|
||||
default => cli_unknown($command),
|
||||
@@ -157,6 +162,7 @@ Maintenance:
|
||||
|
||||
Database:
|
||||
db:path
|
||||
db:doctor
|
||||
db:backup [--output=/path/to/media.db]
|
||||
db:vacuum
|
||||
|
||||
@@ -164,6 +170,46 @@ HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function cli_command_requires_database_write(string $command): bool {
|
||||
return in_array($command, [
|
||||
'settings:set',
|
||||
'admin:password',
|
||||
'password:set',
|
||||
'video:add',
|
||||
'video:update',
|
||||
'video:publish',
|
||||
'video:unpublish',
|
||||
'video:toggle',
|
||||
'video:delete',
|
||||
'source:add',
|
||||
'source:update',
|
||||
'source:delete',
|
||||
'maintenance:catalogue-order',
|
||||
'maintenance:youtube-timestamps',
|
||||
'maintenance:external-views',
|
||||
'maintenance:all',
|
||||
'db:vacuum',
|
||||
], true);
|
||||
}
|
||||
|
||||
function cli_assert_database_writable(): void {
|
||||
$paths = cli_database_writable_checks();
|
||||
$problems = [];
|
||||
|
||||
foreach ($paths as $check) {
|
||||
if (!$check['ok']) $problems[] = $check['message'];
|
||||
}
|
||||
|
||||
if ($problems) {
|
||||
$details = implode(PHP_EOL . ' - ', $problems);
|
||||
throw new RuntimeException(
|
||||
"Database is not writable by the current CLI user (" . cli_current_user_label() . ")." .
|
||||
PHP_EOL . " - " . $details .
|
||||
PHP_EOL . "Run db:doctor for details, then make the data directory and media.db writable by this user."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function cli_unknown(string $command): int {
|
||||
fwrite(STDERR, "Unknown command: {$command}" . PHP_EOL . PHP_EOL);
|
||||
cli_help();
|
||||
@@ -768,6 +814,66 @@ function cli_db_path(): int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function cli_db_doctor(): int {
|
||||
$rows = [
|
||||
['Current user', cli_current_user_label()],
|
||||
['Database path', DB_PATH],
|
||||
['Data directory', dirname(DB_PATH)],
|
||||
['Database exists', cli_yes_no(file_exists(DB_PATH))],
|
||||
];
|
||||
|
||||
foreach (cli_database_writable_checks() as $check) {
|
||||
$rows[] = [$check['label'], $check['ok'] ? 'ok' : $check['message']];
|
||||
}
|
||||
|
||||
cli_table(['check', 'result'], $rows);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function cli_database_writable_checks(): array {
|
||||
$directory = dirname(DB_PATH);
|
||||
$checks = [];
|
||||
|
||||
$checks[] = [
|
||||
'label' => 'data directory',
|
||||
'ok' => is_dir($directory) && is_writable($directory),
|
||||
'message' => is_dir($directory)
|
||||
? "data directory is not writable: {$directory}"
|
||||
: "data directory does not exist: {$directory}",
|
||||
];
|
||||
|
||||
if (file_exists(DB_PATH)) {
|
||||
$checks[] = [
|
||||
'label' => 'media.db',
|
||||
'ok' => is_writable(DB_PATH),
|
||||
'message' => "database file is not writable: " . DB_PATH,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ([DB_PATH . '-wal', DB_PATH . '-shm'] as $path) {
|
||||
if (!file_exists($path)) continue;
|
||||
$checks[] = [
|
||||
'label' => basename($path),
|
||||
'ok' => is_writable($path),
|
||||
'message' => "SQLite sidecar file is not writable: {$path}",
|
||||
];
|
||||
}
|
||||
|
||||
return $checks;
|
||||
}
|
||||
|
||||
function cli_current_user_label(): string {
|
||||
if (function_exists('posix_geteuid') && function_exists('posix_getpwuid')) {
|
||||
$uid = posix_geteuid();
|
||||
$info = posix_getpwuid($uid);
|
||||
$name = is_array($info) && isset($info['name']) ? (string)$info['name'] : '';
|
||||
return $name !== '' ? "{$name} (uid {$uid})" : "uid {$uid}";
|
||||
}
|
||||
|
||||
$user = get_current_user();
|
||||
return $user !== '' ? $user : 'unknown';
|
||||
}
|
||||
|
||||
function cli_db_backup(array $parsed): int {
|
||||
cli_db()->exec('PRAGMA wal_checkpoint(FULL)');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user