| @@ -44,8 +44,15 @@ | ||
| 44 | 44 | module.exports = window.wp.data; |
| 45 | 45 | } |
| 46 | 46 | }); |
| 47 | 47 | |
| 48 | + // package-external:@wordpress/url | |
| 49 | + var require_url = __commonJS({ | |
| 50 | + "package-external:@wordpress/url"(exports, module) { | |
| 51 | + module.exports = window.wp.url; | |
| 52 | + } | |
| 53 | + }); | |
| 54 | + | |
| 48 | 55 | // package-external:@wordpress/i18n |
| 49 | 56 | var require_i18n = __commonJS({ |
| 50 | 57 | "package-external:@wordpress/i18n"(exports, module) { |
| 51 | 58 | module.exports = window.wp.i18n; |
| @@ -51,15 +58,8 @@ | ||
| 51 | 58 | module.exports = window.wp.i18n; |
| 52 | 59 | } |
| 53 | 60 | }); |
| 54 | 61 | |
| 55 | - // package-external:@wordpress/url | |
| 56 | - var require_url = __commonJS({ | |
| 57 | - "package-external:@wordpress/url"(exports, module) { | |
| 58 | - module.exports = window.wp.url; | |
| 59 | - } | |
| 60 | - }); | |
| 61 | - | |
| 62 | 62 | // package-external:@wordpress/blob |
| 63 | 63 | var require_blob = __commonJS({ |
| 64 | 64 | "package-external:@wordpress/blob"(exports, module) { |
| 65 | 65 | module.exports = window.wp.blob; |
| @@ -96,16 +96,13 @@ | ||
| 96 | 96 | |
| 97 | 97 | // packages/upload-media/build-module/index.mjs |
| 98 | 98 | var index_exports = {}; |
| 99 | 99 | __export(index_exports, { |
| 100 | - ErrorCode: () => ErrorCode, | |
| 101 | 100 | MediaUploadProvider: () => provider_default, |
| 102 | 101 | UploadError: () => UploadError, |
| 103 | 102 | clearFeatureDetectionCache: () => clearFeatureDetectionCache, |
| 104 | 103 | detectClientSideMediaSupport: () => detectClientSideMediaSupport, |
| 105 | - getErrorMessage: () => getErrorMessage, | |
| 106 | 104 | isClientSideMediaSupported: () => isClientSideMediaSupported, |
| 107 | - isHeicCanvasSupported: () => isHeicCanvasSupported, | |
| 108 | 105 | store: () => store |
| 109 | 106 | }); |
| 110 | 107 | |
| 111 | 108 | // packages/upload-media/build-module/store/index.mjs |
| @@ -118,9 +115,8 @@ | ||
| 118 | 115 | Type2["Prepare"] = "PREPARE_ITEM"; |
| 119 | 116 | Type2["Cancel"] = "CANCEL_ITEM"; |
| 120 | 117 | Type2["Remove"] = "REMOVE_ITEM"; |
| 121 | 118 | Type2["RetryItem"] = "RETRY_ITEM"; |
| 122 | - Type2["ScheduleRetry"] = "SCHEDULE_RETRY"; | |
| 123 | 119 | Type2["PauseItem"] = "PAUSE_ITEM"; |
| 124 | 120 | Type2["ResumeItem"] = "RESUME_ITEM"; |
| 125 | 121 | Type2["PauseQueue"] = "PAUSE_QUEUE"; |
| 126 | 122 | Type2["ResumeQueue"] = "RESUME_QUEUE"; |
| @@ -129,9 +125,8 @@ | ||
| 129 | 125 | Type2["AddOperations"] = "ADD_OPERATIONS"; |
| 130 | 126 | Type2["CacheBlobUrl"] = "CACHE_BLOB_URL"; |
| 131 | 127 | Type2["RevokeBlobUrls"] = "REVOKE_BLOB_URLS"; |
| 132 | 128 | Type2["UpdateProgress"] = "UPDATE_PROGRESS"; |
| 133 | - Type2["AccumulateSubSize"] = "ACCUMULATE_SUB_SIZE"; | |
| 134 | 129 | Type2["UpdateSettings"] = "UPDATE_SETTINGS"; |
| 135 | 130 | return Type2; |
| 136 | 131 | })(Type || {}); |
| 137 | 132 | var ItemStatus = /* @__PURE__ */ ((ItemStatus2) => { |
| @@ -137,9 +132,8 @@ | ||
| 137 | 132 | var ItemStatus = /* @__PURE__ */ ((ItemStatus2) => { |
| 138 | 133 | ItemStatus2["Queued"] = "QUEUED"; |
| 139 | 134 | ItemStatus2["Processing"] = "PROCESSING"; |
| 140 | 135 | ItemStatus2["Paused"] = "PAUSED"; |
| 141 | - ItemStatus2["PendingRetry"] = "PENDING_RETRY"; | |
| 142 | 136 | ItemStatus2["Uploaded"] = "UPLOADED"; |
| 143 | 137 | ItemStatus2["Error"] = "ERROR"; |
| 144 | 138 | return ItemStatus2; |
| 145 | 139 | })(ItemStatus || {}); |
| @@ -148,12 +142,9 @@ | ||
| 148 | 142 | OperationType2["Upload"] = "UPLOAD"; |
| 149 | 143 | OperationType2["ResizeCrop"] = "RESIZE_CROP"; |
| 150 | 144 | OperationType2["Rotate"] = "ROTATE"; |
| 151 | 145 | OperationType2["TranscodeImage"] = "TRANSCODE_IMAGE"; |
| 152 | - OperationType2["TranscodeGif"] = "TRANSCODE_GIF"; | |
| 153 | 146 | OperationType2["ThumbnailGeneration"] = "THUMBNAIL_GENERATION"; |
| 154 | - OperationType2["Finalize"] = "FINALIZE"; | |
| 155 | - OperationType2["DetectUltraHdr"] = "DETECT_ULTRAHDR"; | |
| 156 | 147 | return OperationType2; |
| 157 | 148 | })(OperationType || {}); |
| 158 | 149 | |
| 159 | 150 | // packages/upload-media/build-module/store/constants.mjs |
| @@ -159,15 +150,8 @@ | ||
| 159 | 150 | // packages/upload-media/build-module/store/constants.mjs |
| 160 | 151 | var STORE_NAME = "core/upload-media"; |
| 161 | 152 | var DEFAULT_MAX_CONCURRENT_UPLOADS = 5; |
| 162 | 153 | var DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING = 2; |
| 163 | - var DEFAULT_RETRY_SETTINGS = { | |
| 164 | - maxRetryAttempts: 3, | |
| 165 | - initialRetryDelayMs: 1e3, | |
| 166 | - maxRetryDelayMs: 3e4, | |
| 167 | - backoffMultiplier: 2, | |
| 168 | - retryJitter: 0.1 | |
| 169 | - }; | |
| 170 | 154 | var CLIENT_SIDE_SUPPORTED_MIME_TYPES = [ |
| 171 | 155 | "image/jpeg", |
| 172 | 156 | "image/png", |
| 173 | 157 | "image/gif", |
| @@ -173,12 +157,8 @@ | ||
| 173 | 157 | "image/gif", |
| 174 | 158 | "image/webp", |
| 175 | 159 | "image/avif" |
| 176 | 160 | ]; |
| 177 | - var HEIC_MIME_TYPES = [ | |
| 178 | - "image/heic", | |
| 179 | - "image/heif" | |
| 180 | - ]; | |
| 181 | 161 | |
| 182 | 162 | // packages/upload-media/build-module/store/reducer.mjs |
| 183 | 163 | var noop = () => { |
| 184 | 164 | }; |
| @@ -188,10 +168,9 @@ | ||
| 188 | 168 | blobUrls: {}, |
| 189 | 169 | settings: { |
| 190 | 170 | mediaUpload: noop, |
| 191 | 171 | maxConcurrentUploads: DEFAULT_MAX_CONCURRENT_UPLOADS, |
| 192 | - maxConcurrentImageProcessing: DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING, | |
| 193 | - retry: { ...DEFAULT_RETRY_SETTINGS } | |
| 172 | + maxConcurrentImageProcessing: DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING | |
| 194 | 173 | } |
| 195 | 174 | }; |
| 196 | 175 | function reducer(state = DEFAULT_STATE, action = { type: Type.Unknown }) { |
| 197 | 176 | switch (action.type) { |
| @@ -249,26 +228,12 @@ | ||
| 249 | 228 | (item) => item.id === action.id ? { |
| 250 | 229 | ...item, |
| 251 | 230 | status: ItemStatus.Processing, |
| 252 | 231 | error: void 0, |
| 253 | - retryCount: (item.retryCount ?? 0) + 1, | |
| 254 | - abortController: new AbortController() | |
| 232 | + retryCount: (item.retryCount ?? 0) + 1 | |
| 255 | 233 | } : item |
| 256 | 234 | ) |
| 257 | 235 | }; |
| 258 | - case Type.ScheduleRetry: | |
| 259 | - return { | |
| 260 | - ...state, | |
| 261 | - queue: state.queue.map( | |
| 262 | - (item) => item.id === action.id ? { | |
| 263 | - ...item, | |
| 264 | - status: ItemStatus.PendingRetry, | |
| 265 | - error: action.error, | |
| 266 | - retryCount: action.retryCount, | |
| 267 | - nextRetryTimestamp: action.nextRetryTimestamp | |
| 268 | - } : item | |
| 269 | - ) | |
| 270 | - }; | |
| 271 | 236 | case Type.Remove: |
| 272 | 237 | return { |
| 273 | 238 | ...state, |
| 274 | 239 | queue: state.queue.filter((item) => item.id !== action.id) |
| @@ -352,21 +317,8 @@ | ||
| 352 | 317 | progress: action.progress |
| 353 | 318 | } : item |
| 354 | 319 | ) |
| 355 | 320 | }; |
| 356 | - case Type.AccumulateSubSize: | |
| 357 | - return { | |
| 358 | - ...state, | |
| 359 | - queue: state.queue.map( | |
| 360 | - (item) => item.id === action.id ? { | |
| 361 | - ...item, | |
| 362 | - subSizes: [ | |
| 363 | - ...item.subSizes || [], | |
| 364 | - action.subSize | |
| 365 | - ] | |
| 366 | - } : item | |
| 367 | - ) | |
| 368 | - }; | |
| 369 | 321 | case Type.UpdateSettings: { |
| 370 | 322 | return { |
| 371 | 323 | ...state, |
| 372 | 324 | settings: { |
| @@ -413,20 +365,20 @@ | ||
| 413 | 365 | var private_selectors_exports = {}; |
| 414 | 366 | __export(private_selectors_exports, { |
| 415 | 367 | getActiveImageProcessingCount: () => getActiveImageProcessingCount, |
| 416 | 368 | getActiveUploadCount: () => getActiveUploadCount, |
| 417 | - getActiveVideoProcessingCount: () => getActiveVideoProcessingCount, | |
| 418 | 369 | getAllItems: () => getAllItems, |
| 419 | 370 | getBlobUrls: () => getBlobUrls, |
| 420 | 371 | getFailedItems: () => getFailedItems, |
| 421 | 372 | getItem: () => getItem, |
| 422 | 373 | getItemProgress: () => getItemProgress, |
| 374 | + getPausedUploadForPost: () => getPausedUploadForPost, | |
| 423 | 375 | getPendingImageProcessing: () => getPendingImageProcessing, |
| 424 | 376 | getPendingUploads: () => getPendingUploads, |
| 425 | - getPendingVideoProcessing: () => getPendingVideoProcessing, | |
| 426 | 377 | hasPendingItemsByParentId: () => hasPendingItemsByParentId, |
| 427 | 378 | isBatchUploaded: () => isBatchUploaded, |
| 428 | - isPaused: () => isPaused | |
| 379 | + isPaused: () => isPaused, | |
| 380 | + isUploadingToPost: () => isUploadingToPost | |
| 429 | 381 | }); |
| 430 | 382 | function getAllItems(state) { |
| 431 | 383 | return state.queue; |
| 432 | 384 | } |
| @@ -438,8 +390,18 @@ | ||
| 438 | 390 | (item) => batchId === item.batchId |
| 439 | 391 | ); |
| 440 | 392 | return batchItems.length === 0; |
| 441 | 393 | } |
| 394 | + function isUploadingToPost(state, postOrAttachmentId) { | |
| 395 | + return state.queue.some( | |
| 396 | + (item) => item.currentOperation === OperationType.Upload && item.additionalData.post === postOrAttachmentId | |
| 397 | + ); | |
| 398 | + } | |
| 399 | + function getPausedUploadForPost(state, postOrAttachmentId) { | |
| 400 | + return state.queue.find( | |
| 401 | + (item) => item.status === ItemStatus.Paused && item.additionalData.post === postOrAttachmentId | |
| 402 | + ); | |
| 403 | + } | |
| 442 | 404 | function isPaused(state) { |
| 443 | 405 | return state.queueStatus === "paused"; |
| 444 | 406 | } |
| 445 | 407 | function getBlobUrls(state, id) { |
| @@ -460,13 +422,8 @@ | ||
| 460 | 422 | return state.queue.filter( |
| 461 | 423 | (item) => item.currentOperation === OperationType.ResizeCrop || item.currentOperation === OperationType.Rotate |
| 462 | 424 | ).length; |
| 463 | 425 | } |
| 464 | - function getActiveVideoProcessingCount(state) { | |
| 465 | - return state.queue.filter( | |
| 466 | - (item) => item.currentOperation === OperationType.TranscodeGif | |
| 467 | - ).length; | |
| 468 | - } | |
| 469 | 426 | function getPendingImageProcessing(state) { |
| 470 | 427 | return state.queue.filter((item) => { |
| 471 | 428 | const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; |
| 472 | 429 | return (nextOperation === OperationType.ResizeCrop || nextOperation === OperationType.Rotate) && item.currentOperation !== OperationType.ResizeCrop && item.currentOperation !== OperationType.Rotate; |
| @@ -471,14 +428,8 @@ | ||
| 471 | 428 | const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; |
| 472 | 429 | return (nextOperation === OperationType.ResizeCrop || nextOperation === OperationType.Rotate) && item.currentOperation !== OperationType.ResizeCrop && item.currentOperation !== OperationType.Rotate; |
| 473 | 430 | }); |
| 474 | 431 | } |
| 475 | - function getPendingVideoProcessing(state) { | |
| 476 | - return state.queue.filter((item) => { | |
| 477 | - const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; | |
| 478 | - return nextOperation === OperationType.TranscodeGif && item.currentOperation !== OperationType.TranscodeGif; | |
| 479 | - }); | |
| 480 | - } | |
| 481 | 432 | function getFailedItems(state) { |
| 482 | 433 | return state.queue.filter((item) => item.error !== void 0); |
| 483 | 434 | } |
| 484 | 435 | function hasPendingItemsByParentId(state, parentId) { |
| @@ -493,48 +444,50 @@ | ||
| 493 | 444 | var actions_exports = {}; |
| 494 | 445 | __export(actions_exports, { |
| 495 | 446 | addItems: () => addItems, |
| 496 | 447 | cancelItem: () => cancelItem, |
| 497 | - executeRetry: () => executeRetry, | |
| 498 | - retryItem: () => retryItem, | |
| 499 | - scheduleRetry: () => scheduleRetry | |
| 448 | + retryItem: () => retryItem | |
| 500 | 449 | }); |
| 501 | 450 | |
| 502 | - // node_modules/uuid/dist/stringify.js | |
| 451 | + // node_modules/uuid/dist/esm-browser/rng.js | |
| 452 | + var getRandomValues; | |
| 453 | + var rnds8 = new Uint8Array(16); | |
| 454 | + function rng() { | |
| 455 | + if (!getRandomValues) { | |
| 456 | + getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); | |
| 457 | + if (!getRandomValues) { | |
| 458 | + throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported"); | |
| 459 | + } | |
| 460 | + } | |
| 461 | + return getRandomValues(rnds8); | |
| 462 | + } | |
| 463 | + | |
| 464 | + // node_modules/uuid/dist/esm-browser/stringify.js | |
| 503 | 465 | var byteToHex = []; |
| 504 | 466 | for (let i = 0; i < 256; ++i) { |
| 505 | 467 | byteToHex.push((i + 256).toString(16).slice(1)); |
| 506 | 468 | } |
| 507 | 469 | function unsafeStringify(arr, offset = 0) { |
| 508 | - return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); | |
| 470 | + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; | |
| 509 | 471 | } |
| 510 | 472 | |
| 511 | - // node_modules/uuid/dist/rng.js | |
| 512 | - var rnds8 = new Uint8Array(16); | |
| 513 | - function rng() { | |
| 514 | - return crypto.getRandomValues(rnds8); | |
| 515 | - } | |
| 473 | + // node_modules/uuid/dist/esm-browser/native.js | |
| 474 | + var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto); | |
| 475 | + var native_default = { | |
| 476 | + randomUUID | |
| 477 | + }; | |
| 516 | 478 | |
| 517 | - // node_modules/uuid/dist/v4.js | |
| 479 | + // node_modules/uuid/dist/esm-browser/v4.js | |
| 518 | 480 | function v4(options, buf, offset) { |
| 519 | - if (!buf && !options && crypto.randomUUID) { | |
| 520 | - return crypto.randomUUID(); | |
| 481 | + if (native_default.randomUUID && !buf && !options) { | |
| 482 | + return native_default.randomUUID(); | |
| 521 | 483 | } |
| 522 | - return _v4(options, buf, offset); | |
| 523 | - } | |
| 524 | - function _v4(options, buf, offset) { | |
| 525 | 484 | options = options || {}; |
| 526 | - const rnds = options.random ?? options.rng?.() ?? rng(); | |
| 527 | - if (rnds.length < 16) { | |
| 528 | - throw new Error("Random bytes length must be >= 16"); | |
| 529 | - } | |
| 485 | + const rnds = options.random || (options.rng || rng)(); | |
| 530 | 486 | rnds[6] = rnds[6] & 15 | 64; |
| 531 | 487 | rnds[8] = rnds[8] & 63 | 128; |
| 532 | 488 | if (buf) { |
| 533 | 489 | offset = offset || 0; |
| 534 | - if (offset < 0 || offset + 16 > buf.length) { | |
| 535 | - throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`); | |
| 536 | - } | |
| 537 | 490 | for (let i = 0; i < 16; ++i) { |
| 538 | 491 | buf[offset + i] = rnds[i]; |
| 539 | 492 | } |
| 540 | 493 | return buf; |
| @@ -542,50 +495,8 @@ | ||
| 542 | 495 | return unsafeStringify(rnds); |
| 543 | 496 | } |
| 544 | 497 | var v4_default = v4; |
| 545 | 498 | |
| 546 | - // packages/upload-media/build-module/store/actions.mjs | |
| 547 | - var import_i18n5 = __toESM(require_i18n(), 1); | |
| 548 | - | |
| 549 | - // packages/upload-media/build-module/store/utils/retry.mjs | |
| 550 | - function calculateRetryDelay(options) { | |
| 551 | - const { attempt, initialDelay, maxDelay, multiplier, jitter } = options; | |
| 552 | - const exponentialDelay = initialDelay * Math.pow(multiplier, attempt - 1); | |
| 553 | - const cappedDelay = Math.min(exponentialDelay, maxDelay); | |
| 554 | - const jitterFactor = 1 + (Math.random() * 2 - 1) * jitter; | |
| 555 | - return Math.floor(cappedDelay * jitterFactor); | |
| 556 | - } | |
| 557 | - var RETRYABLE_MESSAGE_PATTERNS = [ | |
| 558 | - /network/i, | |
| 559 | - /timeout/i, | |
| 560 | - /ECONNRESET/i, | |
| 561 | - /fetch failed/i, | |
| 562 | - /connection/i, | |
| 563 | - /socket/i, | |
| 564 | - /ETIMEDOUT/i, | |
| 565 | - /ENOTFOUND/i, | |
| 566 | - /Could not get a valid response/i, | |
| 567 | - /Failed to fetch/i, | |
| 568 | - /Load failed/i | |
| 569 | - ]; | |
| 570 | - function shouldRetryError(error, retryCount, maxRetries) { | |
| 571 | - if (retryCount >= maxRetries) { | |
| 572 | - return false; | |
| 573 | - } | |
| 574 | - const message = typeof error === "string" ? error : error?.message || ""; | |
| 575 | - return RETRYABLE_MESSAGE_PATTERNS.some( | |
| 576 | - (pattern) => pattern.test(message) | |
| 577 | - ); | |
| 578 | - } | |
| 579 | - var retryTimers = /* @__PURE__ */ new Map(); | |
| 580 | - function clearRetryTimer(id) { | |
| 581 | - const pendingTimer = retryTimers.get(id); | |
| 582 | - if (pendingTimer !== void 0) { | |
| 583 | - clearTimeout(pendingTimer); | |
| 584 | - retryTimers.delete(id); | |
| 585 | - } | |
| 586 | - } | |
| 587 | - | |
| 588 | 499 | // packages/upload-media/build-module/image-file.mjs |
| 589 | 500 | var ImageFile = class extends File { |
| 590 | 501 | width = 0; |
| 591 | 502 | height = 0; |
| @@ -636,24 +547,8 @@ | ||
| 636 | 547 | } |
| 637 | 548 | function getFileBasename(name) { |
| 638 | 549 | return name.includes(".") ? name.split(".").slice(0, -1).join(".") : name; |
| 639 | 550 | } |
| 640 | - function isAnimatedGif(buffer) { | |
| 641 | - const view = new Uint8Array(buffer); | |
| 642 | - if (view.length < 4 || view[0] !== 71 || view[1] !== 73 || view[2] !== 70 || view[3] !== 56) { | |
| 643 | - return false; | |
| 644 | - } | |
| 645 | - let frameCount = 0; | |
| 646 | - for (let i = 0; i < view.length - 2; i++) { | |
| 647 | - if (view[i] === 0 && view[i + 1] === 33 && view[i + 2] === 249) { | |
| 648 | - frameCount++; | |
| 649 | - if (frameCount > 1) { | |
| 650 | - return true; | |
| 651 | - } | |
| 652 | - } | |
| 653 | - } | |
| 654 | - return false; | |
| 655 | - } | |
| 656 | 551 | |
| 657 | 552 | // packages/upload-media/build-module/store/utils/index.mjs |
| 658 | 553 | var vipsModulePromise; |
| 659 | 554 | var vipsModule; |
| @@ -667,9 +562,9 @@ | ||
| 667 | 562 | ); |
| 668 | 563 | } |
| 669 | 564 | return vipsModulePromise; |
| 670 | 565 | } |
| 671 | - async function vipsConvertImageFormat(id, file, type, options = {}) { | |
| 566 | + async function vipsConvertImageFormat(id, file, type, quality, interlaced) { | |
| 672 | 567 | const { vipsConvertImageFormat: convertImageFormat } = await loadVipsModule(); |
| 673 | 568 | const buffer = await convertImageFormat( |
| 674 | 569 | id, |
| 675 | 570 | await file.arrayBuffer(), |
| @@ -674,9 +569,10 @@ | ||
| 674 | 569 | id, |
| 675 | 570 | await file.arrayBuffer(), |
| 676 | 571 | file.type, |
| 677 | 572 | type, |
| 678 | - options | |
| 573 | + quality, | |
| 574 | + interlaced | |
| 679 | 575 | ); |
| 680 | 576 | const ext = type.split("/")[1]; |
| 681 | 577 | const fileName = `${getFileBasename(file.name)}.${ext}`; |
| 682 | 578 | return new File([new Blob([buffer])], fileName, { |
| @@ -690,32 +586,21 @@ | ||
| 690 | 586 | throw new Error(`Failed to fetch image: ${response.status}`); |
| 691 | 587 | } |
| 692 | 588 | return hasTransparency(await response.arrayBuffer()); |
| 693 | 589 | } |
| 694 | - async function vipsGetUltraHdrInfo(buffer) { | |
| 695 | - const { vipsGetUltraHdrInfo: getUltraHdrInfo } = await loadVipsModule(); | |
| 696 | - return getUltraHdrInfo(buffer); | |
| 697 | - } | |
| 698 | - async function vipsResizeImage(id, file, resize, options = {}) { | |
| 699 | - const { | |
| 700 | - smartCrop = false, | |
| 701 | - addSuffix = false, | |
| 702 | - signal, | |
| 703 | - scaledSuffix, | |
| 704 | - quality, | |
| 705 | - stripMeta, | |
| 706 | - maxBitdepth | |
| 707 | - } = options; | |
| 590 | + async function vipsResizeImage(id, file, resize, smartCrop, addSuffix, signal, scaledSuffix, quality) { | |
| 708 | 591 | if (signal?.aborted) { |
| 709 | 592 | throw new Error("Operation aborted"); |
| 710 | 593 | } |
| 711 | 594 | const { vipsResizeImage: resizeImage } = await loadVipsModule(); |
| 712 | - const { buffer, width, height, originalWidth, originalHeight } = await resizeImage(id, await file.arrayBuffer(), file.type, resize, { | |
| 595 | + const { buffer, width, height, originalWidth, originalHeight } = await resizeImage( | |
| 596 | + id, | |
| 597 | + await file.arrayBuffer(), | |
| 598 | + file.type, | |
| 599 | + resize, | |
| 713 | 600 | smartCrop, |
| 714 | - quality, | |
| 715 | - stripMeta, | |
| 716 | - maxBitdepth | |
| 717 | - }); | |
| 601 | + quality | |
| 602 | + ); | |
| 718 | 603 | let fileName = file.name; |
| 719 | 604 | const wasResized = originalWidth > width || originalHeight > height; |
| 720 | 605 | if (wasResized) { |
| 721 | 606 | const basename = getFileBasename(file.name); |
| @@ -782,171 +667,13 @@ | ||
| 782 | 667 | if (vipsModule) { |
| 783 | 668 | vipsModule.terminateVipsWorker(); |
| 784 | 669 | } |
| 785 | 670 | } |
| 786 | - var completedVipsOperations = 0; | |
| 787 | - var MAX_VIPS_OPS_BEFORE_RECYCLE = 50; | |
| 788 | - function maybeRecycleVipsWorker(activeImageProcessingCount) { | |
| 789 | - completedVipsOperations++; | |
| 790 | - if (completedVipsOperations >= MAX_VIPS_OPS_BEFORE_RECYCLE && activeImageProcessingCount === 0) { | |
| 791 | - terminateVipsWorker(); | |
| 792 | - completedVipsOperations = 0; | |
| 793 | - } | |
| 794 | - } | |
| 795 | 671 | |
| 796 | - // packages/upload-media/build-module/store/utils/video-conversion.mjs | |
| 797 | - var UNSUPPORTED_ERROR_PREFIX = "Unsupported"; | |
| 798 | - var SIZE_LIMIT_ERROR_PREFIX = `${UNSUPPORTED_ERROR_PREFIX}: GIF exceeds maximum conversion size`; | |
| 799 | - var CONVERSION_TIMEOUT_ERROR_PREFIX = "GIF to video conversion timed out"; | |
| 800 | - var DEFAULT_CONVERSION_TIMEOUT = 3e4; | |
| 801 | - function isUnsupportedConversionError(error) { | |
| 802 | - return error instanceof Error && error.message.startsWith(UNSUPPORTED_ERROR_PREFIX); | |
| 803 | - } | |
| 804 | - function isSizeLimitConversionError(error) { | |
| 805 | - return error instanceof Error && error.message.startsWith(SIZE_LIMIT_ERROR_PREFIX); | |
| 806 | - } | |
| 807 | - function isConversionTimeoutError(error) { | |
| 808 | - return error instanceof Error && error.message.startsWith(CONVERSION_TIMEOUT_ERROR_PREFIX); | |
| 809 | - } | |
| 810 | - var videoConversionModulePromise; | |
| 811 | - var videoConversionModule; | |
| 812 | - function loadVideoConversionModule() { | |
| 813 | - if (!videoConversionModulePromise) { | |
| 814 | - videoConversionModulePromise = import("@wordpress/video-conversion/worker").then((mod) => { | |
| 815 | - videoConversionModule = mod; | |
| 816 | - return mod; | |
| 817 | - }).catch((error) => { | |
| 818 | - videoConversionModulePromise = void 0; | |
| 819 | - throw error; | |
| 820 | - }); | |
| 821 | - } | |
| 822 | - return videoConversionModulePromise; | |
| 823 | - } | |
| 824 | - async function convertGifToVideo(id, file, outputMimeType, { | |
| 825 | - maxDimensions, | |
| 826 | - timeout = DEFAULT_CONVERSION_TIMEOUT, | |
| 827 | - maxTotalPixels | |
| 828 | - } = {}) { | |
| 829 | - const mod = await loadVideoConversionModule(); | |
| 830 | - const conversion = mod.convertGifToVideo( | |
| 831 | - id, | |
| 832 | - file, | |
| 833 | - outputMimeType, | |
| 834 | - maxDimensions, | |
| 835 | - maxTotalPixels | |
| 836 | - ); | |
| 837 | - let buffer; | |
| 838 | - if (timeout > 0) { | |
| 839 | - let timer; | |
| 840 | - try { | |
| 841 | - buffer = await Promise.race([ | |
| 842 | - conversion, | |
| 843 | - new Promise((_, reject) => { | |
| 844 | - timer = setTimeout(() => { | |
| 845 | - reject( | |
| 846 | - new Error( | |
| 847 | - `${CONVERSION_TIMEOUT_ERROR_PREFIX} after ${timeout}ms` | |
| 848 | - ) | |
| 849 | - ); | |
| 850 | - }, timeout); | |
| 851 | - }) | |
| 852 | - ]); | |
| 853 | - } catch (error) { | |
| 854 | - if (isConversionTimeoutError(error)) { | |
| 855 | - conversion.catch(() => { | |
| 856 | - }); | |
| 857 | - mod.cancelGifToVideoOperations(id).catch(() => { | |
| 858 | - }); | |
| 859 | - } | |
| 860 | - throw error; | |
| 861 | - } finally { | |
| 862 | - clearTimeout(timer); | |
| 863 | - } | |
| 864 | - } else { | |
| 865 | - buffer = await conversion; | |
| 866 | - } | |
| 867 | - const ext = outputMimeType === "video/webm" ? "webm" : "mp4"; | |
| 868 | - const fileName = `${getFileBasename(file.name)}.${ext}`; | |
| 869 | - return new File( | |
| 870 | - [new Blob([buffer], { type: outputMimeType })], | |
| 871 | - fileName, | |
| 872 | - { type: outputMimeType } | |
| 873 | - ); | |
| 874 | - } | |
| 875 | - async function cancelGifToVideoOperations(id) { | |
| 876 | - const mod = videoConversionModule ?? (videoConversionModulePromise ? await videoConversionModulePromise.catch(() => void 0) : void 0); | |
| 877 | - if (!mod) { | |
| 878 | - return false; | |
| 879 | - } | |
| 880 | - return mod.cancelGifToVideoOperations(id); | |
| 881 | - } | |
| 882 | - function terminateVideoConversionWorker() { | |
| 883 | - if (videoConversionModule) { | |
| 884 | - videoConversionModule.terminateVideoConversionWorker(); | |
| 885 | - return; | |
| 886 | - } | |
| 887 | - if (videoConversionModulePromise) { | |
| 888 | - void videoConversionModulePromise.then((mod) => mod.terminateVideoConversionWorker()).catch(() => { | |
| 889 | - }); | |
| 890 | - } | |
| 891 | - } | |
| 672 | + // packages/upload-media/build-module/validate-mime-type.mjs | |
| 673 | + var import_i18n2 = __toESM(require_i18n(), 1); | |
| 892 | 674 | |
| 893 | - // packages/upload-media/build-module/store/utils/debug-logger.mjs | |
| 894 | - function isDebugEnabled() { | |
| 895 | - return true; | |
| 896 | - } | |
| 897 | - function debug(message, ...args) { | |
| 898 | - if (!isDebugEnabled()) { | |
| 899 | - return; | |
| 900 | - } | |
| 901 | - console.debug(`[upload-media] ${message}`, ...args); | |
| 902 | - } | |
| 903 | - function measure(options) { | |
| 904 | - if (!isDebugEnabled()) { | |
| 905 | - return; | |
| 906 | - } | |
| 907 | - const { | |
| 908 | - measureName, | |
| 909 | - startTime, | |
| 910 | - endTime = performance.now(), | |
| 911 | - tooltipText, | |
| 912 | - properties | |
| 913 | - } = options; | |
| 914 | - const detail = { | |
| 915 | - devtools: { | |
| 916 | - dataType: "track-entry", | |
| 917 | - track: "Upload Media", | |
| 918 | - tooltipText, | |
| 919 | - properties: properties?.map(([key, value]) => ({ | |
| 920 | - key, | |
| 921 | - value | |
| 922 | - })) | |
| 923 | - } | |
| 924 | - }; | |
| 925 | - try { | |
| 926 | - performance.measure(measureName, { | |
| 927 | - start: startTime, | |
| 928 | - end: endTime, | |
| 929 | - detail | |
| 930 | - }); | |
| 931 | - } catch { | |
| 932 | - } | |
| 933 | - } | |
| 934 | - | |
| 935 | 675 | // packages/upload-media/build-module/upload-error.mjs |
| 936 | - var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => { | |
| 937 | - ErrorCode2["EMPTY_FILE"] = "EMPTY_FILE"; | |
| 938 | - ErrorCode2["SIZE_ABOVE_LIMIT"] = "SIZE_ABOVE_LIMIT"; | |
| 939 | - ErrorCode2["MIME_TYPE_NOT_SUPPORTED"] = "MIME_TYPE_NOT_SUPPORTED"; | |
| 940 | - ErrorCode2["MIME_TYPE_NOT_ALLOWED_FOR_USER"] = "MIME_TYPE_NOT_ALLOWED_FOR_USER"; | |
| 941 | - ErrorCode2["HEIC_DECODE_ERROR"] = "HEIC_DECODE_ERROR"; | |
| 942 | - ErrorCode2["IMAGE_TRANSCODING_ERROR"] = "IMAGE_TRANSCODING_ERROR"; | |
| 943 | - ErrorCode2["IMAGE_ROTATION_ERROR"] = "IMAGE_ROTATION_ERROR"; | |
| 944 | - ErrorCode2["MEDIA_TRANSCODING_ERROR"] = "MEDIA_TRANSCODING_ERROR"; | |
| 945 | - ErrorCode2["GIF_TRANSCODING_ERROR"] = "GIF_TRANSCODING_ERROR"; | |
| 946 | - ErrorCode2["GENERAL"] = "GENERAL"; | |
| 947 | - return ErrorCode2; | |
| 948 | - })(ErrorCode || {}); | |
| 949 | 676 | var UploadError = class extends Error { |
| 950 | 677 | code; |
| 951 | 678 | file; |
| 952 | 679 | constructor({ code, message, file, cause }) { |
| @@ -957,9 +684,8 @@ | ||
| 957 | 684 | } |
| 958 | 685 | }; |
| 959 | 686 | |
| 960 | 687 | // packages/upload-media/build-module/validate-mime-type.mjs |
| 961 | - var import_i18n2 = __toESM(require_i18n(), 1); | |
| 962 | 688 | function validateMimeType(file, allowedTypes) { |
| 963 | 689 | if (!allowedTypes) { |
| 964 | 690 | return; |
| 965 | 691 | } |
| @@ -970,9 +696,9 @@ | ||
| 970 | 696 | return file.type.startsWith(`${allowedType}/`); |
| 971 | 697 | }); |
| 972 | 698 | if (file.type && !isAllowedType) { |
| 973 | 699 | throw new UploadError({ |
| 974 | - code: ErrorCode.MIME_TYPE_NOT_SUPPORTED, | |
| 700 | + code: "MIME_TYPE_NOT_SUPPORTED", | |
| 975 | 701 | message: (0, import_i18n2.sprintf)( |
| 976 | 702 | // translators: %s: file name. |
| 977 | 703 | (0, import_i18n2.__)("%s: Sorry, this file type is not supported here."), |
| 978 | 704 | file.name |
| @@ -1014,9 +740,9 @@ | ||
| 1014 | 740 | file.type |
| 1015 | 741 | ); |
| 1016 | 742 | if (file.type && !isAllowedMimeTypeForUser) { |
| 1017 | 743 | throw new UploadError({ |
| 1018 | - code: ErrorCode.MIME_TYPE_NOT_ALLOWED_FOR_USER, | |
| 744 | + code: "MIME_TYPE_NOT_ALLOWED_FOR_USER", | |
| 1019 | 745 | message: (0, import_i18n3.sprintf)( |
| 1020 | 746 | // translators: %s: file name. |
| 1021 | 747 | (0, import_i18n3.__)( |
| 1022 | 748 | "%s: Sorry, you are not allowed to upload this file type." |
| @@ -1032,9 +758,9 @@ | ||
| 1032 | 758 | var import_i18n4 = __toESM(require_i18n(), 1); |
| 1033 | 759 | function validateFileSize(file, maxUploadFileSize) { |
| 1034 | 760 | if (file.size <= 0) { |
| 1035 | 761 | throw new UploadError({ |
| 1036 | - code: ErrorCode.EMPTY_FILE, | |
| 762 | + code: "EMPTY_FILE", | |
| 1037 | 763 | message: (0, import_i18n4.sprintf)( |
| 1038 | 764 | // translators: %s: file name. |
| 1039 | 765 | (0, import_i18n4.__)("%s: This file is empty."), |
| 1040 | 766 | file.name |
| @@ -1043,9 +769,9 @@ | ||
| 1043 | 769 | }); |
| 1044 | 770 | } |
| 1045 | 771 | if (maxUploadFileSize && file.size > maxUploadFileSize) { |
| 1046 | 772 | throw new UploadError({ |
| 1047 | - code: ErrorCode.SIZE_ABOVE_LIMIT, | |
| 773 | + code: "SIZE_ABOVE_LIMIT", | |
| 1048 | 774 | message: (0, import_i18n4.sprintf)( |
| 1049 | 775 | // translators: %s: file name. |
| 1050 | 776 | (0, import_i18n4.__)( |
| 1051 | 777 | "%s: This file exceeds the maximum upload size for this site." |
| @@ -1106,38 +832,17 @@ | ||
| 1106 | 832 | const item = select2.getItem(id); |
| 1107 | 833 | if (!item) { |
| 1108 | 834 | return; |
| 1109 | 835 | } |
| 1110 | - clearRetryTimer(id); | |
| 1111 | - if (!silent && error && !item.parentId && !item.attachment?.id) { | |
| 1112 | - const settings = select2.getSettings(); | |
| 1113 | - const retrySettings = settings.retry; | |
| 1114 | - if (retrySettings) { | |
| 1115 | - const retryCount = item.retryCount ?? 0; | |
| 1116 | - const maxRetries = retrySettings.maxRetryAttempts; | |
| 1117 | - if (shouldRetryError(error, retryCount, maxRetries)) { | |
| 1118 | - dispatch.scheduleRetry(id, error); | |
| 1119 | - return; | |
| 1120 | - } | |
| 1121 | - } | |
| 1122 | - } | |
| 1123 | 836 | item.abortController?.abort(); |
| 1124 | - vipsCancelOperations(id).catch(() => { | |
| 1125 | - }); | |
| 1126 | - cancelGifToVideoOperations(id).catch(() => { | |
| 1127 | - }); | |
| 837 | + await vipsCancelOperations(id); | |
| 1128 | 838 | if (!silent) { |
| 1129 | 839 | const { onError } = item; |
| 1130 | 840 | onError?.(error ?? new Error("Upload cancelled")); |
| 1131 | - if (!onError && error && !item.parentId) { | |
| 841 | + if (!onError && error) { | |
| 1132 | 842 | console.error("Upload cancelled", error); |
| 1133 | 843 | } |
| 1134 | - } else { | |
| 1135 | - debug( | |
| 1136 | - `Item cancelled: ${item.file.name} (item ${id}): ${error instanceof Error ? error.message : error}` | |
| 1137 | - ); | |
| 1138 | 844 | } |
| 1139 | - const { currentOperation, parentId, batchId } = item; | |
| 1140 | 845 | dispatch({ |
| 1141 | 846 | type: Type.Cancel, |
| 1142 | 847 | id, |
| 1143 | 848 | error |
| @@ -1143,59 +848,9 @@ | ||
| 1143 | 848 | error |
| 1144 | 849 | }); |
| 1145 | 850 | dispatch.removeItem(id); |
| 1146 | 851 | dispatch.revokeBlobUrls(id); |
| 1147 | - if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate) { | |
| 1148 | - for (const pending of select2.getPendingImageProcessing()) { | |
| 1149 | - dispatch.processItem(pending.id); | |
| 1150 | - } | |
| 1151 | - } | |
| 1152 | - if (currentOperation === OperationType.Upload) { | |
| 1153 | - for (const pending of select2.getPendingUploads()) { | |
| 1154 | - dispatch.processItem(pending.id); | |
| 1155 | - } | |
| 1156 | - } | |
| 1157 | - if (currentOperation === OperationType.TranscodeGif) { | |
| 1158 | - for (const pending of select2.getPendingVideoProcessing()) { | |
| 1159 | - dispatch.processItem(pending.id); | |
| 1160 | - } | |
| 1161 | - } | |
| 1162 | - if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate || currentOperation === OperationType.TranscodeImage) { | |
| 1163 | - maybeRecycleVipsWorker(select2.getActiveImageProcessingCount()); | |
| 1164 | - } | |
| 1165 | - if (parentId) { | |
| 1166 | - const parentItem = select2.getItem(parentId); | |
| 1167 | - if (parentItem) { | |
| 1168 | - const isOptionalCompanion = item.additionalData?.image_size === "animated_video" || item.additionalData?.image_size === "animated_video_poster"; | |
| 1169 | - if (select2.hasPendingItemsByParentId(parentId)) { | |
| 1170 | - if (parentItem.operations && parentItem.operations.length > 0) { | |
| 1171 | - dispatch.processItem(parentId); | |
| 1172 | - } | |
| 1173 | - } else if (parentItem.subSizes && parentItem.subSizes.length > 0 || isOptionalCompanion) { | |
| 1174 | - if (parentItem.operations && parentItem.operations.length > 0) { | |
| 1175 | - dispatch.processItem(parentId); | |
| 1176 | - } | |
| 1177 | - } else { | |
| 1178 | - const parentAttachmentId = parentItem.attachment?.id; | |
| 1179 | - const { mediaDelete } = select2.getSettings(); | |
| 1180 | - if (parentAttachmentId && mediaDelete) { | |
| 1181 | - mediaDelete(parentAttachmentId).catch(() => { | |
| 1182 | - }); | |
| 1183 | - } | |
| 1184 | - await dispatch.cancelItem( | |
| 1185 | - parentId, | |
| 1186 | - new UploadError({ | |
| 1187 | - code: error instanceof UploadError && error.code || ErrorCode.GENERAL, | |
| 1188 | - message: error?.message || (0, import_i18n5.__)("The image could not be uploaded."), | |
| 1189 | - file: parentItem.file, | |
| 1190 | - cause: error instanceof Error ? error : void 0 | |
| 1191 | - }) | |
| 1192 | - ); | |
| 1193 | - } | |
| 1194 | - } | |
| 1195 | - } | |
| 1196 | - if (batchId && select2.isBatchUploaded(batchId)) { | |
| 1197 | - debug(`Batch completed: ${batchId}`); | |
| 852 | + if (item.batchId && select2.isBatchUploaded(item.batchId)) { | |
| 1198 | 853 | item.onBatchSuccess?.(); |
| 1199 | 854 | } |
| 1200 | 855 | }; |
| 1201 | 856 | } |
| @@ -1214,57 +869,8 @@ | ||
| 1214 | 869 | }); |
| 1215 | 870 | dispatch.processItem(id); |
| 1216 | 871 | }; |
| 1217 | 872 | } |
| 1218 | - function scheduleRetry(id, error) { | |
| 1219 | - return async ({ select: select2, dispatch }) => { | |
| 1220 | - const item = select2.getItem(id); | |
| 1221 | - if (!item) { | |
| 1222 | - return; | |
| 1223 | - } | |
| 1224 | - const settings = select2.getSettings(); | |
| 1225 | - const retrySettings = settings.retry; | |
| 1226 | - if (!retrySettings) { | |
| 1227 | - return; | |
| 1228 | - } | |
| 1229 | - const currentRetryCount = item.retryCount ?? 0; | |
| 1230 | - const delay = calculateRetryDelay({ | |
| 1231 | - attempt: currentRetryCount + 1, | |
| 1232 | - initialDelay: retrySettings.initialRetryDelayMs, | |
| 1233 | - maxDelay: retrySettings.maxRetryDelayMs, | |
| 1234 | - multiplier: retrySettings.backoffMultiplier, | |
| 1235 | - jitter: retrySettings.retryJitter | |
| 1236 | - }); | |
| 1237 | - const timerId = setTimeout(() => { | |
| 1238 | - retryTimers.delete(id); | |
| 1239 | - dispatch.executeRetry(id); | |
| 1240 | - }, delay); | |
| 1241 | - retryTimers.set(id, timerId); | |
| 1242 | - dispatch({ | |
| 1243 | - type: Type.ScheduleRetry, | |
| 1244 | - id, | |
| 1245 | - error, | |
| 1246 | - retryCount: currentRetryCount, | |
| 1247 | - nextRetryTimestamp: Date.now() + delay | |
| 1248 | - }); | |
| 1249 | - }; | |
| 1250 | - } | |
| 1251 | - function executeRetry(id) { | |
| 1252 | - return async ({ select: select2, dispatch }) => { | |
| 1253 | - const item = select2.getItem(id); | |
| 1254 | - if (!item || item.status !== ItemStatus.PendingRetry) { | |
| 1255 | - return; | |
| 1256 | - } | |
| 1257 | - if (select2.isPaused()) { | |
| 1258 | - return; | |
| 1259 | - } | |
| 1260 | - dispatch({ | |
| 1261 | - type: Type.RetryItem, | |
| 1262 | - id | |
| 1263 | - }); | |
| 1264 | - dispatch.processItem(id); | |
| 1265 | - }; | |
| 1266 | - } | |
| 1267 | 873 | |
| 1268 | 874 | // packages/upload-media/build-module/store/private-actions.mjs |
| 1269 | 875 | var private_actions_exports = {}; |
| 1270 | 876 | __export(private_actions_exports, { |
| @@ -1269,10 +875,8 @@ | ||
| 1269 | 875 | var private_actions_exports = {}; |
| 1270 | 876 | __export(private_actions_exports, { |
| 1271 | 877 | addItem: () => addItem, |
| 1272 | 878 | addSideloadItem: () => addSideloadItem, |
| 1273 | - detectUltraHdr: () => detectUltraHdr, | |
| 1274 | - finalizeItem: () => finalizeItem, | |
| 1275 | 879 | finishOperation: () => finishOperation, |
| 1276 | 880 | generateThumbnails: () => generateThumbnails, |
| 1277 | 881 | getTranscodeImageOperation: () => getTranscodeImageOperation, |
| 1278 | 882 | pauseItem: () => pauseItem, |
| @@ -1280,13 +884,13 @@ | ||
| 1280 | 884 | prepareItem: () => prepareItem, |
| 1281 | 885 | processItem: () => processItem, |
| 1282 | 886 | removeItem: () => removeItem, |
| 1283 | 887 | resizeCropItem: () => resizeCropItem, |
| 888 | + resumeItemByPostId: () => resumeItemByPostId, | |
| 1284 | 889 | resumeQueue: () => resumeQueue, |
| 1285 | 890 | revokeBlobUrls: () => revokeBlobUrls, |
| 1286 | 891 | rotateItem: () => rotateItem, |
| 1287 | 892 | sideloadItem: () => sideloadItem, |
| 1288 | - transcodeGifItem: () => transcodeGifItem, | |
| 1289 | 893 | transcodeImageItem: () => transcodeImageItem, |
| 1290 | 894 | updateItemProgress: () => updateItemProgress, |
| 1291 | 895 | updateSettings: () => updateSettings, |
| 1292 | 896 | uploadItem: () => uploadItem |
| @@ -1291,1010 +895,9 @@ | ||
| 1291 | 895 | updateSettings: () => updateSettings, |
| 1292 | 896 | uploadItem: () => uploadItem |
| 1293 | 897 | }); |
| 1294 | 898 | var import_blob = __toESM(require_blob(), 1); |
| 1295 | - var import_i18n6 = __toESM(require_i18n(), 1); | |
| 1296 | 899 | |
| 1297 | - // packages/upload-media/build-module/heic-parser.mjs | |
| 1298 | - var Reader = class { | |
| 1299 | - view; | |
| 1300 | - buffer; | |
| 1301 | - pos; | |
| 1302 | - constructor(buffer, offset = 0) { | |
| 1303 | - this.buffer = buffer; | |
| 1304 | - this.view = new DataView(buffer); | |
| 1305 | - this.pos = offset; | |
| 1306 | - } | |
| 1307 | - u8() { | |
| 1308 | - const v = this.view.getUint8(this.pos); | |
| 1309 | - this.pos += 1; | |
| 1310 | - return v; | |
| 1311 | - } | |
| 1312 | - u16() { | |
| 1313 | - const v = this.view.getUint16(this.pos); | |
| 1314 | - this.pos += 2; | |
| 1315 | - return v; | |
| 1316 | - } | |
| 1317 | - u32() { | |
| 1318 | - const v = this.view.getUint32(this.pos); | |
| 1319 | - this.pos += 4; | |
| 1320 | - return v; | |
| 1321 | - } | |
| 1322 | - u64() { | |
| 1323 | - const hi = this.view.getUint32(this.pos); | |
| 1324 | - const lo = this.view.getUint32(this.pos + 4); | |
| 1325 | - this.pos += 8; | |
| 1326 | - return hi * 4294967296 + lo; | |
| 1327 | - } | |
| 1328 | - /** | |
| 1329 | - * Read a variable-width unsigned integer (0, 4 or 8 bytes). | |
| 1330 | - * | |
| 1331 | - * @param size Byte width to read (0, 4, or 8). | |
| 1332 | - */ | |
| 1333 | - uN(size) { | |
| 1334 | - if (size === 0) { | |
| 1335 | - return 0; | |
| 1336 | - } | |
| 1337 | - if (size === 4) { | |
| 1338 | - return this.u32(); | |
| 1339 | - } | |
| 1340 | - if (size === 8) { | |
| 1341 | - return this.u64(); | |
| 1342 | - } | |
| 1343 | - throw new Error(`Unsupported uint size: ${size}`); | |
| 1344 | - } | |
| 1345 | - str(len) { | |
| 1346 | - let s = ""; | |
| 1347 | - for (let i = 0; i < len; i++) { | |
| 1348 | - s += String.fromCharCode(this.view.getUint8(this.pos + i)); | |
| 1349 | - } | |
| 1350 | - this.pos += len; | |
| 1351 | - return s; | |
| 1352 | - } | |
| 1353 | - bytes(len) { | |
| 1354 | - const b = new Uint8Array(this.buffer, this.pos, len); | |
| 1355 | - this.pos += len; | |
| 1356 | - return new Uint8Array(b); | |
| 1357 | - } | |
| 1358 | - }; | |
| 1359 | - function readBox(r) { | |
| 1360 | - if (r.pos + 8 > r.view.byteLength) { | |
| 1361 | - return null; | |
| 1362 | - } | |
| 1363 | - const offset = r.pos; | |
| 1364 | - let size = r.u32(); | |
| 1365 | - const type = r.str(4); | |
| 1366 | - let headerSize = 8; | |
| 1367 | - if (size === 1) { | |
| 1368 | - size = r.u64(); | |
| 1369 | - headerSize = 16; | |
| 1370 | - } else if (size === 0) { | |
| 1371 | - size = r.view.byteLength - offset; | |
| 1372 | - } | |
| 1373 | - return { type, offset, size, headerSize }; | |
| 1374 | - } | |
| 1375 | - function findBoxes(r, start, end) { | |
| 1376 | - const boxes = []; | |
| 1377 | - r.pos = start; | |
| 1378 | - while (r.pos < end) { | |
| 1379 | - const box = readBox(r); | |
| 1380 | - if (!box || box.size < 8) { | |
| 1381 | - break; | |
| 1382 | - } | |
| 1383 | - boxes.push(box); | |
| 1384 | - r.pos = box.offset + box.size; | |
| 1385 | - } | |
| 1386 | - return boxes; | |
| 1387 | - } | |
| 1388 | - function findBox(r, start, end, type) { | |
| 1389 | - r.pos = start; | |
| 1390 | - while (r.pos < end) { | |
| 1391 | - const box = readBox(r); | |
| 1392 | - if (!box || box.size < 8) { | |
| 1393 | - break; | |
| 1394 | - } | |
| 1395 | - if (box.type === type) { | |
| 1396 | - return box; | |
| 1397 | - } | |
| 1398 | - r.pos = box.offset + box.size; | |
| 1399 | - } | |
| 1400 | - return void 0; | |
| 1401 | - } | |
| 1402 | - function parsePitm(r, box) { | |
| 1403 | - r.pos = box.offset + box.headerSize; | |
| 1404 | - const version = r.u8(); | |
| 1405 | - r.pos += 3; | |
| 1406 | - return version === 0 ? r.u16() : r.u32(); | |
| 1407 | - } | |
| 1408 | - function parseIloc(r, box) { | |
| 1409 | - r.pos = box.offset + box.headerSize; | |
| 1410 | - const version = r.u8(); | |
| 1411 | - r.pos += 3; | |
| 1412 | - const byte1 = r.u8(); | |
| 1413 | - const offsetSize = byte1 >> 4 & 15; | |
| 1414 | - const lengthSize = byte1 & 15; | |
| 1415 | - const byte2 = r.u8(); | |
| 1416 | - const baseOffsetSize = byte2 >> 4 & 15; | |
| 1417 | - const indexSize = version >= 1 ? byte2 & 15 : 0; | |
| 1418 | - const itemCount = version < 2 ? r.u16() : r.u32(); | |
| 1419 | - const items = /* @__PURE__ */ new Map(); | |
| 1420 | - for (let i = 0; i < itemCount; i++) { | |
| 1421 | - const itemId = version < 2 ? r.u16() : r.u32(); | |
| 1422 | - let constructionMethod = 0; | |
| 1423 | - if (version === 1 || version === 2) { | |
| 1424 | - const cm = r.u16(); | |
| 1425 | - constructionMethod = cm & 15; | |
| 1426 | - } | |
| 1427 | - r.u16(); | |
| 1428 | - const baseOffset = r.uN(baseOffsetSize); | |
| 1429 | - const extentCount = r.u16(); | |
| 1430 | - const extents = []; | |
| 1431 | - for (let j = 0; j < extentCount; j++) { | |
| 1432 | - if (version >= 1) { | |
| 1433 | - r.uN(indexSize); | |
| 1434 | - } | |
| 1435 | - const extOffset = r.uN(offsetSize); | |
| 1436 | - const extLength = r.uN(lengthSize); | |
| 1437 | - extents.push({ | |
| 1438 | - offset: baseOffset + extOffset, | |
| 1439 | - length: extLength | |
| 1440 | - }); | |
| 1441 | - } | |
| 1442 | - items.set(itemId, { constructionMethod, extents }); | |
| 1443 | - } | |
| 1444 | - return items; | |
| 1445 | - } | |
| 1446 | - function parseIpma(r, box) { | |
| 1447 | - r.pos = box.offset + box.headerSize; | |
| 1448 | - const vf = r.u32(); | |
| 1449 | - const version = vf >>> 24; | |
| 1450 | - const flags = vf & 16777215; | |
| 1451 | - const largeIndex = (flags & 1) !== 0; | |
| 1452 | - const entryCount = r.u32(); | |
| 1453 | - const associations = /* @__PURE__ */ new Map(); | |
| 1454 | - for (let i = 0; i < entryCount; i++) { | |
| 1455 | - const itemId = version < 1 ? r.u16() : r.u32(); | |
| 1456 | - const assocCount = r.u8(); | |
| 1457 | - const indices = []; | |
| 1458 | - for (let j = 0; j < assocCount; j++) { | |
| 1459 | - if (largeIndex) { | |
| 1460 | - indices.push(r.u16() & 32767); | |
| 1461 | - } else { | |
| 1462 | - indices.push(r.u8() & 127); | |
| 1463 | - } | |
| 1464 | - } | |
| 1465 | - associations.set(itemId, indices); | |
| 1466 | - } | |
| 1467 | - return associations; | |
| 1468 | - } | |
| 1469 | - function parseIspe(r, box) { | |
| 1470 | - r.pos = box.offset + box.headerSize + 4; | |
| 1471 | - return { width: r.u32(), height: r.u32() }; | |
| 1472 | - } | |
| 1473 | - function parseIrot(r, box) { | |
| 1474 | - r.pos = box.offset + box.headerSize; | |
| 1475 | - return (r.u8() & 3) * 90; | |
| 1476 | - } | |
| 1477 | - function parseIinf(r, box) { | |
| 1478 | - r.pos = box.offset + box.headerSize; | |
| 1479 | - const version = r.u8(); | |
| 1480 | - r.pos += 3; | |
| 1481 | - const entryCount = version === 0 ? r.u16() : r.u32(); | |
| 1482 | - const itemTypes = /* @__PURE__ */ new Map(); | |
| 1483 | - const entriesStart = r.pos; | |
| 1484 | - const boxEnd = box.offset + box.size; | |
| 1485 | - const infeBoxes = findBoxes(r, entriesStart, boxEnd); | |
| 1486 | - for (let i = 0; i < Math.min(entryCount, infeBoxes.length); i++) { | |
| 1487 | - const infe = infeBoxes[i]; | |
| 1488 | - if (infe.type !== "infe") { | |
| 1489 | - continue; | |
| 1490 | - } | |
| 1491 | - r.pos = infe.offset + infe.headerSize; | |
| 1492 | - const infeVersion = r.u8(); | |
| 1493 | - r.pos += 3; | |
| 1494 | - if (infeVersion >= 2) { | |
| 1495 | - const itemId = infeVersion === 2 ? r.u16() : r.u32(); | |
| 1496 | - r.u16(); | |
| 1497 | - const itemType = r.str(4); | |
| 1498 | - itemTypes.set(itemId, itemType); | |
| 1499 | - } | |
| 1500 | - } | |
| 1501 | - return itemTypes; | |
| 1502 | - } | |
| 1503 | - function parseIref(r, box, refType) { | |
| 1504 | - r.pos = box.offset + box.headerSize; | |
| 1505 | - const version = r.u8(); | |
| 1506 | - r.pos += 3; | |
| 1507 | - const refs = /* @__PURE__ */ new Map(); | |
| 1508 | - const boxEnd = box.offset + box.size; | |
| 1509 | - while (r.pos < boxEnd) { | |
| 1510 | - const refBox = readBox(r); | |
| 1511 | - if (!refBox || refBox.size < 8) { | |
| 1512 | - break; | |
| 1513 | - } | |
| 1514 | - r.pos = refBox.offset + refBox.headerSize; | |
| 1515 | - const fromId = version === 0 ? r.u16() : r.u32(); | |
| 1516 | - const refCount = r.u16(); | |
| 1517 | - const toIds = []; | |
| 1518 | - for (let i = 0; i < refCount; i++) { | |
| 1519 | - toIds.push(version === 0 ? r.u16() : r.u32()); | |
| 1520 | - } | |
| 1521 | - if (refBox.type === refType) { | |
| 1522 | - refs.set(fromId, toIds); | |
| 1523 | - } | |
| 1524 | - r.pos = refBox.offset + refBox.size; | |
| 1525 | - } | |
| 1526 | - return refs; | |
| 1527 | - } | |
| 1528 | - function reverseBits32(n) { | |
| 1529 | - n = n >>> 1 & 1431655765 | (n & 1431655765) << 1; | |
| 1530 | - n = n >>> 2 & 858993459 | (n & 858993459) << 2; | |
| 1531 | - n = n >>> 4 & 252645135 | (n & 252645135) << 4; | |
| 1532 | - n = n >>> 8 & 16711935 | (n & 16711935) << 8; | |
| 1533 | - n = n >>> 16 | n << 16; | |
| 1534 | - return n >>> 0; | |
| 1535 | - } | |
| 1536 | - function buildCodecString(r, recordOffset) { | |
| 1537 | - r.pos = recordOffset; | |
| 1538 | - r.u8(); | |
| 1539 | - const byte1 = r.u8(); | |
| 1540 | - const profileSpace = byte1 >> 6 & 3; | |
| 1541 | - const tierFlag = byte1 >> 5 & 1; | |
| 1542 | - const profileIdc = byte1 & 31; | |
| 1543 | - const compatFlags = r.u32(); | |
| 1544 | - const constraintBytes = r.bytes(6); | |
| 1545 | - const levelIdc = r.u8(); | |
| 1546 | - const spacePrefix = profileSpace > 0 ? String.fromCharCode(64 + profileSpace) : ""; | |
| 1547 | - const compatHex = reverseBits32(compatFlags).toString(16).toUpperCase(); | |
| 1548 | - const tierChar = tierFlag ? "H" : "L"; | |
| 1549 | - let lastNonZero = -1; | |
| 1550 | - for (let i = 5; i >= 0; i--) { | |
| 1551 | - if (constraintBytes[i] !== 0) { | |
| 1552 | - lastNonZero = i; | |
| 1553 | - break; | |
| 1554 | - } | |
| 1555 | - } | |
| 1556 | - let constraintStr = ""; | |
| 1557 | - if (lastNonZero >= 0) { | |
| 1558 | - const parts = []; | |
| 1559 | - for (let i = 0; i <= lastNonZero; i++) { | |
| 1560 | - parts.push(constraintBytes[i].toString(16).toUpperCase()); | |
| 1561 | - } | |
| 1562 | - constraintStr = "." + parts.join("."); | |
| 1563 | - } | |
| 1564 | - return `hvc1.${spacePrefix}${profileIdc}.${compatHex}.${tierChar}${levelIdc}${constraintStr}`; | |
| 1565 | - } | |
| 1566 | - function readItemData(buffer, loc, idatOffset) { | |
| 1567 | - const baseOffset = loc.constructionMethod === 1 ? idatOffset : 0; | |
| 1568 | - if (loc.extents.length === 1) { | |
| 1569 | - const ext = loc.extents[0]; | |
| 1570 | - const start = baseOffset + ext.offset; | |
| 1571 | - return new Uint8Array(buffer.slice(start, start + ext.length)); | |
| 1572 | - } | |
| 1573 | - let totalLength = 0; | |
| 1574 | - for (const ext of loc.extents) { | |
| 1575 | - totalLength += ext.length; | |
| 1576 | - } | |
| 1577 | - const data = new Uint8Array(totalLength); | |
| 1578 | - let pos = 0; | |
| 1579 | - for (const ext of loc.extents) { | |
| 1580 | - const start = baseOffset + ext.offset; | |
| 1581 | - data.set( | |
| 1582 | - new Uint8Array(buffer.slice(start, start + ext.length)), | |
| 1583 | - pos | |
| 1584 | - ); | |
| 1585 | - pos += ext.length; | |
| 1586 | - } | |
| 1587 | - return data; | |
| 1588 | - } | |
| 1589 | - function findHvcProperties(propIndices, properties) { | |
| 1590 | - let hvcCBox; | |
| 1591 | - let ispeBox; | |
| 1592 | - let irotBox; | |
| 1593 | - for (const idx of propIndices) { | |
| 1594 | - if (idx < 1 || idx > properties.length) { | |
| 1595 | - continue; | |
| 1596 | - } | |
| 1597 | - const prop = properties[idx - 1]; | |
| 1598 | - if (prop.type === "hvcC" && !hvcCBox) { | |
| 1599 | - hvcCBox = prop; | |
| 1600 | - } | |
| 1601 | - if (prop.type === "ispe" && !ispeBox) { | |
| 1602 | - ispeBox = prop; | |
| 1603 | - } | |
| 1604 | - if (prop.type === "irot" && !irotBox) { | |
| 1605 | - irotBox = prop; | |
| 1606 | - } | |
| 1607 | - } | |
| 1608 | - if (!hvcCBox) { | |
| 1609 | - throw new Error("No HEVC configuration (hvcC) found"); | |
| 1610 | - } | |
| 1611 | - if (!ispeBox) { | |
| 1612 | - throw new Error("No image dimensions (ispe) found"); | |
| 1613 | - } | |
| 1614 | - return { hvcCBox, ispeBox, irotBox }; | |
| 1615 | - } | |
| 1616 | - function parseHeic(buffer) { | |
| 1617 | - const r = new Reader(buffer); | |
| 1618 | - const fileEnd = buffer.byteLength; | |
| 1619 | - const metaBox = findBox(r, 0, fileEnd, "meta"); | |
| 1620 | - if (!metaBox) { | |
| 1621 | - throw new Error("No meta box found in HEIC file"); | |
| 1622 | - } | |
| 1623 | - const metaChildStart = metaBox.offset + metaBox.headerSize + 4; | |
| 1624 | - const metaEnd = metaBox.offset + metaBox.size; | |
| 1625 | - const children = findBoxes(r, metaChildStart, metaEnd); | |
| 1626 | - const pitmBox = children.find((b) => b.type === "pitm"); | |
| 1627 | - const ilocBox = children.find((b) => b.type === "iloc"); | |
| 1628 | - const iprpBox = children.find((b) => b.type === "iprp"); | |
| 1629 | - const iinfBox = children.find((b) => b.type === "iinf"); | |
| 1630 | - const irefBox = children.find((b) => b.type === "iref"); | |
| 1631 | - const idatBox = children.find((b) => b.type === "idat"); | |
| 1632 | - const idatOffset = idatBox ? idatBox.offset + idatBox.headerSize : 0; | |
| 1633 | - if (!pitmBox || !ilocBox || !iprpBox) { | |
| 1634 | - throw new Error("Missing required boxes (pitm, iloc, iprp) in HEIC"); | |
| 1635 | - } | |
| 1636 | - const primaryId = parsePitm(r, pitmBox); | |
| 1637 | - const locations = parseIloc(r, ilocBox); | |
| 1638 | - const iprpStart = iprpBox.offset + iprpBox.headerSize; | |
| 1639 | - const iprpEnd = iprpBox.offset + iprpBox.size; | |
| 1640 | - const iprpChildren = findBoxes(r, iprpStart, iprpEnd); | |
| 1641 | - const ipcoBox = iprpChildren.find((b) => b.type === "ipco"); | |
| 1642 | - const ipmaBox = iprpChildren.find((b) => b.type === "ipma"); | |
| 1643 | - if (!ipcoBox || !ipmaBox) { | |
| 1644 | - throw new Error("Missing ipco or ipma in HEIC properties"); | |
| 1645 | - } | |
| 1646 | - const allAssoc = parseIpma(r, ipmaBox); | |
| 1647 | - const ipcoStart = ipcoBox.offset + ipcoBox.headerSize; | |
| 1648 | - const ipcoEnd = ipcoBox.offset + ipcoBox.size; | |
| 1649 | - const properties = findBoxes(r, ipcoStart, ipcoEnd); | |
| 1650 | - let primaryItemType = "hvc1"; | |
| 1651 | - if (iinfBox) { | |
| 1652 | - const itemTypes = parseIinf(r, iinfBox); | |
| 1653 | - const t = itemTypes.get(primaryId); | |
| 1654 | - if (t) { | |
| 1655 | - primaryItemType = t; | |
| 1656 | - } | |
| 1657 | - } | |
| 1658 | - if (primaryItemType === "grid") { | |
| 1659 | - return parseGridImage( | |
| 1660 | - r, | |
| 1661 | - buffer, | |
| 1662 | - primaryId, | |
| 1663 | - locations, | |
| 1664 | - allAssoc, | |
| 1665 | - properties, | |
| 1666 | - irefBox, | |
| 1667 | - idatOffset | |
| 1668 | - ); | |
| 1669 | - } | |
| 1670 | - const primaryLoc = locations.get(primaryId); | |
| 1671 | - if (!primaryLoc || primaryLoc.extents.length === 0) { | |
| 1672 | - throw new Error(`No location data for primary item ${primaryId}`); | |
| 1673 | - } | |
| 1674 | - const primaryPropIndices = allAssoc.get(primaryId); | |
| 1675 | - if (!primaryPropIndices || primaryPropIndices.length === 0) { | |
| 1676 | - throw new Error("No property associations for primary item"); | |
| 1677 | - } | |
| 1678 | - const { hvcCBox, ispeBox, irotBox } = findHvcProperties( | |
| 1679 | - primaryPropIndices, | |
| 1680 | - properties | |
| 1681 | - ); | |
| 1682 | - const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize; | |
| 1683 | - const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize; | |
| 1684 | - const description = new Uint8Array( | |
| 1685 | - buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize) | |
| 1686 | - ); | |
| 1687 | - const codecString = buildCodecString(r, hvcCDataStart); | |
| 1688 | - const { width, height } = parseIspe(r, ispeBox); | |
| 1689 | - const rotation = irotBox ? parseIrot(r, irotBox) : 0; | |
| 1690 | - return { | |
| 1691 | - codecString, | |
| 1692 | - description, | |
| 1693 | - tiles: [ | |
| 1694 | - { | |
| 1695 | - data: readItemData(buffer, primaryLoc, idatOffset), | |
| 1696 | - x: 0, | |
| 1697 | - y: 0 | |
| 1698 | - } | |
| 1699 | - ], | |
| 1700 | - tileWidth: width, | |
| 1701 | - tileHeight: height, | |
| 1702 | - outputWidth: width, | |
| 1703 | - outputHeight: height, | |
| 1704 | - rotation, | |
| 1705 | - exifOrientation: rotation === 0 ? getUnappliedExifOrientation(buffer) : 1 | |
| 1706 | - }; | |
| 1707 | - } | |
| 1708 | - function parseGridImage(r, buffer, gridItemId, locations, allAssoc, properties, irefBox, idatOffset) { | |
| 1709 | - const gridLoc = locations.get(gridItemId); | |
| 1710 | - if (!gridLoc || gridLoc.extents.length === 0) { | |
| 1711 | - throw new Error("No location data for grid item"); | |
| 1712 | - } | |
| 1713 | - const gridData = readItemData(buffer, gridLoc, idatOffset); | |
| 1714 | - const largeFields = gridData.length > 1 && (gridData[1] & 1) !== 0; | |
| 1715 | - const minGridSize = largeFields ? 12 : 8; | |
| 1716 | - if (gridData.length < minGridSize) { | |
| 1717 | - throw new Error( | |
| 1718 | - `Grid descriptor too short: ${gridData.length} bytes` | |
| 1719 | - ); | |
| 1720 | - } | |
| 1721 | - const rows = gridData[2] + 1; | |
| 1722 | - const columns = gridData[3] + 1; | |
| 1723 | - const gv = new DataView(gridData.buffer, gridData.byteOffset); | |
| 1724 | - let outputWidth; | |
| 1725 | - let outputHeight; | |
| 1726 | - if (largeFields) { | |
| 1727 | - outputWidth = gv.getUint32(4); | |
| 1728 | - outputHeight = gv.getUint32(8); | |
| 1729 | - } else { | |
| 1730 | - outputWidth = gv.getUint16(4); | |
| 1731 | - outputHeight = gv.getUint16(6); | |
| 1732 | - } | |
| 1733 | - if (!irefBox) { | |
| 1734 | - throw new Error("Grid image requires iref box"); | |
| 1735 | - } | |
| 1736 | - const dimgRefs = parseIref(r, irefBox, "dimg"); | |
| 1737 | - const tileItemIds = dimgRefs.get(gridItemId); | |
| 1738 | - if (!tileItemIds || tileItemIds.length === 0) { | |
| 1739 | - throw new Error("No tile references found for grid item"); | |
| 1740 | - } | |
| 1741 | - const expectedTiles = rows * columns; | |
| 1742 | - if (tileItemIds.length < expectedTiles) { | |
| 1743 | - throw new Error( | |
| 1744 | - `Grid expects ${expectedTiles} tiles but found ${tileItemIds.length}` | |
| 1745 | - ); | |
| 1746 | - } | |
| 1747 | - const firstTileProps = allAssoc.get(tileItemIds[0]); | |
| 1748 | - if (!firstTileProps || firstTileProps.length === 0) { | |
| 1749 | - throw new Error("No property associations for tile item"); | |
| 1750 | - } | |
| 1751 | - const { hvcCBox, ispeBox } = findHvcProperties( | |
| 1752 | - firstTileProps, | |
| 1753 | - properties | |
| 1754 | - ); | |
| 1755 | - const gridProps = allAssoc.get(gridItemId) || []; | |
| 1756 | - let irotBox; | |
| 1757 | - for (const idx of gridProps) { | |
| 1758 | - if (idx >= 1 && idx <= properties.length) { | |
| 1759 | - const prop = properties[idx - 1]; | |
| 1760 | - if (prop.type === "irot") { | |
| 1761 | - irotBox = prop; | |
| 1762 | - break; | |
| 1763 | - } | |
| 1764 | - } | |
| 1765 | - } | |
| 1766 | - const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize; | |
| 1767 | - const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize; | |
| 1768 | - const description = new Uint8Array( | |
| 1769 | - buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize) | |
| 1770 | - ); | |
| 1771 | - const codecString = buildCodecString(r, hvcCDataStart); | |
| 1772 | - const { width: tileWidth, height: tileHeight } = parseIspe(r, ispeBox); | |
| 1773 | - const tiles = []; | |
| 1774 | - for (let row = 0; row < rows; row++) { | |
| 1775 | - for (let col = 0; col < columns; col++) { | |
| 1776 | - const tileIdx = row * columns + col; | |
| 1777 | - const tileId = tileItemIds[tileIdx]; | |
| 1778 | - const tileLoc = locations.get(tileId); | |
| 1779 | - if (!tileLoc || tileLoc.extents.length === 0) { | |
| 1780 | - throw new Error(`No location data for tile item ${tileId}`); | |
| 1781 | - } | |
| 1782 | - tiles.push({ | |
| 1783 | - data: readItemData(buffer, tileLoc, idatOffset), | |
| 1784 | - x: col * tileWidth, | |
| 1785 | - y: row * tileHeight | |
| 1786 | - }); | |
| 1787 | - } | |
| 1788 | - } | |
| 1789 | - const rotation = irotBox ? parseIrot(r, irotBox) : 0; | |
| 1790 | - return { | |
| 1791 | - codecString, | |
| 1792 | - description, | |
| 1793 | - tiles, | |
| 1794 | - tileWidth, | |
| 1795 | - tileHeight, | |
| 1796 | - outputWidth, | |
| 1797 | - outputHeight, | |
| 1798 | - rotation, | |
| 1799 | - exifOrientation: rotation === 0 ? getUnappliedExifOrientation(buffer) : 1 | |
| 1800 | - }; | |
| 1801 | - } | |
| 1802 | - function readTiffOrientation(payload) { | |
| 1803 | - if (payload.length < 8) { | |
| 1804 | - return 1; | |
| 1805 | - } | |
| 1806 | - const view = new DataView( | |
| 1807 | - payload.buffer, | |
| 1808 | - payload.byteOffset, | |
| 1809 | - payload.byteLength | |
| 1810 | - ); | |
| 1811 | - let tiffStart = 0; | |
| 1812 | - const firstWord = view.getUint16(0); | |
| 1813 | - if (firstWord !== 18761 && firstWord !== 19789) { | |
| 1814 | - tiffStart = view.getUint32(0) + 4; | |
| 1815 | - } | |
| 1816 | - if (tiffStart + 8 > payload.length) { | |
| 1817 | - return 1; | |
| 1818 | - } | |
| 1819 | - const byteOrder = view.getUint16(tiffStart); | |
| 1820 | - let little; | |
| 1821 | - if (byteOrder === 18761) { | |
| 1822 | - little = true; | |
| 1823 | - } else if (byteOrder === 19789) { | |
| 1824 | - little = false; | |
| 1825 | - } else { | |
| 1826 | - return 1; | |
| 1827 | - } | |
| 1828 | - const ifd0 = tiffStart + view.getUint32(tiffStart + 4, little); | |
| 1829 | - if (ifd0 + 2 > payload.length) { | |
| 1830 | - return 1; | |
| 1831 | - } | |
| 1832 | - const entryCount = view.getUint16(ifd0, little); | |
| 1833 | - for (let i = 0; i < entryCount; i++) { | |
| 1834 | - const entry = ifd0 + 2 + i * 12; | |
| 1835 | - if (entry + 12 > payload.length) { | |
| 1836 | - break; | |
| 1837 | - } | |
| 1838 | - if (view.getUint16(entry, little) === 274) { | |
| 1839 | - const value = view.getUint16(entry + 8, little); | |
| 1840 | - return value >= 1 && value <= 8 ? value : 1; | |
| 1841 | - } | |
| 1842 | - } | |
| 1843 | - return 1; | |
| 1844 | - } | |
| 1845 | - function findMeta(r) { | |
| 1846 | - const metaBox = findBox(r, 0, r.view.byteLength, "meta"); | |
| 1847 | - if (!metaBox) { | |
| 1848 | - return null; | |
| 1849 | - } | |
| 1850 | - const start = metaBox.offset + metaBox.headerSize + 4; | |
| 1851 | - const end = metaBox.offset + metaBox.size; | |
| 1852 | - return { box: metaBox, children: findBoxes(r, start, end) }; | |
| 1853 | - } | |
| 1854 | - function parseExifOrientation(buffer) { | |
| 1855 | - try { | |
| 1856 | - const r = new Reader(buffer); | |
| 1857 | - const meta = findMeta(r); | |
| 1858 | - if (!meta) { | |
| 1859 | - return 1; | |
| 1860 | - } | |
| 1861 | - const iinfBox = meta.children.find((b) => b.type === "iinf"); | |
| 1862 | - const ilocBox = meta.children.find((b) => b.type === "iloc"); | |
| 1863 | - if (!iinfBox || !ilocBox) { | |
| 1864 | - return 1; | |
| 1865 | - } | |
| 1866 | - const itemTypes = parseIinf(r, iinfBox); | |
| 1867 | - let exifItemId; | |
| 1868 | - for (const [id, type] of itemTypes) { | |
| 1869 | - if (type === "Exif") { | |
| 1870 | - exifItemId = id; | |
| 1871 | - break; | |
| 1872 | - } | |
| 1873 | - } | |
| 1874 | - if (exifItemId === void 0) { | |
| 1875 | - return 1; | |
| 1876 | - } | |
| 1877 | - const loc = parseIloc(r, ilocBox).get(exifItemId); | |
| 1878 | - if (!loc || loc.extents.length === 0) { | |
| 1879 | - return 1; | |
| 1880 | - } | |
| 1881 | - const idatBox = meta.children.find((b) => b.type === "idat"); | |
| 1882 | - const idatOffset = idatBox ? idatBox.offset + idatBox.headerSize : 0; | |
| 1883 | - return readTiffOrientation(readItemData(buffer, loc, idatOffset)); | |
| 1884 | - } catch { | |
| 1885 | - return 1; | |
| 1886 | - } | |
| 1887 | - } | |
| 1888 | - function hasNativeTransform(r) { | |
| 1889 | - const meta = findMeta(r); | |
| 1890 | - if (!meta) { | |
| 1891 | - return false; | |
| 1892 | - } | |
| 1893 | - const iprp = meta.children.find((b) => b.type === "iprp"); | |
| 1894 | - if (!iprp) { | |
| 1895 | - return false; | |
| 1896 | - } | |
| 1897 | - const ipco = findBox( | |
| 1898 | - r, | |
| 1899 | - iprp.offset + iprp.headerSize, | |
| 1900 | - iprp.offset + iprp.size, | |
| 1901 | - "ipco" | |
| 1902 | - ); | |
| 1903 | - if (!ipco) { | |
| 1904 | - return false; | |
| 1905 | - } | |
| 1906 | - const start = ipco.offset + ipco.headerSize; | |
| 1907 | - const end = ipco.offset + ipco.size; | |
| 1908 | - return Boolean( | |
| 1909 | - findBox(r, start, end, "irot") || findBox(r, start, end, "imir") | |
| 1910 | - ); | |
| 1911 | - } | |
| 1912 | - function getUnappliedExifOrientation(buffer) { | |
| 1913 | - try { | |
| 1914 | - if (hasNativeTransform(new Reader(buffer))) { | |
| 1915 | - return 1; | |
| 1916 | - } | |
| 1917 | - } catch { | |
| 1918 | - return 1; | |
| 1919 | - } | |
| 1920 | - return parseExifOrientation(buffer); | |
| 1921 | - } | |
| 1922 | - | |
| 1923 | - // packages/upload-media/build-module/canvas-utils.mjs | |
| 1924 | - async function canvasConvertToJpeg(file, quality = 0.82) { | |
| 1925 | - const baseName = getFileBasename(file.name); | |
| 1926 | - try { | |
| 1927 | - const bitmap = await createImageBitmap(file); | |
| 1928 | - try { | |
| 1929 | - const canvas = new OffscreenCanvas(bitmap.width, bitmap.height); | |
| 1930 | - const ctx = canvas.getContext("2d"); | |
| 1931 | - if (!ctx) { | |
| 1932 | - throw new Error("Could not get canvas 2d context"); | |
| 1933 | - } | |
| 1934 | - ctx.drawImage(bitmap, 0, 0); | |
| 1935 | - const jpegBlob = await canvas.convertToBlob({ | |
| 1936 | - type: "image/jpeg", | |
| 1937 | - quality | |
| 1938 | - }); | |
| 1939 | - return new File([jpegBlob], `${baseName}.jpg`, { | |
| 1940 | - type: "image/jpeg" | |
| 1941 | - }); | |
| 1942 | - } finally { | |
| 1943 | - bitmap.close(); | |
| 1944 | - } | |
| 1945 | - } catch { | |
| 1946 | - } | |
| 1947 | - if (typeof ImageDecoder !== "undefined") { | |
| 1948 | - const supported = await ImageDecoder.isTypeSupported(file.type); | |
| 1949 | - if (supported) { | |
| 1950 | - const decoder = new ImageDecoder({ | |
| 1951 | - type: file.type, | |
| 1952 | - data: file.stream() | |
| 1953 | - }); | |
| 1954 | - try { | |
| 1955 | - const { image: videoFrame } = await decoder.decode(); | |
| 1956 | - try { | |
| 1957 | - const canvas = new OffscreenCanvas( | |
| 1958 | - videoFrame.displayWidth, | |
| 1959 | - videoFrame.displayHeight | |
| 1960 | - ); | |
| 1961 | - const ctx = canvas.getContext("2d"); | |
| 1962 | - if (!ctx) { | |
| 1963 | - throw new Error("Could not get canvas 2d context"); | |
| 1964 | - } | |
| 1965 | - ctx.drawImage(videoFrame, 0, 0); | |
| 1966 | - const jpegBlob = await canvas.convertToBlob({ | |
| 1967 | - type: "image/jpeg", | |
| 1968 | - quality | |
| 1969 | - }); | |
| 1970 | - return new File([jpegBlob], `${baseName}.jpg`, { | |
| 1971 | - type: "image/jpeg" | |
| 1972 | - }); | |
| 1973 | - } finally { | |
| 1974 | - videoFrame.close(); | |
| 1975 | - } | |
| 1976 | - } finally { | |
| 1977 | - decoder.close(); | |
| 1978 | - } | |
| 1979 | - } | |
| 1980 | - } | |
| 1981 | - if (typeof VideoDecoder !== "undefined") { | |
| 1982 | - try { | |
| 1983 | - const heicData = parseHeic(await file.arrayBuffer()); | |
| 1984 | - const support = await VideoDecoder.isConfigSupported({ | |
| 1985 | - codec: heicData.codecString | |
| 1986 | - }); | |
| 1987 | - if (support.supported) { | |
| 1988 | - const canvas = new OffscreenCanvas( | |
| 1989 | - heicData.outputWidth, | |
| 1990 | - heicData.outputHeight | |
| 1991 | - ); | |
| 1992 | - const ctx = canvas.getContext("2d"); | |
| 1993 | - if (!ctx) { | |
| 1994 | - throw new Error("Could not get canvas 2d context"); | |
| 1995 | - } | |
| 1996 | - for (const tile of heicData.tiles) { | |
| 1997 | - const frame = await decodeHevcFrame( | |
| 1998 | - heicData.codecString, | |
| 1999 | - heicData.description, | |
| 2000 | - heicData.tileWidth, | |
| 2001 | - heicData.tileHeight, | |
| 2002 | - tile.data | |
| 2003 | - ); | |
| 2004 | - try { | |
| 2005 | - ctx.drawImage(frame, tile.x, tile.y); | |
| 2006 | - } finally { | |
| 2007 | - frame.close(); | |
| 2008 | - } | |
| 2009 | - } | |
| 2010 | - const outputCanvas = heicData.rotation !== 0 ? applyRotation(canvas, heicData.rotation) : applyExifOrientation( | |
| 2011 | - canvas, | |
| 2012 | - heicData.exifOrientation | |
| 2013 | - ); | |
| 2014 | - const jpegBlob = await outputCanvas.convertToBlob({ | |
| 2015 | - type: "image/jpeg", | |
| 2016 | - quality | |
| 2017 | - }); | |
| 2018 | - return new File([jpegBlob], `${baseName}.jpg`, { | |
| 2019 | - type: "image/jpeg" | |
| 2020 | - }); | |
| 2021 | - } | |
| 2022 | - } catch { | |
| 2023 | - } | |
| 2024 | - } | |
| 2025 | - throw new Error( | |
| 2026 | - "This browser cannot decode HEIC images. Please use Safari or convert to JPEG before uploading." | |
| 2027 | - ); | |
| 2028 | - } | |
| 2029 | - function applyRotation(source, rotation) { | |
| 2030 | - if (rotation === 0) { | |
| 2031 | - return source; | |
| 2032 | - } | |
| 2033 | - const swap = rotation === 90 || rotation === 270; | |
| 2034 | - const w = swap ? source.height : source.width; | |
| 2035 | - const h = swap ? source.width : source.height; | |
| 2036 | - const rotated = new OffscreenCanvas(w, h); | |
| 2037 | - const ctx = rotated.getContext("2d"); | |
| 2038 | - if (!ctx) { | |
| 2039 | - return source; | |
| 2040 | - } | |
| 2041 | - ctx.translate(w / 2, h / 2); | |
| 2042 | - ctx.rotate(-rotation * Math.PI / 180); | |
| 2043 | - ctx.drawImage(source, -source.width / 2, -source.height / 2); | |
| 2044 | - return rotated; | |
| 2045 | - } | |
| 2046 | - function applyExifOrientation(source, orientation) { | |
| 2047 | - if (orientation <= 1 || orientation > 8) { | |
| 2048 | - return source; | |
| 2049 | - } | |
| 2050 | - const { width: sw, height: sh } = source; | |
| 2051 | - const swap = orientation >= 5; | |
| 2052 | - const out = new OffscreenCanvas(swap ? sh : sw, swap ? sw : sh); | |
| 2053 | - const ctx = out.getContext("2d"); | |
| 2054 | - if (!ctx) { | |
| 2055 | - return source; | |
| 2056 | - } | |
| 2057 | - switch (orientation) { | |
| 2058 | - case 2: | |
| 2059 | - ctx.transform(-1, 0, 0, 1, sw, 0); | |
| 2060 | - break; | |
| 2061 | - case 3: | |
| 2062 | - ctx.transform(-1, 0, 0, -1, sw, sh); | |
| 2063 | - break; | |
| 2064 | - case 4: | |
| 2065 | - ctx.transform(1, 0, 0, -1, 0, sh); | |
| 2066 | - break; | |
| 2067 | - case 5: | |
| 2068 | - ctx.transform(0, 1, 1, 0, 0, 0); | |
| 2069 | - break; | |
| 2070 | - case 6: | |
| 2071 | - ctx.transform(0, 1, -1, 0, sh, 0); | |
| 2072 | - break; | |
| 2073 | - case 7: | |
| 2074 | - ctx.transform(0, -1, -1, 0, sh, sw); | |
| 2075 | - break; | |
| 2076 | - case 8: | |
| 2077 | - ctx.transform(0, -1, 1, 0, 0, sw); | |
| 2078 | - break; | |
| 2079 | - } | |
| 2080 | - ctx.drawImage(source, 0, 0); | |
| 2081 | - return out; | |
| 2082 | - } | |
| 2083 | - function decodeHevcFrame(codec, description, width, height, data) { | |
| 2084 | - return new Promise((resolve, reject) => { | |
| 2085 | - const decoder = new VideoDecoder({ | |
| 2086 | - output: (frame) => { | |
| 2087 | - decoder.close(); | |
| 2088 | - resolve(frame); | |
| 2089 | - }, | |
| 2090 | - error: (e) => { | |
| 2091 | - if (decoder.state !== "closed") { | |
| 2092 | - decoder.close(); | |
| 2093 | - } | |
| 2094 | - reject(e); | |
| 2095 | - } | |
| 2096 | - }); | |
| 2097 | - decoder.configure({ | |
| 2098 | - codec, | |
| 2099 | - codedWidth: width, | |
| 2100 | - codedHeight: height, | |
| 2101 | - description | |
| 2102 | - }); | |
| 2103 | - decoder.decode( | |
| 2104 | - new EncodedVideoChunk({ | |
| 2105 | - type: "key", | |
| 2106 | - timestamp: 0, | |
| 2107 | - data | |
| 2108 | - }) | |
| 2109 | - ); | |
| 2110 | - decoder.flush().catch((e) => { | |
| 2111 | - if (decoder.state !== "closed") { | |
| 2112 | - decoder.close(); | |
| 2113 | - } | |
| 2114 | - reject(e); | |
| 2115 | - }); | |
| 2116 | - }); | |
| 2117 | - } | |
| 2118 | - | |
| 2119 | - // packages/upload-media/build-module/feature-detection.mjs | |
| 2120 | - var cachedResult = null; | |
| 2121 | - function detectClientSideMediaSupport() { | |
| 2122 | - if (cachedResult !== null) { | |
| 2123 | - return cachedResult; | |
| 2124 | - } | |
| 2125 | - if (typeof WebAssembly === "undefined") { | |
| 2126 | - cachedResult = { | |
| 2127 | - supported: false, | |
| 2128 | - reason: "WebAssembly is not supported in this browser." | |
| 2129 | - }; | |
| 2130 | - return cachedResult; | |
| 2131 | - } | |
| 2132 | - if (typeof SharedArrayBuffer === "undefined") { | |
| 2133 | - cachedResult = { | |
| 2134 | - supported: false, | |
| 2135 | - reason: "SharedArrayBuffer is not available. This may be due to missing cross-origin isolation headers." | |
| 2136 | - }; | |
| 2137 | - return cachedResult; | |
| 2138 | - } | |
| 2139 | - if (typeof Worker === "undefined") { | |
| 2140 | - cachedResult = { | |
| 2141 | - supported: false, | |
| 2142 | - reason: "Web Workers are not supported in this browser." | |
| 2143 | - }; | |
| 2144 | - return cachedResult; | |
| 2145 | - } | |
| 2146 | - if (typeof navigator !== "undefined" && "deviceMemory" in navigator && navigator.deviceMemory <= 2) { | |
| 2147 | - cachedResult = { | |
| 2148 | - supported: false, | |
| 2149 | - reason: "Device has insufficient memory for client-side media processing." | |
| 2150 | - }; | |
| 2151 | - return cachedResult; | |
| 2152 | - } | |
| 2153 | - if (typeof navigator !== "undefined" && "hardwareConcurrency" in navigator && navigator.hardwareConcurrency < 2) { | |
| 2154 | - cachedResult = { | |
| 2155 | - supported: false, | |
| 2156 | - reason: "Device has insufficient CPU cores for client-side media processing." | |
| 2157 | - }; | |
| 2158 | - return cachedResult; | |
| 2159 | - } | |
| 2160 | - if (typeof navigator !== "undefined") { | |
| 2161 | - const connection = navigator.connection; | |
| 2162 | - if (connection) { | |
| 2163 | - if (connection.saveData) { | |
| 2164 | - cachedResult = { | |
| 2165 | - supported: false, | |
| 2166 | - reason: "Data saver mode is enabled." | |
| 2167 | - }; | |
| 2168 | - return cachedResult; | |
| 2169 | - } | |
| 2170 | - if (connection.effectiveType === "slow-2g" || connection.effectiveType === "2g") { | |
| 2171 | - cachedResult = { | |
| 2172 | - supported: false, | |
| 2173 | - reason: "Network connection is too slow for client-side media processing." | |
| 2174 | - }; | |
| 2175 | - return cachedResult; | |
| 2176 | - } | |
| 2177 | - } | |
| 2178 | - } | |
| 2179 | - if (typeof window !== "undefined") { | |
| 2180 | - try { | |
| 2181 | - const testBlob = new Blob([""], { | |
| 2182 | - type: "application/javascript" | |
| 2183 | - }); | |
| 2184 | - const testUrl = URL.createObjectURL(testBlob); | |
| 2185 | - try { | |
| 2186 | - const testWorker = new Worker(testUrl); | |
| 2187 | - testWorker.terminate(); | |
| 2188 | - } finally { | |
| 2189 | - URL.revokeObjectURL(testUrl); | |
| 2190 | - } | |
| 2191 | - } catch { | |
| 2192 | - cachedResult = { | |
| 2193 | - supported: false, | |
| 2194 | - reason: "The site's Content Security Policy (CSP) does not allow blob: workers. The worker-src directive must include blob: to enable client-side media processing." | |
| 2195 | - }; | |
| 2196 | - return cachedResult; | |
| 2197 | - } | |
| 2198 | - } | |
| 2199 | - cachedResult = { supported: true }; | |
| 2200 | - return cachedResult; | |
| 2201 | - } | |
| 2202 | - function isClientSideMediaSupported() { | |
| 2203 | - return detectClientSideMediaSupport().supported; | |
| 2204 | - } | |
| 2205 | - function isHeicCanvasSupported() { | |
| 2206 | - return typeof createImageBitmap !== "undefined" && typeof OffscreenCanvas !== "undefined"; | |
| 2207 | - } | |
| 2208 | - function clearFeatureDetectionCache() { | |
| 2209 | - cachedResult = null; | |
| 2210 | - } | |
| 2211 | - var BYTES_PER_PIXEL = 4; | |
| 2212 | - var INTERLACED_MEMORY_BUDGET = 0.5 * 1024 * 1024 * 1024; | |
| 2213 | - var BASELINE_MEMORY_BUDGET = 0.9 * 1024 * 1024 * 1024; | |
| 2214 | - function exceedsClientProcessingMemory(dimensions) { | |
| 2215 | - const { width, height, interlaced } = dimensions; | |
| 2216 | - const estimatedBytes = width * height * BYTES_PER_PIXEL; | |
| 2217 | - const budget = interlaced ? INTERLACED_MEMORY_BUDGET : BASELINE_MEMORY_BUDGET; | |
| 2218 | - return estimatedBytes > budget; | |
| 2219 | - } | |
| 2220 | - | |
| 2221 | - // packages/upload-media/build-module/get-image-dimensions.mjs | |
| 2222 | - var MAX_HEADER_BYTES = 512 * 1024; | |
| 2223 | - function parseJpeg(view) { | |
| 2224 | - let offset = 2; | |
| 2225 | - while (offset < view.byteLength) { | |
| 2226 | - if (view.getUint8(offset) !== 255) { | |
| 2227 | - return null; | |
| 2228 | - } | |
| 2229 | - while (offset < view.byteLength && view.getUint8(offset) === 255) { | |
| 2230 | - offset++; | |
| 2231 | - } | |
| 2232 | - if (offset >= view.byteLength) { | |
| 2233 | - return null; | |
| 2234 | - } | |
| 2235 | - const marker = view.getUint8(offset); | |
| 2236 | - offset++; | |
| 2237 | - if (marker === 1 || marker >= 208 && marker <= 217) { | |
| 2238 | - continue; | |
| 2239 | - } | |
| 2240 | - if (marker === 218) { | |
| 2241 | - return null; | |
| 2242 | - } | |
| 2243 | - if (offset + 2 > view.byteLength) { | |
| 2244 | - return null; | |
| 2245 | - } | |
| 2246 | - const segmentLength = view.getUint16(offset); | |
| 2247 | - if (segmentLength < 2) { | |
| 2248 | - return null; | |
| 2249 | - } | |
| 2250 | - const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204; | |
| 2251 | - if (isStartOfFrame) { | |
| 2252 | - if (offset + 7 > view.byteLength) { | |
| 2253 | - return null; | |
| 2254 | - } | |
| 2255 | - const height = view.getUint16(offset + 3); | |
| 2256 | - const width = view.getUint16(offset + 5); | |
| 2257 | - const interlaced = marker === 194 || marker === 198 || marker === 202 || marker === 206; | |
| 2258 | - return { width, height, interlaced }; | |
| 2259 | - } | |
| 2260 | - offset += segmentLength; | |
| 2261 | - } | |
| 2262 | - return null; | |
| 2263 | - } | |
| 2264 | - function parsePng(view) { | |
| 2265 | - if (view.byteLength < 29) { | |
| 2266 | - return null; | |
| 2267 | - } | |
| 2268 | - const isIhdr = view.getUint8(12) === 73 && // I | |
| 2269 | - view.getUint8(13) === 72 && // H | |
| 2270 | - view.getUint8(14) === 68 && // D | |
| 2271 | - view.getUint8(15) === 82; | |
| 2272 | - if (!isIhdr) { | |
| 2273 | - return null; | |
| 2274 | - } | |
| 2275 | - const width = view.getUint32(16); | |
| 2276 | - const height = view.getUint32(20); | |
| 2277 | - const interlaceMethod = view.getUint8(28); | |
| 2278 | - return { width, height, interlaced: interlaceMethod !== 0 }; | |
| 2279 | - } | |
| 2280 | - async function getImageDimensions(file) { | |
| 2281 | - try { | |
| 2282 | - const headerBytes = Math.min(file.size, MAX_HEADER_BYTES); | |
| 2283 | - const buffer = await file.slice(0, headerBytes).arrayBuffer(); | |
| 2284 | - const view = new DataView(buffer); | |
| 2285 | - if (view.byteLength >= 3 && view.getUint16(0) === 65496) { | |
| 2286 | - return parseJpeg(view); | |
| 2287 | - } | |
| 2288 | - if (view.byteLength >= 8 && view.getUint32(0) === 2303741511 && view.getUint32(4) === 218765834) { | |
| 2289 | - return parsePng(view); | |
| 2290 | - } | |
| 2291 | - return null; | |
| 2292 | - } catch { | |
| 2293 | - return null; | |
| 2294 | - } | |
| 2295 | - } | |
| 2296 | - | |
| 2297 | 900 | // packages/upload-media/build-module/stub-file.mjs |
| 2298 | 901 | var StubFile = class extends File { |
| 2299 | 902 | constructor(fileName = "stub-file") { |
| 2300 | 903 | super([], fileName); |
| @@ -2302,9 +905,14 @@ | ||
| 2302 | 905 | }; |
| 2303 | 906 | |
| 2304 | 907 | // packages/upload-media/build-module/store/private-actions.mjs |
| 2305 | 908 | var DEFAULT_OUTPUT_QUALITY = 0.82; |
| 2306 | - var ultraHdrItems = /* @__PURE__ */ new Set(); | |
| 909 | + function shouldPauseForSideload(item, operation, select2) { | |
| 910 | + if (operation !== OperationType.Upload || !item.parentId || !item.additionalData.post) { | |
| 911 | + return false; | |
| 912 | + } | |
| 913 | + return select2.isUploadingToPost(item.additionalData.post); | |
| 914 | + } | |
| 2307 | 915 | function addItem({ |
| 2308 | 916 | file: fileOrBlob, |
| 2309 | 917 | batchId, |
| 2310 | 918 | onChange, |
| @@ -2340,8 +948,9 @@ | ||
| 2340 | 948 | attachment: { |
| 2341 | 949 | url: blobUrl |
| 2342 | 950 | }, |
| 2343 | 951 | additionalData: { |
| 952 | + convert_format: false, | |
| 2344 | 953 | generate_sub_sizes: false, |
| 2345 | 954 | ...additionalData |
| 2346 | 955 | }, |
| 2347 | 956 | onChange, |
| @@ -2405,8 +1014,15 @@ | ||
| 2405 | 1014 | parentId |
| 2406 | 1015 | } = item; |
| 2407 | 1016 | const operation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; |
| 2408 | 1017 | const operationArgs = Array.isArray(item.operations?.[0]) ? item.operations[0][1] : void 0; |
| 1018 | + if (shouldPauseForSideload(item, operation, select2)) { | |
| 1019 | + dispatch({ | |
| 1020 | + type: Type.PauseItem, | |
| 1021 | + id | |
| 1022 | + }); | |
| 1023 | + return; | |
| 1024 | + } | |
| 2409 | 1025 | if (operation === OperationType.Upload) { |
| 2410 | 1026 | const settings = select2.getSettings(); |
| 2411 | 1027 | const activeCount = select2.getActiveUploadCount(); |
| 2412 | 1028 | if (activeCount >= settings.maxConcurrentUploads) { |
| @@ -2419,19 +1035,10 @@ | ||
| 2419 | 1035 | if (activeCount >= settings.maxConcurrentImageProcessing) { |
| 2420 | 1036 | return; |
| 2421 | 1037 | } |
| 2422 | 1038 | } |
| 2423 | - if (operation === OperationType.TranscodeGif) { | |
| 2424 | - const activeCount = select2.getActiveVideoProcessingCount(); | |
| 2425 | - if (activeCount >= 1) { | |
| 2426 | - return; | |
| 2427 | - } | |
| 2428 | - } | |
| 2429 | 1039 | if (attachment) { |
| 2430 | - const isHeicUrl = attachment.url && /\.hei[cf]$/i.test(attachment.url); | |
| 2431 | - if (!isHeicUrl) { | |
| 2432 | - onChange?.([attachment]); | |
| 2433 | - } | |
| 1040 | + onChange?.([attachment]); | |
| 2434 | 1041 | } |
| 2435 | 1042 | if (!operation) { |
| 2436 | 1043 | if (parentId || !parentId && !select2.hasPendingItemsByParentId(id)) { |
| 2437 | 1044 | if (attachment) { |
| @@ -2447,12 +1054,8 @@ | ||
| 2447 | 1054 | const parentItem = select2.getItem(parentId); |
| 2448 | 1055 | if (!parentItem) { |
| 2449 | 1056 | return; |
| 2450 | 1057 | } |
| 2451 | - if (parentItem.operations && parentItem.operations.length > 0) { | |
| 2452 | - dispatch.processItem(parentId); | |
| 2453 | - return; | |
| 2454 | - } | |
| 2455 | 1058 | if (attachment) { |
| 2456 | 1059 | parentItem.onSuccess?.([attachment]); |
| 2457 | 1060 | } |
| 2458 | 1061 | dispatch.removeItem(parentId); |
| @@ -2462,19 +1065,13 @@ | ||
| 2462 | 1065 | } |
| 2463 | 1066 | } |
| 2464 | 1067 | return; |
| 2465 | 1068 | } |
| 2466 | - if (operation === OperationType.Finalize && select2.hasPendingItemsByParentId(id)) { | |
| 2467 | - return; | |
| 2468 | - } | |
| 2469 | 1069 | dispatch({ |
| 2470 | 1070 | type: Type.OperationStart, |
| 2471 | 1071 | id, |
| 2472 | 1072 | operation |
| 2473 | 1073 | }); |
| 2474 | - debug( | |
| 2475 | - `Starting operation ${operation} for ${item.file.name} (item ${item.id})` | |
| 2476 | - ); | |
| 2477 | 1074 | switch (operation) { |
| 2478 | 1075 | case OperationType.Prepare: |
| 2479 | 1076 | dispatch.prepareItem(item.id); |
| 2480 | 1077 | break; |
| @@ -2495,14 +1092,8 @@ | ||
| 2495 | 1092 | item.id, |
| 2496 | 1093 | operationArgs |
| 2497 | 1094 | ); |
| 2498 | 1095 | break; |
| 2499 | - case OperationType.TranscodeGif: | |
| 2500 | - dispatch.transcodeGifItem( | |
| 2501 | - item.id, | |
| 2502 | - operationArgs | |
| 2503 | - ); | |
| 2504 | - break; | |
| 2505 | 1096 | case OperationType.Upload: |
| 2506 | 1097 | if (item.parentId) { |
| 2507 | 1098 | dispatch.sideloadItem(id); |
| 2508 | 1099 | } else { |
| @@ -2511,14 +1102,8 @@ | ||
| 2511 | 1102 | break; |
| 2512 | 1103 | case OperationType.ThumbnailGeneration: |
| 2513 | 1104 | dispatch.generateThumbnails(id); |
| 2514 | 1105 | break; |
| 2515 | - case OperationType.Finalize: | |
| 2516 | - dispatch.finalizeItem(id); | |
| 2517 | - break; | |
| 2518 | - case OperationType.DetectUltraHdr: | |
| 2519 | - dispatch.detectUltraHdr(id); | |
| 2520 | - break; | |
| 2521 | 1106 | } |
| 2522 | 1107 | }; |
| 2523 | 1108 | } |
| 2524 | 1109 | function pauseQueue() { |
| @@ -2531,13 +1116,9 @@ | ||
| 2531 | 1116 | dispatch({ |
| 2532 | 1117 | type: Type.ResumeQueue |
| 2533 | 1118 | }); |
| 2534 | 1119 | for (const item of select2.getAllItems()) { |
| 2535 | - if (item.status === ItemStatus.PendingRetry) { | |
| 2536 | - dispatch.executeRetry(item.id); | |
| 2537 | - } else { | |
| 2538 | - dispatch.processItem(item.id); | |
| 2539 | - } | |
| 1120 | + dispatch.processItem(item.id); | |
| 2540 | 1121 | } |
| 2541 | 1122 | }; |
| 2542 | 1123 | } |
| 2543 | 1124 | function pauseItem(id) { |
| @@ -2547,8 +1128,20 @@ | ||
| 2547 | 1128 | id |
| 2548 | 1129 | }); |
| 2549 | 1130 | }; |
| 2550 | 1131 | } |
| 1132 | + function resumeItemByPostId(postOrAttachmentId) { | |
| 1133 | + return async ({ select: select2, dispatch }) => { | |
| 1134 | + const item = select2.getPausedUploadForPost(postOrAttachmentId); | |
| 1135 | + if (item) { | |
| 1136 | + dispatch({ | |
| 1137 | + type: Type.ResumeItem, | |
| 1138 | + id: item.id | |
| 1139 | + }); | |
| 1140 | + dispatch.processItem(item.id); | |
| 1141 | + } | |
| 1142 | + }; | |
| 1143 | + } | |
| 2551 | 1144 | function removeItem(id) { |
| 2552 | 1145 | return async ({ select: select2, dispatch }) => { |
| 2553 | 1146 | const item = select2.getItem(id); |
| 2554 | 1147 | if (!item) { |
| @@ -2553,10 +1146,8 @@ | ||
| 2553 | 1146 | const item = select2.getItem(id); |
| 2554 | 1147 | if (!item) { |
| 2555 | 1148 | return; |
| 2556 | 1149 | } |
| 2557 | - ultraHdrItems.delete(id); | |
| 2558 | - clearRetryTimer(id); | |
| 2559 | 1150 | dispatch({ |
| 2560 | 1151 | type: Type.Remove, |
| 2561 | 1152 | id |
| 2562 | 1153 | }); |
| @@ -2561,9 +1152,8 @@ | ||
| 2561 | 1152 | id |
| 2562 | 1153 | }); |
| 2563 | 1154 | if (select2.getAllItems().length === 0) { |
| 2564 | 1155 | terminateVipsWorker(); |
| 2565 | - terminateVideoConversionWorker(); | |
| 2566 | 1156 | } |
| 2567 | 1157 | }; |
| 2568 | 1158 | } |
| 2569 | 1159 | function finishOperation(id, updates) { |
| @@ -2587,17 +1177,8 @@ | ||
| 2587 | 1177 | for (const pendingItem of pendingItems) { |
| 2588 | 1178 | dispatch.processItem(pendingItem.id); |
| 2589 | 1179 | } |
| 2590 | 1180 | } |
| 2591 | - if (previousOperation === OperationType.TranscodeGif) { | |
| 2592 | - const pendingItems = select2.getPendingVideoProcessing(); | |
| 2593 | - for (const pendingItem of pendingItems) { | |
| 2594 | - dispatch.processItem(pendingItem.id); | |
| 2595 | - } | |
| 2596 | - } | |
| 2597 | - if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate || previousOperation === OperationType.TranscodeImage) { | |
| 2598 | - maybeRecycleVipsWorker(select2.getActiveImageProcessingCount()); | |
| 2599 | - } | |
| 2600 | 1181 | }; |
| 2601 | 1182 | } |
| 2602 | 1183 | var VALID_IMAGE_FORMATS = ["jpeg", "webp", "avif", "png", "gif"]; |
| 2603 | 1184 | function isValidImageFormat(format) { |
| @@ -2602,9 +1183,21 @@ | ||
| 2602 | 1183 | var VALID_IMAGE_FORMATS = ["jpeg", "webp", "avif", "png", "gif"]; |
| 2603 | 1184 | function isValidImageFormat(format) { |
| 2604 | 1185 | return VALID_IMAGE_FORMATS.includes(format); |
| 2605 | 1186 | } |
| 2606 | - async function getTranscodeImageOperation(file, outputMimeType, interlaced = false, quality = DEFAULT_OUTPUT_QUALITY) { | |
| 1187 | + function getInterlacedSetting(outputMimeType, settings) { | |
| 1188 | + switch (outputMimeType) { | |
| 1189 | + case "image/jpeg": | |
| 1190 | + return settings.jpegInterlaced ?? false; | |
| 1191 | + case "image/png": | |
| 1192 | + return settings.pngInterlaced ?? false; | |
| 1193 | + case "image/gif": | |
| 1194 | + return settings.gifInterlaced ?? false; | |
| 1195 | + default: | |
| 1196 | + return false; | |
| 1197 | + } | |
| 1198 | + } | |
| 1199 | + async function getTranscodeImageOperation(file, outputMimeType, settings) { | |
| 2607 | 1200 | if (file.type === "image/png" && outputMimeType === "image/jpeg") { |
| 2608 | 1201 | const blobUrl = (0, import_blob.createBlobURL)(file); |
| 2609 | 1202 | try { |
| 2610 | 1203 | const hasAlpha = await vipsHasTransparency(blobUrl); |
| @@ -2624,10 +1217,10 @@ | ||
| 2624 | 1217 | return [ |
| 2625 | 1218 | OperationType.TranscodeImage, |
| 2626 | 1219 | { |
| 2627 | 1220 | outputFormat: formatPart, |
| 2628 | - outputQuality: quality, | |
| 2629 | - interlaced | |
| 1221 | + outputQuality: DEFAULT_OUTPUT_QUALITY, | |
| 1222 | + interlaced: getInterlacedSetting(outputMimeType, settings) | |
| 2630 | 1223 | } |
| 2631 | 1224 | ]; |
| 2632 | 1225 | } |
| 2633 | 1226 | function prepareItem(id) { |
| @@ -2638,86 +1231,28 @@ | ||
| 2638 | 1231 | } |
| 2639 | 1232 | const { file } = item; |
| 2640 | 1233 | const operations = []; |
| 2641 | 1234 | const settings = select2.getSettings(); |
| 2642 | - if (file.type === "image/gif" && settings.gifConvert !== false && typeof ImageDecoder !== "undefined" && typeof VideoEncoder !== "undefined") { | |
| 2643 | - let isAnimated = false; | |
| 2644 | - try { | |
| 2645 | - isAnimated = isAnimatedGif(await file.arrayBuffer()); | |
| 2646 | - } catch { | |
| 2647 | - isAnimated = false; | |
| 2648 | - } | |
| 2649 | - if (isAnimated) { | |
| 2650 | - let hasTransparency = false; | |
| 2651 | - const blobUrl = (0, import_blob.createBlobURL)(file); | |
| 2652 | - try { | |
| 2653 | - hasTransparency = await vipsHasTransparency(blobUrl); | |
| 2654 | - } catch { | |
| 2655 | - hasTransparency = true; | |
| 2656 | - } finally { | |
| 2657 | - (0, import_blob.revokeBlobURL)(blobUrl); | |
| 2658 | - } | |
| 2659 | - if (!hasTransparency) { | |
| 2660 | - operations.push( | |
| 2661 | - OperationType.Upload, | |
| 2662 | - OperationType.ThumbnailGeneration, | |
| 2663 | - OperationType.Finalize | |
| 2664 | - ); | |
| 2665 | - dispatch({ | |
| 2666 | - type: Type.AddOperations, | |
| 2667 | - id, | |
| 2668 | - operations | |
| 2669 | - }); | |
| 2670 | - dispatch.finishOperation(id, { | |
| 2671 | - animatedGifFile: item.file | |
| 2672 | - }); | |
| 2673 | - return; | |
| 2674 | - } | |
| 2675 | - } | |
| 2676 | - } | |
| 2677 | - let heicJpeg = null; | |
| 2678 | 1235 | const isImage = file.type.startsWith("image/"); |
| 2679 | 1236 | const isVipsSupported = CLIENT_SIDE_SUPPORTED_MIME_TYPES.includes( |
| 2680 | 1237 | file.type |
| 2681 | 1238 | ); |
| 2682 | - const isHeic = HEIC_MIME_TYPES.includes(file.type); | |
| 2683 | - let tooLargeForClient = false; | |
| 2684 | 1239 | if (isImage && isVipsSupported) { |
| 2685 | - const dimensions = await getImageDimensions(file); | |
| 2686 | - if (dimensions && exceedsClientProcessingMemory(dimensions)) { | |
| 2687 | - tooLargeForClient = true; | |
| 2688 | - } | |
| 2689 | - } | |
| 2690 | - if (file.type === "image/jpeg" && !tooLargeForClient) { | |
| 2691 | - operations.push(OperationType.DetectUltraHdr); | |
| 2692 | - } | |
| 2693 | - if (isImage && isVipsSupported && !tooLargeForClient) { | |
| 2694 | - operations.push( | |
| 2695 | - OperationType.Upload, | |
| 2696 | - OperationType.ThumbnailGeneration, | |
| 2697 | - OperationType.Finalize | |
| 2698 | - ); | |
| 2699 | - } else if (isImage && isHeic) { | |
| 2700 | - try { | |
| 2701 | - heicJpeg = await canvasConvertToJpeg( | |
| 1240 | + const { imageOutputFormats } = settings; | |
| 1241 | + const outputMimeType = imageOutputFormats?.[file.type]; | |
| 1242 | + if (outputMimeType && outputMimeType !== file.type) { | |
| 1243 | + const transcodeOperation = await getTranscodeImageOperation( | |
| 2702 | 1244 | file, |
| 2703 | - settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY | |
| 1245 | + outputMimeType, | |
| 1246 | + settings | |
| 2704 | 1247 | ); |
| 2705 | - } catch { | |
| 2706 | - dispatch.cancelItem( | |
| 2707 | - id, | |
| 2708 | - new UploadError({ | |
| 2709 | - code: ErrorCode.HEIC_DECODE_ERROR, | |
| 2710 | - message: "This browser cannot decode HEIC images and the server does not support them either. Please convert to JPEG before uploading.", | |
| 2711 | - file | |
| 2712 | - }) | |
| 2713 | - ); | |
| 2714 | - return; | |
| 1248 | + if (transcodeOperation) { | |
| 1249 | + operations.push(transcodeOperation); | |
| 1250 | + } | |
| 2715 | 1251 | } |
| 2716 | 1252 | operations.push( |
| 2717 | 1253 | OperationType.Upload, |
| 2718 | - OperationType.ThumbnailGeneration, | |
| 2719 | - OperationType.Finalize | |
| 1254 | + OperationType.ThumbnailGeneration | |
| 2720 | 1255 | ); |
| 2721 | 1256 | } else { |
| 2722 | 1257 | operations.push(OperationType.Upload); |
| 2723 | 1258 | } |
| @@ -2725,58 +1260,17 @@ | ||
| 2725 | 1260 | type: Type.AddOperations, |
| 2726 | 1261 | id, |
| 2727 | 1262 | operations |
| 2728 | 1263 | }); |
| 2729 | - let updates; | |
| 2730 | - if (isHeic && heicJpeg) { | |
| 2731 | - const vipsAvailable = isClientSideMediaSupported(); | |
| 2732 | - updates = { | |
| 2733 | - file: heicJpeg, | |
| 2734 | - sourceFile: heicJpeg, | |
| 2735 | - originalHeicFile: item.file, | |
| 2736 | - additionalData: { | |
| 2737 | - ...item.additionalData, | |
| 2738 | - generate_sub_sizes: !vipsAvailable, | |
| 2739 | - convert_format: true | |
| 2740 | - } | |
| 2741 | - }; | |
| 2742 | - } else if (!isVipsSupported || !isImage || tooLargeForClient) { | |
| 2743 | - updates = { | |
| 2744 | - additionalData: { | |
| 2745 | - ...item.additionalData, | |
| 2746 | - generate_sub_sizes: true, | |
| 2747 | - convert_format: true | |
| 2748 | - } | |
| 2749 | - }; | |
| 2750 | - } else { | |
| 2751 | - updates = { | |
| 2752 | - additionalData: { | |
| 2753 | - ...item.additionalData, | |
| 2754 | - generate_sub_sizes: false | |
| 2755 | - } | |
| 2756 | - }; | |
| 2757 | - } | |
| 1264 | + const updates = !isVipsSupported || !isImage ? { | |
| 1265 | + additionalData: { | |
| 1266 | + ...item.additionalData, | |
| 1267 | + generate_sub_sizes: true | |
| 1268 | + } | |
| 1269 | + } : {}; | |
| 2758 | 1270 | dispatch.finishOperation(id, updates); |
| 2759 | 1271 | }; |
| 2760 | 1272 | } |
| 2761 | - function detectUltraHdr(id) { | |
| 2762 | - return async ({ select: select2, dispatch }) => { | |
| 2763 | - const item = select2.getItem(id); | |
| 2764 | - if (!item) { | |
| 2765 | - return; | |
| 2766 | - } | |
| 2767 | - let info; | |
| 2768 | - try { | |
| 2769 | - const buffer = await item.file.arrayBuffer(); | |
| 2770 | - info = await vipsGetUltraHdrInfo(buffer); | |
| 2771 | - } catch { | |
| 2772 | - } | |
| 2773 | - if (info) { | |
| 2774 | - ultraHdrItems.add(id); | |
| 2775 | - } | |
| 2776 | - dispatch.finishOperation(id, {}); | |
| 2777 | - }; | |
| 2778 | - } | |
| 2779 | 1273 | function uploadItem(id) { |
| 2780 | 1274 | return async ({ select: select2, dispatch }) => { |
| 2781 | 1275 | const item = select2.getItem(id); |
| 2782 | 1276 | if (!item) { |
| @@ -2781,42 +1275,23 @@ | ||
| 2781 | 1275 | const item = select2.getItem(id); |
| 2782 | 1276 | if (!item) { |
| 2783 | 1277 | return; |
| 2784 | 1278 | } |
| 2785 | - const startTime = performance.now(); | |
| 2786 | - let finished = false; | |
| 2787 | - const finishUpload = (attachment) => { | |
| 2788 | - if (finished) { | |
| 2789 | - return; | |
| 2790 | - } | |
| 2791 | - finished = true; | |
| 2792 | - measure({ | |
| 2793 | - measureName: `Upload ${item.file.name}`, | |
| 2794 | - startTime, | |
| 2795 | - tooltipText: item.file.name, | |
| 2796 | - properties: [ | |
| 2797 | - ["Item ID", item.id], | |
| 2798 | - ["File name", item.file.name] | |
| 2799 | - ] | |
| 2800 | - }); | |
| 2801 | - dispatch.finishOperation(id, { attachment }); | |
| 2802 | - }; | |
| 2803 | 1279 | select2.getSettings().mediaUpload({ |
| 2804 | 1280 | filesList: [item.file], |
| 2805 | 1281 | additionalData: item.additionalData, |
| 2806 | 1282 | signal: item.abortController?.signal, |
| 2807 | - // The queue's own items drive upload progress UI and save | |
| 2808 | - // locking; without this, consumers that track uploads themselves | |
| 2809 | - // (e.g. the editor's progress snackbar) would count this file a | |
| 2810 | - // second time. | |
| 2811 | - isTransportOnly: true, | |
| 2812 | 1283 | onFileChange: ([attachment]) => { |
| 2813 | - if (attachment && !(0, import_blob.isBlobURL)(attachment.url)) { | |
| 2814 | - finishUpload(attachment); | |
| 1284 | + if (!(0, import_blob.isBlobURL)(attachment.url)) { | |
| 1285 | + dispatch.finishOperation(id, { | |
| 1286 | + attachment | |
| 1287 | + }); | |
| 2815 | 1288 | } |
| 2816 | 1289 | }, |
| 2817 | 1290 | onSuccess: ([attachment]) => { |
| 2818 | - finishUpload(attachment); | |
| 1291 | + dispatch.finishOperation(id, { | |
| 1292 | + attachment | |
| 1293 | + }); | |
| 2819 | 1294 | }, |
| 2820 | 1295 | onError: (error) => { |
| 2821 | 1296 | dispatch.cancelItem(id, error); |
| 2822 | 1297 | } |
| @@ -2834,35 +1309,20 @@ | ||
| 2834 | 1309 | if (!mediaSideload) { |
| 2835 | 1310 | dispatch.finishOperation(id, {}); |
| 2836 | 1311 | return; |
| 2837 | 1312 | } |
| 2838 | - const startTime = performance.now(); | |
| 2839 | 1313 | mediaSideload({ |
| 2840 | 1314 | file: item.file, |
| 2841 | 1315 | attachmentId: post, |
| 2842 | 1316 | additionalData, |
| 2843 | 1317 | signal: item.abortController?.signal, |
| 2844 | - onSuccess: (subSize) => { | |
| 2845 | - measure({ | |
| 2846 | - measureName: `Sideload ${item.file.name}`, | |
| 2847 | - startTime, | |
| 2848 | - tooltipText: item.file.name, | |
| 2849 | - properties: [ | |
| 2850 | - ["Item ID", item.id], | |
| 2851 | - ["File name", item.file.name] | |
| 2852 | - ] | |
| 2853 | - }); | |
| 2854 | - if (item.parentId) { | |
| 2855 | - dispatch({ | |
| 2856 | - type: Type.AccumulateSubSize, | |
| 2857 | - id: item.parentId, | |
| 2858 | - subSize | |
| 2859 | - }); | |
| 2860 | - } | |
| 2861 | - dispatch.finishOperation(id, {}); | |
| 1318 | + onFileChange: ([attachment]) => { | |
| 1319 | + dispatch.finishOperation(id, { attachment }); | |
| 1320 | + dispatch.resumeItemByPostId(post); | |
| 2862 | 1321 | }, |
| 2863 | 1322 | onError: (error) => { |
| 2864 | 1323 | dispatch.cancelItem(id, error); |
| 1324 | + dispatch.resumeItemByPostId(post); | |
| 2865 | 1325 | } |
| 2866 | 1326 | }); |
| 2867 | 1327 | }; |
| 2868 | 1328 | } |
| @@ -2877,36 +1337,21 @@ | ||
| 2877 | 1337 | file: item.file |
| 2878 | 1338 | }); |
| 2879 | 1339 | return; |
| 2880 | 1340 | } |
| 2881 | - const startTime = performance.now(); | |
| 2882 | 1341 | const addSuffix = Boolean(item.parentId); |
| 2883 | 1342 | const scaledSuffix = Boolean(args.isThresholdResize); |
| 2884 | - const { imageStripMeta, imageMaxBitDepth } = select2.getSettings(); | |
| 2885 | 1343 | try { |
| 2886 | 1344 | const file = await vipsResizeImage( |
| 2887 | 1345 | item.id, |
| 2888 | 1346 | item.file, |
| 2889 | 1347 | args.resize, |
| 2890 | - { | |
| 2891 | - smartCrop: false, | |
| 2892 | - addSuffix, | |
| 2893 | - signal: item.abortController?.signal, | |
| 2894 | - scaledSuffix, | |
| 2895 | - quality: args.quality, | |
| 2896 | - stripMeta: imageStripMeta, | |
| 2897 | - maxBitdepth: imageMaxBitDepth | |
| 2898 | - } | |
| 1348 | + false, | |
| 1349 | + // smartCrop | |
| 1350 | + addSuffix, | |
| 1351 | + item.abortController?.signal, | |
| 1352 | + scaledSuffix | |
| 2899 | 1353 | ); |
| 2900 | - measure({ | |
| 2901 | - measureName: `ResizeCrop ${item.file.name}`, | |
| 2902 | - startTime, | |
| 2903 | - tooltipText: item.file.name, | |
| 2904 | - properties: [ | |
| 2905 | - ["Item ID", item.id], | |
| 2906 | - ["File name", item.file.name] | |
| 2907 | - ] | |
| 2908 | - }); | |
| 2909 | 1354 | const blobUrl = (0, import_blob.createBlobURL)(file); |
| 2910 | 1355 | dispatch({ |
| 2911 | 1356 | type: Type.CacheBlobUrl, |
| 2912 | 1357 | id, |
| @@ -2921,12 +1366,10 @@ | ||
| 2921 | 1366 | } catch (error) { |
| 2922 | 1367 | dispatch.cancelItem( |
| 2923 | 1368 | id, |
| 2924 | 1369 | new UploadError({ |
| 2925 | - code: ErrorCode.IMAGE_TRANSCODING_ERROR, | |
| 2926 | - message: (0, import_i18n6.__)( | |
| 2927 | - "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading." | |
| 2928 | - ), | |
| 1370 | + code: "IMAGE_TRANSCODING_ERROR", | |
| 1371 | + message: "File could not be uploaded", | |
| 2929 | 1372 | file: item.file, |
| 2930 | 1373 | cause: error instanceof Error ? error : void 0 |
| 2931 | 1374 | }) |
| 2932 | 1375 | ); |
| @@ -2944,9 +1387,8 @@ | ||
| 2944 | 1387 | file: item.file |
| 2945 | 1388 | }); |
| 2946 | 1389 | return; |
| 2947 | 1390 | } |
| 2948 | - const startTime = performance.now(); | |
| 2949 | 1391 | try { |
| 2950 | 1392 | const file = await vipsRotateImage( |
| 2951 | 1393 | item.id, |
| 2952 | 1394 | item.file, |
| @@ -2952,17 +1394,8 @@ | ||
| 2952 | 1394 | item.file, |
| 2953 | 1395 | args.orientation, |
| 2954 | 1396 | item.abortController?.signal |
| 2955 | 1397 | ); |
| 2956 | - measure({ | |
| 2957 | - measureName: `Rotate ${item.file.name}`, | |
| 2958 | - startTime, | |
| 2959 | - tooltipText: item.file.name, | |
| 2960 | - properties: [ | |
| 2961 | - ["Item ID", item.id], | |
| 2962 | - ["File name", item.file.name] | |
| 2963 | - ] | |
| 2964 | - }); | |
| 2965 | 1398 | const blobUrl = (0, import_blob.createBlobURL)(file); |
| 2966 | 1399 | dispatch({ |
| 2967 | 1400 | type: Type.CacheBlobUrl, |
| 2968 | 1401 | id, |
| @@ -2977,12 +1410,10 @@ | ||
| 2977 | 1410 | } catch (error) { |
| 2978 | 1411 | dispatch.cancelItem( |
| 2979 | 1412 | id, |
| 2980 | 1413 | new UploadError({ |
| 2981 | - code: ErrorCode.IMAGE_ROTATION_ERROR, | |
| 2982 | - message: (0, import_i18n6.__)( | |
| 2983 | - "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading." | |
| 2984 | - ), | |
| 1414 | + code: "IMAGE_ROTATION_ERROR", | |
| 1415 | + message: "Image could not be rotated", | |
| 2985 | 1416 | file: item.file, |
| 2986 | 1417 | cause: error instanceof Error ? error : void 0 |
| 2987 | 1418 | }) |
| 2988 | 1419 | ); |
| @@ -3000,34 +1431,19 @@ | ||
| 3000 | 1431 | file: item.file |
| 3001 | 1432 | }); |
| 3002 | 1433 | return; |
| 3003 | 1434 | } |
| 3004 | - const startTime = performance.now(); | |
| 3005 | 1435 | const outputMimeType = `image/${args.outputFormat}`; |
| 3006 | 1436 | const quality = args.outputQuality ?? DEFAULT_OUTPUT_QUALITY; |
| 3007 | 1437 | const interlaced = args.interlaced ?? false; |
| 3008 | - const { imageStripMeta, imageMaxBitDepth } = select2.getSettings(); | |
| 3009 | 1438 | try { |
| 3010 | 1439 | const file = await vipsConvertImageFormat( |
| 3011 | 1440 | item.id, |
| 3012 | 1441 | item.file, |
| 3013 | 1442 | outputMimeType, |
| 3014 | - { | |
| 3015 | - quality, | |
| 3016 | - interlaced, | |
| 3017 | - stripMeta: imageStripMeta, | |
| 3018 | - maxBitdepth: imageMaxBitDepth | |
| 3019 | - } | |
| 1443 | + quality, | |
| 1444 | + interlaced | |
| 3020 | 1445 | ); |
| 3021 | - measure({ | |
| 3022 | - measureName: `Transcode ${item.file.name}`, | |
| 3023 | - startTime, | |
| 3024 | - tooltipText: item.file.name, | |
| 3025 | - properties: [ | |
| 3026 | - ["Item ID", item.id], | |
| 3027 | - ["File name", item.file.name] | |
| 3028 | - ] | |
| 3029 | - }); | |
| 3030 | 1446 | const blobUrl = (0, import_blob.createBlobURL)(file); |
| 3031 | 1447 | dispatch({ |
| 3032 | 1448 | type: Type.CacheBlobUrl, |
| 3033 | 1449 | id, |
| @@ -3042,9 +1458,9 @@ | ||
| 3042 | 1458 | } catch (error) { |
| 3043 | 1459 | dispatch.cancelItem( |
| 3044 | 1460 | id, |
| 3045 | 1461 | new UploadError({ |
| 3046 | - code: ErrorCode.MEDIA_TRANSCODING_ERROR, | |
| 1462 | + code: "MEDIA_TRANSCODING_ERROR", | |
| 3047 | 1463 | message: "Image could not be transcoded to the target format", |
| 3048 | 1464 | file: item.file, |
| 3049 | 1465 | cause: error instanceof Error ? error : void 0 |
| 3050 | 1466 | }) |
| @@ -3051,91 +1467,8 @@ | ||
| 3051 | 1467 | ); |
| 3052 | 1468 | } |
| 3053 | 1469 | }; |
| 3054 | 1470 | } |
| 3055 | - function transcodeGifItem(id, args) { | |
| 3056 | - return async ({ select: select2, dispatch }) => { | |
| 3057 | - const item = select2.getItem(id); | |
| 3058 | - if (!item) { | |
| 3059 | - return; | |
| 3060 | - } | |
| 3061 | - const outputFormat = args?.outputFormat ?? "mp4"; | |
| 3062 | - const outputMimeType = `video/${outputFormat}`; | |
| 3063 | - const gifFile = item.file; | |
| 3064 | - try { | |
| 3065 | - const file = await convertGifToVideo( | |
| 3066 | - item.id, | |
| 3067 | - gifFile, | |
| 3068 | - outputMimeType, | |
| 3069 | - { | |
| 3070 | - timeout: args?.timeout, | |
| 3071 | - maxTotalPixels: args?.maxTotalPixels | |
| 3072 | - } | |
| 3073 | - ); | |
| 3074 | - dispatch.finishOperation(id, { file }); | |
| 3075 | - dispatch.addSideloadItem({ | |
| 3076 | - file: gifFile, | |
| 3077 | - batchId: v4_default(), | |
| 3078 | - parentId: item.parentId, | |
| 3079 | - additionalData: { | |
| 3080 | - post: item.additionalData?.post, | |
| 3081 | - image_size: "animated_video_poster", | |
| 3082 | - convert_format: false | |
| 3083 | - }, | |
| 3084 | - operations: [ | |
| 3085 | - [ | |
| 3086 | - OperationType.TranscodeImage, | |
| 3087 | - { | |
| 3088 | - outputFormat: "jpeg", | |
| 3089 | - outputQuality: DEFAULT_OUTPUT_QUALITY, | |
| 3090 | - interlaced: false | |
| 3091 | - } | |
| 3092 | - ], | |
| 3093 | - OperationType.Upload | |
| 3094 | - ] | |
| 3095 | - }); | |
| 3096 | - } catch (error) { | |
| 3097 | - if (isUnsupportedConversionError(error)) { | |
| 3098 | - if (isSizeLimitConversionError(error)) { | |
| 3099 | - debug( | |
| 3100 | - `Skipping GIF to video conversion: ${error instanceof Error ? error.message : error}` | |
| 3101 | - ); | |
| 3102 | - } | |
| 3103 | - dispatch.cancelItem( | |
| 3104 | - id, | |
| 3105 | - new Error("Animated GIF conversion unsupported"), | |
| 3106 | - true | |
| 3107 | - ); | |
| 3108 | - return; | |
| 3109 | - } | |
| 3110 | - if (isConversionTimeoutError(error)) { | |
| 3111 | - debug( | |
| 3112 | - `GIF to video conversion timed out; keeping the original GIF only: ${error instanceof Error ? error.message : error}` | |
| 3113 | - ); | |
| 3114 | - dispatch.cancelItem( | |
| 3115 | - id, | |
| 3116 | - new Error("Animated GIF conversion timed out"), | |
| 3117 | - true | |
| 3118 | - ); | |
| 3119 | - return; | |
| 3120 | - } | |
| 3121 | - console.error( | |
| 3122 | - "[video-conversion] GIF to video conversion failed:", | |
| 3123 | - error | |
| 3124 | - ); | |
| 3125 | - dispatch.cancelItem( | |
| 3126 | - id, | |
| 3127 | - new UploadError({ | |
| 3128 | - code: ErrorCode.GIF_TRANSCODING_ERROR, | |
| 3129 | - message: "Animated GIF could not be converted to video", | |
| 3130 | - file: item.file, | |
| 3131 | - cause: error instanceof Error ? error : void 0 | |
| 3132 | - }), | |
| 3133 | - true | |
| 3134 | - ); | |
| 3135 | - } | |
| 3136 | - }; | |
| 3137 | - } | |
| 3138 | 1471 | function generateThumbnails(id) { |
| 3139 | 1472 | return async ({ select: select2, dispatch }) => { |
| 3140 | 1473 | const item = select2.getItem(id); |
| 3141 | 1474 | if (!item) { |
| @@ -3145,74 +1478,19 @@ | ||
| 3145 | 1478 | dispatch.finishOperation(id, {}); |
| 3146 | 1479 | return; |
| 3147 | 1480 | } |
| 3148 | 1481 | const attachment = item.attachment; |
| 3149 | - const settings = select2.getSettings(); | |
| 3150 | - if (item.originalHeicFile && attachment.id) { | |
| 3151 | - dispatch.addSideloadItem({ | |
| 3152 | - file: item.originalHeicFile, | |
| 3153 | - batchId: v4_default(), | |
| 3154 | - parentId: item.id, | |
| 3155 | - additionalData: { | |
| 3156 | - post: attachment.id, | |
| 3157 | - image_size: "source_original", | |
| 3158 | - convert_format: false | |
| 3159 | - }, | |
| 3160 | - operations: [OperationType.Upload] | |
| 3161 | - }); | |
| 3162 | - } | |
| 3163 | - if (item.animatedGifFile && attachment.id) { | |
| 3164 | - const outputFormat = settings.videoOutputFormat === "video/webm" ? "webm" : "mp4"; | |
| 3165 | - dispatch.addSideloadItem({ | |
| 3166 | - file: item.animatedGifFile, | |
| 3167 | - batchId: v4_default(), | |
| 3168 | - parentId: item.id, | |
| 3169 | - additionalData: { | |
| 3170 | - post: attachment.id, | |
| 3171 | - image_size: "animated_video", | |
| 3172 | - convert_format: false | |
| 3173 | - }, | |
| 3174 | - operations: [ | |
| 3175 | - [ | |
| 3176 | - OperationType.TranscodeGif, | |
| 3177 | - { | |
| 3178 | - outputFormat | |
| 3179 | - } | |
| 3180 | - ], | |
| 3181 | - OperationType.Upload | |
| 3182 | - ] | |
| 3183 | - }); | |
| 3184 | - } | |
| 3185 | - let exifOrientation = attachment.exif_orientation || 1; | |
| 3186 | - const sourceType = item.sourceFile.type; | |
| 3187 | - const isHeifFamily = sourceType === "image/avif" || sourceType === "image/heif"; | |
| 3188 | - let needsClientRotation = false; | |
| 3189 | - if (isHeifFamily) { | |
| 3190 | - exifOrientation = getUnappliedExifOrientation( | |
| 3191 | - await item.sourceFile.arrayBuffer() | |
| 3192 | - ); | |
| 3193 | - needsClientRotation = exifOrientation !== 1; | |
| 3194 | - } | |
| 3195 | - let rotatedSource; | |
| 3196 | - { | |
| 3197 | - const needsRotation = exifOrientation !== 1 && !item.file.name.includes("-scaled"); | |
| 3198 | - if ((needsRotation || needsClientRotation) && attachment.id) { | |
| 3199 | - try { | |
| 3200 | - rotatedSource = await vipsRotateImage( | |
| 3201 | - item.id, | |
| 3202 | - item.sourceFile, | |
| 3203 | - exifOrientation, | |
| 3204 | - item.abortController?.signal | |
| 3205 | - ); | |
| 3206 | - } catch { | |
| 3207 | - console.warn( | |
| 3208 | - "Failed to rotate image, continuing with thumbnails" | |
| 3209 | - ); | |
| 3210 | - } | |
| 3211 | - } | |
| 3212 | - if (needsRotation && rotatedSource && attachment.id) { | |
| 1482 | + const needsRotation = attachment.exif_orientation && attachment.exif_orientation !== 1 && !item.file.name.includes("-scaled"); | |
| 1483 | + if (needsRotation && attachment.id) { | |
| 1484 | + try { | |
| 1485 | + const rotatedFile = await vipsRotateImage( | |
| 1486 | + item.id, | |
| 1487 | + item.sourceFile, | |
| 1488 | + attachment.exif_orientation, | |
| 1489 | + item.abortController?.signal | |
| 1490 | + ); | |
| 3213 | 1491 | dispatch.addSideloadItem({ |
| 3214 | - file: rotatedSource, | |
| 1492 | + file: rotatedFile, | |
| 3215 | 1493 | batchId: v4_default(), |
| 3216 | 1494 | parentId: item.id, |
| 3217 | 1495 | additionalData: { |
| 3218 | 1496 | post: attachment.id, |
| @@ -3220,40 +1498,31 @@ | ||
| 3220 | 1498 | convert_format: false |
| 3221 | 1499 | }, |
| 3222 | 1500 | operations: [OperationType.Upload] |
| 3223 | 1501 | }); |
| 1502 | + } catch { | |
| 1503 | + console.warn( | |
| 1504 | + "Failed to rotate image, continuing with thumbnails" | |
| 1505 | + ); | |
| 3224 | 1506 | } |
| 3225 | 1507 | } |
| 3226 | 1508 | if (!item.parentId && attachment.missing_image_sizes && attachment.missing_image_sizes.length > 0) { |
| 1509 | + const file = attachment.filename ? renameFile(item.sourceFile, attachment.filename) : item.sourceFile; | |
| 1510 | + const batchId = v4_default(); | |
| 1511 | + const settings = select2.getSettings(); | |
| 3227 | 1512 | const allImageSizes = settings.allImageSizes || {}; |
| 3228 | - const sizesToGenerate = attachment.missing_image_sizes; | |
| 3229 | - const thumbnailSource = needsClientRotation && rotatedSource ? rotatedSource : item.sourceFile; | |
| 3230 | - const file = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource; | |
| 3231 | - const batchId = v4_default(); | |
| 3232 | - const isUltraHdr = ultraHdrItems.has(item.id); | |
| 3233 | - const outputMimeType = attachment.image_output_format; | |
| 3234 | - const interlaced = attachment.image_save_progressive ?? false; | |
| 3235 | - const imageQuality = attachment.image_quality; | |
| 3236 | - const fallbackQuality = settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY; | |
| 3237 | - const defaultQuality = typeof imageQuality?.default === "number" ? imageQuality.default / 100 : fallbackQuality; | |
| 3238 | - const qualityForSize = (sizeName) => { | |
| 3239 | - const sized = imageQuality?.sizes?.[sizeName]; | |
| 3240 | - if (typeof sized === "number") { | |
| 3241 | - return sized / 100; | |
| 3242 | - } | |
| 3243 | - return defaultQuality; | |
| 3244 | - }; | |
| 1513 | + const { imageOutputFormats } = settings; | |
| 1514 | + const sourceType = item.sourceFile.type; | |
| 1515 | + const outputMimeType = imageOutputFormats?.[sourceType]; | |
| 3245 | 1516 | let thumbnailTranscodeOperation = null; |
| 3246 | - if (!isUltraHdr && outputMimeType) { | |
| 1517 | + if (outputMimeType && outputMimeType !== sourceType) { | |
| 3247 | 1518 | thumbnailTranscodeOperation = await getTranscodeImageOperation( |
| 3248 | - thumbnailSource, | |
| 1519 | + item.sourceFile, | |
| 3249 | 1520 | outputMimeType, |
| 3250 | - interlaced, | |
| 3251 | - defaultQuality | |
| 1521 | + settings | |
| 3252 | 1522 | ); |
| 3253 | 1523 | } |
| 3254 | - const dimensionGroups = /* @__PURE__ */ new Map(); | |
| 3255 | - for (const name of sizesToGenerate) { | |
| 1524 | + for (const name of attachment.missing_image_sizes) { | |
| 3256 | 1525 | const imageSize = allImageSizes[name]; |
| 3257 | 1526 | if (!imageSize) { |
| 3258 | 1527 | console.warn( |
| 3259 | 1528 | `Image size "${name}" not found in configuration` |
| @@ -3259,38 +1528,23 @@ | ||
| 3259 | 1528 | `Image size "${name}" not found in configuration` |
| 3260 | 1529 | ); |
| 3261 | 1530 | continue; |
| 3262 | 1531 | } |
| 3263 | - const key = `${imageSize.width}x${imageSize.height}x${imageSize.crop}`; | |
| 3264 | - const group = dimensionGroups.get(key); | |
| 3265 | - if (group) { | |
| 3266 | - group.push(name); | |
| 3267 | - } else { | |
| 3268 | - dimensionGroups.set(key, [name]); | |
| 3269 | - } | |
| 3270 | - } | |
| 3271 | - for (const [, names] of dimensionGroups) { | |
| 3272 | - const imageSize = allImageSizes[names[0]]; | |
| 3273 | - const sizeQuality = qualityForSize(names[0]); | |
| 3274 | 1532 | const thumbnailOperations = [ |
| 3275 | - [ | |
| 3276 | - OperationType.ResizeCrop, | |
| 3277 | - { resize: imageSize, quality: sizeQuality } | |
| 3278 | - ] | |
| 1533 | + [OperationType.ResizeCrop, { resize: imageSize }] | |
| 3279 | 1534 | ]; |
| 3280 | - if (!isUltraHdr && thumbnailTranscodeOperation) { | |
| 3281 | - thumbnailOperations.push([ | |
| 3282 | - thumbnailTranscodeOperation[0], | |
| 3283 | - { | |
| 3284 | - ...thumbnailTranscodeOperation[1], | |
| 3285 | - outputQuality: sizeQuality | |
| 3286 | - } | |
| 3287 | - ]); | |
| 1535 | + if (thumbnailTranscodeOperation) { | |
| 1536 | + thumbnailOperations.push(thumbnailTranscodeOperation); | |
| 3288 | 1537 | } |
| 3289 | 1538 | thumbnailOperations.push(OperationType.Upload); |
| 3290 | - const imageSizeParam = names.length === 1 ? names[0] : names; | |
| 3291 | 1539 | dispatch.addSideloadItem({ |
| 3292 | 1540 | file, |
| 1541 | + onChange: ([updatedAttachment]) => { | |
| 1542 | + if ((0, import_blob.isBlobURL)(updatedAttachment.url)) { | |
| 1543 | + return; | |
| 1544 | + } | |
| 1545 | + item.onChange?.([updatedAttachment]); | |
| 1546 | + }, | |
| 3293 | 1547 | batchId, |
| 3294 | 1548 | parentId: item.id, |
| 3295 | 1549 | additionalData: { |
| 3296 | 1550 | // Sideloading does not use the parent post ID but the |
| @@ -3295,53 +1549,54 @@ | ||
| 3295 | 1549 | additionalData: { |
| 3296 | 1550 | // Sideloading does not use the parent post ID but the |
| 3297 | 1551 | // attachment ID as the image sizes need to be added to it. |
| 3298 | 1552 | post: attachment.id, |
| 3299 | - image_size: imageSizeParam, | |
| 1553 | + image_size: name, | |
| 3300 | 1554 | convert_format: false |
| 3301 | 1555 | }, |
| 3302 | 1556 | operations: thumbnailOperations |
| 3303 | 1557 | }); |
| 3304 | 1558 | } |
| 3305 | - { | |
| 3306 | - const { bigImageSizeThreshold } = settings; | |
| 3307 | - if (bigImageSizeThreshold && attachment.id) { | |
| 3308 | - const bitmap = await createImageBitmap(thumbnailSource); | |
| 3309 | - const needsScaling = bitmap.width > bigImageSizeThreshold || bitmap.height > bigImageSizeThreshold; | |
| 3310 | - bitmap.close(); | |
| 3311 | - if (needsScaling) { | |
| 3312 | - const sourceForScaled = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource; | |
| 3313 | - const scaledOperations = [ | |
| 3314 | - [ | |
| 3315 | - OperationType.ResizeCrop, | |
| 3316 | - { | |
| 3317 | - resize: { | |
| 3318 | - width: bigImageSizeThreshold, | |
| 3319 | - height: bigImageSizeThreshold | |
| 3320 | - }, | |
| 3321 | - isThresholdResize: true, | |
| 3322 | - quality: defaultQuality | |
| 3323 | - } | |
| 3324 | - ] | |
| 3325 | - ]; | |
| 3326 | - if (!isUltraHdr && thumbnailTranscodeOperation) { | |
| 3327 | - scaledOperations.push( | |
| 3328 | - thumbnailTranscodeOperation | |
| 3329 | - ); | |
| 3330 | - } | |
| 3331 | - scaledOperations.push(OperationType.Upload); | |
| 3332 | - dispatch.addSideloadItem({ | |
| 3333 | - file: sourceForScaled, | |
| 3334 | - batchId, | |
| 3335 | - parentId: item.id, | |
| 3336 | - additionalData: { | |
| 3337 | - post: attachment.id, | |
| 3338 | - image_size: "scaled", | |
| 3339 | - convert_format: false | |
| 3340 | - }, | |
| 3341 | - operations: scaledOperations | |
| 3342 | - }); | |
| 1559 | + const { bigImageSizeThreshold } = settings; | |
| 1560 | + if (bigImageSizeThreshold && attachment.id) { | |
| 1561 | + const bitmap = await createImageBitmap(item.sourceFile); | |
| 1562 | + const needsScaling = bitmap.width > bigImageSizeThreshold || bitmap.height > bigImageSizeThreshold; | |
| 1563 | + bitmap.close(); | |
| 1564 | + if (needsScaling) { | |
| 1565 | + const sourceForScaled = attachment.filename ? renameFile(item.sourceFile, attachment.filename) : item.sourceFile; | |
| 1566 | + const scaledOperations = [ | |
| 1567 | + [ | |
| 1568 | + OperationType.ResizeCrop, | |
| 1569 | + { | |
| 1570 | + resize: { | |
| 1571 | + width: bigImageSizeThreshold, | |
| 1572 | + height: bigImageSizeThreshold | |
| 1573 | + }, | |
| 1574 | + isThresholdResize: true | |
| 1575 | + } | |
| 1576 | + ] | |
| 1577 | + ]; | |
| 1578 | + if (thumbnailTranscodeOperation) { | |
| 1579 | + scaledOperations.push(thumbnailTranscodeOperation); | |
| 3343 | 1580 | } |
| 1581 | + scaledOperations.push(OperationType.Upload); | |
| 1582 | + dispatch.addSideloadItem({ | |
| 1583 | + file: sourceForScaled, | |
| 1584 | + onChange: ([updatedAttachment]) => { | |
| 1585 | + if ((0, import_blob.isBlobURL)(updatedAttachment.url)) { | |
| 1586 | + return; | |
| 1587 | + } | |
| 1588 | + item.onChange?.([updatedAttachment]); | |
| 1589 | + }, | |
| 1590 | + batchId, | |
| 1591 | + parentId: item.id, | |
| 1592 | + additionalData: { | |
| 1593 | + post: attachment.id, | |
| 1594 | + image_size: "scaled", | |
| 1595 | + convert_format: false | |
| 1596 | + }, | |
| 1597 | + operations: scaledOperations | |
| 1598 | + }); | |
| 3344 | 1599 | } |
| 3345 | 1600 | } |
| 3346 | 1601 | } |
| 3347 | 1602 | dispatch.finishOperation(id, {}); |
| @@ -3346,33 +1601,8 @@ | ||
| 3346 | 1601 | } |
| 3347 | 1602 | dispatch.finishOperation(id, {}); |
| 3348 | 1603 | }; |
| 3349 | 1604 | } |
| 3350 | - function finalizeItem(id) { | |
| 3351 | - return async ({ select: select2, dispatch }) => { | |
| 3352 | - const item = select2.getItem(id); | |
| 3353 | - if (!item) { | |
| 3354 | - return; | |
| 3355 | - } | |
| 3356 | - const attachment = item.attachment; | |
| 3357 | - const { mediaFinalize } = select2.getSettings(); | |
| 3358 | - const updates = {}; | |
| 3359 | - if (attachment?.id && mediaFinalize) { | |
| 3360 | - try { | |
| 3361 | - const updatedAttachment = await mediaFinalize( | |
| 3362 | - attachment.id, | |
| 3363 | - item.subSizes || [] | |
| 3364 | - ); | |
| 3365 | - if (updatedAttachment) { | |
| 3366 | - updates.attachment = updatedAttachment; | |
| 3367 | - } | |
| 3368 | - } catch (error) { | |
| 3369 | - console.warn("Media finalization failed:", error); | |
| 3370 | - } | |
| 3371 | - } | |
| 3372 | - dispatch.finishOperation(id, updates); | |
| 3373 | - }; | |
| 3374 | - } | |
| 3375 | 1605 | function revokeBlobUrls(id) { |
| 3376 | 1606 | return async ({ select: select2, dispatch }) => { |
| 3377 | 1607 | const blobUrls = select2.getBlobUrls(id); |
| 3378 | 1608 | for (const blobUrl of blobUrls) { |
| @@ -3474,103 +1704,103 @@ | ||
| 3474 | 1704 | return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }); |
| 3475 | 1705 | }); |
| 3476 | 1706 | var provider_default = MediaUploadProvider; |
| 3477 | 1707 | |
| 3478 | - // packages/upload-media/build-module/error-messages.mjs | |
| 3479 | - var import_i18n7 = __toESM(require_i18n(), 1); | |
| 3480 | - function getErrorMessage(code, fileName) { | |
| 3481 | - const messages = { | |
| 3482 | - [ErrorCode.EMPTY_FILE]: { | |
| 3483 | - title: (0, import_i18n7.__)("Empty file"), | |
| 3484 | - description: (0, import_i18n7.sprintf)( | |
| 3485 | - /* translators: %s: file name */ | |
| 3486 | - (0, import_i18n7.__)('"%s" is empty.'), | |
| 3487 | - fileName | |
| 3488 | - ), | |
| 3489 | - action: (0, import_i18n7.__)("Please choose a different file.") | |
| 3490 | - }, | |
| 3491 | - [ErrorCode.SIZE_ABOVE_LIMIT]: { | |
| 3492 | - title: (0, import_i18n7.__)("File too large"), | |
| 3493 | - description: (0, import_i18n7.sprintf)( | |
| 3494 | - /* translators: %s: file name */ | |
| 3495 | - (0, import_i18n7.__)('"%s" exceeds the maximum upload size.'), | |
| 3496 | - fileName | |
| 3497 | - ), | |
| 3498 | - action: (0, import_i18n7.__)("Please reduce the file size and try again.") | |
| 3499 | - }, | |
| 3500 | - [ErrorCode.MIME_TYPE_NOT_SUPPORTED]: { | |
| 3501 | - title: (0, import_i18n7.__)("Unsupported file type"), | |
| 3502 | - description: (0, import_i18n7.sprintf)( | |
| 3503 | - /* translators: %s: file name */ | |
| 3504 | - (0, import_i18n7.__)('"%s" is not a supported file type.'), | |
| 3505 | - fileName | |
| 3506 | - ), | |
| 3507 | - action: (0, import_i18n7.__)("Please upload a different file format.") | |
| 3508 | - }, | |
| 3509 | - [ErrorCode.MIME_TYPE_NOT_ALLOWED_FOR_USER]: { | |
| 3510 | - title: (0, import_i18n7.__)("File type not allowed"), | |
| 3511 | - description: (0, import_i18n7.sprintf)( | |
| 3512 | - /* translators: %s: file name */ | |
| 3513 | - (0, import_i18n7.__)('You are not allowed to upload "%s".'), | |
| 3514 | - fileName | |
| 3515 | - ), | |
| 3516 | - action: (0, import_i18n7.__)("Please contact your site administrator.") | |
| 3517 | - }, | |
| 3518 | - [ErrorCode.HEIC_DECODE_ERROR]: { | |
| 3519 | - title: (0, import_i18n7.__)("HEIC decode failed"), | |
| 3520 | - description: (0, import_i18n7.sprintf)( | |
| 3521 | - /* translators: %s: file name */ | |
| 3522 | - (0, import_i18n7.__)('Failed to decode HEIC file "%s".'), | |
| 3523 | - fileName | |
| 3524 | - ), | |
| 3525 | - action: (0, import_i18n7.__)("Try converting the image to JPEG or PNG first.") | |
| 3526 | - }, | |
| 3527 | - [ErrorCode.IMAGE_TRANSCODING_ERROR]: { | |
| 3528 | - title: (0, import_i18n7.__)("Image processing failed"), | |
| 3529 | - description: (0, import_i18n7.sprintf)( | |
| 3530 | - /* translators: %s: file name */ | |
| 3531 | - (0, import_i18n7.__)('Failed to process "%s".'), | |
| 3532 | - fileName | |
| 3533 | - ), | |
| 3534 | - action: (0, import_i18n7.__)("The image may be corrupted. Try a different file.") | |
| 3535 | - }, | |
| 3536 | - [ErrorCode.IMAGE_ROTATION_ERROR]: { | |
| 3537 | - title: (0, import_i18n7.__)("Image rotation failed"), | |
| 3538 | - description: (0, import_i18n7.sprintf)( | |
| 3539 | - /* translators: %s: file name */ | |
| 3540 | - (0, import_i18n7.__)('Failed to rotate "%s".'), | |
| 3541 | - fileName | |
| 3542 | - ), | |
| 3543 | - action: (0, import_i18n7.__)("The image may be corrupted. Try a different file.") | |
| 3544 | - }, | |
| 3545 | - [ErrorCode.MEDIA_TRANSCODING_ERROR]: { | |
| 3546 | - title: (0, import_i18n7.__)("Media processing failed"), | |
| 3547 | - description: (0, import_i18n7.sprintf)( | |
| 3548 | - /* translators: %s: file name */ | |
| 3549 | - (0, import_i18n7.__)('Failed to convert "%s" to the target format.'), | |
| 3550 | - fileName | |
| 3551 | - ), | |
| 3552 | - action: (0, import_i18n7.__)("The file may be corrupted. Try a different file.") | |
| 3553 | - }, | |
| 3554 | - [ErrorCode.GENERAL]: { | |
| 3555 | - title: (0, import_i18n7.__)("Upload failed"), | |
| 3556 | - description: (0, import_i18n7.sprintf)( | |
| 3557 | - /* translators: %s: file name */ | |
| 3558 | - (0, import_i18n7.__)('Failed to upload "%s".'), | |
| 3559 | - fileName | |
| 3560 | - ), | |
| 3561 | - action: (0, import_i18n7.__)("Please try again.") | |
| 1708 | + // packages/upload-media/build-module/feature-detection.mjs | |
| 1709 | + var cachedResult = null; | |
| 1710 | + function detectClientSideMediaSupport() { | |
| 1711 | + if (cachedResult !== null) { | |
| 1712 | + return cachedResult; | |
| 1713 | + } | |
| 1714 | + if (typeof WebAssembly === "undefined") { | |
| 1715 | + cachedResult = { | |
| 1716 | + supported: false, | |
| 1717 | + reason: "WebAssembly is not supported in this browser." | |
| 1718 | + }; | |
| 1719 | + return cachedResult; | |
| 1720 | + } | |
| 1721 | + if (typeof SharedArrayBuffer === "undefined") { | |
| 1722 | + cachedResult = { | |
| 1723 | + supported: false, | |
| 1724 | + reason: "SharedArrayBuffer is not available. This may be due to missing cross-origin isolation headers." | |
| 1725 | + }; | |
| 1726 | + return cachedResult; | |
| 1727 | + } | |
| 1728 | + if (typeof Worker === "undefined") { | |
| 1729 | + cachedResult = { | |
| 1730 | + supported: false, | |
| 1731 | + reason: "Web Workers are not supported in this browser." | |
| 1732 | + }; | |
| 1733 | + return cachedResult; | |
| 1734 | + } | |
| 1735 | + if (typeof window !== "undefined" && window.HTMLIFrameElement && !("credentialless" in window.HTMLIFrameElement.prototype)) { | |
| 1736 | + cachedResult = { | |
| 1737 | + supported: false, | |
| 1738 | + reason: "Browser does not support credentialless iframes. Cross-origin isolation would break third-party embeds" | |
| 1739 | + }; | |
| 1740 | + return cachedResult; | |
| 1741 | + } | |
| 1742 | + if (typeof navigator !== "undefined" && "deviceMemory" in navigator && navigator.deviceMemory <= 2) { | |
| 1743 | + cachedResult = { | |
| 1744 | + supported: false, | |
| 1745 | + reason: "Device has insufficient memory for client-side media processing." | |
| 1746 | + }; | |
| 1747 | + return cachedResult; | |
| 1748 | + } | |
| 1749 | + if (typeof navigator !== "undefined" && "hardwareConcurrency" in navigator && navigator.hardwareConcurrency < 4) { | |
| 1750 | + cachedResult = { | |
| 1751 | + supported: false, | |
| 1752 | + reason: "Device has insufficient CPU cores for client-side media processing." | |
| 1753 | + }; | |
| 1754 | + return cachedResult; | |
| 1755 | + } | |
| 1756 | + if (typeof navigator !== "undefined") { | |
| 1757 | + const connection = navigator.connection; | |
| 1758 | + if (connection) { | |
| 1759 | + if (connection.saveData) { | |
| 1760 | + cachedResult = { | |
| 1761 | + supported: false, | |
| 1762 | + reason: "Data saver mode is enabled." | |
| 1763 | + }; | |
| 1764 | + return cachedResult; | |
| 1765 | + } | |
| 1766 | + if (connection.effectiveType === "slow-2g" || connection.effectiveType === "2g" || connection.effectiveType === "3g") { | |
| 1767 | + cachedResult = { | |
| 1768 | + supported: false, | |
| 1769 | + reason: "Network connection is too slow for client-side media processing." | |
| 1770 | + }; | |
| 1771 | + return cachedResult; | |
| 1772 | + } | |
| 3562 | 1773 | } |
| 3563 | - }; | |
| 3564 | - return messages[code] || { | |
| 3565 | - title: (0, import_i18n7.__)("Upload failed"), | |
| 3566 | - description: (0, import_i18n7.sprintf)( | |
| 3567 | - /* translators: %s: file name */ | |
| 3568 | - (0, import_i18n7.__)('Failed to upload "%s".'), | |
| 3569 | - fileName | |
| 3570 | - ), | |
| 3571 | - action: (0, import_i18n7.__)("Please try again.") | |
| 3572 | - }; | |
| 1774 | + } | |
| 1775 | + if (typeof window !== "undefined") { | |
| 1776 | + try { | |
| 1777 | + const testBlob = new Blob([""], { | |
| 1778 | + type: "application/javascript" | |
| 1779 | + }); | |
| 1780 | + const testUrl = URL.createObjectURL(testBlob); | |
| 1781 | + try { | |
| 1782 | + const testWorker = new Worker(testUrl); | |
| 1783 | + testWorker.terminate(); | |
| 1784 | + } finally { | |
| 1785 | + URL.revokeObjectURL(testUrl); | |
| 1786 | + } | |
| 1787 | + } catch { | |
| 1788 | + cachedResult = { | |
| 1789 | + supported: false, | |
| 1790 | + reason: "The site's Content Security Policy (CSP) does not allow blob: workers. The worker-src directive must include blob: to enable client-side media processing." | |
| 1791 | + }; | |
| 1792 | + return cachedResult; | |
| 1793 | + } | |
| 1794 | + } | |
| 1795 | + cachedResult = { supported: true }; | |
| 1796 | + return cachedResult; | |
| 1797 | + } | |
| 1798 | + function isClientSideMediaSupported() { | |
| 1799 | + return detectClientSideMediaSupport().supported; | |
| 1800 | + } | |
| 1801 | + function clearFeatureDetectionCache() { | |
| 1802 | + cachedResult = null; | |
| 3573 | 1803 | } |
| 3574 | 1804 | return __toCommonJS(index_exports); |
| 3575 | 1805 | })(); |
| 3576 | 1806 | //# sourceMappingURL=index.js.map |