Added GIF detection
This commit is contained in:
parent
38bfbfb8f3
commit
5412ac14b9
15 changed files with 114 additions and 9 deletions
|
@ -158,6 +158,9 @@
|
||||||
.post-small.post-type-flash .link::after {
|
.post-small.post-type-flash .link::after {
|
||||||
content: 'flash';
|
content: 'flash';
|
||||||
}
|
}
|
||||||
|
.post-small.post-type-animation .link::after {
|
||||||
|
content: 'anim';
|
||||||
|
}
|
||||||
|
|
||||||
.post-small .action {
|
.post-small .action {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
var postContentUrl = '/data/posts/' + post.name + '?' + Math.round(Math.random() * 1000) /* reset gif animations */
|
var postContentUrl = '/data/posts/' + post.name + '?' + Math.round(Math.random() * 1000) /* reset gif animations */
|
||||||
var width;
|
var width;
|
||||||
var height;
|
var height;
|
||||||
if (post.contentType === 'image' || post.contentType === 'flash') {
|
if (post.contentType === 'image' || post.contentType === 'animation' || post.contentType === 'flash') {
|
||||||
width = post.imageWidth;
|
width = post.imageWidth;
|
||||||
height = post.imageHeight;
|
height = post.imageHeight;
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
data-height="<%= height %>"
|
data-height="<%= height %>"
|
||||||
style="max-width: <%= width %>px">
|
style="max-width: <%= width %>px">
|
||||||
|
|
||||||
<% if (post.contentType === 'image') { %>
|
<% if (post.contentType === 'image' || post.contentType === 'animation') { %>
|
||||||
|
|
||||||
<img alt="<%= post.name %>" src="<%= postContentUrl %>"/>
|
<img alt="<%= post.name %>" src="<%= postContentUrl %>"/>
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ final class Post extends Entity
|
||||||
const POST_TYPE_FLASH = 2;
|
const POST_TYPE_FLASH = 2;
|
||||||
const POST_TYPE_VIDEO = 3;
|
const POST_TYPE_VIDEO = 3;
|
||||||
const POST_TYPE_YOUTUBE = 4;
|
const POST_TYPE_YOUTUBE = 4;
|
||||||
|
const POST_TYPE_ANIMATED_IMAGE = 5;
|
||||||
|
|
||||||
const FLAG_LOOP = 1;
|
const FLAG_LOOP = 1;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ class EnumHelper
|
||||||
'video' => Post::POST_TYPE_VIDEO,
|
'video' => Post::POST_TYPE_VIDEO,
|
||||||
'flash' => Post::POST_TYPE_FLASH,
|
'flash' => Post::POST_TYPE_FLASH,
|
||||||
'youtube' => Post::POST_TYPE_YOUTUBE,
|
'youtube' => Post::POST_TYPE_YOUTUBE,
|
||||||
|
'animation' => Post::POST_TYPE_ANIMATED_IMAGE,
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $snapshotTypeMap =
|
private static $snapshotTypeMap =
|
||||||
|
|
|
@ -18,6 +18,12 @@ class MimeHelper
|
||||||
return self::getMimeTypeFrom16Bytes(substr($buffer, 0, 16));
|
return self::getMimeTypeFrom16Bytes(substr($buffer, 0, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isBufferAnimatedGif($buffer)
|
||||||
|
{
|
||||||
|
return strtolower(self::getMimeTypeFromBuffer($buffer)) === 'image/gif'
|
||||||
|
and preg_match_all('#\x21\xf9\x04.{4}\x00[\x2c\x21]#s', $buffer) > 1;
|
||||||
|
}
|
||||||
|
|
||||||
public static function isFlash($mime)
|
public static function isFlash($mime)
|
||||||
{
|
{
|
||||||
return strtolower($mime) === 'application/x-shockwave-flash';
|
return strtolower($mime) === 'application/x-shockwave-flash';
|
||||||
|
|
|
@ -206,13 +206,24 @@ class PostService
|
||||||
$post->setContentMimeType($mime);
|
$post->setContentMimeType($mime);
|
||||||
|
|
||||||
if (MimeHelper::isFlash($mime))
|
if (MimeHelper::isFlash($mime))
|
||||||
|
{
|
||||||
$post->setContentType(Post::POST_TYPE_FLASH);
|
$post->setContentType(Post::POST_TYPE_FLASH);
|
||||||
|
}
|
||||||
elseif (MimeHelper::isImage($mime))
|
elseif (MimeHelper::isImage($mime))
|
||||||
$post->setContentType(Post::POST_TYPE_IMAGE);
|
{
|
||||||
|
$post->setContentType(
|
||||||
|
MimeHelper::isBufferAnimatedGif($content)
|
||||||
|
? Post::POST_TYPE_ANIMATED_IMAGE
|
||||||
|
: Post::POST_TYPE_IMAGE);
|
||||||
|
}
|
||||||
elseif (MimeHelper::isVideo($mime))
|
elseif (MimeHelper::isVideo($mime))
|
||||||
|
{
|
||||||
$post->setContentType(Post::POST_TYPE_VIDEO);
|
$post->setContentType(Post::POST_TYPE_VIDEO);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
throw new \DomainException('Unhandled file type: "' . $mime . '"');
|
throw new \DomainException('Unhandled file type: "' . $mime . '"');
|
||||||
|
}
|
||||||
|
|
||||||
$post->setContentChecksum(sha1($content));
|
$post->setContentChecksum(sha1($content));
|
||||||
$this->assertNoPostWithThisContentChecksum($post);
|
$this->assertNoPostWithThisContentChecksum($post);
|
||||||
|
|
|
@ -41,13 +41,10 @@ final class UpgradeService
|
||||||
if ($this->isUpgradeNeeded($upgrade))
|
if ($this->isUpgradeNeeded($upgrade))
|
||||||
{
|
{
|
||||||
if ($verbose)
|
if ($verbose)
|
||||||
{
|
$this->log('Running ' . get_class($upgrade));
|
||||||
echo 'Running ' . get_class($upgrade) . PHP_EOL;
|
|
||||||
if (ob_get_level())
|
|
||||||
ob_flush();
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
$this->runUpgrade($upgrade);
|
$this->runUpgrade($upgrade);
|
||||||
|
if ($verbose)
|
||||||
|
$this->log(PHP_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,4 +84,12 @@ final class UpgradeService
|
||||||
preg_match('/(\d+)/', $className, $matches);
|
preg_match('/(\d+)/', $className, $matches);
|
||||||
return intval($matches[1]);
|
return intval($matches[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function log($message)
|
||||||
|
{
|
||||||
|
echo $message;
|
||||||
|
if (ob_get_level())
|
||||||
|
ob_flush();
|
||||||
|
flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
52
src/Upgrades/Upgrade38.php
Normal file
52
src/Upgrades/Upgrade38.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Upgrades;
|
||||||
|
use Szurubooru\Dao\PostDao;
|
||||||
|
use Szurubooru\Dao\PublicFileDao;
|
||||||
|
use Szurubooru\DatabaseConnection;
|
||||||
|
use Szurubooru\Entities\Post;
|
||||||
|
use Szurubooru\Helpers\MimeHelper;
|
||||||
|
|
||||||
|
class Upgrade38 implements IUpgrade
|
||||||
|
{
|
||||||
|
private $postDao;
|
||||||
|
private $fileDao;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
PostDao $postDao,
|
||||||
|
PublicFileDao $fileDao)
|
||||||
|
{
|
||||||
|
$this->postDao = $postDao;
|
||||||
|
$this->fileDao = $fileDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(DatabaseConnection $databaseConnection)
|
||||||
|
{
|
||||||
|
$posts = $this->postDao->findAll();
|
||||||
|
$progress = 0;
|
||||||
|
foreach ($posts as $post)
|
||||||
|
{
|
||||||
|
if ($post->getContentType() === Post::POST_TYPE_IMAGE)
|
||||||
|
{
|
||||||
|
$fullPath = $this->fileDao->getFullPath($post->getContentPath());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$contents = file_get_contents($fullPath);
|
||||||
|
}
|
||||||
|
catch (\Exception $e)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (MimeHelper::isBufferAnimatedGif($contents))
|
||||||
|
{
|
||||||
|
$post->setContentType(Post::POST_TYPE_ANIMATED_IMAGE);
|
||||||
|
$this->postDao->save($post);
|
||||||
|
}
|
||||||
|
if (++ $progress == 100)
|
||||||
|
{
|
||||||
|
echo '.';
|
||||||
|
$progress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ return [
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade35::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade35::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade36::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade36::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade37::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade37::class),
|
||||||
|
$container->get(\Szurubooru\Upgrades\Upgrade38::class),
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,19 @@ use Szurubooru\Tests\AbstractTestCase;
|
||||||
|
|
||||||
final class MimeHelperTest extends AbstractTestCase
|
final class MimeHelperTest extends AbstractTestCase
|
||||||
{
|
{
|
||||||
|
public static function animatedGifProvider()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
['test_files/video.mp4', false],
|
||||||
|
['test_files/static.gif', false],
|
||||||
|
['test_files/animated.gif', true],
|
||||||
|
['test_files/animated2.gif', true],
|
||||||
|
['test_files/animated3.gif', true],
|
||||||
|
['test_files/animated4.gif', true],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function testGettingMime()
|
public function testGettingMime()
|
||||||
{
|
{
|
||||||
$expected = 'image/jpeg';
|
$expected = 'image/jpeg';
|
||||||
|
@ -38,4 +51,16 @@ final class MimeHelperTest extends AbstractTestCase
|
||||||
$this->assertTrue(MimeHelper::isVideo('application/ogg'));
|
$this->assertTrue(MimeHelper::isVideo('application/ogg'));
|
||||||
$this->assertFalse(MimeHelper::isVideo('something else'));
|
$this->assertFalse(MimeHelper::isVideo('something else'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider animatedGifProvider
|
||||||
|
*/
|
||||||
|
public function testIsAnimatedGif($path, $expected)
|
||||||
|
{
|
||||||
|
$fullPath = __DIR__
|
||||||
|
. DIRECTORY_SEPARATOR . '..'
|
||||||
|
. DIRECTORY_SEPARATOR . $path;
|
||||||
|
$actual = MimeHelper::isBufferAnimatedGif(file_get_contents($fullPath));
|
||||||
|
$this->assertEquals($expected, $actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
tests/test_files/animated.gif
Normal file
BIN
tests/test_files/animated.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
BIN
tests/test_files/animated2.gif
Normal file
BIN
tests/test_files/animated2.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 491 KiB |
BIN
tests/test_files/animated3.gif
Normal file
BIN
tests/test_files/animated3.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
tests/test_files/animated4.gif
Normal file
BIN
tests/test_files/animated4.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 KiB |
BIN
tests/test_files/static.gif
Normal file
BIN
tests/test_files/static.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in a new issue