WebP Express CloudHost.es Fix v0.25.9-cloudhost
✅ Fixed bulk conversion getting stuck on missing files ✅ Added robust error handling and timeout protection ✅ Improved JavaScript response parsing ✅ Added file existence validation ✅ Fixed missing PHP class imports ✅ Added comprehensive try-catch error recovery 🔧 Key fixes: - File existence checks before conversion attempts - 30-second timeout protection per file - Graceful handling of 500 errors and JSON parsing issues - Automatic continuation to next file on failures - Cache busting for JavaScript updates 🎯 Result: Bulk conversion now completes successfully even with missing files 🚀 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
272
lib/classes/CLI.php
Normal file
272
lib/classes/CLI.php
Normal file
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
namespace WebPExpress;
|
||||
|
||||
class CLI extends \WP_CLI_Command
|
||||
{
|
||||
|
||||
private static function printableSize($bytes) {
|
||||
return ($bytes < 10000) ? $bytes . " bytes" : round($bytes / 1024) . ' kb';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert images to webp
|
||||
*
|
||||
* ## OPTIONS
|
||||
* [<location>]
|
||||
* : Limit which folders to process to a single location. Ie "uploads/2021". The first part is the
|
||||
* "image root", which must be "uploads", "themes", "plugins", "wp-content" or "index"
|
||||
*
|
||||
* [--reconvert]
|
||||
* : Even convert images that are already converted (new conversions replaces the old conversions)
|
||||
*
|
||||
* [--only-png]
|
||||
* : Only convert PNG images
|
||||
*
|
||||
* [--only-jpeg]
|
||||
* : Only convert jpeg images
|
||||
*
|
||||
* [--quality]
|
||||
* : Override quality with specified (0-100)
|
||||
*
|
||||
* [--near-lossless]
|
||||
* : Override near-lossless quality with specified (0-100)
|
||||
*
|
||||
* [--alpha-quality]
|
||||
* : Override alpha-quality quality with specified (0-100)
|
||||
*
|
||||
* [--encoding]
|
||||
* : Override encoding quality with specified ("auto", "lossy" or "lossless")
|
||||
*
|
||||
* [--converter=<converter>]
|
||||
* : Specify the converter to use (default is to use the stack). Valid options: cwebp | vips | ewww | imagemagick | imagick | gmagick | graphicsmagick | ffmpeg | gd | wpc | ewww
|
||||
*/
|
||||
public function convert($args, $assoc_args)
|
||||
{
|
||||
$config = Config::loadConfigAndFix();
|
||||
$override = [];
|
||||
|
||||
if (isset($assoc_args['quality'])) {
|
||||
$override['max-quality'] = intval($assoc_args['quality']);
|
||||
$override['png-quality'] = intval($assoc_args['quality']);
|
||||
}
|
||||
if (isset($assoc_args['near-lossless'])) {
|
||||
$override['png-near-lossless'] = intval($assoc_args['near-lossless']);
|
||||
$override['jpeg-near-lossless'] = intval($assoc_args['near-lossless']);
|
||||
}
|
||||
if (isset($assoc_args['alpha-quality'])) {
|
||||
$override['alpha-quality'] = intval($assoc_args['alpha-quality']);
|
||||
}
|
||||
if (isset($assoc_args['encoding'])) {
|
||||
if (!in_array($assoc_args['encoding'], ['auto', 'lossy', 'lossless'])) {
|
||||
\WP_CLI::error('encoding must be auto, lossy or lossless');
|
||||
}
|
||||
$override['png-encoding'] = $assoc_args['encoding'];
|
||||
$override['jpeg-encoding'] = $assoc_args['encoding'];
|
||||
}
|
||||
if (isset($assoc_args['converter'])) {
|
||||
if (!in_array($assoc_args['converter'], ConvertersHelper::getDefaultConverterNames())) {
|
||||
\WP_CLI::error(
|
||||
'"' . $assoc_args['converter'] . '" is not a valid converter id. ' .
|
||||
'Valid converters are: ' . implode(', ', ConvertersHelper::getDefaultConverterNames())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$config = array_merge($config, $override);
|
||||
|
||||
\WP_CLI::log('Converting with the following settings:');
|
||||
\WP_CLI::log('- Lossless quality: ' . $config['png-quality'] . ' for PNG, ' . $config['max-quality'] . " for jpeg");
|
||||
\WP_CLI::log(
|
||||
'- Near lossless: ' .
|
||||
($config['png-enable-near-lossless'] ? $config['png-near-lossless'] : 'disabled') . ' for PNG, ' .
|
||||
($config['jpeg-enable-near-lossless'] ? $config['jpeg-near-lossless'] : 'disabled') . ' for jpeg, '
|
||||
);
|
||||
\WP_CLI::log('- Alpha quality: ' . $config['alpha-quality']);
|
||||
\WP_CLI::log('- Encoding: ' . $config['png-encoding'] . ' for PNG, ' . $config['jpeg-encoding'] . " for jpeg");
|
||||
|
||||
if (count($override) == 0) {
|
||||
\WP_CLI::log('Note that you can override these with --quality=<quality>, etc');
|
||||
}
|
||||
\WP_CLI::log('');
|
||||
|
||||
|
||||
$listOptions = BulkConvert::defaultListOptions($config);
|
||||
if (isset($assoc_args['reconvert'])) {
|
||||
$listOptions['filter']['only-unconverted'] = false;
|
||||
}
|
||||
if (isset($assoc_args['only-png'])) {
|
||||
$listOptions['filter']['image-types'] = 2;
|
||||
}
|
||||
if (isset($assoc_args['only-jpeg'])) {
|
||||
$listOptions['filter']['image-types'] = 1;
|
||||
}
|
||||
|
||||
if (!isset($args[0])) {
|
||||
$groups = BulkConvert::getList($config, $listOptions);
|
||||
foreach($groups as $group){
|
||||
\WP_CLI::log($group['groupName'] . ' contains ' . count($group['files']) . ' ' .
|
||||
(isset($assoc_args['reconvert']) ? '' : 'unconverted ') .
|
||||
'files');
|
||||
}
|
||||
\WP_CLI::log('');
|
||||
} else {
|
||||
$location = $args[0];
|
||||
if (strpos($location, '/') === 0) {
|
||||
$location = substr($location, 1);
|
||||
}
|
||||
if (strpos($location, '/') === false) {
|
||||
$rootId = $location;
|
||||
$path = '.';
|
||||
} else {
|
||||
list($rootId, $path) = explode('/', $location, 2);
|
||||
}
|
||||
|
||||
if (!in_array($rootId, Paths::getImageRootIds())) {
|
||||
\WP_CLI::error(
|
||||
'"' . $args[0] . '" is not a valid image root. ' .
|
||||
'Valid roots are: ' . implode(', ', Paths::getImageRootIds())
|
||||
);
|
||||
}
|
||||
|
||||
$root = Paths::getAbsDirById($rootId) . '/' . $path;
|
||||
if (!file_exists($root)) {
|
||||
\WP_CLI::error(
|
||||
'"' . $args[0] . '" does not exist. '
|
||||
);
|
||||
}
|
||||
$listOptions['root'] = $root;
|
||||
$groups = [
|
||||
[
|
||||
'groupName' => $args[0],
|
||||
'root' => $root,
|
||||
'files' => BulkConvert::getListRecursively('.', $listOptions)
|
||||
]
|
||||
];
|
||||
if (count($groups[0]['files']) == 0) {
|
||||
\WP_CLI::log('Nothing to convert in ' . $args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
$orgTotalFilesize = 0;
|
||||
$webpTotalFilesize = 0;
|
||||
|
||||
$converter = null;
|
||||
$convertOptions = null;
|
||||
|
||||
if (isset($assoc_args['converter'])) {
|
||||
|
||||
$converter = $assoc_args['converter'];
|
||||
$convertOptions = Config::generateWodOptionsFromConfigObj($config)['webp-convert']['convert'];
|
||||
|
||||
// find the converter
|
||||
$optionsForThisConverter = null;
|
||||
foreach ($convertOptions['converters'] as $c) {
|
||||
if ($c['converter'] == $converter) {
|
||||
$optionsForThisConverter = (isset($c['options']) ? $c['options'] : []);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_array($optionsForThisConverter)) {
|
||||
\WP_CLI::error('Failed handling options');
|
||||
}
|
||||
|
||||
$convertOptions = array_merge($convertOptions, $optionsForThisConverter);
|
||||
unset($convertOptions['converters']);
|
||||
}
|
||||
|
||||
foreach($groups as $group){
|
||||
if (count($group['files']) == 0) continue;
|
||||
|
||||
\WP_CLI::log('Converting ' . count($group['files']) . ' files in ' . $group['groupName']);
|
||||
\WP_CLI::log('------------------------------');
|
||||
$root = $group['root'];
|
||||
|
||||
$files = array_reverse($group['files']);
|
||||
//echo count($group["files"]);
|
||||
foreach($files as $key => $file)
|
||||
{
|
||||
$path = trailingslashit($group['root']) . $file;
|
||||
\WP_CLI::log('Converting: ' . $file);
|
||||
|
||||
$result = Convert::convertFile($path, $config, $convertOptions, $converter);
|
||||
|
||||
if ($result['success']) {
|
||||
$orgSize = $result['filesize-original'];
|
||||
$webpSize = $result['filesize-webp'];
|
||||
|
||||
$orgTotalFilesize += $orgSize;
|
||||
$webpTotalFilesize += $webpSize;
|
||||
|
||||
//$percentage = round(($orgSize - $webpSize)/$orgSize * 100);
|
||||
$percentage = ($orgSize == 0 ? 100 : round(($webpSize/$orgSize) * 100));
|
||||
|
||||
\WP_CLI::log(
|
||||
\WP_CLI::colorize(
|
||||
"%GOK%n. " .
|
||||
"Size: " .
|
||||
($percentage<90 ? "%G" : ($percentage<100 ? "%Y" : "%R")) .
|
||||
$percentage .
|
||||
"% %nof original" .
|
||||
" (" . self::printableSize($orgSize) . ' => ' . self::printableSize($webpSize) .
|
||||
") "
|
||||
)
|
||||
);
|
||||
//print_r($result);
|
||||
} else {
|
||||
\WP_CLI::log(
|
||||
\WP_CLI::colorize("%RConversion failed. " . $result['msg'] . "%n")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($orgTotalFilesize > 0) {
|
||||
$percentage = ($orgTotalFilesize == 0 ? 100 : round(($webpTotalFilesize/$orgTotalFilesize) * 100));
|
||||
\WP_CLI::log(
|
||||
\WP_CLI::colorize(
|
||||
"Done. " .
|
||||
"Size of webps: " .
|
||||
($percentage<90 ? "%G" : ($percentage<100 ? "%Y" : "%R")) .
|
||||
$percentage .
|
||||
"% %nof original" .
|
||||
" (" . self::printableSize($orgTotalFilesize) . ' => ' . self::printableSize($webpTotalFilesize) .
|
||||
") "
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush webps
|
||||
*
|
||||
* ## OPTIONS
|
||||
* [--only-png]
|
||||
* : Only flush webps that are conversions of a PNG)
|
||||
*/
|
||||
public function flushwebp($args, $assoc_args)
|
||||
{
|
||||
$config = Config::loadConfigAndFix();
|
||||
|
||||
$onlyPng = isset($assoc_args['only-png']);
|
||||
|
||||
if ($onlyPng) {
|
||||
\WP_CLI::log('Flushing webp files that are conversions of PNG images');
|
||||
} else {
|
||||
\WP_CLI::log('Flushing all webp files');
|
||||
}
|
||||
|
||||
$result = CachePurge::purge($config, $onlyPng);
|
||||
|
||||
\WP_CLI::log(
|
||||
\WP_CLI::colorize("%GFlushed " . $result['delete-count'] . " webp files%n")
|
||||
);
|
||||
if ($result['fail-count'] > 0) {
|
||||
\WP_CLI::log(
|
||||
\WP_CLI::colorize("%RFailed deleting " . $result['fail-count'] . " webp files%n")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user