diff options
Diffstat (limited to 'src/application/actions/thumb/get.php')
-rw-r--r-- | src/application/actions/thumb/get.php | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/application/actions/thumb/get.php b/src/application/actions/thumb/get.php new file mode 100644 index 0000000..c34bf92 --- /dev/null +++ b/src/application/actions/thumb/get.php @@ -0,0 +1,101 @@ +<?php + +use FFMpeg\Coordinate\TimeCode; +use FFMpeg\FFMpeg; +use FFMpeg\FFProbe; +use mystic\forum\orm\Attachment; + +$attId = $_GET["attachment"] ?? throw new Exception("Missing attachment id"); +$attachment = new Attachment(); +$attachment->id = $attId; +if (!$db->fetch($attachment)) { + http_response_code(404); + msg_error(__("No attachment exists with this id")); + exit; +} + +$isImage = str_starts_with($attachment->mimeType, "image/"); +$isVideo = str_starts_with($attachment->mimeType, "video/"); + +if (!$isImage && !$isVideo) { + http_response_code(400); + msg_error(__("Attachment is neither an image nor a video")); + exit; +} + +$contentHash = hash("sha256", $attachment->contents); + +$cacheId = bin2hex($attachment->id); +$cacheDir = sys_get_temp_dir() . "/mystic/forum/0/cache/thumbs/" . substr($cacheId, 0, 2) . "/" . substr($cacheId, 0, 8) . "/"; +if (!is_dir($cacheDir)) + mkdir($cacheDir, recursive: true); + +$cacheFileData = $cacheDir . $cacheId . ".data"; +$cacheFileInfo = $cacheDir . $cacheId . ".info"; + +if (is_file($cacheFileData) && is_file($cacheFileInfo)) { + $info = json_decode(file_get_contents($cacheFileInfo)); + if ($info->contentHash === $contentHash) { + header("Content-Type: image/jpeg"); + header("Cache-Control: max-age=86400"); + //header("X-Debug-Content: $cacheFileData"); + readfile($cacheFileData); + exit; + } +} + +if ($isVideo) { + $suffix = (microtime(true) * 1000) . "-" . random_int(0, 99999); + $tempVid = sys_get_temp_dir() . "/video_" . $suffix; + file_put_contents($tempVid, $attachment->contents); + $tempImg = sys_get_temp_dir() . "/image_" . $suffix . ".jpg"; + + try { + $ffprobe = FFProbe::create(); + /** @var string $duration */ + $duration = $ffprobe + ->format($tempVid) + ->get("duration", "0"); + + $screenshotFramePoint = TimeCode::fromSeconds(floatval($duration) / 2.0); + + $ffmpeg = FFMpeg::create(); + $video = $ffmpeg->open($tempVid); + $screenshot = $video + ->frame($screenshotFramePoint) + ->save($tempImg); + $im = imagecreatefromjpeg($tempImg); + } finally { + if (is_file($tempVid)) unlink($tempVid); + if (is_file($tempImg)) unlink($tempImg); + } +} elseif ($isImage) { + $im = imagecreatefromstring($attachment->contents); +} + +$w = imagesx($im); +$h = imagesy($im); +$r = $w / floatval($h); + +if ($w > $h) { + $nw = THUMB_MAX_DIM; + $nh = floor($nw / $r); +} else { + $nh = THUMB_MAX_DIM; + $nw = floor($r * $nh); +} + +$thumb = imagecreatetruecolor($nw, $nh); +imagecopyresampled($thumb, $im, 0, 0, 0, 0, $nw, $nh, $w, $h); +imagedestroy($im); + +header("Content-Type: image/jpeg"); +header("Cache-Control: max-age=86400"); +imagejpeg($thumb, $cacheFileData, 40); +imagedestroy($thumb); +file_put_contents($cacheFileInfo, json_encode([ + "format" => 1, + "contentHash" => $contentHash, + "created" => time(), +], JSON_UNESCAPED_SLASHES)); +readfile($cacheFileData); |