From 6c5d21ec44c4e6f9207fb9f9518589b47234d76b Mon Sep 17 00:00:00 2001 From: Werbeagentur AWEOS Date: Tue, 17 Sep 2019 23:14:29 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 1 + Plugin.php | 212 +++++++++++++++++++++ composer.json | 13 ++ composer.lock | 295 ++++++++++++++++++++++++++++++ console/ClearOld.php | 63 +++++++ console/ResizeMake.php | 177 ++++++++++++++++++ console/ResizePurge.php | 67 +++++++ models/Setting.php | 41 +++++ models/setting/columns.yaml | 8 + models/setting/fields.yaml | 31 ++++ updates/create_settings_table.php | 22 +++ updates/version.yaml | 1 + 12 files changed, 931 insertions(+) create mode 100644 .gitignore create mode 100644 Plugin.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 console/ClearOld.php create mode 100644 console/ResizeMake.php create mode 100644 console/ResizePurge.php create mode 100644 models/Setting.php create mode 100644 models/setting/columns.yaml create mode 100644 models/setting/fields.yaml create mode 100644 updates/create_settings_table.php create mode 100644 updates/version.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61ead86 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/Plugin.php b/Plugin.php new file mode 100644 index 0000000..104464c --- /dev/null +++ b/Plugin.php @@ -0,0 +1,212 @@ + 'resizer', + 'description' => 'No description provided yet...', + 'author' => 'aweos', + 'icon' => 'icon-leaf' + ]; + } + + /** + * Register method, called when the plugin is first registered. + * + * @return void + */ + public function register() + { + $this->registerConsoleCommand('resizer.resizemake', ResizeMake::class); + $this->registerConsoleCommand('resizer.resizepurge', ResizePurge::class); + $this->registerConsoleCommand('resizer.clearold', ClearOld::class); + } + + /** + * Boot method, called right before the request route. + * + * @return array + */ + public function boot() + { + + } + + /** + * Registers any front-end components implemented in this plugin. + * + * @return array + */ + public function registerComponents() + { + return []; // Remove this line to activate + + return [ + 'Aweos\Resizer\Components\MyComponent' => 'myComponent', + ]; + } + + /** + * Registers any back-end permissions used by this plugin. + * + * @return array + */ + public function registerPermissions() + { + return []; // Remove this line to activate + + return [ + 'aweos.resizer.some_permission' => [ + 'tab' => 'resizer', + 'label' => 'Some permission' + ], + ]; + } + + /** + * Registers back-end navigation items for this plugin. + * + * @return array + */ + public function registerNavigation() + { + return []; // Remove this line to activate + + return [ + 'resizer' => [ + 'label' => 'resizer', + 'url' => Backend::url('aweos/resizer/mycontroller'), + 'icon' => 'icon-leaf', + 'permissions' => ['aweos.resizer.*'], + 'order' => 500, + ], + ]; + } + + public function registerSettings() { + return [ + 'resizer' => [ + 'label' => 'Resizer Settings', + 'description' => 'Change how images are resized and compressed', + 'category' => 'Base', + 'icon' => 'icon-cog', + 'class' => '\Aweos\Resizer\Models\Setting', + 'order' => 500, + 'keywords' => 'setting', + 'permissions' => ['aweos.resizer.*'] + ] + ]; + } + + public function registerMarkupTags() { + return [ + 'filters' => [ + 'resize' => function($media, $breakpoints = [], $name = '') { + return Cache::remember('resized_image.'.$name.$media, 3600, function() use ($media, $breakpoints) { + ksort($breakpoints); + $l = MediaLibrary::instance(); + $folders = Setting::get('folders'); + $sizes = Setting::get('srcx'); + + $media = '/'.ltrim($media, '/'); + $filename = basename($media); + $dirname = dirname($media); + $extension = pathinfo($media, PATHINFO_EXTENSION); + + if (! $l->folderExists($dirname.'/c')) { + return 'src="'.$l->getPathUrl($media).'"'; + } + + $sizes = collect($l->listFolderContents($dirname.'/c')) + ->filter(function($f) use ($sizes, $filename) { + foreach ($sizes as $size) { + if (pathinfo($f->path, PATHINFO_FILENAME).'.'.pathinfo($filename, PATHINFO_EXTENSION) + == pathinfo($filename, PATHINFO_FILENAME).'-'.$size.'t.'.pathinfo($filename, PATHINFO_EXTENSION)) { + return true; + } + + if (pathinfo($f->path, PATHINFO_FILENAME).'.'.pathinfo($filename, PATHINFO_EXTENSION) + == pathinfo($filename, PATHINFO_FILENAME).'-'.$size.'.'.pathinfo($filename, PATHINFO_EXTENSION)) { + return true; + } + } + + return false; + }) + ->map(function($fileVersion) use ($l) { + $sizes = getimagesize($l->getPathUrl($fileVersion->path)); + + return [$l->getPathUrl($fileVersion->path), $sizes[0], $sizes[1]]; + })->sortBy(function($size) { + return $size[1]; + }) + ; + + if ($sizes->isEmpty()) { + return 'src="'.$l->getPathUrl($media).'"'; + } + + $srcset = 'srcset="'; + $s = ''; + + foreach($sizes as $size) { + $srcset .= $size[0].' '.$size[1].'w, '; + $s .= '(max-width: '.$size[1].'px) '.$size[1].'px, '; + } + + $s = 'sizes="'.substr($s, 0, -2).', 1920px"'; + + if (!empty($breakpoints)) { + $s = $this->breakpointsToSizes($breakpoints); + } + + $srcset = substr($srcset, 0, -2).'"'; + + $normalSize = 'width="'.$sizes->last()[1].'" height="'.$sizes->last()[2].'"'; + + return 'src="'.$l->getPathUrl($media).'" '.$srcset.' '.$s.' '.$normalSize; + }); + } + ] + ]; + } + + public function breakpointsToSizes($breakpoints) { + $s = []; + + foreach ($breakpoints as $size => $bp) { + if ($size === 'max') { continue; } + + $s[] = '(max-width: '.$size.'px) '.$bp; + } + + if (array_key_exists('max', $breakpoints)) { + $s[] = $breakpoints['max']; + } + + return 'sizes="'.implode(', ', $s).'"'; + } + + public function registerSchedule($schedule) { + $schedule->command('resize:make')->dailyAt('01:00'); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7d0e834 --- /dev/null +++ b/composer.json @@ -0,0 +1,13 @@ +{ + "name": "aweos/oc-resizer-plugin", + "type": "october-plugin", + "require": { + "guzzlehttp/guzzle": "^6.3" + }, + "authors": [ + { + "name": "Werbeagentur AWEOS", + "email": "philipp@aweos.de" + } + ] +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..bf6fd2d --- /dev/null +++ b/composer.lock @@ -0,0 +1,295 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "82331c61df9e7f95117f9b82b35b6ce2", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a", + "reference": "239400de7a173fe9901b9ac7c06497751f00727a", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "suggest": { + "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2019-07-01T23:21:34+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2019-03-08T08:55:37+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/console/ClearOld.php b/console/ClearOld.php new file mode 100644 index 0000000..ce913b9 --- /dev/null +++ b/console/ClearOld.php @@ -0,0 +1,63 @@ +images)->map(function($image) { + if (!strpos($image['image'], 'cropped-images')) { + return $image; + } + + $n = preg_replace('/-(\d+-){4}\d+/', '', $image['image']); + $n = str_replace('cropped-images/', '', $n); + + if (!\Storage::has('media'.$n)) { + return $image; + } + + $image['image'] = $n; + return $image; + }); + + $k->update(['images' => $newImages]); + } + } + + /** + * Get the console command arguments. + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/console/ResizeMake.php b/console/ResizeMake.php new file mode 100644 index 0000000..bad1b1e --- /dev/null +++ b/console/ResizeMake.php @@ -0,0 +1,177 @@ +start($folder['folder'], $sizes, $callback); + } + } + + /** + * Execute the console command. + * @return void + */ + public function handle() + { + $this->http = new Client(['base_uri' => 'https://api.tinify.com']); + $this->media = MediaLibrary::instance(); + ProgressBar::setFormatDefinition('custom', '%current%/%max% %bar% -- %message% (%size%)'); + $tinifyKey = Setting::get('tinify') ? Setting::get('tinypngkey') : null; + + $i = 0; + $this->forAllResizables(function($file, $w) use (&$i) { + $i++; + }); + + $bar = $this->output->createProgressBar($i); + $bar->setFormat('custom'); + + /** + * @param File $file The current filename + * @param int $w Current width + * @param string $compressed compressed file + * @param string $uncompressed uncompressed file + */ + $this->forAllResizables(function($file, $w, $compressed, $uncompressed) use ($bar, $tinifyKey) { + $bar->setMessage($file->path); + $bar->setMessage($w, 'size'); + $bar->advance(); + + if (Storage::exists($compressed)) { + return; + } + + if (!Storage::exists($uncompressed)) { + $r = Resizer::open(Storage::disk('local')->path('media'.$file->path)); + $r->resize($w, 0); + $r->save(Storage::disk('local')->path($uncompressed)); + $this->info(Storage::url($uncompressed)); + } + + if (!is_null($tinifyKey)) { + $newUrl = url($this->media->getPathUrl(preg_replace('/^media/', '', $uncompressed))); + + try { + $response = $this->http->post('/shrink', [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => 'Basic '.base64_encode('api:'.$tinifyKey) + ], + 'json' => [ + 'source' => ['url' => $newUrl] + ] + ]); + + $output = json_decode((string) $response->getBody()); + $url = $output->output->url; + + $response = $this->http->get($output->output->url, [ + 'headers' => [ + 'Authorization' => 'Basic '.base64_encode('api:'.$tinifyKey) + ] + ]); + $image = (string) $response->getBody(); + + Storage::put($compressed, $image); + Storage::delete($uncompressed); + } catch(ClientException $e) { + return; + } + } + + $bar->advance(); + }); + + $bar->finish(); + } + + public function getMediaOfType($f, $type) { + return array_filter($this->media->listFolderContents($f, 'title', 'image'), function($item) use ($f, $type) { + return $item->type == $type && $item->path != $f.'/c'; + }); + } + + public function start($f, $sizes, $callback) { + $f = '/'.ltrim(rtrim($f, '/'), '/'); + + $folders = $this->getMediaOfType($f, 'folder'); + + foreach ($folders as $folder) { + $this->start($folder->path, $sizes, $callback); + } + + $files = $this->getMediaOfType($f, 'file'); + + // Create C-Folder as current subfolder if it doesnt exist yet + if(count($files) && !$this->media->folderExists($f.'/c')) { + $this->media->makeFolder($f.'/c'); + } + + foreach ($files as $file) { + foreach ($sizes as $w) { + $imagesize = getimagesize(Storage::path('media'.$file->path)); + + $uncompressedFilename = pathinfo($file->path, PATHINFO_FILENAME).'-'.$w.'.'.pathinfo($file->path, PATHINFO_EXTENSION); + $compressedFilename = pathinfo($file->path, PATHINFO_FILENAME).'-'.$w.'t.'.pathinfo($file->path, PATHINFO_EXTENSION); + + $compressed = 'media'.dirname($file->path).'/c/'.$compressedFilename; + $uncompressed = 'media'.dirname($file->path).'/c/'.$uncompressedFilename; + + if ($imagesize[0] < $w) { + continue; + } + + call_user_func($callback, $file, $w, $compressed, $uncompressed); + } + } + } + + /** + * Get the console command arguments. + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/console/ResizePurge.php b/console/ResizePurge.php new file mode 100644 index 0000000..c0f9e8d --- /dev/null +++ b/console/ResizePurge.php @@ -0,0 +1,67 @@ +start($f, $sizes); + } + } + + public function start($f, $sizes) { + $l = MediaLibrary::instance(); + + $folders = array_filter(\Storage::allDirectories('media/'.$f), function($item) use ($f) { + return pathinfo($item, PATHINFO_FILENAME) == 'c'; + }); + + foreach ($folders as $folder) { + \Storage::deleteDirectory($folder); + } + } + + /** + * Get the console command arguments. + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * Get the console command options. + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/models/Setting.php b/models/Setting.php new file mode 100644 index 0000000..ff23434 --- /dev/null +++ b/models/Setting.php @@ -0,0 +1,41 @@ +engine = 'InnoDB'; + $table->increments('id'); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('aweos_resizer_settings'); + } +} diff --git a/updates/version.yaml b/updates/version.yaml new file mode 100644 index 0000000..0deacc4 --- /dev/null +++ b/updates/version.yaml @@ -0,0 +1 @@ +1.0.1: First version of resizer