diff --git a/actions/attachment_thumbnail.php b/actions/attachment_thumbnail.php index e1a87faf79..05f4696695 100644 --- a/actions/attachment_thumbnail.php +++ b/actions/attachment_thumbnail.php @@ -74,6 +74,6 @@ class Attachment_thumbnailAction extends Attachment_viewAction // script execution, and we don't want to have any more errors until then, so don't reset it @ini_set('display_errors', 0); - common_send_file($filepath, $this->mimetype, $filename, 'inline'); + common_send_file($filepath, image_type_to_mime_type(IMAGETYPE_WEBP), $filename, 'inline'); } } diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php index 1c31816dc1..1a09826a1b 100644 --- a/classes/File_thumbnail.php +++ b/classes/File_thumbnail.php @@ -100,11 +100,15 @@ class File_thumbnail extends Managed_DataObject case 'image/svg+xml': throw new UseFileAsThumbnailException($file); } - } else { - throw new ServerException("This remote file has no local thumbnail."); } } - $image = ImageFile::fromFileObject($file); + try { + $image = ImageFile::fromFileObject($file); + } catch (InvalidFilenameException $e) { + // Not having an original local file doesn't mean we don't have a thumbnail. + $existing_thumb = File_thumbnail::byFile($file); + $image = new ImageFile($file->getID(), $existing_thumb->getPath(), null, $existing_thumb->url); + } $imgPath = $image->getPath(); $media = common_get_mime_media($file->mimetype); if (Event::handle('CreateFileImageThumbnailSource', [$file, &$imgPath, $media])) { @@ -280,7 +284,7 @@ class File_thumbnail extends Managed_DataObject public function getUrl() { - $url = common_local_url('attachment_thumbnail', ['filehash' => $this->getFile()->filehash]); + $url = common_local_url('attachment_thumbnail', ['attachment' => $this->getFile()->getID()]); if (strpos($url, '?') === false) { $url .= '?'; } diff --git a/lib/util/router.php b/lib/util/router.php index 76387ee625..9426cc308f 100644 --- a/lib/util/router.php +++ b/lib/util/router.php @@ -228,10 +228,14 @@ class Router ['action' => 'attachment'], ['attachment' => '[0-9]+']); + // Retrieve thumbnail + $m->connect("thumbnail/:attachment", + ['action' => 'attachment_thumbnail'], + ['attachment' => '[0-9]+']); + // Retrieve local file foreach (['/view' => 'attachment_view', - '/download' => 'attachment_download', - '/thumbnail' => 'attachment_thumbnail'] as $postfix => $action) { + '/download' => 'attachment_download'] as $postfix => $action) { $m->connect("attachment/:filehash{$postfix}", ['action' => $action], ['filehash' => '[A-Za-z0-9._-]{64}']); diff --git a/plugins/Embed/EmbedPlugin.php b/plugins/Embed/EmbedPlugin.php index 228a1e4912..4aab42c944 100644 --- a/plugins/Embed/EmbedPlugin.php +++ b/plugins/Embed/EmbedPlugin.php @@ -57,7 +57,7 @@ class EmbedPlugin extends Plugin public $thumbnail_width = null; public $thumbnail_height = null; - public $crop = true; + public $crop = null; public $max_size = null; protected $imgData = []; @@ -77,6 +77,7 @@ class EmbedPlugin extends Plugin $this->thumbnail_width = $this->thumbnail_width ?? common_config('thumbnail', 'width'); $this->thumbnail_height = $this->thumbnail_height ?? common_config('thumbnail', 'height'); $this->max_size = $this->max_size ?? common_config('attachments', 'file_quota'); + $this->crop = $this->crop ?? common_config('thumbnail', 'crop'); } /** @@ -617,7 +618,7 @@ class EmbedPlugin extends Plugin ); } - $url = $thumbnail->getUrl(); + $url = $thumbnail->url; // Important not to use the getter here. if (substr($url, 0, 7) == 'file://') { $filename = substr($url, 7); @@ -675,7 +676,7 @@ class EmbedPlugin extends Plugin } try { - // Update our database for the file record + // Update our database for the thumbnail record $orig = clone($thumbnail); $thumbnail->filename = $filename; $thumbnail->width = $width; diff --git a/plugins/Embed/README.md b/plugins/Embed/README.md index 4bcbee9824..30c7f5f27f 100644 --- a/plugins/Embed/README.md +++ b/plugins/Embed/README.md @@ -12,7 +12,7 @@ Settings * `check_whitelist`: Whether to check the domain_whitelist. * `thumbnail_width`: Maximum width of the thumbnail in pixels. Defaults to global `[thumbnail][width]`. * `thumbnail_height`: Maximum height of the thumbnail in pixels. Defaults to global `[thumbnail][height]`. -* `crop`: Crop to the thumbnail size and don't preserve the original file. Defaults to true. +* `crop`: Crop to the size (not preserving aspect ratio). Defaults to global `[thumbnail][crop]`. * `max_size`: Max media size. Anything bigger than this is rejected. Defaults to global `[attachments][file_quota]`. Relevant GNU social global settings diff --git a/plugins/StoreRemoteMedia/README.md b/plugins/StoreRemoteMedia/README.md index d42eca72b1..ad3860b651 100644 --- a/plugins/StoreRemoteMedia/README.md +++ b/plugins/StoreRemoteMedia/README.md @@ -17,8 +17,9 @@ domain_whitelist array are accepted for local storage. * `thumbnail_width`: Maximum width of the thumbnail in pixels. Defaults to global `[thumbnail][width]`. * `thumbnail_height`: Maximum height of the thumbnail in pixels. Defaults to global `[thumbnail][height]`. -* `crop`: Crop to the thumbnail size and don't preserve the original file. Defaults to false. +* `crop`: Crop to the size (not preserving aspect ratio). Defaults to global `[thumbnail][crop]`. * `max_size`: Max media size. Anything bigger than this is rejected. Defaults to global `[attachments][file_quota]`. +* `store_original`: Whether to maintain a copy of the original media or only a thumbnail of it. Defaults to false. Example ======= diff --git a/plugins/StoreRemoteMedia/StoreRemoteMediaPlugin.php b/plugins/StoreRemoteMedia/StoreRemoteMediaPlugin.php index 5103b3f8b6..1a99a61e2a 100644 --- a/plugins/StoreRemoteMedia/StoreRemoteMediaPlugin.php +++ b/plugins/StoreRemoteMedia/StoreRemoteMediaPlugin.php @@ -41,10 +41,10 @@ class StoreRemoteMediaPlugin extends Plugin public $append_whitelist = []; // fill this array as domain_whitelist to add more trusted sources public $check_whitelist = false; // security/abuse precaution - public $store_original = true; // Whether to maintain a copy of the original media or only a thumbnail of it + public $store_original = false; // Whether to maintain a copy of the original media or only a thumbnail of it public $thumbnail_width = null; public $thumbnail_height = null; - public $crop = false; + public $crop = null; public $max_size = null; protected $imgData = []; @@ -58,12 +58,13 @@ class StoreRemoteMediaPlugin extends Plugin { parent::initialize(); + $this->domain_whitelist = array_merge($this->domain_whitelist, $this->append_whitelist); + // Load global configuration if specific not provided $this->thumbnail_width = $this->thumbnail_width ?? common_config('thumbnail', 'width'); $this->thumbnail_height = $this->thumbnail_height ?? common_config('thumbnail', 'height'); $this->max_size = $this->max_size ?? common_config('attachments', 'file_quota'); - - $this->domain_whitelist = array_merge($this->domain_whitelist, $this->append_whitelist); + $this->crop = $this->crop ?? common_config('thumbnail', 'crop'); } /** @@ -103,7 +104,7 @@ class StoreRemoteMediaPlugin extends Plugin // We can move on } - $url = $file->getUrl(); + $url = $file->getUrl(false); if (substr($url, 0, 7) == 'file://') { $filename = substr($url, 7); @@ -160,19 +161,38 @@ class StoreRemoteMediaPlugin extends Plugin } } - try { - // Update our database for the file record - $orig = clone($file); - $file->filename = $filename; - $file->filehash = $filehash; - $file->width = $width; - $file->height = $height; - // Throws exception on failure. - $file->updateWithKeys($orig); - } catch (Exception $err) { - common_log(LOG_ERR, "Went to update a file entry to the database in " . - "StoreRemoteMediaPlugin::storeRemoteThumbnail but encountered error: ".$err); - throw $err; + if ($this->store_original) { + try { + // Update our database for the file record + $orig = clone($file); + $file->filename = $filename; + $file->filehash = $filehash; + $file->width = $width; + $file->height = $height; + // Throws exception on failure. + $file->updateWithKeys($orig); + } catch (Exception $err) { + common_log(LOG_ERR, "Went to update a file entry on the database in " . + "StoreRemoteMediaPlugin::storeRemoteThumbnail but encountered error: " . $err); + throw $err; + } + } else { + try { + // Insert a thumbnail record for this file + $data = new stdClass(); + $data->thumbnail_url = $url; + $data->thumbnail_width = $width; + $data->thumbnail_height = $height; + File_thumbnail::saveNew($data, $file->getID()); + $ft = File_thumbnail::byFile($file); + $orig = clone($ft); + $ft->filename = $filename; + $ft->updateWithKeys($orig); + } catch (Exception $err) { + common_log(LOG_ERR, "Went to write a thumbnail entry to the database in " . + "StoreRemoteMediaPlugin::storeRemoteThumbnail but encountered error: " . $err); + throw $err; + } } // Out @@ -258,15 +278,15 @@ class StoreRemoteMediaPlugin extends Plugin $original_name = HTTPClient::get_filename($url, $headers); } $filename = MediaFile::encodeFilename($original_name ?? _m('Untitled attachment'), $filehash); - $filepath = File::path($filename); + $fullpath = $this->store_original ? File::path($filename) : File_thumbnail::path($filename); // Write the file to disk. Throw Exception on failure - if (!file_exists($filepath)) { - if (strpos($filepath, INSTALLDIR) !== 0 || file_put_contents($filepath, $imgData) === false) { + if (!file_exists($fullpath)) { + if (strpos($fullpath, INSTALLDIR) !== 0 || file_put_contents($fullpath, $imgData) === false) { throw new ServerException(_m('Could not write downloaded file to disk.')); } - if (common_get_mime_media(MediaFile::getUploadedMimeType($filepath)) !== 'image') { - @unlink($filepath); + if (common_get_mime_media(MediaFile::getUploadedMimeType($fullpath)) !== 'image') { + @unlink($fullpath); throw new UnsupportedMediaException( _m('Remote file format was not identified as an image.'), $url @@ -274,9 +294,9 @@ class StoreRemoteMediaPlugin extends Plugin } // If the image is not of the desired size, resize it - if ($this->crop && ($info[0] > $this->thumbnail_width || $info[1] > $this->thumbnail_height)) { + if (!$this->store_original && $this->crop && ($info[0] > $this->thumbnail_width || $info[1] > $this->thumbnail_height)) { // Temporary object, not stored in DB - $img = new ImageFile(-1, $filepath); + $img = new ImageFile(-1, $fullpath); list($width, $height, $x, $y, $w, $h) = $img->scaleToFit($this->thumbnail_width, $this->thumbnail_height, $this->crop); // The boundary box for our resizing @@ -288,11 +308,11 @@ class StoreRemoteMediaPlugin extends Plugin $width = $box['width']; $height = $box['height']; - $img->resizeTo($filepath, $box); + $img->resizeTo($fullpath, $box); } } else { throw new AlreadyFulfilledException('A thumbnail seems to already exist for remote file' . - ($file_id ? 'with id==' . $file_id : '') . ' at path ' . $filepath); + ($file_id ? 'with id==' . $file_id : '') . ' at path ' . $fullpath); } } catch (AlreadyFulfilledException $e) { // Carry on