2026-02-02 12:14:18 -05:00
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* get_files.php - Recursively scans media directories and returns file structure as JSON
|
|
|
|
|
*/
|
2026-02-02 12:26:55 -05:00
|
|
|
declare(strict_types=1);
|
2026-02-03 13:19:20 -05:00
|
|
|
|
2026-02-02 14:05:21 -05:00
|
|
|
require_once __DIR__ . '/auth.php';
|
2026-03-02 13:45:28 -05:00
|
|
|
require_once __DIR__ . '/media_cache_lib.php';
|
2026-02-02 14:05:21 -05:00
|
|
|
require_auth(true);
|
|
|
|
|
|
2026-02-02 12:26:55 -05:00
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
2026-02-02 12:14:18 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
/**
|
|
|
|
|
* Emit JSON response with cache/timing observability headers.
|
|
|
|
|
*/
|
|
|
|
|
function fm_emit_response(array $payload, string $type, string $cacheStatus, float $startedAt, bool $forceRefresh, ?string $cacheGeneratedAt = null): void
|
|
|
|
|
{
|
|
|
|
|
$elapsedMs = (int)round((microtime(true) - $startedAt) * 1000);
|
2026-02-02 12:26:55 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
header('X-Media-Type: ' . $type);
|
|
|
|
|
header('X-Media-Cache: ' . $cacheStatus);
|
|
|
|
|
header('X-Media-Time-Ms: ' . (string)$elapsedMs);
|
|
|
|
|
header('X-Media-Force-Refresh: ' . ($forceRefresh ? '1' : '0'));
|
2026-02-03 13:19:20 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
if (is_string($cacheGeneratedAt) && $cacheGeneratedAt !== '') {
|
|
|
|
|
header('X-Media-Cache-Generated-At: ' . $cacheGeneratedAt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
2026-02-03 13:19:20 -05:00
|
|
|
exit;
|
|
|
|
|
}
|
2026-02-02 12:14:18 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
$startedAt = microtime(true);
|
2026-02-02 12:14:18 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
// Media type from query parameter (default: videos)
|
|
|
|
|
$type = $_GET['type'] ?? 'videos';
|
|
|
|
|
if (!is_string($type)) {
|
|
|
|
|
$type = 'unknown';
|
2026-02-02 12:14:18 -05:00
|
|
|
}
|
|
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
$forceRefresh = isset($_GET['refresh']) && (string)$_GET['refresh'] === '1';
|
2026-02-02 12:14:18 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
if (!is_string($type) || !fm_is_valid_type($type)) {
|
|
|
|
|
fm_emit_response(['error' => 'Invalid media type'], $type, 'invalid_type', $startedAt, $forceRefresh);
|
2026-02-02 12:14:18 -05:00
|
|
|
}
|
|
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
$resolveError = null;
|
|
|
|
|
$baseDir = fm_resolve_media_root($resolveError);
|
|
|
|
|
if ($baseDir === null) {
|
|
|
|
|
fm_emit_response(['error' => $resolveError ?? 'MEDIA_ROOT base directory not found'], $type, 'error', $startedAt, $forceRefresh);
|
|
|
|
|
}
|
2026-02-02 12:26:55 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
if (!$forceRefresh) {
|
|
|
|
|
$cacheError = null;
|
|
|
|
|
$cached = fm_read_cache_payload($type, $baseDir, $cacheError);
|
|
|
|
|
if (is_array($cached)) {
|
|
|
|
|
$tree = $cached['tree'];
|
|
|
|
|
fm_emit_response(
|
|
|
|
|
empty($tree) ? ['message' => 'No media files found'] : $tree,
|
|
|
|
|
$type,
|
|
|
|
|
'hit',
|
|
|
|
|
$startedAt,
|
|
|
|
|
$forceRefresh,
|
|
|
|
|
isset($cached['generated_at']) && is_string($cached['generated_at']) ? $cached['generated_at'] : null
|
|
|
|
|
);
|
2026-02-02 12:14:18 -05:00
|
|
|
}
|
2026-03-02 13:45:28 -05:00
|
|
|
}
|
2026-02-02 12:26:55 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
$rebuildError = null;
|
|
|
|
|
$tree = fm_rebuild_cache($type, $baseDir, false, $rebuildError);
|
|
|
|
|
|
|
|
|
|
if (!is_array($tree)) {
|
|
|
|
|
$scanError = null;
|
|
|
|
|
$tree = fm_scan_media_tree($type, $baseDir, $scanError);
|
|
|
|
|
if (!is_array($tree)) {
|
|
|
|
|
fm_emit_response(
|
|
|
|
|
['error' => $scanError ?? $rebuildError ?? 'Failed to scan media directory'],
|
|
|
|
|
$type,
|
|
|
|
|
'error',
|
|
|
|
|
$startedAt,
|
|
|
|
|
$forceRefresh
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-02-02 12:26:55 -05:00
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
fm_emit_response(
|
|
|
|
|
empty($tree) ? ['message' => 'No media files found'] : $tree,
|
|
|
|
|
$type,
|
|
|
|
|
'fallback_scan',
|
|
|
|
|
$startedAt,
|
|
|
|
|
$forceRefresh
|
|
|
|
|
);
|
2026-02-02 12:14:18 -05:00
|
|
|
}
|
|
|
|
|
|
2026-03-02 13:45:28 -05:00
|
|
|
fm_emit_response(
|
2026-02-02 12:26:55 -05:00
|
|
|
empty($tree) ? ['message' => 'No media files found'] : $tree,
|
2026-03-02 13:45:28 -05:00
|
|
|
$type,
|
|
|
|
|
$forceRefresh ? 'rebuild_forced' : 'rebuild',
|
|
|
|
|
$startedAt,
|
|
|
|
|
$forceRefresh
|
2026-02-02 12:26:55 -05:00
|
|
|
);
|