UI improved
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// Serves a cached course thumbnail — a frame captured from the course's first
|
||||
// video at THUMBNAIL_SEEK_PERCENT, generated by the scanner (see
|
||||
// generateThumbnails() in includes/functions.php). Looked up by folder ID
|
||||
// only, mirroring stream.php's containment check; 404s (no thumbnail yet, or
|
||||
// the id isn't a course) are expected and handled by the client falling back
|
||||
// to its colour-block placeholder.
|
||||
require_once __DIR__ . '/includes/auth.php';
|
||||
require_once __DIR__ . '/includes/functions.php';
|
||||
|
||||
$userId = currentUserId();
|
||||
if ($userId === null) {
|
||||
http_response_code(403);
|
||||
exit('Forbidden');
|
||||
}
|
||||
|
||||
$courseId = (int)($_GET['course_id'] ?? 0);
|
||||
$dir = realpath(THUMBNAILS_DIR);
|
||||
$file = ($courseId > 0 && $dir !== false)
|
||||
? realpath($dir . '/' . $courseId . '.jpg')
|
||||
: false;
|
||||
|
||||
if ($dir === false || $file === false || !str_starts_with($file, $dir . DIRECTORY_SEPARATOR)
|
||||
|| !is_file($file)) {
|
||||
http_response_code(404);
|
||||
exit('No thumbnail');
|
||||
}
|
||||
|
||||
$mtime = filemtime($file);
|
||||
$etag = '"' . md5($courseId . '-' . $mtime) . '"';
|
||||
|
||||
header('Cache-Control: private, max-age=86400');
|
||||
header('ETag: ' . $etag);
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $mtime) . ' GMT');
|
||||
|
||||
if (($_SERVER['HTTP_IF_NONE_MATCH'] ?? null) === $etag) {
|
||||
http_response_code(304);
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Content-Type: image/jpeg');
|
||||
header('Content-Length: ' . filesize($file));
|
||||
readfile($file);
|
||||
Reference in New Issue
Block a user