Added thumbnail support for videos and embedded covers in audio.
This commit is contained in:
parent
5ab496b833
commit
a6ef98210c
2 changed files with 79 additions and 39 deletions
|
@ -132,6 +132,7 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
|||
$uploadInfo->bumpExpiry();
|
||||
}
|
||||
|
||||
$fileName = $uploadInfo->getName();
|
||||
$contentType = $uploadInfo->getType();
|
||||
|
||||
if($contentType === 'application/octet-stream' || substr($contentType, 0, 5) === 'text/')
|
||||
|
@ -139,49 +140,16 @@ if(preg_match('#^/uploads/([a-zA-Z0-9-_]{32})(\.t)?/?$#', $reqPath, $matches)) {
|
|||
|
||||
$sourceDir = basename($getThumbnail ? PRM_THUMBS : PRM_UPLOADS);
|
||||
|
||||
if($getThumbnail) {
|
||||
if(substr($contentType, 0, 6) !== 'image/') {
|
||||
http_response_code(404);
|
||||
echo 'Thumbnails are not supported for this filetype.';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$imagick = new \Imagick($uploadInfo->getPath());
|
||||
$imagick->setImageFormat('jpg');
|
||||
$imagick->setImageCompressionQuality(40);
|
||||
|
||||
$thumbRes = 100;
|
||||
$width = $imagick->getImageWidth();
|
||||
$height = $imagick->getImageHeight();
|
||||
|
||||
if ($width > $height) {
|
||||
$resizeWidth = $width * $thumbRes / $height;
|
||||
$resizeHeight = $thumbRes;
|
||||
} else {
|
||||
$resizeWidth = $thumbRes;
|
||||
$resizeHeight = $height * $thumbRes / $width;
|
||||
}
|
||||
|
||||
$imagick->resizeImage(
|
||||
$resizeWidth, $resizeHeight,
|
||||
\Imagick::FILTER_GAUSSIAN, 0.7
|
||||
);
|
||||
|
||||
$imagick->cropImage(
|
||||
$thumbRes,
|
||||
$thumbRes,
|
||||
($resizeWidth - $thumbRes) / 2,
|
||||
($resizeHeight - $thumbRes) / 2
|
||||
);
|
||||
|
||||
$imagick->writeImage($uploadInfo->getThumbPath());
|
||||
} catch(\Exception $ex) {}
|
||||
if($getThumbnail && $uploadInfo->supportsThumbnail()) {
|
||||
if(!is_file($uploadInfo->getThumbPath()))
|
||||
$uploadInfo->createThumbnail();
|
||||
$contentType = 'image/jpeg';
|
||||
$fileName = pathinfo($fileName, PATHINFO_FILENAME) . '-thumb.jpg';
|
||||
}
|
||||
|
||||
header(sprintf('X-Accel-Redirect: /%s/%s', $sourceDir, $uploadInfo->getId()));
|
||||
header(sprintf('Content-Type: %s', $contentType));
|
||||
header(sprintf('Content-Disposition: inline; filename="%s"', addslashes($uploadInfo->getName())));
|
||||
header(sprintf('Content-Disposition: inline; filename="%s"', addslashes($fileName)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace EEPROM;
|
||||
|
||||
use Exception;
|
||||
use Imagick;
|
||||
use JsonSerializable;
|
||||
|
||||
class UploadNotFoundException extends Exception {};
|
||||
|
@ -70,6 +71,15 @@ final class Upload implements JsonSerializable {
|
|||
public function getType(): string {
|
||||
return $this->upload_type ?? 'text/plain';
|
||||
}
|
||||
public function isImage(): bool {
|
||||
return substr($this->getType(), 0, 6) === 'image/';
|
||||
}
|
||||
public function isVideo(): bool {
|
||||
return substr($this->getType(), 0, 6) === 'video/';
|
||||
}
|
||||
public function isAudio(): bool {
|
||||
return substr($this->getType(), 0, 6) === 'audio/';
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
return $this->upload_name ?? '';
|
||||
|
@ -387,4 +397,66 @@ final class Upload implements JsonSerializable {
|
|||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function supportsThumbnail(): bool {
|
||||
return $this->isImage() || $this->isAudio() || $this->isVideo();
|
||||
}
|
||||
|
||||
public function createThumbnail(): void {
|
||||
$tmpFile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'eeprom' . bin2hex(random_bytes(10)) . '.jpg';
|
||||
|
||||
try {
|
||||
if($this->isImage())
|
||||
$imagick = new Imagick($this->getPath());
|
||||
elseif($this->isAudio())
|
||||
$imagick = $this->getCoverFromAudio($tmpFile);
|
||||
elseif($this->isVideo())
|
||||
$imagick = $this->getFrameFromVideo($tmpFile);
|
||||
|
||||
if(!isset($imagick))
|
||||
return;
|
||||
|
||||
$imagick->setImageFormat('jpg');
|
||||
$imagick->setImageCompressionQuality(40);
|
||||
|
||||
$thumbRes = 100;
|
||||
$width = $imagick->getImageWidth();
|
||||
$height = $imagick->getImageHeight();
|
||||
|
||||
if ($width > $height) {
|
||||
$resizeWidth = $width * $thumbRes / $height;
|
||||
$resizeHeight = $thumbRes;
|
||||
} else {
|
||||
$resizeWidth = $thumbRes;
|
||||
$resizeHeight = $height * $thumbRes / $width;
|
||||
}
|
||||
|
||||
$imagick->resizeImage(
|
||||
$resizeWidth, $resizeHeight,
|
||||
Imagick::FILTER_GAUSSIAN, 0.7
|
||||
);
|
||||
|
||||
$imagick->cropImage(
|
||||
$thumbRes,
|
||||
$thumbRes,
|
||||
($resizeWidth - $thumbRes) / 2,
|
||||
($resizeHeight - $thumbRes) / 2
|
||||
);
|
||||
|
||||
$imagick->writeImage($this->getThumbPath());
|
||||
} catch(Exception $ex) {}
|
||||
|
||||
if(is_file($tmpFile))
|
||||
unlink($tmpFile);
|
||||
}
|
||||
|
||||
private function getFrameFromVideo(string $path): Imagick {
|
||||
shell_exec(sprintf('ffmpeg -i %s -ss 00:00:01.000 -vframes 1 %s', $this->getPath(), $path));
|
||||
return new Imagick($path);
|
||||
}
|
||||
|
||||
private function getCoverFromAudio(string $path): Imagick {
|
||||
shell_exec(sprintf('ffmpeg -i %s -an -vcodec copy %s', $this->getPath(), $path));
|
||||
return new Imagick($path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue