diff --git a/data/config.ini b/data/config.ini index cd81d9f4..3c1a334b 100644 --- a/data/config.ini +++ b/data/config.ini @@ -4,7 +4,7 @@ dbLocation = "./data/db.sqlite" dbUser = "test" dbPass = "test" filesPath = "./data/files/" -thumbsPath = "./data/thumbs/" +thumbsPath = "./public_html/thumbs/" logsPath = "./data/logs/{yyyy}-{mm}.log" mediaPath = "./public_html/media/" title = "szurubooru" diff --git a/public_html/.htaccess b/public_html/.htaccess index 725416c0..2590a8d3 100644 --- a/public_html/.htaccess +++ b/public_html/.htaccess @@ -6,6 +6,10 @@ ErrorDocument 403 /dispatch.php?request=error/http&code=403 ErrorDocument 404 /dispatch.php?request=error/http&code=404 ErrorDocument 500 /dispatch.php?request=error/http&code=500 +RewriteCond %{DOCUMENT_ROOT}/thumbs/$1.thumb -f +RewriteRule ^/?post/(.*)/thumb/?$ /thumbs/$1.thumb +RewriteRule ^/?thumbs/(.*).thumb - [L,T=image/jpeg] + RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^.*$ /dispatch.php diff --git a/data/thumbs/.gitignore b/public_html/thumbs/.gitignore similarity index 100% rename from data/thumbs/.gitignore rename to public_html/thumbs/.gitignore diff --git a/src/Api/JobArgs/JobArgs.php b/src/Api/JobArgs/JobArgs.php index 98c41c86..b99f1c5b 100644 --- a/src/Api/JobArgs/JobArgs.php +++ b/src/Api/JobArgs/JobArgs.php @@ -24,9 +24,6 @@ class JobArgs const ARG_LOG_ID = 'log-id'; - const ARG_THUMB_WIDTH = 'thumb-width'; - const ARG_THUMB_HEIGHT = 'thumb-height'; - const ARG_NEW_TEXT = 'new-text'; const ARG_NEW_STATE = 'new-state'; diff --git a/src/Api/Jobs/PostJobs/GetPostThumbJob.php b/src/Api/Jobs/PostJobs/GetPostThumbJob.php index 7b3892e4..acde0132 100644 --- a/src/Api/Jobs/PostJobs/GetPostThumbJob.php +++ b/src/Api/Jobs/PostJobs/GetPostThumbJob.php @@ -19,17 +19,14 @@ class GetPostThumbJob extends AbstractJob $name = $post->getName(); } - $width = $this->hasArgument(JobArgs::ARG_THUMB_WIDTH) ? $this->getArgument(JobArgs::ARG_THUMB_WIDTH) : null; - $height = $this->hasArgument(JobArgs::ARG_THUMB_HEIGHT) ? $this->getArgument(JobArgs::ARG_THUMB_HEIGHT) : null; - - $path = PostModel::tryGetWorkingThumbPath($name, $width, $height); + $path = PostModel::tryGetWorkingThumbPath($name); if (!$path) { $post = PostModel::getByName($name); $post = $this->postRetriever->retrieve(); - $post->generateThumb($width, $height); - $path = PostModel::tryGetWorkingThumbPath($name, $width, $height); + $post->generateThumb(); + $path = PostModel::tryGetWorkingThumbPath($name); if (!$path) { @@ -43,15 +40,11 @@ class GetPostThumbJob extends AbstractJob public function getRequiredArguments() { - return JobArgs::Conjunction( - $this->postRetriever->getRequiredArguments(), - JobArgs::Optional(JobArgs::ARG_THUMB_WIDTH), - JobArgs::Optional(JobArgs::ARG_THUMB_HEIGHT)); + return $this->postRetriever->getRequiredArguments(); } public function getRequiredPrivileges() { - //privilege check removed to make thumbs faster return false; } } diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index 134949d5..0444a874 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -267,12 +267,9 @@ class PostController $context->layoutName = 'layout-file'; } - public function thumbView($name, $width = null, $height = null) + public function thumbView($name) { - $ret = Api::run(new GetPostThumbJob(), [ - JobArgs::ARG_POST_NAME => $name, - JobArgs::ARG_THUMB_WIDTH => $width, - JobArgs::ARG_THUMB_HEIGHT => $height]); + $ret = Api::run(new GetPostThumbJob(), [JobArgs::ARG_POST_NAME => $name]); $context = getContext(); $context->transport->cacheDaysToLive = 365; diff --git a/src/Models/Entities/PostEntity.php b/src/Models/Entities/PostEntity.php index 20fb4b99..a0530fc0 100644 --- a/src/Models/Entities/PostEntity.php +++ b/src/Models/Entities/PostEntity.php @@ -328,24 +328,24 @@ final class PostEntity extends AbstractEntity implements IValidatable return PostModel::getFullPath($this->getName()); } - public function tryGetWorkingThumbPath($width = null, $height = null) + public function tryGetWorkingThumbPath() { - return PostModel::tryGetWorkingThumbPath($this->getName(), $width, $height); + return PostModel::tryGetWorkingThumbPath($this->getName()); } - public function getThumbCustomPath($width = null, $height = null) + public function getThumbCustomSourcePath() { - return PostModel::getThumbCustomPath($this->getName(), $width, $height); + return PostModel::getThumbCustomSourcePath($this->getName()); } - public function getThumbDefaultPath($width = null, $height = null) + public function getThumbPath() { - return PostModel::getThumbDefaultPath($this->getName(), $width, $height); + return PostModel::getThumbPath($this->getName()); } - public function hasCustomThumb($width = null, $height = null) + public function hasCustomThumb() { - $thumbPath = $this->getThumbCustomPath($width, $height); + $thumbPath = $this->getThumbCustomSourcePath(); return file_exists($thumbPath); } @@ -357,26 +357,21 @@ final class PostEntity extends AbstractEntity implements IValidatable if (!in_array($mimeType, ['image/gif', 'image/png', 'image/jpeg'])) throw new SimpleException('Invalid thumbnail type "%s"', $mimeType); - list ($imageWidth, $imageHeight) = getimagesize($srcPath); - if ($imageWidth != $config->browsing->thumbWidth - or $imageHeight != $config->browsing->thumbHeight) - { - throw new SimpleException( - 'Invalid thumbnail size (should be %dx%d)', - $config->browsing->thumbWidth, - $config->browsing->thumbHeight); - } - - $dstPath = $this->getThumbCustomPath(); + $dstPath = $this->getThumbCustomSourcePath(); TransferHelper::copy($srcPath, $dstPath); + + $this->generateThumb(); } - public function generateThumb($width = null, $height = null) + public function generateThumb() { - list ($width, $height) = PostModel::validateThumbSize($width, $height); - $srcPath = $this->getFullPath(); - $dstPath = $this->getThumbDefaultPath($width, $height); + $width = getConfig()->browsing->thumbWidth; + $height = getConfig()->browsing->thumbHeight; + $dstPath = $this->getThumbPath($width, $height); + + if (file_exists($this->getThumbCustomSourcePath())) + return ThumbnailHelper::generateFromPath($this->getThumbCustomSourcePath(), $dstPath, $width, $height); if ($this->getType()->toInteger() == PostType::Youtube) { @@ -388,7 +383,7 @@ final class PostEntity extends AbstractEntity implements IValidatable } else { - return ThumbnailHelper::generateFromPath($srcPath, $dstPath, $width, $height); + return ThumbnailHelper::generateFromPath($this->getFullPath(), $dstPath, $width, $height); } } @@ -445,7 +440,7 @@ final class PostEntity extends AbstractEntity implements IValidatable TransferHelper::copy($srcPath, $dstPath); - $thumbPath = $this->getThumbDefaultPath(); + $thumbPath = $this->getThumbPath(); if (file_exists($thumbPath)) unlink($thumbPath); } @@ -467,7 +462,7 @@ final class PostEntity extends AbstractEntity implements IValidatable $this->setImageWidth(null); $this->setImageHeight(null); - $thumbPath = $this->getThumbDefaultPath(); + $thumbPath = $this->getThumbPath(); if (file_exists($thumbPath)) unlink($thumbPath); diff --git a/src/Models/PostModel.php b/src/Models/PostModel.php index 8cd50abe..bc85c6f5 100644 --- a/src/Models/PostModel.php +++ b/src/Models/PostModel.php @@ -255,46 +255,29 @@ final class PostModel extends AbstractCrudModel - public static function validateThumbSize($width, $height) + public static function tryGetWorkingThumbPath($name) { - $width = $width === null ? getConfig()->browsing->thumbWidth : $width; - $height = $height === null ? getConfig()->browsing->thumbHeight : $height; - $width = min(1000, max(1, $width)); - $height = min(1000, max(1, $height)); - return [$width, $height]; - } - - public static function tryGetWorkingThumbPath($name, $width = null, $height = null) - { - $path = PostModel::getThumbCustomPath($name, $width, $height); - if (file_exists($path) and is_readable($path)) - return $path; - - $path = PostModel::getThumbDefaultPath($name, $width, $height); + $path = PostModel::getThumbPath($name); if (file_exists($path) and is_readable($path)) return $path; return null; } - public static function getThumbCustomPath($name, $width = null, $height = null) + public static function getThumbCustomSourcePath($name) { - return self::getThumbPathTokenized('{fullpath}.custom', $name, $width, $height); + return self::getThumbPathTokenized('{fullpath}.thumb_source', $name); } - public static function getThumbDefaultPath($name, $width = null, $height = null) + public static function getThumbPath($name) { - return self::getThumbPathTokenized('{fullpath}-{width}x{height}.default', $name, $width, $height); + return self::getThumbPathTokenized('{fullpath}.thumb', $name); } - private static function getThumbPathTokenized($text, $name, $width = null, $height = null) + private static function getThumbPathTokenized($text, $name) { - list ($width, $height) = self::validateThumbSize($width, $height); - return TextHelper::absolutePath(TextHelper::replaceTokens($text, [ - 'fullpath' => getConfig()->main->thumbsPath . DS . $name, - 'width' => $width, - 'height' => $height])); + 'fullpath' => getConfig()->main->thumbsPath . DS . $name])); } public static function tryGetWorkingFullPath($name) diff --git a/tests/Tests/ApiTests/ApiArgumentTest.php b/tests/Tests/ApiTests/ApiArgumentTest.php index 10c9ad6d..6c1e047c 100644 --- a/tests/Tests/ApiTests/ApiArgumentTest.php +++ b/tests/Tests/ApiTests/ApiArgumentTest.php @@ -203,11 +203,7 @@ class ApiArgumentTest extends AbstractFullApiTest public function testGetPostThumbJob() { - $this->testArguments(new GetPostThumbJob(), - JobArgs::Conjunction( - JobArgs::Optional(JobArgs::ARG_THUMB_WIDTH), - JobArgs::Optional(JobArgs::ARG_THUMB_HEIGHT), - $this->getPostSafeSelector())); + $this->testArguments(new GetPostThumbJob(), $this->getPostSafeSelector()); } public function testGetUserJob() diff --git a/tests/Tests/JobTests/EditPostThumbJobTest.php b/tests/Tests/JobTests/EditPostThumbJobTest.php index a2758e60..c98e093e 100644 --- a/tests/Tests/JobTests/EditPostThumbJobTest.php +++ b/tests/Tests/JobTests/EditPostThumbJobTest.php @@ -19,20 +19,19 @@ class EditPostThumbJobTest extends AbstractTest }); $this->assert->isTrue($post->hasCustomThumb()); - $this->assert->isNotNull($post->getThumbCustomPath()); - $this->assert->areEqual($post->getThumbCustomPath(), $post->tryGetWorkingThumbPath()); - $this->assert->areEqual( - file_get_contents($this->testSupport->getPath('thumb.jpg')), - file_get_contents($post->tryGetWorkingThumbPath())); + $img = imagecreatefromjpeg($post->tryGetWorkingThumbPath()); + $this->assert->areEqual(150, imagesx($img)); + $this->assert->areEqual(150, imagesy($img)); + imagedestroy($img); } - public function testFileInvalidDimensions() + public function testFileDifferentDimensions() { $this->grantAccess('editPostThumb'); $post = $this->postMocker->mockSingle(); $this->assert->isFalse($post->hasCustomThumb()); - $this->assert->throws(function() use ($post) + $post = $this->assert->doesNotThrow(function() use ($post) { return Api::run( new EditPostThumbJob(), @@ -41,9 +40,12 @@ class EditPostThumbJobTest extends AbstractTest JobArgs::ARG_NEW_THUMB_CONTENT => new ApiFileInput($this->testSupport->getPath('image.jpg'), 'test.jpg'), ]); - }, 'invalid thumbnail size'); + }); - $this->assert->isFalse($post->hasCustomThumb()); - $this->assert->areNotEqual($post->getThumbCustomPath(), $post->tryGetWorkingThumbPath()); + $this->assert->isTrue($post->hasCustomThumb()); + $img = imagecreatefromjpeg($post->tryGetWorkingThumbPath()); + $this->assert->areEqual(150, imagesx($img)); + $this->assert->areEqual(150, imagesy($img)); + imagedestroy($img); } }