This commit is contained in:
2023-08-25 11:30:57 +10:00
parent f50e6ad209
commit 622229cfc9
7 changed files with 243 additions and 106 deletions

View File

@@ -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}" : '');
} }

View File

@@ -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));

View File

@@ -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
} }

View File

@@ -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) {

View File

@@ -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">

View File

@@ -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(() => {

View File

@@ -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;
}; };