fixes
This commit is contained in:
@@ -6,14 +6,15 @@
|
|||||||
/**
|
/**
|
||||||
* Generate a temporary file path.
|
* Generate a temporary file path.
|
||||||
*
|
*
|
||||||
* @return str The filtered array.
|
* @param string $extension The file extension to use.
|
||||||
|
* @return string The filtered array.
|
||||||
*/
|
*/
|
||||||
function generateTempFilePath(): string
|
function generateTempFilePath(string $extension = ''): string
|
||||||
{
|
{
|
||||||
$temporaryDir = storage_path('app/tmp');
|
$temporaryDir = storage_path('app/tmp');
|
||||||
if (is_dir($temporaryDir) === false) {
|
if (is_dir($temporaryDir) === false) {
|
||||||
mkdir($temporaryDir, 0777, true);
|
mkdir($temporaryDir, 0777, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $temporaryDir . DIRECTORY_SEPARATOR . uniqid('upload_', true);
|
return $temporaryDir . DIRECTORY_SEPARATOR . uniqid('upload_', true) . ($extension !== '' ? ".{$extension}" : '');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ class MediaController extends ApiController
|
|||||||
|
|
||||||
$request->merge([
|
$request->merge([
|
||||||
'title' => $request->get('title', ''),
|
'title' => $request->get('title', ''),
|
||||||
'name' => '',
|
'name' => $file->getClientOriginalName(),
|
||||||
'size' => $file->getSize(),
|
'size' => $file->getSize(),
|
||||||
'mime_type' => $file->getMimeType(),
|
'mime_type' => $file->getMimeType(),
|
||||||
'status' => '',
|
'status' => 'Creating Media',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// We store images by default locally
|
// We store images by default locally
|
||||||
@@ -147,6 +147,7 @@ class MediaController extends ApiController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$medium->status('Updating Media');
|
||||||
$medium->update($request->except(['file','transform']));
|
$medium->update($request->except(['file','transform']));
|
||||||
|
|
||||||
$transformData = [];
|
$transformData = [];
|
||||||
@@ -168,6 +169,8 @@ class MediaController extends ApiController
|
|||||||
|
|
||||||
if (count($transformData) > 0) {
|
if (count($transformData) > 0) {
|
||||||
$medium->transform($transformData);
|
$medium->transform($transformData);
|
||||||
|
} else {
|
||||||
|
$medium->ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->respondAsResource(MediaConductor::model($request, $medium));
|
return $this->respondAsResource(MediaConductor::model($request, $medium));
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ class MediaJob implements ShouldQueue
|
|||||||
*/
|
*/
|
||||||
protected $media;
|
protected $media;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions should be silent (not update the status field)
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $silent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions to make on the Media
|
* Actions to make on the Media
|
||||||
*
|
*
|
||||||
@@ -40,13 +47,15 @@ class MediaJob implements ShouldQueue
|
|||||||
/**
|
/**
|
||||||
* Create a new job instance.
|
* Create a new job instance.
|
||||||
*
|
*
|
||||||
* @param Media $media The media model.
|
* @param Media $media The media model.
|
||||||
* @param array $actions The media actions to make.
|
* @param array $actions The media actions to make.
|
||||||
|
* @param boolean $silent Update the media status with progress.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function __construct(Media $media, array $actions)
|
public function __construct(Media $media, array $actions, bool $silent = false)
|
||||||
{
|
{
|
||||||
$this->media = $media;
|
$this->media = $media;
|
||||||
|
$this->silent = $silent;
|
||||||
$this->actions = $actions;
|
$this->actions = $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +81,10 @@ class MediaJob implements ShouldQueue
|
|||||||
// convert HEIC files to JPG
|
// convert HEIC files to JPG
|
||||||
$fileExtension = File::extension($filePath);
|
$fileExtension = File::extension($filePath);
|
||||||
if ($fileExtension === 'heic') {
|
if ($fileExtension === 'heic') {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Converting image');
|
||||||
|
}
|
||||||
|
|
||||||
// Get the path without the file name
|
// Get the path without the file name
|
||||||
$uploadedFileDirectory = dirname($filePath);
|
$uploadedFileDirectory = dirname($filePath);
|
||||||
|
|
||||||
@@ -90,11 +103,12 @@ class MediaJob implements ShouldQueue
|
|||||||
$filePath = $jpgFilePath;
|
$filePath = $jpgFilePath;
|
||||||
$this->media->name = $jpgFileName;
|
$this->media->name = $jpgFileName;
|
||||||
$this->media->save();
|
$this->media->save();
|
||||||
}
|
}//end if
|
||||||
|
|
||||||
// Check if file already exists
|
// Check if file already exists
|
||||||
if (Storage::disk($this->media->storage)->exists($this->media->name) === true) {
|
if (Storage::disk($this->media->storage)->exists($this->media->name) === true) {
|
||||||
if (array_key_exists('replace', $uploadData) === false || isTrue($uploadData['replace']) === false) {
|
if (array_key_exists('replace', $uploadData) === false || isTrue($uploadData['replace']) === false) {
|
||||||
|
$this->media->error("File already exists in storage");
|
||||||
$errorStr = "cannot upload file {$this->media->storage} " . // phpcs:ignore
|
$errorStr = "cannot upload file {$this->media->storage} " . // phpcs:ignore
|
||||||
"/ {$this->media->name} as it already exists";
|
"/ {$this->media->name} as it already exists";
|
||||||
Log::info($errorStr);
|
Log::info($errorStr);
|
||||||
@@ -110,24 +124,37 @@ class MediaJob implements ShouldQueue
|
|||||||
|
|
||||||
// Modifications
|
// Modifications
|
||||||
if (strpos($this->media->mime_type, 'image/') === 0) {
|
if (strpos($this->media->mime_type, 'image/') === 0) {
|
||||||
$image = Image::make($filePath);
|
$modified = false;
|
||||||
|
$image = Image::make($this->media->getStagingFilePath());
|
||||||
|
|
||||||
// ROTATE
|
// ROTATE
|
||||||
if (array_key_exists("rotate", $this->actions) === true) {
|
if (array_key_exists("rotate", $this->actions) === true) {
|
||||||
$rotate = intval($this->actions["rotate"]);
|
$rotate = intval($this->actions["rotate"]);
|
||||||
if ($rotate !== 0) {
|
if ($rotate !== 0) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Rotating image');
|
||||||
|
}
|
||||||
$image = $image->rotate($rotate);
|
$image = $image->rotate($rotate);
|
||||||
|
$modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FLIP-H/V
|
// FLIP-H/V
|
||||||
if (array_key_exists('flip', $this->actions) === true) {
|
if (array_key_exists('flip', $this->actions) === true) {
|
||||||
if (stripos($this->actions['flip'], 'h') !== false) {
|
if (stripos($this->actions['flip'], 'h') !== false) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Flipping image');
|
||||||
|
}
|
||||||
$image = $image->flip('h');
|
$image = $image->flip('h');
|
||||||
|
$modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stripos($this->actions['flip'], 'v') !== false) {
|
if (stripos($this->actions['flip'], 'v') !== false) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Flipping image');
|
||||||
|
}
|
||||||
$image = $image->flip('v');
|
$image = $image->flip('v');
|
||||||
|
$modified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,10 +166,16 @@ class MediaJob implements ShouldQueue
|
|||||||
$x = intval(arrayDefaultValue("x", $cropData, 0));
|
$x = intval(arrayDefaultValue("x", $cropData, 0));
|
||||||
$y = intval(arrayDefaultValue("y", $cropData, 0));
|
$y = intval(arrayDefaultValue("y", $cropData, 0));
|
||||||
|
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Cropping image');
|
||||||
|
}
|
||||||
$image = $image->crop($width, $height, $x, $y);
|
$image = $image->crop($width, $height, $x, $y);
|
||||||
|
$modified = true;
|
||||||
}//end if
|
}//end if
|
||||||
|
|
||||||
$image->save($filePath);
|
if ($modified === true) {
|
||||||
|
$image->save();
|
||||||
|
}
|
||||||
} elseif (strpos($this->media->mime_type, 'video/') === 0) {
|
} elseif (strpos($this->media->mime_type, 'video/') === 0) {
|
||||||
$ffmpeg = FFMpeg\FFMpeg::create();
|
$ffmpeg = FFMpeg\FFMpeg::create();
|
||||||
$video = $ffmpeg->open($this->media->getStagingFilePath());
|
$video = $ffmpeg->open($this->media->getStagingFilePath());
|
||||||
@@ -157,6 +190,10 @@ class MediaJob implements ShouldQueue
|
|||||||
$rotate = (round($rotate / 90) * 90); // round to nearest 90%
|
$rotate = (round($rotate / 90) * 90); // round to nearest 90%
|
||||||
|
|
||||||
if ($rotate > 0) {
|
if ($rotate > 0) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Rotating video');
|
||||||
|
}
|
||||||
|
|
||||||
if ($rotate === 90) {
|
if ($rotate === 90) {
|
||||||
$filters->rotate(FFMpeg\Filters\Video\RotateFilter::ROTATE_90);
|
$filters->rotate(FFMpeg\Filters\Video\RotateFilter::ROTATE_90);
|
||||||
} elseif ($rotate === 190) {
|
} elseif ($rotate === 190) {
|
||||||
@@ -170,10 +207,16 @@ class MediaJob implements ShouldQueue
|
|||||||
// FLIP-H/V
|
// FLIP-H/V
|
||||||
if (array_key_exists('flip', $this->actions) === true) {
|
if (array_key_exists('flip', $this->actions) === true) {
|
||||||
if (stripos($this->actions['flip'], 'h') !== false) {
|
if (stripos($this->actions['flip'], 'h') !== false) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Flipping video');
|
||||||
|
}
|
||||||
$filters->hflip()->synchronize();
|
$filters->hflip()->synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stripos($this->actions['flip'], 'v') !== false) {
|
if (stripos($this->actions['flip'], 'v') !== false) {
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Flipping video');
|
||||||
|
}
|
||||||
$filters->vflip()->synchronize();
|
$filters->vflip()->synchronize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,6 +233,9 @@ class MediaJob implements ShouldQueue
|
|||||||
|
|
||||||
$cropDimension = new Dimension($width, $height);
|
$cropDimension = new Dimension($width, $height);
|
||||||
|
|
||||||
|
if ($this->silent === false) {
|
||||||
|
$this->media->status('Cropping video');
|
||||||
|
}
|
||||||
$filters->crop($cropDimension, $x, $y)->synchronize();
|
$filters->crop($cropDimension, $x, $y)->synchronize();
|
||||||
}//end if
|
}//end if
|
||||||
|
|
||||||
@@ -213,11 +259,17 @@ class MediaJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finish media object
|
// Finish media object
|
||||||
$this->media->saveStagingFile();
|
$this->media->saveStagingFile(true, $this->silent);
|
||||||
$this->media->ok();
|
$this->media->ok();
|
||||||
|
$this->media->save();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
$this->media->deleteStagingFile();
|
||||||
|
|
||||||
|
if (strpos($this->media->status, 'Error') !== 0) {
|
||||||
|
$this->media->error('Failed to process');
|
||||||
|
}
|
||||||
|
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
$this->media->error("Failed");
|
|
||||||
$this->fail($e);
|
$this->fail($e);
|
||||||
}//end try
|
}//end try
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,10 +374,11 @@ class Media extends Model
|
|||||||
/**
|
/**
|
||||||
* Transform the media through the Media Job Queue
|
* Transform the media through the Media Job Queue
|
||||||
*
|
*
|
||||||
* @param array $transform The transform data.
|
* @param array $transform The transform data.
|
||||||
|
* @param boolean $silent Update the medium progress through its status field.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function transform(array $transform): void
|
public function transform(array $transform, bool $silent = false): void
|
||||||
{
|
{
|
||||||
foreach ($transform as $key => $value) {
|
foreach ($transform as $key => $value) {
|
||||||
if (is_string($value) === true) {
|
if (is_string($value) === true) {
|
||||||
@@ -398,7 +399,7 @@ class Media extends Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MediaJob::dispatch($this, $transform)->onQueue('media');
|
MediaJob::dispatch($this, $transform, $silent)->onQueue('media');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->error('Failed to transform media');
|
$this->error('Failed to transform media');
|
||||||
throw $e;
|
throw $e;
|
||||||
@@ -692,9 +693,10 @@ class Media extends Model
|
|||||||
*/
|
*/
|
||||||
public function createStagingFile(): bool
|
public function createStagingFile(): bool
|
||||||
{
|
{
|
||||||
if ($this->stagingFilePath !== "") {
|
if ($this->stagingFilePath === "") {
|
||||||
$readStream = Storage::disk($this->storageDisk)->readStream($this->name);
|
$readStream = Storage::disk($this->storageDisk)->readStream($this->name);
|
||||||
$filePath = tempnam(sys_get_temp_dir(), 'download-');
|
$filePath = generateTempFilePath(pathinfo($this->name, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
$writeStream = fopen($filePath, 'w');
|
$writeStream = fopen($filePath, 'w');
|
||||||
while (feof($readStream) !== true) {
|
while (feof($readStream) !== true) {
|
||||||
fwrite($writeStream, fread($readStream, 8192));
|
fwrite($writeStream, fread($readStream, 8192));
|
||||||
@@ -703,7 +705,7 @@ class Media extends Model
|
|||||||
fclose($writeStream);
|
fclose($writeStream);
|
||||||
|
|
||||||
$this->stagingFilePath = $filePath;
|
$this->stagingFilePath = $filePath;
|
||||||
}
|
}//end if
|
||||||
|
|
||||||
return $this->stagingFilePath !== "";
|
return $this->stagingFilePath !== "";
|
||||||
}
|
}
|
||||||
@@ -712,9 +714,10 @@ class Media extends Model
|
|||||||
* Save the Staging File to storage
|
* Save the Staging File to storage
|
||||||
*
|
*
|
||||||
* @param boolean $delete Delete the existing staging file.
|
* @param boolean $delete Delete the existing staging file.
|
||||||
|
* @param boolean $silent Update the status field with the progress.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function saveStagingFile(bool $delete = true): void
|
public function saveStagingFile(bool $delete = true, bool $silent = false): void
|
||||||
{
|
{
|
||||||
if (strlen($this->storage) > 0 && strlen($this->name) > 0) {
|
if (strlen($this->storage) > 0 && strlen($this->name) > 0) {
|
||||||
if (Storage::disk($this->storage)->exists($this->name) === true) {
|
if (Storage::disk($this->storage)->exists($this->name) === true) {
|
||||||
@@ -723,10 +726,20 @@ class Media extends Model
|
|||||||
|
|
||||||
/** @var Illuminate\Filesystem\FilesystemAdapter */
|
/** @var Illuminate\Filesystem\FilesystemAdapter */
|
||||||
$fileSystem = Storage::disk($this->storage);
|
$fileSystem = Storage::disk($this->storage);
|
||||||
|
if ($silent === false) {
|
||||||
|
$this->status('Uploading to CDN');
|
||||||
|
}
|
||||||
$fileSystem->putFileAs('/', $this->stagingFilePath, $this->name);
|
$fileSystem->putFileAs('/', $this->stagingFilePath, $this->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($silent === false) {
|
||||||
|
$this->status('Generating Thumbnail');
|
||||||
|
}
|
||||||
$this->generateThumbnail();
|
$this->generateThumbnail();
|
||||||
|
|
||||||
|
if ($silent === false) {
|
||||||
|
$this->status('Generating Variants');
|
||||||
|
}
|
||||||
$this->generateVariants();
|
$this->generateVariants();
|
||||||
|
|
||||||
if ($delete === true) {
|
if ($delete === true) {
|
||||||
@@ -780,7 +793,7 @@ class Media extends Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$filePath = $this->createStagingFile();
|
$filePath = $this->getStagingFilePath();
|
||||||
|
|
||||||
$fileExtension = File::extension($this->name);
|
$fileExtension = File::extension($this->name);
|
||||||
$tempImagePath = tempnam(sys_get_temp_dir(), 'thumb');
|
$tempImagePath = tempnam(sys_get_temp_dir(), 'thumb');
|
||||||
@@ -894,12 +907,12 @@ class Media extends Model
|
|||||||
*/
|
*/
|
||||||
public function generateVariants(): void
|
public function generateVariants(): void
|
||||||
{
|
{
|
||||||
if (strpos($this->media->mime_type, 'image/') === 0) {
|
if (strpos($this->mime_type, 'image/') === 0) {
|
||||||
// Generate additional image sizes
|
// Generate additional image sizes
|
||||||
$sizes = Media::getObjectVariants('image');
|
$sizes = Media::getObjectVariants('image');
|
||||||
|
|
||||||
// download original from CDN if no local file
|
// download original from CDN if no local file
|
||||||
$filePath = $this->createStagingFile();
|
$filePath = $this->getStagingFilePath();
|
||||||
|
|
||||||
// delete existing variants
|
// delete existing variants
|
||||||
if (is_array($this->variants) === true) {
|
if (is_array($this->variants) === true) {
|
||||||
|
|||||||
@@ -1,82 +1,86 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div>
|
||||||
:class="[
|
|
||||||
'flex',
|
|
||||||
'gap-4',
|
|
||||||
'my-4',
|
|
||||||
'select-none',
|
|
||||||
props.showEditor
|
|
||||||
? ['overflow-auto']
|
|
||||||
: ['flex-wrap', 'flex-justify-center'],
|
|
||||||
]">
|
|
||||||
<div
|
<div
|
||||||
v-for="(image, index) in modelValue"
|
:class="[
|
||||||
class="flex flex-col flex-justify-center relative sm-gallery-item p-1"
|
'flex',
|
||||||
:key="index">
|
'gap-4',
|
||||||
<img
|
'my-4',
|
||||||
:src="mediaGetThumbnail(image as Media, 'small')"
|
'select-none',
|
||||||
class="max-h-40 max-w-40 cursor-pointer"
|
props.showEditor
|
||||||
@click="showGalleryModal(index)" />
|
? ['overflow-auto']
|
||||||
|
: ['flex-wrap', 'flex-justify-center'],
|
||||||
|
]">
|
||||||
|
<div
|
||||||
|
v-for="(image, index) in modelValue"
|
||||||
|
class="flex flex-col flex-justify-center relative sm-gallery-item p-1"
|
||||||
|
:key="index">
|
||||||
|
<img
|
||||||
|
:src="mediaGetThumbnail(image as Media, 'small')"
|
||||||
|
class="max-h-40 max-w-40 cursor-pointer"
|
||||||
|
@click="showGalleryModal(index)" />
|
||||||
|
<div
|
||||||
|
v-if="props.showEditor"
|
||||||
|
class="absolute rounded-5 bg-white -top-0.25 -right-0.25 hidden cursor-pointer item-delete"
|
||||||
|
@click="handleRemoveItem((image as Media).id)">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-6 w-6 block"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"
|
||||||
|
fill="rgba(185,28,28,1)" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="props.showEditor"
|
v-if="props.showEditor"
|
||||||
class="absolute rounded-5 bg-white -top-0.25 -right-0.25 hidden cursor-pointer item-delete"
|
class="flex flex-col flex-justify-center">
|
||||||
@click="handleRemoveItem((image as Media).id)">
|
<div
|
||||||
<svg
|
class="flex flex-col flex-justify-center flex-items-center h-23 w-40 cursor-pointer bg-gray-300 text-gray-800 hover:text-gray-600"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
@click="handleAddToGallery">
|
||||||
class="h-6 w-6 block"
|
<svg
|
||||||
viewBox="0 0 24 24">
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<path
|
class="h-15 w-15"
|
||||||
d="M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z"
|
viewBox="0 0 24 24">
|
||||||
fill="rgba(185,28,28,1)" />
|
<title>Add image</title>
|
||||||
</svg>
|
<path
|
||||||
|
d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"
|
||||||
|
fill="currentColor" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="props.showEditor" class="flex flex-col flex-justify-center">
|
<div
|
||||||
|
v-if="props.showEditor == false && showModalImage !== null"
|
||||||
|
:class="[
|
||||||
|
'image-gallery-modal',
|
||||||
|
{ 'image-gallery-modal-buttons': showButtons },
|
||||||
|
]"
|
||||||
|
@click="hideModal"
|
||||||
|
@mousemove="handleModalUpdateButtons"
|
||||||
|
@mouseleave="handleModalUpdateButtons">
|
||||||
|
<img
|
||||||
|
:src="mediaGetVariantUrl(modelValue[showModalImage] as Media)"
|
||||||
|
class="image-gallery-modal-image" />
|
||||||
<div
|
<div
|
||||||
class="flex flex-col flex-justify-center flex-items-center h-23 w-40 cursor-pointer bg-gray-300 text-gray-800 hover:text-gray-600"
|
class="image-gallery-modal-prev"
|
||||||
@click="handleAddToGallery">
|
@click.stop="handleModalPrevImage"></div>
|
||||||
|
<div
|
||||||
|
class="image-gallery-modal-next"
|
||||||
|
@click.stop="handleModalNextImage"></div>
|
||||||
|
<div class="image-gallery-modal-close" @click="hideModal">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="h-15 w-15"
|
class="h-6 w-6"
|
||||||
viewBox="0 0 24 24">
|
viewBox="0 0 24 24">
|
||||||
<title>Add image</title>
|
<title>Close</title>
|
||||||
<path
|
<path
|
||||||
d="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M13,7H11V11H7V13H11V17H13V13H17V11H13V7Z"
|
d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
|
||||||
fill="currentColor" />
|
fill="currentColor" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="props.showEditor == false && showModalImage !== null"
|
|
||||||
:class="[
|
|
||||||
'image-gallery-modal',
|
|
||||||
{ 'image-gallery-modal-buttons': showButtons },
|
|
||||||
]"
|
|
||||||
@click="hideModal"
|
|
||||||
@mousemove="handleModalUpdateButtons"
|
|
||||||
@mouseleave="handleModalUpdateButtons">
|
|
||||||
<img
|
|
||||||
:src="mediaGetVariantUrl(modelValue[showModalImage] as Media)"
|
|
||||||
class="image-gallery-modal-image" />
|
|
||||||
<div
|
|
||||||
class="image-gallery-modal-prev"
|
|
||||||
@click.stop="handleModalPrevImage"></div>
|
|
||||||
<div
|
|
||||||
class="image-gallery-modal-next"
|
|
||||||
@click.stop="handleModalNextImage"></div>
|
|
||||||
<div class="image-gallery-modal-close" @click="hideModal">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
class="h-6 w-6"
|
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<title>Close</title>
|
|
||||||
<path
|
|
||||||
d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
|
|
||||||
fill="currentColor" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -142,6 +142,8 @@
|
|||||||
:style="{
|
:style="{
|
||||||
backgroundImage: `url('${mediaGetThumbnail(
|
backgroundImage: `url('${mediaGetThumbnail(
|
||||||
item,
|
item,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
)}')`,
|
)}')`,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
item.status === 'OK'
|
item.status === 'OK'
|
||||||
@@ -156,11 +158,18 @@
|
|||||||
<SMLoading
|
<SMLoading
|
||||||
v-if="
|
v-if="
|
||||||
item.status !== 'OK' &&
|
item.status !== 'OK' &&
|
||||||
item.status !== 'Failed'
|
item.status.startsWith(
|
||||||
|
'Error',
|
||||||
|
) === false
|
||||||
"
|
"
|
||||||
small
|
small
|
||||||
class="bg-white bg-op-90 w-full h-full" />
|
class="bg-white bg-op-90 w-full h-full" />
|
||||||
<div v-if="item.status == 'Failed'">
|
<div
|
||||||
|
v-if="
|
||||||
|
item.status.startsWith(
|
||||||
|
'Error',
|
||||||
|
) === true
|
||||||
|
">
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="h-10 w-10"
|
class="h-10 w-10"
|
||||||
@@ -232,7 +241,13 @@
|
|||||||
<div
|
<div
|
||||||
class="flex text-xs border-b border-gray-3 pb-4">
|
class="flex text-xs border-b border-gray-3 pb-4">
|
||||||
<img
|
<img
|
||||||
:src="mediaGetThumbnail(lastSelected)"
|
:src="
|
||||||
|
mediaGetThumbnail(
|
||||||
|
lastSelected,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
"
|
||||||
class="max-h-20 max-w-20 mr-2" />
|
class="max-h-20 max-w-20 mr-2" />
|
||||||
<div class="flex flex-col w-100">
|
<div class="flex flex-col w-100">
|
||||||
<p class="m-0 text-bold">
|
<p class="m-0 text-bold">
|
||||||
@@ -256,7 +271,14 @@
|
|||||||
<p
|
<p
|
||||||
v-if="lastSelected.status != 'OK'"
|
v-if="lastSelected.status != 'OK'"
|
||||||
class="m-0 italic">
|
class="m-0 italic">
|
||||||
{{ lastSelected.status }}
|
{{
|
||||||
|
lastSelected.status.split(":")
|
||||||
|
.length > 1
|
||||||
|
? lastSelected.status
|
||||||
|
.split(":")[1]
|
||||||
|
.trim()
|
||||||
|
: lastSelected.status
|
||||||
|
}}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p
|
||||||
v-if="allowEditSelected"
|
v-if="allowEditSelected"
|
||||||
@@ -388,6 +410,8 @@
|
|||||||
:style="{
|
:style="{
|
||||||
backgroundImage: `url('${mediaGetThumbnail(
|
backgroundImage: `url('${mediaGetThumbnail(
|
||||||
item,
|
item,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
)}')`,
|
)}')`,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
item.status === 'OK'
|
item.status === 'OK'
|
||||||
@@ -397,7 +421,7 @@
|
|||||||
<SMLoading
|
<SMLoading
|
||||||
v-if="
|
v-if="
|
||||||
item.status !== 'OK' &&
|
item.status !== 'OK' &&
|
||||||
item.status !== 'Failed'
|
item.status.startsWith('Error') === false
|
||||||
"
|
"
|
||||||
small
|
small
|
||||||
class="bg-white bg-op-90 w-full h-full" />
|
class="bg-white bg-op-90 w-full h-full" />
|
||||||
@@ -804,6 +828,7 @@ const handleChangeSelectFile = async () => {
|
|||||||
handleFilesUpload(refUploadInput.value.files);
|
handleFilesUpload(refUploadInput.value.files);
|
||||||
showFileBrowserTab();
|
showFileBrowserTab();
|
||||||
}
|
}
|
||||||
|
refUploadInput.value.value = "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilesUpload = (files: FileList) => {
|
const handleFilesUpload = (files: FileList) => {
|
||||||
@@ -861,7 +886,6 @@ const startFilesUpload = async () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (result.data) {
|
if (result.data) {
|
||||||
/* empty */
|
|
||||||
const data = result.data as MediaResponse;
|
const data = result.data as MediaResponse;
|
||||||
|
|
||||||
const currentUploadFileNumStr =
|
const currentUploadFileNumStr =
|
||||||
@@ -901,7 +925,7 @@ const updateFiles = async () => {
|
|||||||
if (
|
if (
|
||||||
isUUID(item.id) &&
|
isUUID(item.id) &&
|
||||||
item.status != "OK" &&
|
item.status != "OK" &&
|
||||||
item.status != "Failed"
|
item.status.startsWith("Error") == false
|
||||||
) {
|
) {
|
||||||
remaining = true;
|
remaining = true;
|
||||||
|
|
||||||
@@ -916,10 +940,23 @@ const updateFiles = async () => {
|
|||||||
const updateData =
|
const updateData =
|
||||||
updateResult.data as MediaResponse;
|
updateResult.data as MediaResponse;
|
||||||
if (updateData.medium.status == "OK") {
|
if (updateData.medium.status == "OK") {
|
||||||
totalItems.value++;
|
|
||||||
mediaItems.value[index] = updateData.medium;
|
|
||||||
} else if (updateData.medium.status == "Failed") {
|
|
||||||
mediaItems.value[index] = updateData.medium;
|
mediaItems.value[index] = updateData.medium;
|
||||||
|
if (
|
||||||
|
lastSelected.value &&
|
||||||
|
lastSelected.value.id ==
|
||||||
|
updateData.medium.id
|
||||||
|
) {
|
||||||
|
lastSelected.value = updateData.medium;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
updateData.medium.status.startsWith("Error") ===
|
||||||
|
true
|
||||||
|
) {
|
||||||
|
mediaItems.value = mediaItems.value.filter(
|
||||||
|
(mediaItem) =>
|
||||||
|
mediaItem.id !== updateData.medium.id,
|
||||||
|
);
|
||||||
|
|
||||||
useToastStore().addToast({
|
useToastStore().addToast({
|
||||||
title: "Upload failed",
|
title: "Upload failed",
|
||||||
type: "danger",
|
type: "danger",
|
||||||
@@ -931,13 +968,16 @@ const updateFiles = async () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
/* empty */
|
/* error retreiving data */
|
||||||
|
mediaItems.value = mediaItems.value.filter(
|
||||||
|
(mediaItem) => mediaItem.id !== item.id,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mediaItems.value = mediaItems.value.filter(
|
mediaItems.value = mediaItems.value.filter(
|
||||||
(item) => item.status !== "Failed",
|
(item) => item.status.startsWith("Error") === false,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (remaining) {
|
if (remaining) {
|
||||||
@@ -986,7 +1026,7 @@ const handleLoad = async () => {
|
|||||||
let params = {
|
let params = {
|
||||||
page: page.value,
|
page: page.value,
|
||||||
limit: perPage.value,
|
limit: perPage.value,
|
||||||
status: "!Failed",
|
status: "!Error",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mimeTypesFilter) {
|
if (mimeTypesFilter) {
|
||||||
@@ -1144,6 +1184,7 @@ const formatDate = (date) => {
|
|||||||
const allowEditSelected = computed(() => {
|
const allowEditSelected = computed(() => {
|
||||||
return (
|
return (
|
||||||
lastSelected.value != null &&
|
lastSelected.value != null &&
|
||||||
|
lastSelected.value.status === "OK" &&
|
||||||
userStore.id &&
|
userStore.id &&
|
||||||
(userHasPermission("admin/media") ||
|
(userHasPermission("admin/media") ||
|
||||||
lastSelected.value.user_id == userStore.id)
|
lastSelected.value.user_id == userStore.id)
|
||||||
@@ -1176,7 +1217,7 @@ const handleRotateLeft = async (item: Media) => {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
transform: "rotate-270",
|
transform: "rotate-90",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@@ -1189,6 +1230,8 @@ const handleRotateLeft = async (item: Media) => {
|
|||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
mediaItems.value[index] = data.medium;
|
mediaItems.value[index] = data.medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFiles();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@@ -1203,7 +1246,7 @@ const handleRotateRight = async (item: Media) => {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
},
|
},
|
||||||
body: {
|
body: {
|
||||||
transform: "rotate-90",
|
transform: "rotate-270",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@@ -1216,6 +1259,8 @@ const handleRotateRight = async (item: Media) => {
|
|||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
mediaItems.value[index] = data.medium;
|
mediaItems.value[index] = data.medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateFiles();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|||||||
@@ -40,8 +40,11 @@ export const mimeMatches = (
|
|||||||
|
|
||||||
export const mediaGetThumbnail = (
|
export const mediaGetThumbnail = (
|
||||||
media: Media,
|
media: Media,
|
||||||
useVariant: string = "",
|
useVariant: string | null = "",
|
||||||
|
forceRefresh: boolean = false,
|
||||||
): string => {
|
): string => {
|
||||||
|
let url: string = "";
|
||||||
|
|
||||||
if (!media) {
|
if (!media) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -49,19 +52,35 @@ export const mediaGetThumbnail = (
|
|||||||
if (
|
if (
|
||||||
useVariant &&
|
useVariant &&
|
||||||
useVariant != "" &&
|
useVariant != "" &&
|
||||||
|
useVariant != null &&
|
||||||
media.variants &&
|
media.variants &&
|
||||||
media.variants[useVariant]
|
media.variants[useVariant]
|
||||||
) {
|
) {
|
||||||
return media.url.replace(media.name, media.variants[useVariant]);
|
url = media.url.replace(media.name, media.variants[useVariant]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media.thumbnail && media.thumbnail.length > 0) {
|
if (media.thumbnail && media.thumbnail.length > 0) {
|
||||||
return media.thumbnail;
|
url = media.thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (media.variants && media.variants["thumb"]) {
|
if (media.variants && media.variants["thumb"]) {
|
||||||
return media.url.replace(media.name, media.variants["thumb"]);
|
url = media.url.replace(media.name, media.variants["thumb"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "/assets/fileicons/unknown.webp";
|
if (url === "") {
|
||||||
|
return "/assets/fileicons/unknown.webp";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceRefresh == true) {
|
||||||
|
// Generate a random string
|
||||||
|
const randomString = Math.random().toString(36).substring(7);
|
||||||
|
|
||||||
|
// Check if the URL already has query parameters
|
||||||
|
const separator = url.includes("?") ? "&" : "?";
|
||||||
|
|
||||||
|
// Append the random string as a query parameter
|
||||||
|
url = `${url}${separator}_random=${randomString}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user