Added additional media properties to the images table, video, audio, length, and lossless.
Added new event to handle fetching media properties like height, width, and the newly added fields, and admin controls to manually scan files for their properties. Added a search terms content:video and content:audio to search for images that do (or do not) have those flags.
This commit is contained in:
parent
a41e99d1af
commit
b1db833d51
@ -54,6 +54,19 @@ class Image
|
|||||||
/** @var boolean */
|
/** @var boolean */
|
||||||
public $locked = false;
|
public $locked = false;
|
||||||
|
|
||||||
|
/** @var boolean */
|
||||||
|
public $lossless = null;
|
||||||
|
|
||||||
|
/** @var boolean */
|
||||||
|
public $video = null;
|
||||||
|
|
||||||
|
/** @var boolean */
|
||||||
|
public $audio = null;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $length = null;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One will very rarely construct an image directly, more common
|
* One will very rarely construct an image directly, more common
|
||||||
* would be to use Image::by_id, Image::by_hash, etc.
|
* would be to use Image::by_id, Image::by_hash, etc.
|
||||||
|
@ -194,3 +194,21 @@ function create_image_thumb(string $hash, string $type, string $engine = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const TIME_UNITS = ["s"=>60,"m"=>60,"h"=>24,"d"=>365,"y"=>PHP_INT_MAX];
|
||||||
|
function format_milliseconds(int $input): string
|
||||||
|
{
|
||||||
|
$output = "";
|
||||||
|
|
||||||
|
$remainder = floor($input / 1000);
|
||||||
|
|
||||||
|
foreach (TIME_UNITS AS $unit=>$conversion) {
|
||||||
|
$count = $remainder % $conversion;
|
||||||
|
$remainder = floor($remainder / $conversion);
|
||||||
|
if($count==0&&$remainder<1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$output = "$count".$unit." ".$output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($output);
|
||||||
|
}
|
@ -8,6 +8,26 @@
|
|||||||
|
|
||||||
class FlashFileHandler extends DataHandlerExtension
|
class FlashFileHandler extends DataHandlerExtension
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
|
{
|
||||||
|
switch ($event->ext) {
|
||||||
|
case "swf":
|
||||||
|
$event->lossless = true;
|
||||||
|
$event->video = true;
|
||||||
|
|
||||||
|
$info = getimagesize($event->file_name);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->width = $info[0];
|
||||||
|
$event->height = $info[1];
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function create_thumb(string $hash, string $type): bool
|
protected function create_thumb(string $hash, string $type): bool
|
||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
@ -35,13 +55,7 @@ class FlashFileHandler extends DataHandlerExtension
|
|||||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||||
$image->source = $metadata['source'];
|
$image->source = $metadata['source'];
|
||||||
|
|
||||||
$info = getimagesize($filename);
|
|
||||||
if (!$info) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$image->width = $info[0];
|
|
||||||
$image->height = $info[1];
|
|
||||||
|
|
||||||
return $image;
|
return $image;
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,14 @@ class IcoFileHandler extends DataHandlerExtension
|
|||||||
const SUPPORTED_EXTENSIONS = ["ico", "ani", "cur"];
|
const SUPPORTED_EXTENSIONS = ["ico", "ani", "cur"];
|
||||||
|
|
||||||
|
|
||||||
protected function supported_ext(string $ext): bool
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
{
|
{
|
||||||
return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS);
|
if(in_array($event->ext, self::SUPPORTED_EXTENSIONS)) {
|
||||||
}
|
$event->lossless = true;
|
||||||
|
$event->video = false;
|
||||||
|
$event->audio = false;
|
||||||
|
|
||||||
protected function create_image_from_data(string $filename, array $metadata)
|
$fp = fopen($event->file_name, "r");
|
||||||
{
|
|
||||||
$image = new Image();
|
|
||||||
|
|
||||||
|
|
||||||
$fp = fopen($filename, "r");
|
|
||||||
try {
|
try {
|
||||||
unpack("Snull/Stype/Scount", fread($fp, 6));
|
unpack("Snull/Stype/Scount", fread($fp, 6));
|
||||||
$subheader = unpack("Cwidth/Cheight/Ccolours/Cnull/Splanes/Sbpp/Lsize/loffset", fread($fp, 16));
|
$subheader = unpack("Cwidth/Cheight/Ccolours/Cnull/Splanes/Sbpp/Lsize/loffset", fread($fp, 16));
|
||||||
@ -30,8 +27,20 @@ class IcoFileHandler extends DataHandlerExtension
|
|||||||
|
|
||||||
$width = $subheader['width'];
|
$width = $subheader['width'];
|
||||||
$height = $subheader['height'];
|
$height = $subheader['height'];
|
||||||
$image->width = $width == 0 ? 256 : $width;
|
$event->width = $width == 0 ? 256 : $width;
|
||||||
$image->height = $height == 0 ? 256 : $height;
|
$event->height = $height == 0 ? 256 : $height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function supported_ext(string $ext): bool
|
||||||
|
{
|
||||||
|
return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function create_image_from_data(string $filename, array $metadata)
|
||||||
|
{
|
||||||
|
$image = new Image();
|
||||||
|
|
||||||
$image->filesize = $metadata['size'];
|
$image->filesize = $metadata['size'];
|
||||||
$image->hash = $metadata['hash'];
|
$image->hash = $metadata['hash'];
|
||||||
|
@ -7,6 +7,19 @@
|
|||||||
|
|
||||||
class MP3FileHandler extends DataHandlerExtension
|
class MP3FileHandler extends DataHandlerExtension
|
||||||
{
|
{
|
||||||
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
|
{
|
||||||
|
switch ($event->ext) {
|
||||||
|
case "mp3":
|
||||||
|
$event->audio = true;
|
||||||
|
$event->video = false;
|
||||||
|
$event->lossless = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// TODO: Buff out audio format support, length scanning
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function create_thumb(string $hash, string $type): bool
|
protected function create_thumb(string $hash, string $type): bool
|
||||||
{
|
{
|
||||||
copy("ext/handle_mp3/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash));
|
copy("ext/handle_mp3/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash));
|
||||||
@ -37,6 +50,7 @@ class MP3FileHandler extends DataHandlerExtension
|
|||||||
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
|
||||||
$image->source = $metadata['source'];
|
$image->source = $metadata['source'];
|
||||||
|
|
||||||
|
|
||||||
return $image;
|
return $image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,44 @@ class PixelFileHandler extends DataHandlerExtension
|
|||||||
{
|
{
|
||||||
const SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "gif", "png", "webp"];
|
const SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "gif", "png", "webp"];
|
||||||
|
|
||||||
|
|
||||||
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
|
{
|
||||||
|
if(in_array($event->ext, Media::LOSSLESS_FORMATS)) {
|
||||||
|
$event->lossless = true;
|
||||||
|
} elseif($event->ext=="webp") {
|
||||||
|
$event->lossless = Media::is_lossless_webp($event->file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_array($event->ext,self::SUPPORTED_EXTENSIONS)) {
|
||||||
|
if($event->lossless==null) {
|
||||||
|
$event->lossless = false;
|
||||||
|
}
|
||||||
|
$event->audio = false;
|
||||||
|
switch ($event->ext) {
|
||||||
|
case "gif":
|
||||||
|
$event->video = Media::is_animated_gif($event->file_name);
|
||||||
|
break;
|
||||||
|
case "webp":
|
||||||
|
$event->video = Media::is_animated_webp($event->file_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$event->video = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = getimagesize($event->file_name);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->width = $info[0];
|
||||||
|
$event->height = $info[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected function supported_ext(string $ext): bool
|
protected function supported_ext(string $ext): bool
|
||||||
{
|
{
|
||||||
$ext = (($pos = strpos($ext, '?')) !== false) ? substr($ext, 0, $pos) : $ext;
|
$ext = (($pos = strpos($ext, '?')) !== false) ? substr($ext, 0, $pos) : $ext;
|
||||||
@ -20,14 +58,6 @@ class PixelFileHandler extends DataHandlerExtension
|
|||||||
{
|
{
|
||||||
$image = new Image();
|
$image = new Image();
|
||||||
|
|
||||||
$info = getimagesize($filename);
|
|
||||||
if (!$info) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$image->width = $info[0];
|
|
||||||
$image->height = $info[1];
|
|
||||||
|
|
||||||
$image->filesize = $metadata['size'];
|
$image->filesize = $metadata['size'];
|
||||||
$image->hash = $metadata['hash'];
|
$image->hash = $metadata['hash'];
|
||||||
$image->filename = (($pos = strpos($metadata['filename'], '?')) !== false) ? substr($metadata['filename'], 0, $pos) : $metadata['filename'];
|
$image->filename = (($pos = strpos($metadata['filename'], '?')) !== false) ? substr($metadata['filename'], 0, $pos) : $metadata['filename'];
|
||||||
|
@ -10,6 +10,24 @@ use enshrined\svgSanitize\Sanitizer;
|
|||||||
|
|
||||||
class SVGFileHandler extends DataHandlerExtension
|
class SVGFileHandler extends DataHandlerExtension
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
|
{
|
||||||
|
switch ($event->ext) {
|
||||||
|
case "svg":
|
||||||
|
$event->lossless = true;
|
||||||
|
$event->video = false;
|
||||||
|
$event->audio = false;
|
||||||
|
|
||||||
|
$msp = new MiniSVGParser($event->file_name);
|
||||||
|
$event->width = $msp->width;
|
||||||
|
$event->height = $msp->height;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function onDataUpload(DataUploadEvent $event)
|
public function onDataUpload(DataUploadEvent $event)
|
||||||
{
|
{
|
||||||
if ($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
|
if ($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) {
|
||||||
@ -82,10 +100,6 @@ class SVGFileHandler extends DataHandlerExtension
|
|||||||
{
|
{
|
||||||
$image = new Image();
|
$image = new Image();
|
||||||
|
|
||||||
$msp = new MiniSVGParser($filename);
|
|
||||||
$image->width = $msp->width;
|
|
||||||
$image->height = $msp->height;
|
|
||||||
|
|
||||||
$image->filesize = $metadata['size'];
|
$image->filesize = $metadata['size'];
|
||||||
$image->hash = $metadata['hash'];
|
$image->hash = $metadata['hash'];
|
||||||
$image->filename = $metadata['filename'];
|
$image->filename = $metadata['filename'];
|
||||||
|
@ -48,6 +48,60 @@ class VideoFileHandler extends DataHandlerExtension
|
|||||||
$event->panel->add_block($sb);
|
$event->panel->add_block($sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onMediaCheckProperties(MediaCheckPropertiesEvent $event)
|
||||||
|
{
|
||||||
|
if(in_array($event->ext, self::SUPPORTED_EXT)) {
|
||||||
|
$event->video = true;
|
||||||
|
try {
|
||||||
|
$data = Media::get_ffprobe_data($event->file_name);
|
||||||
|
|
||||||
|
if(is_array($data)) {
|
||||||
|
if(array_key_exists("streams", $data)) {
|
||||||
|
$video = false;
|
||||||
|
$audio = true;
|
||||||
|
$streams = $data["streams"];
|
||||||
|
if (is_array($streams)) {
|
||||||
|
foreach ($streams as $stream) {
|
||||||
|
if(is_array($stream)) {
|
||||||
|
if (array_key_exists("codec_type", $stream)) {
|
||||||
|
$type = $stream["codec_type"];
|
||||||
|
switch ($type) {
|
||||||
|
case "audio":
|
||||||
|
$audio = true;
|
||||||
|
break;
|
||||||
|
case "video":
|
||||||
|
$video = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists("width", $stream) && !empty($stream["width"])
|
||||||
|
&& is_numeric($stream["width"]) && intval($stream["width"]) > ($event->width) ?? 0) {
|
||||||
|
$event->width = intval($stream["width"]);
|
||||||
|
}
|
||||||
|
if (array_key_exists("height", $stream) && !empty($stream["height"])
|
||||||
|
&& is_numeric($stream["height"]) && intval($stream["height"]) > ($event->height) ?? 0) {
|
||||||
|
$event->height = intval($stream["height"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$event->video = $video;
|
||||||
|
$event->audio = $audio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(array_key_exists("format", $data)&& is_array($data["format"])) {
|
||||||
|
$format = $data["format"];
|
||||||
|
if(array_key_exists("duration", $format) && is_numeric($format["duration"])) {
|
||||||
|
$event->length = floor(floatval($format["duration"]) * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(MediaException $e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the Thumbnail image for particular file.
|
* Generate the Thumbnail image for particular file.
|
||||||
*/
|
*/
|
||||||
@ -65,10 +119,6 @@ class VideoFileHandler extends DataHandlerExtension
|
|||||||
{
|
{
|
||||||
$image = new Image();
|
$image = new Image();
|
||||||
|
|
||||||
$size = Media::video_size($filename);
|
|
||||||
$image->width = $size[0];
|
|
||||||
$image->height = $size[1];
|
|
||||||
|
|
||||||
switch (getMimeType($filename)) {
|
switch (getMimeType($filename)) {
|
||||||
case "video/webm":
|
case "video/webm":
|
||||||
$image->ext = "webm";
|
$image->ext = "webm";
|
||||||
|
@ -241,11 +241,11 @@ class ImageIO extends Extension
|
|||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
:owner_id, :owner_ip, :filename, :filesize,
|
:owner_id, :owner_ip, :filename, :filesize,
|
||||||
:hash, :ext, :width, :height, now(), :source
|
:hash, :ext, 0, 0, now(), :source
|
||||||
)",
|
)",
|
||||||
[
|
[
|
||||||
"owner_id" => $user->id, "owner_ip" => $_SERVER['REMOTE_ADDR'], "filename" => substr($image->filename, 0, 255), "filesize" => $image->filesize,
|
"owner_id" => $user->id, "owner_ip" => $_SERVER['REMOTE_ADDR'], "filename" => substr($image->filename, 0, 255), "filesize" => $image->filesize,
|
||||||
"hash"=>$image->hash, "ext"=>strtolower($image->ext), "width"=>$image->width, "height"=>$image->height, "source"=>$image->source
|
"hash" => $image->hash, "ext" => strtolower($image->ext), "source" => $image->source
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
$image->id = $database->get_last_insert_id('images_id_seq');
|
$image->id = $database->get_last_insert_id('images_id_seq');
|
||||||
@ -264,6 +264,13 @@ class ImageIO extends Extension
|
|||||||
if ($image->source !== null) {
|
if ($image->source !== null) {
|
||||||
log_info("core-image", "Source for Image #{$image->id} set to: {$image->source}");
|
log_info("core-image", "Source for Image #{$image->id} set to: {$image->source}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Media::update_image_media_properties($image->hash, strtolower($image->ext));
|
||||||
|
} catch(MediaException $e) {
|
||||||
|
log_warning("add_image","Error while running update_image_media_properties: ".$e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// }}} end add
|
// }}} end add
|
||||||
|
|
||||||
@ -340,10 +347,35 @@ class ImageIO extends Extension
|
|||||||
throw new ImageReplaceException("Image to replace does not exist!");
|
throw new ImageReplaceException("Image to replace does not exist!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$duplicate = Image::by_hash($image->hash);
|
||||||
|
if(!is_null($duplicate)) {
|
||||||
|
$error = "Image <a href='" . make_link("post/view/{$duplicate->id}") . "'>{$duplicate->id}</a> " .
|
||||||
|
"already has hash {$image->hash}:<p>" . $this->theme->build_thumb_html($duplicate);
|
||||||
|
throw new ImageReplaceException($error);
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(trim($image->source)) == 0) {
|
if (strlen(trim($image->source)) == 0) {
|
||||||
$image->source = $existing->get_source();
|
$image->source = $existing->get_source();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the data in the database.
|
||||||
|
$database->Execute(
|
||||||
|
"UPDATE images SET
|
||||||
|
filename = :filename, filesize = :filesize, hash = :hash,
|
||||||
|
ext = :ext, width = 0, height = 0, source = :source
|
||||||
|
WHERE
|
||||||
|
id = :id
|
||||||
|
",
|
||||||
|
[
|
||||||
|
"filename" => substr($image->filename, 0, 255),
|
||||||
|
"filesize" => $image->filesize,
|
||||||
|
"hash" => $image->hash,
|
||||||
|
"ext" => strtolower($image->ext),
|
||||||
|
"source" => $image->source,
|
||||||
|
"id" => $id,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This step could be optional, ie: perhaps move the image somewhere
|
This step could be optional, ie: perhaps move the image somewhere
|
||||||
and have it stored in a 'replaced images' list that could be
|
and have it stored in a 'replaced images' list that could be
|
||||||
@ -353,20 +385,11 @@ class ImageIO extends Extension
|
|||||||
log_debug("image", "Removing image with hash " . $existing->hash);
|
log_debug("image", "Removing image with hash " . $existing->hash);
|
||||||
$existing->remove_image_only(); // Actually delete the old image file from disk
|
$existing->remove_image_only(); // Actually delete the old image file from disk
|
||||||
|
|
||||||
// Update the data in the database.
|
try {
|
||||||
$database->Execute(
|
Media::update_image_media_properties($image->hash, $image->ext);
|
||||||
"UPDATE images SET
|
} catch(MediaException $e) {
|
||||||
filename = :filename, filesize = :filesize, hash = :hash,
|
log_warning("image_replace","Error while running update_image_media_properties: ".$e->getMessage());
|
||||||
ext = :ext, width = :width, height = :height, source = :source
|
}
|
||||||
WHERE
|
|
||||||
id = :id
|
|
||||||
",
|
|
||||||
[
|
|
||||||
"filename" => substr($image->filename, 0, 255), "filesize"=>$image->filesize, "hash"=>$image->hash,
|
|
||||||
"ext"=>strtolower($image->ext), "width"=>$image->width, "height"=>$image->height, "source"=>$image->source,
|
|
||||||
"id"=>$id
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Generate new thumbnail */
|
/* Generate new thumbnail */
|
||||||
send_event(new ThumbnailGenerationEvent($image->hash, strtolower($image->ext)));
|
send_event(new ThumbnailGenerationEvent($image->hash, strtolower($image->ext)));
|
||||||
|
@ -49,7 +49,9 @@ abstract class MediaEngine
|
|||||||
Media::WEBP_LOSSLESS,
|
Media::WEBP_LOSSLESS,
|
||||||
],
|
],
|
||||||
MediaEngine::FFMPEG => [
|
MediaEngine::FFMPEG => [
|
||||||
|
"jpg",
|
||||||
|
"webp",
|
||||||
|
"png"
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
public const INPUT_SUPPORT = [
|
public const INPUT_SUPPORT = [
|
||||||
@ -59,6 +61,8 @@ abstract class MediaEngine
|
|||||||
"jpg",
|
"jpg",
|
||||||
"png",
|
"png",
|
||||||
"webp",
|
"webp",
|
||||||
|
Media::WEBP_LOSSY,
|
||||||
|
Media::WEBP_LOSSLESS
|
||||||
],
|
],
|
||||||
MediaEngine::IMAGICK => [
|
MediaEngine::IMAGICK => [
|
||||||
"bmp",
|
"bmp",
|
||||||
@ -68,6 +72,8 @@ abstract class MediaEngine
|
|||||||
"psd",
|
"psd",
|
||||||
"tiff",
|
"tiff",
|
||||||
"webp",
|
"webp",
|
||||||
|
Media::WEBP_LOSSY,
|
||||||
|
Media::WEBP_LOSSLESS,
|
||||||
"ico",
|
"ico",
|
||||||
],
|
],
|
||||||
MediaEngine::FFMPEG => [
|
MediaEngine::FFMPEG => [
|
||||||
@ -122,11 +128,16 @@ class MediaResizeEvent extends Event
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MediaCheckLosslessEvent extends Event
|
class MediaCheckPropertiesEvent extends Event
|
||||||
{
|
{
|
||||||
public $file_name;
|
public $file_name;
|
||||||
public $ext;
|
public $ext;
|
||||||
public $result = false;
|
public $lossless = null;
|
||||||
|
public $audio = null;
|
||||||
|
public $video = null;
|
||||||
|
public $length = null;
|
||||||
|
public $height = null;
|
||||||
|
public $width = null;
|
||||||
|
|
||||||
public function __construct(string $file_name, string $ext)
|
public function __construct(string $file_name, string $ext)
|
||||||
{
|
{
|
||||||
@ -136,6 +147,7 @@ class MediaCheckLosslessEvent extends Event
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Media extends Extension
|
class Media extends Extension
|
||||||
{
|
{
|
||||||
const WEBP_LOSSY = "webp-lossy";
|
const WEBP_LOSSY = "webp-lossy";
|
||||||
@ -149,11 +161,19 @@ class Media extends Extension
|
|||||||
const LOSSLESS_FORMATS = [
|
const LOSSLESS_FORMATS = [
|
||||||
self::WEBP_LOSSLESS,
|
self::WEBP_LOSSLESS,
|
||||||
"png",
|
"png",
|
||||||
|
"psd",
|
||||||
|
"bmp",
|
||||||
|
"ico",
|
||||||
|
"cur",
|
||||||
|
"ani",
|
||||||
|
"gif"
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const ALPHA_FORMATS = [
|
const ALPHA_FORMATS = [
|
||||||
self::WEBP_LOSSLESS,
|
self::WEBP_LOSSLESS,
|
||||||
self::WEBP_LOSSY,
|
self::WEBP_LOSSY,
|
||||||
|
"webp",
|
||||||
"png",
|
"png",
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -191,7 +211,7 @@ class Media extends Extension
|
|||||||
global $config;
|
global $config;
|
||||||
$config->set_default_string(MediaConfig::FFPROBE_PATH, 'ffprobe');
|
$config->set_default_string(MediaConfig::FFPROBE_PATH, 'ffprobe');
|
||||||
$config->set_default_int(MediaConfig::MEM_LIMIT, parse_shorthand_int('8MB'));
|
$config->set_default_int(MediaConfig::MEM_LIMIT, parse_shorthand_int('8MB'));
|
||||||
$config->set_default_string(MediaConfig::FFMPEG_PATH, '');
|
$config->set_default_string(MediaConfig::FFMPEG_PATH, 'ffmpeg');
|
||||||
$config->set_default_string(MediaConfig::CONVERT_PATH, 'convert');
|
$config->set_default_string(MediaConfig::CONVERT_PATH, 'convert');
|
||||||
|
|
||||||
|
|
||||||
@ -206,6 +226,13 @@ class Media extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($ffprobe = shell_exec((PHP_OS == 'WINNT' ? 'where' : 'which') . ' ffprobe')) {
|
||||||
|
//ffprobe exists in PATH, check if it's executable, and if so, default to it instead of static
|
||||||
|
if (is_executable(strtok($ffprobe, PHP_EOL))) {
|
||||||
|
$config->set_default_string(MediaConfig::FFPROBE_PATH, 'ffprobe');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$current_value = $config->get_string("thumb_convert_path");
|
$current_value = $config->get_string("thumb_convert_path");
|
||||||
if (!empty($current_value)) {
|
if (!empty($current_value)) {
|
||||||
$config->set_string(MediaConfig::CONVERT_PATH, $current_value);
|
$config->set_string(MediaConfig::CONVERT_PATH, $current_value);
|
||||||
@ -226,6 +253,20 @@ class Media extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onPageRequest(PageRequestEvent $event)
|
||||||
|
{
|
||||||
|
global $database, $page, $user;
|
||||||
|
|
||||||
|
if ($event->page_matches("media_rescan/") && $user->is_admin() && isset($_POST['image_id'])) {
|
||||||
|
$image = Image::by_id(int_escape($_POST['image_id']));
|
||||||
|
|
||||||
|
$this->update_image_media_properties($image->hash, $image->ext);
|
||||||
|
|
||||||
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
$page->set_redirect(make_link("post/view/$image->id"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||||
{
|
{
|
||||||
$sb = new SetupBlock("Media Engines");
|
$sb = new SetupBlock("Media Engines");
|
||||||
@ -243,6 +284,7 @@ class Media extends Extension
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
$sb->add_text_option(MediaConfig::FFMPEG_PATH, "<br/>ffmpeg command: ");
|
$sb->add_text_option(MediaConfig::FFMPEG_PATH, "<br/>ffmpeg command: ");
|
||||||
|
$sb->add_text_option(MediaConfig::FFPROBE_PATH, "<br/>ffprobe command: ");
|
||||||
|
|
||||||
$sb->add_shorthand_int_option(MediaConfig::MEM_LIMIT, "<br />Max memory use: ");
|
$sb->add_shorthand_int_option(MediaConfig::MEM_LIMIT, "<br />Max memory use: ");
|
||||||
|
|
||||||
@ -250,6 +292,66 @@ class Media extends Extension
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $database;
|
||||||
|
$types = $database->get_all("SELECT ext, count(*) count FROM images group by ext");
|
||||||
|
|
||||||
|
$this->theme->display_form($types);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onAdminAction(AdminActionEvent $event)
|
||||||
|
{
|
||||||
|
$action = $event->action;
|
||||||
|
if (method_exists($this, $action)) {
|
||||||
|
$event->redirect = $this->$action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
if ($user->can("delete_image")) {
|
||||||
|
$event->add_part($this->theme->get_buttons_html($event->image->id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
|
||||||
|
if ($user->is_admin()) {
|
||||||
|
$event->add_action("bulk_media_rescan", "Scan Media Properties");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onBulkAction(BulkActionEvent $event)
|
||||||
|
{
|
||||||
|
global $user;
|
||||||
|
|
||||||
|
switch ($event->action) {
|
||||||
|
case "bulk_media_rescan":
|
||||||
|
if ($user->is_admin()) {
|
||||||
|
$total = 0;
|
||||||
|
foreach ($event->items as $id) {
|
||||||
|
$image = Image::by_id($id);
|
||||||
|
if ($image == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$this->update_image_media_properties($image->hash, $image->ext);
|
||||||
|
$total++;
|
||||||
|
} catch (MediaException $e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flash_message("Scanned media properties for $total items");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param MediaResizeEvent $event
|
* @param MediaResizeEvent $event
|
||||||
* @throws MediaException
|
* @throws MediaException
|
||||||
@ -302,22 +404,88 @@ class Media extends Extension
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onMediaCheckLossless(MediaCheckLosslessEvent $event)
|
|
||||||
|
const CONTENT_SEARCH_TERM_REGEX = "/^(-)?content[=|:]((video)|(audio))$/i";
|
||||||
|
|
||||||
|
|
||||||
|
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||||
{
|
{
|
||||||
switch ($event->ext) {
|
global $database;
|
||||||
case "png":
|
|
||||||
case "psd":
|
$matches = [];
|
||||||
case "bmp":
|
if (preg_match(self::CONTENT_SEARCH_TERM_REGEX, $event->term, $matches)) {
|
||||||
case "gif":
|
$positive = $matches[1];
|
||||||
case "ico":
|
$field = $matches[2];
|
||||||
$event->result = true;
|
$event->add_querylet(new Querylet("$field = " . $database->scoreql_to_sql($positive != "-" ? "SCORE_BOOL_Y" : "SCORE_BOOL_N")));
|
||||||
break;
|
|
||||||
case "webp":
|
|
||||||
$event->result = Media::is_lossless_webp($event->file_name);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onTagTermParse(TagTermParseEvent $event)
|
||||||
|
{
|
||||||
|
$matches = [];
|
||||||
|
|
||||||
|
if (preg_match(self::SEARCH_TERM_REGEX, strtolower($event->term), $matches) && $event->parse) {
|
||||||
|
// Nothing to save, just helping filter out reserved tags
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($matches)) {
|
||||||
|
$event->metatag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function media_rescan(): bool
|
||||||
|
{
|
||||||
|
$ext = "";
|
||||||
|
if (array_key_exists("media_rescan_type", $_POST)) {
|
||||||
|
$ext = $_POST["media_rescan_type"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $this->get_images($ext);
|
||||||
|
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$this->update_image_media_properties($result["hash"], $result["ext"]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function update_image_media_properties(string $hash, string $ext)
|
||||||
|
{
|
||||||
|
global $database;
|
||||||
|
|
||||||
|
$path = warehouse_path(Image::IMAGE_DIR, $hash);
|
||||||
|
$mcpe = new MediaCheckPropertiesEvent($path, $ext);
|
||||||
|
send_event($mcpe);
|
||||||
|
|
||||||
|
|
||||||
|
$database->execute(
|
||||||
|
"UPDATE images SET
|
||||||
|
lossless = :lossless, video = :video, audio = :audio,
|
||||||
|
height = :height, width = :width,
|
||||||
|
length = :length WHERE hash = :hash",
|
||||||
|
[
|
||||||
|
"hash" => $hash,
|
||||||
|
"width" => $mcpe->width ?? 0,
|
||||||
|
"height" => $mcpe->height ?? 0,
|
||||||
|
"lossless" => $database->scoresql_value_prepare($mcpe->lossless),
|
||||||
|
"video" => $database->scoresql_value_prepare($mcpe->video),
|
||||||
|
"audio" => $database->scoresql_value_prepare($mcpe->audio),
|
||||||
|
"length" => $mcpe->length
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_images(String $ext = null)
|
||||||
|
{
|
||||||
|
global $database;
|
||||||
|
|
||||||
|
$query = "SELECT id, hash, ext FROM images ";
|
||||||
|
$args = [];
|
||||||
|
if (!empty($ext)) {
|
||||||
|
$query .= " WHERE ext = :ext";
|
||||||
|
$args["ext"] = $ext;
|
||||||
|
}
|
||||||
|
return $database->get_all($query, $args);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check Memory usage limits
|
* Check Memory usage limits
|
||||||
*
|
*
|
||||||
@ -404,6 +572,41 @@ class Media extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function get_ffprobe_data($filename): array
|
||||||
|
{
|
||||||
|
global $config;
|
||||||
|
|
||||||
|
$ffprobe = $config->get_string(MediaConfig::FFPROBE_PATH);
|
||||||
|
if ($ffprobe == null || $ffprobe == "") {
|
||||||
|
throw new MediaException("ffprobe command configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
$args = [
|
||||||
|
escapeshellarg($ffprobe),
|
||||||
|
"-print_format", "json",
|
||||||
|
"-v", "quiet",
|
||||||
|
"-show_format",
|
||||||
|
"-show_streams",
|
||||||
|
escapeshellarg($filename),
|
||||||
|
];
|
||||||
|
|
||||||
|
$cmd = escapeshellcmd(implode(" ", $args));
|
||||||
|
|
||||||
|
exec($cmd, $output, $ret);
|
||||||
|
|
||||||
|
if ((int)$ret == (int)0) {
|
||||||
|
log_debug('Media', "Getting media data `$cmd`, returns $ret");
|
||||||
|
$output = implode($output);
|
||||||
|
$data = json_decode($output, true);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} else {
|
||||||
|
log_error('Media', "Getting media data `$cmd`, returns $ret");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function determine_ext(String $format): String
|
public static function determine_ext(String $format): String
|
||||||
{
|
{
|
||||||
$format = self::normalize_format($format);
|
$format = self::normalize_format($format);
|
||||||
@ -773,8 +976,6 @@ class Media extends Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static function compare_file_bytes(String $file_name, array $comparison): bool
|
private static function compare_file_bytes(String $file_name, array $comparison): bool
|
||||||
{
|
{
|
||||||
$size = filesize($file_name);
|
$size = filesize($file_name);
|
||||||
@ -823,9 +1024,9 @@ class Media extends Extension
|
|||||||
return in_array(self::normalize_format($format), self::ALPHA_FORMATS);
|
return in_array(self::normalize_format($format), self::ALPHA_FORMATS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function is_input_supported($engine, $format): bool
|
public static function is_input_supported($engine, $format, ?bool $lossless = null): bool
|
||||||
{
|
{
|
||||||
$format = self::normalize_format($format);
|
$format = self::normalize_format($format, $lossless);
|
||||||
if (!in_array($format, MediaEngine::INPUT_SUPPORT[$engine])) {
|
if (!in_array($format, MediaEngine::INPUT_SUPPORT[$engine])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -849,8 +1050,16 @@ class Media extends Extension
|
|||||||
* @param $format
|
* @param $format
|
||||||
* @return string|null The format name that the media extension will recognize.
|
* @return string|null The format name that the media extension will recognize.
|
||||||
*/
|
*/
|
||||||
static public function normalize_format($format): ?string
|
static public function normalize_format(string $format, ?bool $lossless = null): ?string
|
||||||
{
|
{
|
||||||
|
if ($format == "webp") {
|
||||||
|
if ($lossless === true) {
|
||||||
|
$format = Media::WEBP_LOSSLESS;
|
||||||
|
} else {
|
||||||
|
$format = Media::WEBP_LOSSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists($format, Media::FORMAT_ALIASES)) {
|
if (array_key_exists($format, Media::FORMAT_ALIASES)) {
|
||||||
return self::FORMAT_ALIASES[$format];
|
return self::FORMAT_ALIASES[$format];
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,29 @@
|
|||||||
|
|
||||||
class MediaTheme extends Themelet
|
class MediaTheme extends Themelet
|
||||||
{
|
{
|
||||||
|
public function display_form(array $types)
|
||||||
|
{
|
||||||
|
global $page, $database;
|
||||||
|
|
||||||
|
$html = "Use this to force scanning for media properties.";
|
||||||
|
$html .= make_form(make_link("admin/media_rescan"));
|
||||||
|
$html .= "<select name='media_rescan_type'><option value=''>All</option>";
|
||||||
|
foreach ($types as $type) {
|
||||||
|
$html .= "<option value='".$type["ext"]."'>".$type["ext"]." (".$type["count"].")</option>";
|
||||||
|
}
|
||||||
|
$html .= "</select><br/>";
|
||||||
|
$html .= "<input type='submit' value='Scan Media Information'>";
|
||||||
|
$html .= "</form>\n";
|
||||||
|
$page->add_block(new Block("Media Tools", $html));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_buttons_html(int $image_id): string
|
||||||
|
{
|
||||||
|
return "
|
||||||
|
".make_form(make_link("media_rescan/"))."
|
||||||
|
<input type='hidden' name='image_id' value='$image_id'>
|
||||||
|
<input type='submit' value='Scan Media Properties'>
|
||||||
|
</form>
|
||||||
|
";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ class ResizeImage extends Extension
|
|||||||
{
|
{
|
||||||
global $user, $config;
|
global $user, $config;
|
||||||
if ($user->is_admin() && $config->get_bool(ResizeConfig::ENABLED)
|
if ($user->is_admin() && $config->get_bool(ResizeConfig::ENABLED)
|
||||||
&& $this->can_resize_format($event->image->ext)) {
|
&& $this->can_resize_format($event->image->ext, $event->image->lossless)) {
|
||||||
/* Add a link to resize the image */
|
/* Add a link to resize the image */
|
||||||
$event->add_part($this->theme->get_resize_html($event->image));
|
$event->add_part($this->theme->get_resize_html($event->image));
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ class ResizeImage extends Extension
|
|||||||
$image_obj = Image::by_id($event->image_id);
|
$image_obj = Image::by_id($event->image_id);
|
||||||
|
|
||||||
if ($config->get_bool(ResizeConfig::UPLOAD) == true
|
if ($config->get_bool(ResizeConfig::UPLOAD) == true
|
||||||
&& $this->can_resize_format($event->type)) {
|
&& $this->can_resize_format($event->type, $image_obj->lossless)) {
|
||||||
$width = $height = 0;
|
$width = $height = 0;
|
||||||
|
|
||||||
if ($config->get_int(ResizeConfig::DEFAULT_WIDTH) !== 0) {
|
if ($config->get_int(ResizeConfig::DEFAULT_WIDTH) !== 0) {
|
||||||
@ -170,7 +170,7 @@ class ResizeImage extends Extension
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function can_resize_format($format): bool
|
private function can_resize_format($format, ?bool $lossless): bool
|
||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
$engine = $config->get_string(ResizeConfig::ENGINE);
|
$engine = $config->get_string(ResizeConfig::ENGINE);
|
||||||
|
@ -80,8 +80,8 @@ class TranscodeImage extends Extension
|
|||||||
|
|
||||||
if ($user->is_admin()) {
|
if ($user->is_admin()) {
|
||||||
$engine = $config->get_string(TranscodeConfig::ENGINE);
|
$engine = $config->get_string(TranscodeConfig::ENGINE);
|
||||||
if ($this->can_convert_format($engine, $event->image->ext)) {
|
if ($this->can_convert_format($engine, $event->image->ext, $event->image->lossless)) {
|
||||||
$options = $this->get_supported_output_formats($engine, $event->image->ext);
|
$options = $this->get_supported_output_formats($engine, $event->image->ext, $event->image->lossless??false);
|
||||||
$event->add_part($this->theme->get_transcode_html($event->image, $options));
|
$event->add_part($this->theme->get_transcode_html($event->image, $options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,23 +222,27 @@ class TranscodeImage extends Extension
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function can_convert_format($engine, $format): bool
|
private function can_convert_format($engine, $format, ?bool $lossless = null): bool
|
||||||
{
|
{
|
||||||
return Media::is_input_supported($engine, $format);
|
return Media::is_input_supported($engine, $format, $lossless);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function get_supported_output_formats($engine, ?String $omit_format = null): array
|
private function get_supported_output_formats($engine, ?String $omit_format = null, ?bool $lossless = null): array
|
||||||
{
|
{
|
||||||
$omit_format = Media::normalize_format($omit_format);
|
if($omit_format!=null) {
|
||||||
|
$omit_format = Media::normalize_format($omit_format, $lossless);
|
||||||
|
}
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
|
|
||||||
foreach (self::OUTPUT_FORMATS as $key=>$value) {
|
foreach (self::OUTPUT_FORMATS as $key=>$value) {
|
||||||
if ($value=="") {
|
if ($value=="") {
|
||||||
$output[$key] = $value;
|
$output[$key] = $value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(Media::is_output_supported($engine, $value)
|
if(Media::is_output_supported($engine, $value)
|
||||||
&&(empty($omit_format)||$omit_format!=Media::determine_ext($value))) {
|
&&(empty($omit_format)||$omit_format!=$value)) {
|
||||||
$output[$key] = $value;
|
$output[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,7 +282,7 @@ class TranscodeImage extends Extension
|
|||||||
{
|
{
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
if ($source_format==Media::determine_ext($target_format)) {
|
if ($source_format==$target_format) {
|
||||||
throw new ImageTranscodeException("Source and target formats are the same: ".$source_format);
|
throw new ImageTranscodeException("Source and target formats are the same: ".$source_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +317,7 @@ class TranscodeImage extends Extension
|
|||||||
try {
|
try {
|
||||||
$result = false;
|
$result = false;
|
||||||
switch ($target_format) {
|
switch ($target_format) {
|
||||||
|
case "webp":
|
||||||
case Media::WEBP_LOSSY:
|
case Media::WEBP_LOSSY:
|
||||||
$result = imagewebp($image, $tmp_name, $q);
|
$result = imagewebp($image, $tmp_name, $q);
|
||||||
break;
|
break;
|
||||||
|
11
ext/transcode/script.js
Normal file
11
ext/transcode/script.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function transcodeSubmit(e) {
|
||||||
|
var format = document.getElementById('transcode_format').value;
|
||||||
|
if(format!="webp-lossless" && format != "png") {
|
||||||
|
var lossless = document.getElementById('image_lossless');
|
||||||
|
if(lossless!=null && lossless.value=='1') {
|
||||||
|
return confirm('You are about to transcode from a lossless format to a lossy format. Lossless formats compress with no quality loss, but converting to a lossy format always results in quality loss, and it will lose more quality every time it is done again on the same image. Are you sure you want to perform this transcode?');
|
||||||
|
} else {
|
||||||
|
return confirm('Converting to a lossy format always results in quality loss, and it will lose more quality every time it is done again on the same image. Are you sure you want to perform this transcode?');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,8 +10,10 @@ class TranscodeImageTheme extends Themelet
|
|||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$html = "
|
$html = "
|
||||||
".make_form(make_link("transcode/{$image->id}"), 'POST')."
|
".make_form(make_link("transcode/{$image->id}"), 'POST', false, "",
|
||||||
|
"return transcodeSubmit()")."
|
||||||
<input type='hidden' name='image_id' value='{$image->id}'>
|
<input type='hidden' name='image_id' value='{$image->id}'>
|
||||||
|
<input type='hidden' id='image_lossless' name='image_lossless' value='{$image->lossless}'>
|
||||||
".$this->get_transcode_picker_html($options)."
|
".$this->get_transcode_picker_html($options)."
|
||||||
<br><input id='transcodebutton' type='submit' value='Transcode'>
|
<br><input id='transcodebutton' type='submit' value='Transcode'>
|
||||||
</form>
|
</form>
|
||||||
|
@ -166,6 +166,63 @@ class Upgrade extends Extension
|
|||||||
log_info("upgrade", "Database at version 16");
|
log_info("upgrade", "Database at version 16");
|
||||||
$config->set_bool("in_upgrade", false);
|
$config->set_bool("in_upgrade", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($config->get_int("db_version") < 17) {
|
||||||
|
$config->set_bool("in_upgrade", true);
|
||||||
|
$config->set_int("db_version", 17);
|
||||||
|
|
||||||
|
log_info("upgrade", "Adding media information columns to images table");
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"ALTER TABLE images ADD COLUMN lossless SCORE_BOOL NULL"
|
||||||
|
));
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"ALTER TABLE images ADD COLUMN video SCORE_BOOL NULL"
|
||||||
|
));
|
||||||
|
$database->execute($database->scoreql_to_sql(
|
||||||
|
"ALTER TABLE images ADD COLUMN audio SCORE_BOOL NULL"
|
||||||
|
));
|
||||||
|
$database->execute("ALTER TABLE images ADD COLUMN length INTEGER NULL ");
|
||||||
|
|
||||||
|
log_info("upgrade", "Setting indexes for media columns");
|
||||||
|
switch($database->get_driver_name()) {
|
||||||
|
case DatabaseDriver::PGSQL:
|
||||||
|
case DatabaseDriver::SQLITE:
|
||||||
|
$database->execute('CREATE INDEX images_video_idx ON images(video) WHERE video IS NOT NULL');
|
||||||
|
$database->execute('CREATE INDEX images_audio_idx ON images(audio) WHERE audio IS NOT NULL');
|
||||||
|
$database->execute('CREATE INDEX images_length_idx ON images(length) WHERE length IS NOT NULL');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$database->execute('CREATE INDEX images_video_idx ON images(video)');
|
||||||
|
$database->execute('CREATE INDEX images_audio_idx ON images(audio)');
|
||||||
|
$database->execute('CREATE INDEX images_length_idx ON images(length)');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($database->get_driver_name()==DatabaseDriver::PGSQL) { // These updates can take a little bit
|
||||||
|
$database->execute("SET statement_timeout TO 300000;");
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("upgrade", "Setting index for ext column");
|
||||||
|
$database->execute('CREATE INDEX images_ext_idx ON images(ext)');
|
||||||
|
|
||||||
|
|
||||||
|
$database->commit(); // Each of these commands could hit a lot of data, combining them into one big transaction would not be a good idea.
|
||||||
|
log_info("upgrade", "Setting predictable media values for known file types");
|
||||||
|
$database->execute("UPDATE images SET lossless = true, video = true WHERE ext IN ('swf')");
|
||||||
|
$database->execute("UPDATE images SET lossless = false, video = false, audio = true WHERE ext IN ('mp3')");
|
||||||
|
$database->execute("UPDATE images SET lossless = false, video = false, audio = false WHERE ext IN ('jpg','jpeg')");
|
||||||
|
$database->execute("UPDATE images SET lossless = true, video = false, audio = false WHERE ext IN ('ico','ani','cur','png','svg')");
|
||||||
|
$database->execute("UPDATE images SET lossless = true, audio = false WHERE ext IN ('gif')");
|
||||||
|
$database->execute("UPDATE images SET audio = false WHERE ext IN ('webp')");
|
||||||
|
$database->execute("UPDATE images SET lossless = false, video = true WHERE ext IN ('flv','mp4','m4v','ogv','webm')");
|
||||||
|
|
||||||
|
|
||||||
|
log_info("upgrade", "Database at version 17");
|
||||||
|
$config->set_bool("in_upgrade", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_priority(): int
|
public function get_priority(): int
|
||||||
|
@ -18,6 +18,7 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
$h_owner = html_escape($image->get_owner()->name);
|
$h_owner = html_escape($image->get_owner()->name);
|
||||||
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
||||||
$h_ip = html_escape($image->owner_ip);
|
$h_ip = html_escape($image->owner_ip);
|
||||||
|
$h_type = html_escape($image->get_mime_type());
|
||||||
$h_date = autodate($image->posted);
|
$h_date = autodate($image->posted);
|
||||||
$h_filesize = to_shorthand_int($image->filesize);
|
$h_filesize = to_shorthand_int($image->filesize);
|
||||||
|
|
||||||
@ -31,7 +32,12 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
<br>Posted: $h_date by $h_ownerlink
|
<br>Posted: $h_date by $h_ownerlink
|
||||||
<br>Size: {$image->width}x{$image->height}
|
<br>Size: {$image->width}x{$image->height}
|
||||||
<br>Filesize: $h_filesize
|
<br>Filesize: $h_filesize
|
||||||
";
|
<br>Type: $h_type";
|
||||||
|
|
||||||
|
if($image->length!=null) {
|
||||||
|
$h_length = format_milliseconds($image->length);
|
||||||
|
$html .= "<br/>Length: $h_length";
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_null($image->source)) {
|
if (!is_null($image->source)) {
|
||||||
$h_source = html_escape($image->source);
|
$h_source = html_escape($image->source);
|
||||||
|
@ -17,6 +17,7 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
$h_owner = html_escape($image->get_owner()->name);
|
$h_owner = html_escape($image->get_owner()->name);
|
||||||
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
||||||
$h_ip = html_escape($image->owner_ip);
|
$h_ip = html_escape($image->owner_ip);
|
||||||
|
$h_type = html_escape($image->get_mime_type());
|
||||||
$h_date = autodate($image->posted);
|
$h_date = autodate($image->posted);
|
||||||
$h_filesize = to_shorthand_int($image->filesize);
|
$h_filesize = to_shorthand_int($image->filesize);
|
||||||
|
|
||||||
@ -30,8 +31,15 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
<br>Uploader: $h_ownerlink
|
<br>Uploader: $h_ownerlink
|
||||||
<br>Date: $h_date
|
<br>Date: $h_date
|
||||||
<br>Size: $h_filesize ({$image->width}x{$image->height})
|
<br>Size: $h_filesize ({$image->width}x{$image->height})
|
||||||
|
<br>Type: $h_type
|
||||||
";
|
";
|
||||||
|
|
||||||
|
if($image->length!=null) {
|
||||||
|
$h_length = format_milliseconds($image->length);
|
||||||
|
$html .= "<br/>Length: $h_length";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!is_null($image->source)) {
|
if (!is_null($image->source)) {
|
||||||
$h_source = html_escape($image->source);
|
$h_source = html_escape($image->source);
|
||||||
if (substr($image->source, 0, 7) != "http://" && substr($image->source, 0, 8) != "https://") {
|
if (substr($image->source, 0, 7) != "http://" && substr($image->source, 0, 8) != "https://") {
|
||||||
|
@ -34,6 +34,11 @@ class CustomViewImageTheme extends ViewImageTheme
|
|||||||
<br>Filesize: $h_filesize
|
<br>Filesize: $h_filesize
|
||||||
<br>Type: ".$h_type."
|
<br>Type: ".$h_type."
|
||||||
";
|
";
|
||||||
|
if($image->length!=null) {
|
||||||
|
$h_length = format_milliseconds($image->length);
|
||||||
|
$html .= "<br/>Length: $h_length";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!is_null($image->source)) {
|
if (!is_null($image->source)) {
|
||||||
$h_source = html_escape($image->source);
|
$h_source = html_escape($image->source);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user