@wordpress/upload-media
Version:
Core media upload logic.
1,123 lines (1,122 loc) • 31.3 kB
JavaScript
// packages/upload-media/src/store/private-actions.ts
import { v4 as uuidv4 } from "uuid";
import { createBlobURL, isBlobURL, revokeBlobURL } from "@wordpress/blob";
import { __ } from "@wordpress/i18n";
import {
cloneFile,
convertBlobToFile,
isAnimatedGif,
renameFile
} from "../utils.mjs";
import { canvasConvertToJpeg } from "../canvas-utils.mjs";
import { getUnappliedExifOrientation } from "../heic-parser.mjs";
import {
isClientSideMediaSupported,
exceedsClientProcessingMemory
} from "../feature-detection.mjs";
import { getImageDimensions } from "../get-image-dimensions.mjs";
import { CLIENT_SIDE_SUPPORTED_MIME_TYPES, HEIC_MIME_TYPES } from "./constants.mjs";
import { StubFile } from "../stub-file.mjs";
import { ErrorCode, UploadError } from "../upload-error.mjs";
import { measure } from "./utils/debug-logger.mjs";
import {
vipsResizeImage,
vipsRotateImage,
vipsConvertImageFormat,
vipsHasTransparency,
vipsGetUltraHdrInfo,
terminateVipsWorker,
maybeRecycleVipsWorker
} from "./utils/index.mjs";
import {
convertGifToVideo,
isUnsupportedConversionError,
terminateVideoConversionWorker
} from "./utils/video-conversion.mjs";
import { ItemStatus, OperationType, Type } from "./types.mjs";
import { clearRetryTimer } from "./utils/retry.mjs";
var DEFAULT_OUTPUT_QUALITY = 0.82;
var ultraHdrItems = /* @__PURE__ */ new Set();
function addItem({
file: fileOrBlob,
batchId,
onChange,
onSuccess,
onBatchSuccess,
onError,
additionalData = {},
sourceUrl,
sourceAttachmentId,
abortController,
operations
}) {
return async ({ dispatch }) => {
const itemId = uuidv4();
const file = convertBlobToFile(fileOrBlob);
let blobUrl;
if (!(file instanceof StubFile)) {
blobUrl = createBlobURL(file);
dispatch({
type: Type.CacheBlobUrl,
id: itemId,
blobUrl
});
}
dispatch({
type: Type.Add,
item: {
id: itemId,
batchId,
status: ItemStatus.Processing,
sourceFile: cloneFile(file),
file,
attachment: {
url: blobUrl
},
additionalData: {
generate_sub_sizes: false,
...additionalData
},
onChange,
onSuccess,
onBatchSuccess,
onError,
sourceUrl,
sourceAttachmentId,
abortController: abortController || new AbortController(),
operations: Array.isArray(operations) ? operations : [OperationType.Prepare]
}
});
dispatch.processItem(itemId);
};
}
function addSideloadItem({
file,
onChange,
additionalData,
operations,
batchId,
parentId
}) {
return ({ dispatch }) => {
const itemId = uuidv4();
dispatch({
type: Type.Add,
item: {
id: itemId,
batchId,
status: ItemStatus.Processing,
sourceFile: cloneFile(file),
file,
onChange,
additionalData: {
...additionalData
},
parentId,
operations: Array.isArray(operations) ? operations : [OperationType.Prepare],
abortController: new AbortController()
}
});
dispatch.processItem(itemId);
};
}
function processItem(id) {
return async ({ select, dispatch }) => {
if (select.isPaused()) {
return;
}
const item = select.getItem(id);
if (!item) {
return;
}
const {
attachment,
onChange,
onSuccess,
onBatchSuccess,
batchId,
parentId
} = item;
const operation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0];
const operationArgs = Array.isArray(item.operations?.[0]) ? item.operations[0][1] : void 0;
if (operation === OperationType.Upload) {
const settings = select.getSettings();
const activeCount = select.getActiveUploadCount();
if (activeCount >= settings.maxConcurrentUploads) {
return;
}
}
if (operation === OperationType.ResizeCrop || operation === OperationType.Rotate) {
const settings = select.getSettings();
const activeCount = select.getActiveImageProcessingCount();
if (activeCount >= settings.maxConcurrentImageProcessing) {
return;
}
}
if (operation === OperationType.TranscodeGif) {
const activeCount = select.getActiveVideoProcessingCount();
if (activeCount >= 1) {
return;
}
}
if (attachment) {
const isHeicUrl = attachment.url && /\.hei[cf]$/i.test(attachment.url);
if (!isHeicUrl) {
onChange?.([attachment]);
}
}
if (!operation) {
if (parentId || !parentId && !select.hasPendingItemsByParentId(id)) {
if (attachment) {
onSuccess?.([attachment]);
}
dispatch.removeItem(id);
dispatch.revokeBlobUrls(id);
if (batchId && select.isBatchUploaded(batchId)) {
onBatchSuccess?.();
}
}
if (parentId && batchId && select.isBatchUploaded(batchId)) {
const parentItem = select.getItem(parentId);
if (!parentItem) {
return;
}
if (parentItem.operations && parentItem.operations.length > 0) {
dispatch.processItem(parentId);
return;
}
if (attachment) {
parentItem.onSuccess?.([attachment]);
}
dispatch.removeItem(parentId);
dispatch.revokeBlobUrls(parentId);
if (parentItem.batchId && select.isBatchUploaded(parentItem.batchId)) {
parentItem.onBatchSuccess?.();
}
}
return;
}
if (operation === OperationType.Finalize && select.hasPendingItemsByParentId(id)) {
return;
}
dispatch({
type: Type.OperationStart,
id,
operation
});
switch (operation) {
case OperationType.Prepare:
dispatch.prepareItem(item.id);
break;
case OperationType.ResizeCrop:
dispatch.resizeCropItem(
item.id,
operationArgs
);
break;
case OperationType.Rotate:
dispatch.rotateItem(
item.id,
operationArgs
);
break;
case OperationType.TranscodeImage:
dispatch.transcodeImageItem(
item.id,
operationArgs
);
break;
case OperationType.TranscodeGif:
dispatch.transcodeGifItem(
item.id,
operationArgs
);
break;
case OperationType.Upload:
if (item.parentId) {
dispatch.sideloadItem(id);
} else {
dispatch.uploadItem(id);
}
break;
case OperationType.ThumbnailGeneration:
dispatch.generateThumbnails(id);
break;
case OperationType.Finalize:
dispatch.finalizeItem(id);
break;
case OperationType.DetectUltraHdr:
dispatch.detectUltraHdr(id);
break;
}
};
}
function pauseQueue() {
return {
type: Type.PauseQueue
};
}
function resumeQueue() {
return async ({ select, dispatch }) => {
dispatch({
type: Type.ResumeQueue
});
for (const item of select.getAllItems()) {
if (item.status === ItemStatus.PendingRetry) {
dispatch.executeRetry(item.id);
} else {
dispatch.processItem(item.id);
}
}
};
}
function pauseItem(id) {
return async ({ dispatch }) => {
dispatch({
type: Type.PauseItem,
id
});
};
}
function removeItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
ultraHdrItems.delete(id);
clearRetryTimer(id);
dispatch({
type: Type.Remove,
id
});
if (select.getAllItems().length === 0) {
terminateVipsWorker();
terminateVideoConversionWorker();
}
};
}
function finishOperation(id, updates) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
const previousOperation = item?.currentOperation;
dispatch({
type: Type.OperationFinish,
id,
item: updates
});
dispatch.processItem(id);
if (previousOperation === OperationType.Upload) {
const pendingUploads = select.getPendingUploads();
for (const pendingItem of pendingUploads) {
dispatch.processItem(pendingItem.id);
}
}
if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate) {
const pendingItems = select.getPendingImageProcessing();
for (const pendingItem of pendingItems) {
dispatch.processItem(pendingItem.id);
}
}
if (previousOperation === OperationType.TranscodeGif) {
const pendingItems = select.getPendingVideoProcessing();
for (const pendingItem of pendingItems) {
dispatch.processItem(pendingItem.id);
}
}
if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate || previousOperation === OperationType.TranscodeImage) {
maybeRecycleVipsWorker(select.getActiveImageProcessingCount());
}
};
}
var VALID_IMAGE_FORMATS = ["jpeg", "webp", "avif", "png", "gif"];
function isValidImageFormat(format) {
return VALID_IMAGE_FORMATS.includes(format);
}
async function getTranscodeImageOperation(file, outputMimeType, interlaced = false, quality = DEFAULT_OUTPUT_QUALITY) {
if (file.type === "image/png" && outputMimeType === "image/jpeg") {
const blobUrl = createBlobURL(file);
try {
const hasAlpha = await vipsHasTransparency(blobUrl);
if (hasAlpha) {
return null;
}
} catch {
return null;
} finally {
revokeBlobURL(blobUrl);
}
}
const formatPart = outputMimeType.split("/")[1];
if (!isValidImageFormat(formatPart)) {
return null;
}
return [
OperationType.TranscodeImage,
{
outputFormat: formatPart,
outputQuality: quality,
interlaced
}
];
}
function prepareItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const { file } = item;
const operations = [];
const settings = select.getSettings();
if (file.type === "image/gif" && settings.gifConvert !== false && typeof ImageDecoder !== "undefined" && typeof VideoEncoder !== "undefined") {
let isAnimated = false;
try {
isAnimated = isAnimatedGif(await file.arrayBuffer());
} catch {
isAnimated = false;
}
if (isAnimated) {
let hasTransparency = false;
const blobUrl = createBlobURL(file);
try {
hasTransparency = await vipsHasTransparency(blobUrl);
} catch {
hasTransparency = true;
} finally {
revokeBlobURL(blobUrl);
}
if (!hasTransparency) {
operations.push(
OperationType.Upload,
OperationType.ThumbnailGeneration,
OperationType.Finalize
);
dispatch({
type: Type.AddOperations,
id,
operations
});
dispatch.finishOperation(id, {
animatedGifFile: item.file
});
return;
}
}
}
let heicJpeg = null;
const isImage = file.type.startsWith("image/");
const isVipsSupported = CLIENT_SIDE_SUPPORTED_MIME_TYPES.includes(
file.type
);
const isHeic = HEIC_MIME_TYPES.includes(file.type);
let tooLargeForClient = false;
if (isImage && isVipsSupported) {
const dimensions = await getImageDimensions(file);
if (dimensions && exceedsClientProcessingMemory(dimensions)) {
tooLargeForClient = true;
}
}
if (file.type === "image/jpeg" && !tooLargeForClient) {
operations.push(OperationType.DetectUltraHdr);
}
if (isImage && isVipsSupported && !tooLargeForClient) {
operations.push(
OperationType.Upload,
OperationType.ThumbnailGeneration,
OperationType.Finalize
);
} else if (isImage && isHeic) {
try {
heicJpeg = await canvasConvertToJpeg(
file,
settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY
);
} catch {
dispatch.cancelItem(
id,
new UploadError({
code: ErrorCode.HEIC_DECODE_ERROR,
message: "This browser cannot decode HEIC images and the server does not support them either. Please convert to JPEG before uploading.",
file
})
);
return;
}
operations.push(
OperationType.Upload,
OperationType.ThumbnailGeneration,
OperationType.Finalize
);
} else {
operations.push(OperationType.Upload);
}
dispatch({
type: Type.AddOperations,
id,
operations
});
let updates;
if (isHeic && heicJpeg) {
const vipsAvailable = isClientSideMediaSupported();
updates = {
file: heicJpeg,
sourceFile: heicJpeg,
originalHeicFile: item.file,
additionalData: {
...item.additionalData,
generate_sub_sizes: !vipsAvailable,
convert_format: true
}
};
} else if (!isVipsSupported || !isImage || tooLargeForClient) {
updates = {
additionalData: {
...item.additionalData,
generate_sub_sizes: true,
convert_format: true
}
};
} else {
updates = {
additionalData: {
...item.additionalData,
generate_sub_sizes: false
}
};
}
dispatch.finishOperation(id, updates);
};
}
function detectUltraHdr(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
let info;
try {
const buffer = await item.file.arrayBuffer();
info = await vipsGetUltraHdrInfo(buffer);
} catch {
}
if (info) {
ultraHdrItems.add(id);
}
dispatch.finishOperation(id, {});
};
}
function uploadItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const startTime = performance.now();
let finished = false;
const finishUpload = (attachment) => {
if (finished) {
return;
}
finished = true;
measure({
measureName: `Upload ${item.file.name}`,
startTime,
tooltipText: item.file.name,
properties: [
["Item ID", item.id],
["File name", item.file.name]
]
});
dispatch.finishOperation(id, { attachment });
};
select.getSettings().mediaUpload({
filesList: [item.file],
additionalData: item.additionalData,
signal: item.abortController?.signal,
onFileChange: ([attachment]) => {
if (attachment && !isBlobURL(attachment.url)) {
finishUpload(attachment);
}
},
onSuccess: ([attachment]) => {
finishUpload(attachment);
},
onError: (error) => {
dispatch.cancelItem(id, error);
}
});
};
}
function sideloadItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const { post, ...additionalData } = item.additionalData;
const mediaSideload = select.getSettings().mediaSideload;
if (!mediaSideload) {
dispatch.finishOperation(id, {});
return;
}
const startTime = performance.now();
mediaSideload({
file: item.file,
attachmentId: post,
additionalData,
signal: item.abortController?.signal,
onSuccess: (subSize) => {
measure({
measureName: `Sideload ${item.file.name}`,
startTime,
tooltipText: item.file.name,
properties: [
["Item ID", item.id],
["File name", item.file.name]
]
});
if (item.parentId) {
dispatch({
type: Type.AccumulateSubSize,
id: item.parentId,
subSize
});
}
dispatch.finishOperation(id, {});
},
onError: (error) => {
dispatch.cancelItem(id, error);
}
});
};
}
function resizeCropItem(id, args) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
if (!args?.resize) {
dispatch.finishOperation(id, {
file: item.file
});
return;
}
const startTime = performance.now();
const addSuffix = Boolean(item.parentId);
const scaledSuffix = Boolean(args.isThresholdResize);
try {
const file = await vipsResizeImage(
item.id,
item.file,
args.resize,
false,
// smartCrop
addSuffix,
item.abortController?.signal,
scaledSuffix,
args.quality
);
measure({
measureName: `ResizeCrop ${item.file.name}`,
startTime,
tooltipText: item.file.name,
properties: [
["Item ID", item.id],
["File name", item.file.name]
]
});
const blobUrl = createBlobURL(file);
dispatch({
type: Type.CacheBlobUrl,
id,
blobUrl
});
dispatch.finishOperation(id, {
file,
attachment: {
url: blobUrl
}
});
} catch (error) {
dispatch.cancelItem(
id,
new UploadError({
code: ErrorCode.IMAGE_TRANSCODING_ERROR,
message: __(
"The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading."
),
file: item.file,
cause: error instanceof Error ? error : void 0
})
);
}
};
}
function rotateItem(id, args) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
if (!args?.orientation || args.orientation === 1) {
dispatch.finishOperation(id, {
file: item.file
});
return;
}
const startTime = performance.now();
try {
const file = await vipsRotateImage(
item.id,
item.file,
args.orientation,
item.abortController?.signal
);
measure({
measureName: `Rotate ${item.file.name}`,
startTime,
tooltipText: item.file.name,
properties: [
["Item ID", item.id],
["File name", item.file.name]
]
});
const blobUrl = createBlobURL(file);
dispatch({
type: Type.CacheBlobUrl,
id,
blobUrl
});
dispatch.finishOperation(id, {
file,
attachment: {
url: blobUrl
}
});
} catch (error) {
dispatch.cancelItem(
id,
new UploadError({
code: ErrorCode.IMAGE_ROTATION_ERROR,
message: __(
"The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading."
),
file: item.file,
cause: error instanceof Error ? error : void 0
})
);
}
};
}
function transcodeImageItem(id, args) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
if (!args?.outputFormat) {
dispatch.finishOperation(id, {
file: item.file
});
return;
}
const startTime = performance.now();
const outputMimeType = `image/${args.outputFormat}`;
const quality = args.outputQuality ?? DEFAULT_OUTPUT_QUALITY;
const interlaced = args.interlaced ?? false;
try {
const file = await vipsConvertImageFormat(
item.id,
item.file,
outputMimeType,
quality,
interlaced
);
measure({
measureName: `Transcode ${item.file.name}`,
startTime,
tooltipText: item.file.name,
properties: [
["Item ID", item.id],
["File name", item.file.name]
]
});
const blobUrl = createBlobURL(file);
dispatch({
type: Type.CacheBlobUrl,
id,
blobUrl
});
dispatch.finishOperation(id, {
file,
attachment: {
url: blobUrl
}
});
} catch (error) {
dispatch.cancelItem(
id,
new UploadError({
code: ErrorCode.MEDIA_TRANSCODING_ERROR,
message: "Image could not be transcoded to the target format",
file: item.file,
cause: error instanceof Error ? error : void 0
})
);
}
};
}
function transcodeGifItem(id, args) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const outputFormat = args?.outputFormat ?? "mp4";
const outputMimeType = `video/${outputFormat}`;
const gifFile = item.file;
try {
const file = await convertGifToVideo(
item.id,
gifFile,
outputMimeType
);
dispatch.finishOperation(id, { file });
dispatch.addSideloadItem({
file: gifFile,
batchId: uuidv4(),
parentId: item.parentId,
additionalData: {
post: item.additionalData?.post,
image_size: "animated_video_poster",
convert_format: false
},
operations: [
[
OperationType.TranscodeImage,
{
outputFormat: "jpeg",
outputQuality: DEFAULT_OUTPUT_QUALITY,
interlaced: false
}
],
OperationType.Upload
]
});
} catch (error) {
if (isUnsupportedConversionError(error)) {
dispatch.cancelItem(
id,
new Error("Animated GIF conversion unsupported"),
true
);
return;
}
console.error(
"[video-conversion] GIF to video conversion failed:",
error
);
dispatch.cancelItem(
id,
new UploadError({
code: ErrorCode.GIF_TRANSCODING_ERROR,
message: "Animated GIF could not be converted to video",
file: item.file,
cause: error instanceof Error ? error : void 0
}),
true
);
}
};
}
function generateThumbnails(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
if (!item.attachment) {
dispatch.finishOperation(id, {});
return;
}
const attachment = item.attachment;
const settings = select.getSettings();
if (item.originalHeicFile && attachment.id) {
dispatch.addSideloadItem({
file: item.originalHeicFile,
batchId: uuidv4(),
parentId: item.id,
additionalData: {
post: attachment.id,
image_size: "source_original",
convert_format: false
},
operations: [OperationType.Upload]
});
}
if (item.animatedGifFile && attachment.id) {
const outputFormat = settings.videoOutputFormat === "video/webm" ? "webm" : "mp4";
dispatch.addSideloadItem({
file: item.animatedGifFile,
batchId: uuidv4(),
parentId: item.id,
additionalData: {
post: attachment.id,
image_size: "animated_video",
convert_format: false
},
operations: [
[
OperationType.TranscodeGif,
{
outputFormat
}
],
OperationType.Upload
]
});
}
let exifOrientation = attachment.exif_orientation || 1;
const sourceType = item.sourceFile.type;
const isHeifFamily = sourceType === "image/avif" || sourceType === "image/heif";
let needsClientRotation = false;
if (isHeifFamily) {
exifOrientation = getUnappliedExifOrientation(
await item.sourceFile.arrayBuffer()
);
needsClientRotation = exifOrientation !== 1;
}
let rotatedSource;
{
const needsRotation = exifOrientation !== 1 && !item.file.name.includes("-scaled");
if ((needsRotation || needsClientRotation) && attachment.id) {
try {
rotatedSource = await vipsRotateImage(
item.id,
item.sourceFile,
exifOrientation,
item.abortController?.signal
);
} catch {
console.warn(
"Failed to rotate image, continuing with thumbnails"
);
}
}
if (needsRotation && rotatedSource && attachment.id) {
dispatch.addSideloadItem({
file: rotatedSource,
batchId: uuidv4(),
parentId: item.id,
additionalData: {
post: attachment.id,
image_size: "original",
convert_format: false
},
operations: [OperationType.Upload]
});
}
}
if (!item.parentId && attachment.missing_image_sizes && attachment.missing_image_sizes.length > 0) {
const allImageSizes = settings.allImageSizes || {};
const sizesToGenerate = attachment.missing_image_sizes;
const thumbnailSource = needsClientRotation && rotatedSource ? rotatedSource : item.sourceFile;
const file = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource;
const batchId = uuidv4();
const isUltraHdr = ultraHdrItems.has(item.id);
const outputMimeType = attachment.image_output_format;
const interlaced = attachment.image_save_progressive ?? false;
const imageQuality = attachment.image_quality;
const fallbackQuality = settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY;
const defaultQuality = typeof imageQuality?.default === "number" ? imageQuality.default / 100 : fallbackQuality;
const qualityForSize = (sizeName) => {
const sized = imageQuality?.sizes?.[sizeName];
if (typeof sized === "number") {
return sized / 100;
}
return defaultQuality;
};
let thumbnailTranscodeOperation = null;
if (!isUltraHdr && outputMimeType) {
thumbnailTranscodeOperation = await getTranscodeImageOperation(
thumbnailSource,
outputMimeType,
interlaced,
defaultQuality
);
}
const dimensionGroups = /* @__PURE__ */ new Map();
for (const name of sizesToGenerate) {
const imageSize = allImageSizes[name];
if (!imageSize) {
console.warn(
`Image size "${name}" not found in configuration`
);
continue;
}
const key = `${imageSize.width}x${imageSize.height}x${imageSize.crop}`;
const group = dimensionGroups.get(key);
if (group) {
group.push(name);
} else {
dimensionGroups.set(key, [name]);
}
}
for (const [, names] of dimensionGroups) {
const imageSize = allImageSizes[names[0]];
const sizeQuality = qualityForSize(names[0]);
const thumbnailOperations = [
[
OperationType.ResizeCrop,
{ resize: imageSize, quality: sizeQuality }
]
];
if (!isUltraHdr && thumbnailTranscodeOperation) {
thumbnailOperations.push([
thumbnailTranscodeOperation[0],
{
...thumbnailTranscodeOperation[1],
outputQuality: sizeQuality
}
]);
}
thumbnailOperations.push(OperationType.Upload);
const imageSizeParam = names.length === 1 ? names[0] : names;
dispatch.addSideloadItem({
file,
batchId,
parentId: item.id,
additionalData: {
// Sideloading does not use the parent post ID but the
// attachment ID as the image sizes need to be added to it.
post: attachment.id,
image_size: imageSizeParam,
convert_format: false
},
operations: thumbnailOperations
});
}
{
const { bigImageSizeThreshold } = settings;
if (bigImageSizeThreshold && attachment.id) {
const bitmap = await createImageBitmap(thumbnailSource);
const needsScaling = bitmap.width > bigImageSizeThreshold || bitmap.height > bigImageSizeThreshold;
bitmap.close();
if (needsScaling) {
const sourceForScaled = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource;
const scaledOperations = [
[
OperationType.ResizeCrop,
{
resize: {
width: bigImageSizeThreshold,
height: bigImageSizeThreshold
},
isThresholdResize: true,
quality: defaultQuality
}
]
];
if (!isUltraHdr && thumbnailTranscodeOperation) {
scaledOperations.push(
thumbnailTranscodeOperation
);
}
scaledOperations.push(OperationType.Upload);
dispatch.addSideloadItem({
file: sourceForScaled,
batchId,
parentId: item.id,
additionalData: {
post: attachment.id,
image_size: "scaled",
convert_format: false
},
operations: scaledOperations
});
}
}
}
}
dispatch.finishOperation(id, {});
};
}
function finalizeItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const attachment = item.attachment;
const { mediaFinalize } = select.getSettings();
const updates = {};
if (attachment?.id && mediaFinalize) {
try {
const updatedAttachment = await mediaFinalize(
attachment.id,
item.subSizes || []
);
if (updatedAttachment) {
updates.attachment = updatedAttachment;
}
} catch (error) {
console.warn("Media finalization failed:", error);
}
}
dispatch.finishOperation(id, updates);
};
}
function revokeBlobUrls(id) {
return async ({ select, dispatch }) => {
const blobUrls = select.getBlobUrls(id);
for (const blobUrl of blobUrls) {
revokeBlobURL(blobUrl);
}
dispatch({
type: Type.RevokeBlobUrls,
id
});
};
}
function updateItemProgress(id, progress) {
return async ({ dispatch }) => {
dispatch({
type: Type.UpdateProgress,
id,
progress
});
};
}
function updateSettings(settings) {
return {
type: Type.UpdateSettings,
settings
};
}
export {
addItem,
addSideloadItem,
detectUltraHdr,
finalizeItem,
finishOperation,
generateThumbnails,
getTranscodeImageOperation,
pauseItem,
pauseQueue,
prepareItem,
processItem,
removeItem,
resizeCropItem,
resumeQueue,
revokeBlobUrls,
rotateItem,
sideloadItem,
transcodeGifItem,
transcodeImageItem,
updateItemProgress,
updateSettings,
uploadItem
};
//# sourceMappingURL=private-actions.mjs.map