| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 (function() { 2 "use strict"; 3 var wp; 4 (wp ||= {}).uploadMedia = (() => { 5 var __create = Object.create; 6 var __defProp = Object.defineProperty; 7 var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 8 var __getOwnPropNames = Object.getOwnPropertyNames; 9 var __getProtoOf = Object.getPrototypeOf; 10 var __hasOwnProp = Object.prototype.hasOwnProperty; 11 var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { 12 get: (a, b) => (typeof require !== "undefined" ? require : a)[b] 13 }) : x)(function(x) { 14 if (typeof require !== "undefined") return require.apply(this, arguments); 15 throw Error('Dynamic require of "' + x + '" is not supported'); 16 }); 17 var __commonJS = (cb, mod) => function __require2() { 18 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 19 }; 20 var __export = (target, all) => { 21 for (var name in all) 22 __defProp(target, name, { get: all[name], enumerable: true }); 23 }; 24 var __copyProps = (to, from, except, desc) => { 25 if (from && typeof from === "object" || typeof from === "function") { 26 for (let key of __getOwnPropNames(from)) 27 if (!__hasOwnProp.call(to, key) && key !== except) 28 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 29 } 30 return to; 31 }; 32 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 33 // If the importer is in node compatibility mode or this is not an ESM 34 // file that has been converted to a CommonJS file using a Babel- 35 // compatible transform (i.e. "__esModule" has not been set), then set 36 // "default" to the CommonJS "module.exports" for node compatibility. 37 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 38 mod 39 )); 40 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 41 42 // package-external:@wordpress/data 43 var require_data = __commonJS({ 44 "package-external:@wordpress/data"(exports, module) { 45 module.exports = window.wp.data; 46 } 47 }); 48 49 // package-external:@wordpress/i18n 50 var require_i18n = __commonJS({ 51 "package-external:@wordpress/i18n"(exports, module) { 52 module.exports = window.wp.i18n; 53 } 54 }); 55 56 // package-external:@wordpress/blob 57 var require_blob = __commonJS({ 58 "package-external:@wordpress/blob"(exports, module) { 59 module.exports = window.wp.blob; 60 } 61 }); 62 63 // package-external:@wordpress/private-apis 64 var require_private_apis = __commonJS({ 65 "package-external:@wordpress/private-apis"(exports, module) { 66 module.exports = window.wp.privateApis; 67 } 68 }); 69 70 // package-external:@wordpress/element 71 var require_element = __commonJS({ 72 "package-external:@wordpress/element"(exports, module) { 73 module.exports = window.wp.element; 74 } 75 }); 76 77 // package-external:@wordpress/compose 78 var require_compose = __commonJS({ 79 "package-external:@wordpress/compose"(exports, module) { 80 module.exports = window.wp.compose; 81 } 82 }); 83 84 // vendor-external:react/jsx-runtime 85 var require_jsx_runtime = __commonJS({ 86 "vendor-external:react/jsx-runtime"(exports, module) { 87 module.exports = window.ReactJSXRuntime; 88 } 89 }); 90 91 // packages/upload-media/build-module/index.mjs 92 var index_exports = {}; 93 __export(index_exports, { 94 ErrorCode: () => ErrorCode, 95 MediaUploadProvider: () => provider_default, 96 UploadError: () => UploadError, 97 clearFeatureDetectionCache: () => clearFeatureDetectionCache, 98 detectClientSideMediaSupport: () => detectClientSideMediaSupport, 99 getErrorMessage: () => getErrorMessage, 100 getHeicConversionAdvice: () => getHeicConversionAdvice, 101 getHeicUnsupportedMessage: () => getHeicUnsupportedMessage, 102 isClientSideMediaSupported: () => isClientSideMediaSupported, 103 isHeicCanvasSupported: () => isHeicCanvasSupported, 104 isHeicFile: () => isHeicFile, 105 store: () => store 106 }); 107 108 // packages/upload-media/build-module/store/index.mjs 109 var import_data = __toESM(require_data(), 1); 110 111 // packages/upload-media/build-module/store/types.mjs 112 var Type = /* @__PURE__ */ ((Type2) => { 113 Type2["Unknown"] = "REDUX_UNKNOWN"; 114 Type2["Add"] = "ADD_ITEM"; 115 Type2["Prepare"] = "PREPARE_ITEM"; 116 Type2["Cancel"] = "CANCEL_ITEM"; 117 Type2["Remove"] = "REMOVE_ITEM"; 118 Type2["RetryItem"] = "RETRY_ITEM"; 119 Type2["ScheduleRetry"] = "SCHEDULE_RETRY"; 120 Type2["PauseItem"] = "PAUSE_ITEM"; 121 Type2["ResumeItem"] = "RESUME_ITEM"; 122 Type2["PauseQueue"] = "PAUSE_QUEUE"; 123 Type2["ResumeQueue"] = "RESUME_QUEUE"; 124 Type2["OperationStart"] = "OPERATION_START"; 125 Type2["OperationFinish"] = "OPERATION_FINISH"; 126 Type2["AddOperations"] = "ADD_OPERATIONS"; 127 Type2["CacheBlobUrl"] = "CACHE_BLOB_URL"; 128 Type2["RevokeBlobUrls"] = "REVOKE_BLOB_URLS"; 129 Type2["UpdateProgress"] = "UPDATE_PROGRESS"; 130 Type2["AccumulateSubSize"] = "ACCUMULATE_SUB_SIZE"; 131 Type2["UpdateSettings"] = "UPDATE_SETTINGS"; 132 return Type2; 133 })(Type || {}); 134 var ItemStatus = /* @__PURE__ */ ((ItemStatus2) => { 135 ItemStatus2["Queued"] = "QUEUED"; 136 ItemStatus2["Processing"] = "PROCESSING"; 137 ItemStatus2["Paused"] = "PAUSED"; 138 ItemStatus2["PendingRetry"] = "PENDING_RETRY"; 139 ItemStatus2["Uploaded"] = "UPLOADED"; 140 ItemStatus2["Error"] = "ERROR"; 141 return ItemStatus2; 142 })(ItemStatus || {}); 143 var OperationType = /* @__PURE__ */ ((OperationType2) => { 144 OperationType2["Prepare"] = "PREPARE"; 145 OperationType2["Upload"] = "UPLOAD"; 146 OperationType2["ResizeCrop"] = "RESIZE_CROP"; 147 OperationType2["Rotate"] = "ROTATE"; 148 OperationType2["TranscodeImage"] = "TRANSCODE_IMAGE"; 149 OperationType2["TranscodeGif"] = "TRANSCODE_GIF"; 150 OperationType2["ThumbnailGeneration"] = "THUMBNAIL_GENERATION"; 151 OperationType2["Finalize"] = "FINALIZE"; 152 OperationType2["DetectUltraHdr"] = "DETECT_ULTRAHDR"; 153 return OperationType2; 154 })(OperationType || {}); 155 156 // packages/upload-media/build-module/store/constants.mjs 157 var STORE_NAME = "core/upload-media"; 158 var DEFAULT_MAX_CONCURRENT_UPLOADS = 5; 159 var DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING = 2; 160 var DEFAULT_RETRY_SETTINGS = { 161 maxRetryAttempts: 3, 162 initialRetryDelayMs: 1e3, 163 maxRetryDelayMs: 3e4, 164 backoffMultiplier: 2, 165 retryJitter: 0.1 166 }; 167 var CLIENT_SIDE_SUPPORTED_MIME_TYPES = [ 168 "image/jpeg", 169 "image/png", 170 "image/gif", 171 "image/webp", 172 "image/avif" 173 ]; 174 var HEIC_MIME_TYPES = [ 175 "image/heic", 176 "image/heif" 177 ]; 178 179 // packages/upload-media/build-module/store/reducer.mjs 180 var noop = () => { 181 }; 182 var DEFAULT_STATE = { 183 queue: [], 184 queueStatus: "active", 185 blobUrls: {}, 186 settings: { 187 mediaUpload: noop, 188 maxConcurrentUploads: DEFAULT_MAX_CONCURRENT_UPLOADS, 189 maxConcurrentImageProcessing: DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING, 190 retry: { ...DEFAULT_RETRY_SETTINGS } 191 }, 192 failureCount: 0 193 }; 194 function reducer(state = DEFAULT_STATE, action = { type: Type.Unknown }) { 195 switch (action.type) { 196 case Type.PauseQueue: { 197 return { 198 ...state, 199 queueStatus: "paused" 200 }; 201 } 202 case Type.ResumeQueue: { 203 return { 204 ...state, 205 queueStatus: "active" 206 }; 207 } 208 case Type.PauseItem: 209 return { 210 ...state, 211 queue: state.queue.map( 212 (item) => item.id === action.id ? { 213 ...item, 214 status: ItemStatus.Paused 215 } : item 216 ) 217 }; 218 case Type.ResumeItem: 219 return { 220 ...state, 221 queue: state.queue.map( 222 (item) => item.id === action.id ? { 223 ...item, 224 status: ItemStatus.Processing 225 } : item 226 ) 227 }; 228 case Type.Add: 229 return { 230 ...state, 231 queue: [...state.queue, action.item] 232 }; 233 case Type.Cancel: { 234 const cancelled = state.queue.find( 235 (item) => item.id === action.id 236 ); 237 return { 238 ...state, 239 failureCount: cancelled && !cancelled.parentId ? state.failureCount + 1 : state.failureCount, 240 queue: state.queue.map( 241 (item) => item.id === action.id ? { 242 ...item, 243 error: action.error 244 } : item 245 ) 246 }; 247 } 248 case Type.RetryItem: 249 return { 250 ...state, 251 queue: state.queue.map( 252 (item) => item.id === action.id ? { 253 ...item, 254 status: ItemStatus.Processing, 255 error: void 0, 256 retryCount: (item.retryCount ?? 0) + 1, 257 abortController: new AbortController(), 258 /* 259 * The failed operation is still recorded on 260 * the item: nothing finishes it when it 261 * fails, and while the item waits out the 262 * backoff that is what keeps it out of the 263 * concurrency pools. Clear it now that the 264 * item is about to run again, so processItem 265 * does not mistake it for an operation still 266 * in flight and skip the retry. 267 */ 268 currentOperation: void 0 269 } : item 270 ) 271 }; 272 case Type.ScheduleRetry: 273 return { 274 ...state, 275 queue: state.queue.map( 276 (item) => item.id === action.id ? { 277 ...item, 278 status: ItemStatus.PendingRetry, 279 error: action.error, 280 retryCount: action.retryCount, 281 nextRetryTimestamp: action.nextRetryTimestamp 282 } : item 283 ) 284 }; 285 case Type.Remove: 286 return { 287 ...state, 288 queue: state.queue.filter((item) => item.id !== action.id) 289 }; 290 case Type.OperationStart: { 291 return { 292 ...state, 293 queue: state.queue.map( 294 (item) => item.id === action.id ? { 295 ...item, 296 currentOperation: action.operation 297 } : item 298 ) 299 }; 300 } 301 case Type.AddOperations: 302 return { 303 ...state, 304 queue: state.queue.map((item) => { 305 if (item.id !== action.id) { 306 return item; 307 } 308 return { 309 ...item, 310 operations: [ 311 ...item.operations || [], 312 ...action.operations 313 ] 314 }; 315 }) 316 }; 317 case Type.OperationFinish: 318 return { 319 ...state, 320 queue: state.queue.map((item) => { 321 if (item.id !== action.id) { 322 return item; 323 } 324 const operations = item.operations ? item.operations.slice(1) : []; 325 const attachment = item.attachment || action.item.attachment ? { 326 ...item.attachment, 327 ...action.item.attachment 328 } : void 0; 329 return { 330 ...item, 331 currentOperation: void 0, 332 operations, 333 ...action.item, 334 attachment, 335 additionalData: { 336 ...item.additionalData, 337 ...action.item.additionalData 338 } 339 }; 340 }) 341 }; 342 case Type.CacheBlobUrl: { 343 const blobUrls = state.blobUrls[action.id] || []; 344 return { 345 ...state, 346 blobUrls: { 347 ...state.blobUrls, 348 [action.id]: [...blobUrls, action.blobUrl] 349 } 350 }; 351 } 352 case Type.RevokeBlobUrls: { 353 const newBlobUrls = { ...state.blobUrls }; 354 delete newBlobUrls[action.id]; 355 return { 356 ...state, 357 blobUrls: newBlobUrls 358 }; 359 } 360 case Type.UpdateProgress: 361 return { 362 ...state, 363 queue: state.queue.map( 364 (item) => item.id === action.id ? { 365 ...item, 366 progress: action.progress 367 } : item 368 ) 369 }; 370 case Type.AccumulateSubSize: 371 return { 372 ...state, 373 queue: state.queue.map( 374 (item) => item.id === action.id ? { 375 ...item, 376 subSizes: [ 377 ...item.subSizes || [], 378 action.subSize 379 ] 380 } : item 381 ) 382 }; 383 case Type.UpdateSettings: { 384 return { 385 ...state, 386 settings: { 387 ...state.settings, 388 ...action.settings 389 } 390 }; 391 } 392 } 393 return state; 394 } 395 var reducer_default = reducer; 396 397 // packages/upload-media/build-module/store/selectors.mjs 398 var selectors_exports = {}; 399 __export(selectors_exports, { 400 getItems: () => getItems, 401 getSettings: () => getSettings, 402 isUploading: () => isUploading, 403 isUploadingById: () => isUploadingById, 404 isUploadingByUrl: () => isUploadingByUrl 405 }); 406 function getItems(state) { 407 return state.queue; 408 } 409 function isUploading(state) { 410 return state.queue.length >= 1; 411 } 412 function isUploadingByUrl(state, url) { 413 return state.queue.some( 414 (item) => item.attachment?.url === url || item.sourceUrl === url 415 ); 416 } 417 function isUploadingById(state, attachmentId) { 418 return state.queue.some( 419 (item) => item.attachment?.id === attachmentId || item.sourceAttachmentId === attachmentId 420 ); 421 } 422 function getSettings(state) { 423 return state.settings; 424 } 425 426 // packages/upload-media/build-module/store/private-selectors.mjs 427 var private_selectors_exports = {}; 428 __export(private_selectors_exports, { 429 getActiveImageProcessingCount: () => getActiveImageProcessingCount, 430 getActiveUploadCount: () => getActiveUploadCount, 431 getActiveVideoProcessingCount: () => getActiveVideoProcessingCount, 432 getAllItems: () => getAllItems, 433 getBlobUrls: () => getBlobUrls, 434 getFailedItems: () => getFailedItems, 435 getFailureCount: () => getFailureCount, 436 getItem: () => getItem, 437 getItemProgress: () => getItemProgress, 438 getPendingImageProcessing: () => getPendingImageProcessing, 439 getPendingUploads: () => getPendingUploads, 440 getPendingVideoProcessing: () => getPendingVideoProcessing, 441 hasPendingItemsByParentId: () => hasPendingItemsByParentId, 442 isBatchUploaded: () => isBatchUploaded, 443 isPaused: () => isPaused 444 }); 445 function getAllItems(state) { 446 return state.queue; 447 } 448 function getFailureCount(state) { 449 return state.failureCount; 450 } 451 function getItem(state, id) { 452 return state.queue.find((item) => item.id === id); 453 } 454 function isBatchUploaded(state, batchId) { 455 const batchItems = state.queue.filter( 456 (item) => batchId === item.batchId 457 ); 458 return batchItems.length === 0; 459 } 460 function isPaused(state) { 461 return state.queueStatus === "paused"; 462 } 463 function getBlobUrls(state, id) { 464 return state.blobUrls[id] || []; 465 } 466 function getActiveUploadCount(state) { 467 return state.queue.filter( 468 (item) => item.currentOperation === OperationType.Upload 469 ).length; 470 } 471 function getPendingUploads(state) { 472 return state.queue.filter((item) => { 473 const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; 474 return nextOperation === OperationType.Upload && item.currentOperation !== OperationType.Upload; 475 }); 476 } 477 function getActiveImageProcessingCount(state) { 478 return state.queue.filter( 479 (item) => item.currentOperation === OperationType.ResizeCrop || item.currentOperation === OperationType.Rotate 480 ).length; 481 } 482 function getActiveVideoProcessingCount(state) { 483 return state.queue.filter( 484 (item) => item.currentOperation === OperationType.TranscodeGif 485 ).length; 486 } 487 function getPendingImageProcessing(state) { 488 return state.queue.filter((item) => { 489 const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; 490 return (nextOperation === OperationType.ResizeCrop || nextOperation === OperationType.Rotate) && item.currentOperation !== OperationType.ResizeCrop && item.currentOperation !== OperationType.Rotate; 491 }); 492 } 493 function getPendingVideoProcessing(state) { 494 return state.queue.filter((item) => { 495 const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; 496 return nextOperation === OperationType.TranscodeGif && item.currentOperation !== OperationType.TranscodeGif; 497 }); 498 } 499 function getFailedItems(state) { 500 return state.queue.filter((item) => item.error !== void 0); 501 } 502 function hasPendingItemsByParentId(state, parentId) { 503 return state.queue.some((item) => item.parentId === parentId); 504 } 505 function getItemProgress(state, id) { 506 const item = state.queue.find((i) => i.id === id); 507 return item?.progress; 508 } 509 510 // packages/upload-media/build-module/store/actions.mjs 511 var actions_exports = {}; 512 __export(actions_exports, { 513 addItems: () => addItems, 514 cancelItem: () => cancelItem, 515 executeRetry: () => executeRetry, 516 retryItem: () => retryItem, 517 scheduleRetry: () => scheduleRetry 518 }); 519 520 // node_modules/.store/uuid@14.0.2-ALlTd6-Rf9bZs703d7TIjQ/node_modules/uuid/dist/stringify.js 521 var byteToHex = []; 522 for (let i = 0; i < 256; ++i) { 523 byteToHex.push((i + 256).toString(16).slice(1)); 524 } 525 function unsafeStringify(arr, offset = 0) { 526 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(); 527 } 528 529 // node_modules/.store/uuid@14.0.2-ALlTd6-Rf9bZs703d7TIjQ/node_modules/uuid/dist/rng.js 530 var rnds8 = new Uint8Array(16); 531 function rng() { 532 return crypto.getRandomValues(rnds8); 533 } 534 535 // node_modules/.store/uuid@14.0.2-ALlTd6-Rf9bZs703d7TIjQ/node_modules/uuid/dist/v4.js 536 function v4(options, buf, offset) { 537 if (!buf && !options && crypto.randomUUID) { 538 return crypto.randomUUID(); 539 } 540 return _v4(options, buf, offset); 541 } 542 function _v4(options, buf, offset) { 543 options = options || {}; 544 const rnds = options.random ?? options.rng?.() ?? rng(); 545 if (rnds.length < 16) { 546 throw new Error("Random bytes length must be >= 16"); 547 } 548 rnds[6] = rnds[6] & 15 | 64; 549 rnds[8] = rnds[8] & 63 | 128; 550 if (buf) { 551 offset = offset || 0; 552 if (offset < 0 || offset + 16 > buf.length) { 553 throw new RangeError(`UUID byte range $offset}:$offset + 15} is out of buffer bounds`); 554 } 555 for (let i = 0; i < 16; ++i) { 556 buf[offset + i] = rnds[i]; 557 } 558 return buf; 559 } 560 return unsafeStringify(rnds); 561 } 562 var v4_default = v4; 563 564 // packages/upload-media/build-module/store/actions.mjs 565 var import_i18n4 = __toESM(require_i18n(), 1); 566 567 // packages/upload-media/build-module/store/utils/retry.mjs 568 function calculateRetryDelay(options) { 569 const { attempt, initialDelay, maxDelay, multiplier, jitter } = options; 570 const exponentialDelay = initialDelay * Math.pow(multiplier, attempt - 1); 571 const cappedDelay = Math.min(exponentialDelay, maxDelay); 572 const jitterFactor = 1 + (Math.random() * 2 - 1) * jitter; 573 return Math.floor(cappedDelay * jitterFactor); 574 } 575 var RETRYABLE_MESSAGE_PATTERNS = [ 576 /network/i, 577 /timeout/i, 578 /ECONNRESET/i, 579 /fetch failed/i, 580 /connection/i, 581 /socket/i, 582 /ETIMEDOUT/i, 583 /ENOTFOUND/i, 584 /Could not get a valid response/i, 585 /Failed to fetch/i, 586 /Load failed/i 587 ]; 588 function shouldRetryError(error, retryCount, maxRetries) { 589 if (retryCount >= maxRetries) { 590 return false; 591 } 592 const message = typeof error === "string" ? error : error?.message || ""; 593 return RETRYABLE_MESSAGE_PATTERNS.some( 594 (pattern) => pattern.test(message) 595 ); 596 } 597 var retryTimers = /* @__PURE__ */ new Map(); 598 function clearRetryTimer(id) { 599 const pendingTimer = retryTimers.get(id); 600 if (pendingTimer !== void 0) { 601 clearTimeout(pendingTimer); 602 retryTimers.delete(id); 603 } 604 } 605 606 // packages/upload-media/build-module/feature-detection.mjs 607 var cachedResult = null; 608 function detectClientSideMediaSupport() { 609 if (cachedResult !== null) { 610 return cachedResult; 611 } 612 if (typeof WebAssembly === "undefined") { 613 cachedResult = { 614 supported: false, 615 reason: "WebAssembly is not supported in this browser." 616 }; 617 return cachedResult; 618 } 619 if (typeof SharedArrayBuffer === "undefined") { 620 cachedResult = { 621 supported: false, 622 reason: "SharedArrayBuffer is not available. This may be due to missing cross-origin isolation headers." 623 }; 624 return cachedResult; 625 } 626 if (typeof Worker === "undefined") { 627 cachedResult = { 628 supported: false, 629 reason: "Web Workers are not supported in this browser." 630 }; 631 return cachedResult; 632 } 633 if (typeof navigator !== "undefined" && "deviceMemory" in navigator && navigator.deviceMemory <= 2) { 634 cachedResult = { 635 supported: false, 636 reason: "Device has insufficient memory for client-side media processing." 637 }; 638 return cachedResult; 639 } 640 if (typeof navigator !== "undefined" && "hardwareConcurrency" in navigator && navigator.hardwareConcurrency < 2) { 641 cachedResult = { 642 supported: false, 643 reason: "Device has insufficient CPU cores for client-side media processing." 644 }; 645 return cachedResult; 646 } 647 if (typeof navigator !== "undefined") { 648 const connection = navigator.connection; 649 if (connection) { 650 if (connection.saveData) { 651 cachedResult = { 652 supported: false, 653 reason: "Data saver mode is enabled." 654 }; 655 return cachedResult; 656 } 657 if (connection.effectiveType === "slow-2g" || connection.effectiveType === "2g") { 658 cachedResult = { 659 supported: false, 660 reason: "Network connection is too slow for client-side media processing." 661 }; 662 return cachedResult; 663 } 664 } 665 } 666 if (typeof window !== "undefined") { 667 try { 668 const testBlob = new Blob([""], { 669 type: "application/javascript" 670 }); 671 const testUrl = URL.createObjectURL(testBlob); 672 try { 673 const testWorker = new Worker(testUrl); 674 testWorker.terminate(); 675 } finally { 676 URL.revokeObjectURL(testUrl); 677 } 678 } catch { 679 cachedResult = { 680 supported: false, 681 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." 682 }; 683 return cachedResult; 684 } 685 } 686 cachedResult = { supported: true }; 687 return cachedResult; 688 } 689 function isClientSideMediaSupported() { 690 return detectClientSideMediaSupport().supported; 691 } 692 function isHeicCanvasSupported() { 693 return typeof createImageBitmap !== "undefined" && typeof OffscreenCanvas !== "undefined"; 694 } 695 function clearFeatureDetectionCache() { 696 cachedResult = null; 697 } 698 var BYTES_PER_PIXEL = 4; 699 var INTERLACED_MEMORY_BUDGET = 0.75 * 1024 * 1024 * 1024; 700 var BASELINE_MEMORY_BUDGET = 1.5 * 1024 * 1024 * 1024; 701 function exceedsClientProcessingMemory(dimensions) { 702 const { width, height, interlaced } = dimensions; 703 const estimatedBytes = width * height * BYTES_PER_PIXEL; 704 const budget = interlaced ? INTERLACED_MEMORY_BUDGET : BASELINE_MEMORY_BUDGET; 705 return estimatedBytes > budget; 706 } 707 708 // packages/upload-media/build-module/image-file.mjs 709 var ImageFile = class extends File { 710 width = 0; 711 height = 0; 712 originalWidth = 0; 713 originalHeight = 0; 714 get wasResized() { 715 return (this.originalWidth || 0) > this.width || (this.originalHeight || 0) > this.height; 716 } 717 constructor(file, width, height, originalWidth, originalHeight) { 718 super([file], file.name, { 719 type: file.type, 720 lastModified: file.lastModified 721 }); 722 this.width = width; 723 this.height = height; 724 this.originalWidth = originalWidth; 725 this.originalHeight = originalHeight; 726 } 727 }; 728 729 // packages/upload-media/build-module/utils.mjs 730 function convertBlobToFile(fileOrBlob) { 731 if (fileOrBlob instanceof File) { 732 return fileOrBlob; 733 } 734 if ("name" in fileOrBlob && typeof fileOrBlob.name === "string") { 735 return new File([fileOrBlob], fileOrBlob.name, { 736 type: fileOrBlob.type, 737 lastModified: fileOrBlob.lastModified 738 }); 739 } 740 const ext = fileOrBlob.type.split("/")[1]; 741 const mediaType = "application/pdf" === fileOrBlob.type ? "document" : fileOrBlob.type.split("/")[0]; 742 return new File([fileOrBlob], `$mediaType}.$ext}`, { 743 type: fileOrBlob.type 744 }); 745 } 746 function renameFile(file, name) { 747 return new File([file], name, { 748 type: file.type, 749 lastModified: file.lastModified 750 }); 751 } 752 function cloneFile(file) { 753 return renameFile(file, file.name); 754 } 755 function getFileBasename(name) { 756 return name.includes(".") ? name.split(".").slice(0, -1).join(".") : name; 757 } 758 function isAnimatedGif(buffer) { 759 const view = new Uint8Array(buffer); 760 if (view.length < 4 || view[0] !== 71 || view[1] !== 73 || view[2] !== 70 || view[3] !== 56) { 761 return false; 762 } 763 let frameCount = 0; 764 for (let i = 0; i < view.length - 2; i++) { 765 if (view[i] === 0 && view[i + 1] === 33 && view[i + 2] === 249) { 766 frameCount++; 767 if (frameCount > 1) { 768 return true; 769 } 770 } 771 } 772 return false; 773 } 774 var FILE_TYPE_BOX_BYTES = 64; 775 var HEIC_BRANDS = [ 776 "heic", 777 "heix", 778 "heim", 779 "heis", 780 "hevc", 781 "hevx", 782 "hevm", 783 "hevs", 784 "mif1", 785 "msf1" 786 ]; 787 var AVIF_BRANDS = ["avif", "avis"]; 788 function isHeicBuffer(buffer) { 789 const view = new Uint8Array(buffer); 790 const readBrand = (offset) => String.fromCharCode(...view.subarray(offset, offset + 4)); 791 if (view.length < 12 || readBrand(4) !== "ftyp") { 792 return false; 793 } 794 const boxEnd = Math.min( 795 view.length, 796 new DataView(buffer).getUint32(0) 797 ); 798 const brands = [readBrand(8)]; 799 for (let offset = 16; offset + 4 <= boxEnd; offset += 4) { 800 brands.push(readBrand(offset)); 801 } 802 if (brands.some((brand) => AVIF_BRANDS.includes(brand))) { 803 return false; 804 } 805 return brands.some((brand) => HEIC_BRANDS.includes(brand)); 806 } 807 async function isHeicFile(file) { 808 if (HEIC_MIME_TYPES.includes(file.type)) { 809 return true; 810 } 811 if (file.type && !file.type.startsWith("image/")) { 812 return false; 813 } 814 try { 815 return isHeicBuffer( 816 await file.slice(0, FILE_TYPE_BOX_BYTES).arrayBuffer() 817 ); 818 } catch { 819 return false; 820 } 821 } 822 823 // packages/upload-media/build-module/store/utils/index.mjs 824 var vipsModulePromise; 825 var vipsModule; 826 function loadVipsModule() { 827 if (!vipsModulePromise) { 828 vipsModulePromise = import("@wordpress/vips/worker").then( 829 (mod) => { 830 vipsModule = mod; 831 return mod; 832 } 833 ); 834 } 835 return vipsModulePromise; 836 } 837 async function vipsConvertImageFormat(id, file, type, options = {}) { 838 const { vipsConvertImageFormat: convertImageFormat } = await loadVipsModule(); 839 const buffer = await convertImageFormat( 840 id, 841 await file.arrayBuffer(), 842 file.type, 843 type, 844 options 845 ); 846 const ext = type.split("/")[1]; 847 const fileName = `$getFileBasename(file.name)}.$ext}`; 848 return new File([new Blob([buffer])], fileName, { 849 type 850 }); 851 } 852 async function vipsEncodeCanvasAsJpeg(id, canvas, source, quality) { 853 const { width, height } = canvas; 854 if (exceedsClientProcessingMemory({ width, height, interlaced: true })) { 855 return null; 856 } 857 const { vipsEncodePixelsAsJpeg: encodePixelsAsJpeg } = await loadVipsModule(); 858 const ctx = canvas.getContext("2d"); 859 if (!ctx) { 860 throw new Error("Could not get canvas 2d context"); 861 } 862 const pixels = ctx.getImageData(0, 0, width, height).data.buffer; 863 const buffer = await encodePixelsAsJpeg(id, pixels, width, height, { 864 quality, 865 metadataSource: await source.arrayBuffer() 866 }); 867 return new Blob([buffer], { type: "image/jpeg" }); 868 } 869 async function vipsHasTransparency(url) { 870 const { vipsHasTransparency: hasTransparency } = await loadVipsModule(); 871 const response = await fetch(url); 872 if (!response.ok) { 873 throw new Error(`Failed to fetch image: $response.status}`); 874 } 875 return hasTransparency(await response.arrayBuffer()); 876 } 877 async function vipsGetUltraHdrInfo(buffer) { 878 const { vipsGetUltraHdrInfo: getUltraHdrInfo } = await loadVipsModule(); 879 return getUltraHdrInfo(buffer); 880 } 881 async function vipsResizeImage(id, file, resize, options = {}) { 882 const { 883 smartCrop = false, 884 addSuffix = false, 885 signal, 886 scaledSuffix, 887 quality, 888 stripMeta, 889 maxBitdepth, 890 preserveAnimation 891 } = options; 892 if (signal?.aborted) { 893 throw new Error("Operation aborted"); 894 } 895 const { vipsResizeImage: resizeImage } = await loadVipsModule(); 896 const { buffer, width, height, originalWidth, originalHeight } = await resizeImage(id, await file.arrayBuffer(), file.type, resize, { 897 smartCrop, 898 quality, 899 stripMeta, 900 maxBitdepth, 901 preserveAnimation 902 }); 903 let fileName = file.name; 904 const wasResized = originalWidth > width || originalHeight > height; 905 if (wasResized) { 906 const basename = getFileBasename(file.name); 907 if (scaledSuffix) { 908 fileName = file.name.replace(basename, `$basename}-scaled`); 909 } else if (addSuffix) { 910 fileName = file.name.replace( 911 basename, 912 `$basename}-$width}x$height}` 913 ); 914 } 915 } 916 const resultFile = new ImageFile( 917 new File( 918 [new Blob([buffer], { type: file.type })], 919 fileName, 920 { 921 type: file.type 922 } 923 ), 924 width, 925 height, 926 originalWidth, 927 originalHeight 928 ); 929 return resultFile; 930 } 931 async function vipsRotateImage(id, file, orientation, signal) { 932 if (signal?.aborted) { 933 throw new Error("Operation aborted"); 934 } 935 if (orientation === 1) { 936 return file; 937 } 938 const { vipsRotateImage: rotateImage } = await loadVipsModule(); 939 const { buffer, width, height } = await rotateImage( 940 id, 941 await file.arrayBuffer(), 942 file.type, 943 orientation 944 ); 945 const basename = getFileBasename(file.name); 946 const fileName = file.name.replace(basename, `$basename}-rotated`); 947 const resultFile = new ImageFile( 948 new File( 949 [new Blob([buffer], { type: file.type })], 950 fileName, 951 { 952 type: file.type 953 } 954 ), 955 width, 956 height 957 ); 958 return resultFile; 959 } 960 async function vipsCancelOperations(id) { 961 if (!vipsModule) { 962 return false; 963 } 964 return vipsModule.vipsCancelOperations(id); 965 } 966 function terminateVipsWorker() { 967 if (vipsModule) { 968 vipsModule.terminateVipsWorker(); 969 } 970 } 971 var completedVipsOperations = 0; 972 var MAX_VIPS_OPS_BEFORE_RECYCLE = 50; 973 function maybeRecycleVipsWorker(activeImageProcessingCount) { 974 completedVipsOperations++; 975 if (completedVipsOperations >= MAX_VIPS_OPS_BEFORE_RECYCLE && activeImageProcessingCount === 0) { 976 terminateVipsWorker(); 977 completedVipsOperations = 0; 978 } 979 } 980 981 // packages/upload-media/build-module/store/utils/video-conversion.mjs 982 var UNSUPPORTED_ERROR_PREFIX = "Unsupported"; 983 var SIZE_LIMIT_ERROR_PREFIX = `$UNSUPPORTED_ERROR_PREFIX}: GIF exceeds maximum conversion size`; 984 var CONVERSION_TIMEOUT_ERROR_PREFIX = "GIF to video conversion timed out"; 985 var DEFAULT_CONVERSION_TIMEOUT = 3e4; 986 function isUnsupportedConversionError(error) { 987 return error instanceof Error && error.message.startsWith(UNSUPPORTED_ERROR_PREFIX); 988 } 989 function isSizeLimitConversionError(error) { 990 return error instanceof Error && error.message.startsWith(SIZE_LIMIT_ERROR_PREFIX); 991 } 992 function isConversionTimeoutError(error) { 993 return error instanceof Error && error.message.startsWith(CONVERSION_TIMEOUT_ERROR_PREFIX); 994 } 995 var videoConversionModulePromise; 996 var videoConversionModule; 997 function loadVideoConversionModule() { 998 if (!videoConversionModulePromise) { 999 videoConversionModulePromise = import("@wordpress/video-conversion/worker").then((mod) => { 1000 videoConversionModule = mod; 1001 return mod; 1002 }).catch((error) => { 1003 videoConversionModulePromise = void 0; 1004 throw error; 1005 }); 1006 } 1007 return videoConversionModulePromise; 1008 } 1009 async function convertGifToVideo(id, file, outputMimeType, { 1010 maxDimensions, 1011 timeout = DEFAULT_CONVERSION_TIMEOUT, 1012 maxTotalPixels 1013 } = {}) { 1014 const mod = await loadVideoConversionModule(); 1015 const conversion = mod.convertGifToVideo( 1016 id, 1017 file, 1018 outputMimeType, 1019 maxDimensions, 1020 maxTotalPixels 1021 ); 1022 let buffer; 1023 if (timeout > 0) { 1024 let timer; 1025 try { 1026 buffer = await Promise.race([ 1027 conversion, 1028 new Promise((_, reject) => { 1029 timer = setTimeout(() => { 1030 reject( 1031 new Error( 1032 `$CONVERSION_TIMEOUT_ERROR_PREFIX} after $timeout}ms` 1033 ) 1034 ); 1035 }, timeout); 1036 }) 1037 ]); 1038 } catch (error) { 1039 if (isConversionTimeoutError(error)) { 1040 conversion.catch(() => { 1041 }); 1042 mod.cancelGifToVideoOperations(id).catch(() => { 1043 }); 1044 } 1045 throw error; 1046 } finally { 1047 clearTimeout(timer); 1048 } 1049 } else { 1050 buffer = await conversion; 1051 } 1052 const ext = outputMimeType === "video/webm" ? "webm" : "mp4"; 1053 const fileName = `$getFileBasename(file.name)}.$ext}`; 1054 return new File( 1055 [new Blob([buffer], { type: outputMimeType })], 1056 fileName, 1057 { type: outputMimeType } 1058 ); 1059 } 1060 async function cancelGifToVideoOperations(id) { 1061 const mod = videoConversionModule ?? (videoConversionModulePromise ? await videoConversionModulePromise.catch(() => void 0) : void 0); 1062 if (!mod) { 1063 return false; 1064 } 1065 return mod.cancelGifToVideoOperations(id); 1066 } 1067 function terminateVideoConversionWorker() { 1068 if (videoConversionModule) { 1069 videoConversionModule.terminateVideoConversionWorker(); 1070 return; 1071 } 1072 if (videoConversionModulePromise) { 1073 void videoConversionModulePromise.then((mod) => mod.terminateVideoConversionWorker()).catch(() => { 1074 }); 1075 } 1076 } 1077 1078 // packages/upload-media/build-module/store/utils/debug-logger.mjs 1079 function isDebugEnabled() { 1080 return true; 1081 } 1082 function debug(message, ...args) { 1083 if (!isDebugEnabled()) { 1084 return; 1085 } 1086 console.debug(`[upload-media] $message}`, ...args); 1087 } 1088 function measure(options) { 1089 if (!isDebugEnabled()) { 1090 return; 1091 } 1092 const { 1093 measureName, 1094 startTime, 1095 endTime = performance.now(), 1096 tooltipText, 1097 properties 1098 } = options; 1099 const detail = { 1100 devtools: { 1101 dataType: "track-entry", 1102 track: "Upload Media", 1103 tooltipText, 1104 properties: properties?.map(([key, value]) => ({ 1105 key, 1106 value 1107 })) 1108 } 1109 }; 1110 try { 1111 performance.measure(measureName, { 1112 start: startTime, 1113 end: endTime, 1114 detail 1115 }); 1116 } catch { 1117 } 1118 } 1119 1120 // packages/upload-media/build-module/upload-error.mjs 1121 var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => { 1122 ErrorCode2["EMPTY_FILE"] = "EMPTY_FILE"; 1123 ErrorCode2["SIZE_ABOVE_LIMIT"] = "SIZE_ABOVE_LIMIT"; 1124 ErrorCode2["MIME_TYPE_NOT_SUPPORTED"] = "MIME_TYPE_NOT_SUPPORTED"; 1125 ErrorCode2["MIME_TYPE_NOT_ALLOWED_FOR_USER"] = "MIME_TYPE_NOT_ALLOWED_FOR_USER"; 1126 ErrorCode2["HEIC_DECODE_ERROR"] = "HEIC_DECODE_ERROR"; 1127 ErrorCode2["IMAGE_TRANSCODING_ERROR"] = "IMAGE_TRANSCODING_ERROR"; 1128 ErrorCode2["IMAGE_ROTATION_ERROR"] = "IMAGE_ROTATION_ERROR"; 1129 ErrorCode2["MEDIA_TRANSCODING_ERROR"] = "MEDIA_TRANSCODING_ERROR"; 1130 ErrorCode2["GIF_TRANSCODING_ERROR"] = "GIF_TRANSCODING_ERROR"; 1131 ErrorCode2["MEDIA_FINALIZE_ERROR"] = "MEDIA_FINALIZE_ERROR"; 1132 ErrorCode2["GENERAL"] = "GENERAL"; 1133 return ErrorCode2; 1134 })(ErrorCode || {}); 1135 var UploadError = class extends Error { 1136 code; 1137 file; 1138 constructor({ code, message, file, cause }) { 1139 super(message, { cause }); 1140 Object.setPrototypeOf(this, new.target.prototype); 1141 this.code = code; 1142 this.file = file; 1143 } 1144 }; 1145 1146 // packages/upload-media/build-module/validate-mime-type.mjs 1147 var import_i18n = __toESM(require_i18n(), 1); 1148 function validateMimeType(file, allowedTypes) { 1149 if (!allowedTypes) { 1150 return; 1151 } 1152 const isAllowedType = allowedTypes.some((allowedType) => { 1153 if (allowedType.includes("/")) { 1154 return allowedType === file.type; 1155 } 1156 return file.type.startsWith(`$allowedType}/`); 1157 }); 1158 if (file.type && !isAllowedType) { 1159 throw new UploadError({ 1160 code: ErrorCode.MIME_TYPE_NOT_SUPPORTED, 1161 message: (0, import_i18n.sprintf)( 1162 // translators: %s: file name. 1163 (0, import_i18n.__)("%s: Sorry, this file type is not supported here."), 1164 file.name 1165 ), 1166 file 1167 }); 1168 } 1169 } 1170 1171 // packages/upload-media/build-module/validate-mime-type-for-user.mjs 1172 var import_i18n2 = __toESM(require_i18n(), 1); 1173 1174 // packages/upload-media/build-module/get-mime-types-array.mjs 1175 function getMimeTypesArray(wpMimeTypesObject) { 1176 if (!wpMimeTypesObject) { 1177 return null; 1178 } 1179 return Object.entries(wpMimeTypesObject).flatMap( 1180 ([extensionsString, mime]) => { 1181 const [type] = mime.split("/"); 1182 const extensions = extensionsString.split("|"); 1183 return [ 1184 mime, 1185 ...extensions.map( 1186 (extension) => `$type}/$extension}` 1187 ) 1188 ]; 1189 } 1190 ); 1191 } 1192 1193 // packages/upload-media/build-module/validate-mime-type-for-user.mjs 1194 function validateMimeTypeForUser(file, wpAllowedMimeTypes) { 1195 const allowedMimeTypesForUser = getMimeTypesArray(wpAllowedMimeTypes); 1196 if (!allowedMimeTypesForUser) { 1197 return; 1198 } 1199 const isAllowedMimeTypeForUser = allowedMimeTypesForUser.includes( 1200 file.type 1201 ); 1202 if (file.type && !isAllowedMimeTypeForUser) { 1203 throw new UploadError({ 1204 code: ErrorCode.MIME_TYPE_NOT_ALLOWED_FOR_USER, 1205 message: (0, import_i18n2.sprintf)( 1206 // translators: %s: file name. 1207 (0, import_i18n2.__)( 1208 "%s: Sorry, you are not allowed to upload this file type." 1209 ), 1210 file.name 1211 ), 1212 file 1213 }); 1214 } 1215 } 1216 1217 // packages/upload-media/build-module/validate-file-size.mjs 1218 var import_i18n3 = __toESM(require_i18n(), 1); 1219 function validateFileSize(file, maxUploadFileSize) { 1220 if (file.size <= 0) { 1221 throw new UploadError({ 1222 code: ErrorCode.EMPTY_FILE, 1223 message: (0, import_i18n3.sprintf)( 1224 // translators: %s: file name. 1225 (0, import_i18n3.__)("%s: This file is empty."), 1226 file.name 1227 ), 1228 file 1229 }); 1230 } 1231 if (maxUploadFileSize && file.size > maxUploadFileSize) { 1232 throw new UploadError({ 1233 code: ErrorCode.SIZE_ABOVE_LIMIT, 1234 message: (0, import_i18n3.sprintf)( 1235 // translators: %s: file name. 1236 (0, import_i18n3.__)( 1237 "%s: This file exceeds the maximum upload size for this site." 1238 ), 1239 file.name 1240 ), 1241 file 1242 }); 1243 } 1244 } 1245 1246 // packages/upload-media/build-module/store/actions.mjs 1247 function addItems({ 1248 files, 1249 onChange, 1250 onSuccess, 1251 onError, 1252 onBatchSuccess, 1253 additionalData, 1254 allowedTypes 1255 }) { 1256 return async ({ select: select2, dispatch }) => { 1257 const batchId = v4_default(); 1258 for (const file of files) { 1259 try { 1260 validateMimeType(file, allowedTypes); 1261 validateMimeTypeForUser( 1262 file, 1263 select2.getSettings().allowedMimeTypes 1264 ); 1265 } catch (error) { 1266 onError?.(error); 1267 continue; 1268 } 1269 try { 1270 validateFileSize( 1271 file, 1272 select2.getSettings().maxUploadFileSize 1273 ); 1274 } catch (error) { 1275 onError?.(error); 1276 continue; 1277 } 1278 dispatch.addItem({ 1279 file, 1280 batchId, 1281 onChange, 1282 onSuccess, 1283 onBatchSuccess, 1284 onError, 1285 additionalData 1286 }); 1287 } 1288 }; 1289 } 1290 function cancelItem(id, error, silent = false) { 1291 return async ({ select: select2, dispatch }) => { 1292 const item = select2.getItem(id); 1293 if (!item) { 1294 return; 1295 } 1296 clearRetryTimer(id); 1297 if (!silent && error && !item.parentId && !item.attachment?.id) { 1298 const settings = select2.getSettings(); 1299 const retrySettings = settings.retry; 1300 if (retrySettings) { 1301 const retryCount = item.retryCount ?? 0; 1302 const maxRetries = retrySettings.maxRetryAttempts; 1303 if (shouldRetryError(error, retryCount, maxRetries)) { 1304 dispatch.scheduleRetry(id, error); 1305 return; 1306 } 1307 } 1308 } 1309 item.abortController?.abort(); 1310 vipsCancelOperations(id).catch(() => { 1311 }); 1312 cancelGifToVideoOperations(id).catch(() => { 1313 }); 1314 if (!silent) { 1315 const { onError } = item; 1316 onError?.(error ?? new Error("Upload cancelled")); 1317 if (!onError && error && !item.parentId) { 1318 console.error("Upload cancelled", error); 1319 } 1320 } else { 1321 debug( 1322 `Item cancelled: $item.file.name} (item $id}): $error instanceof Error ? error.message : error}` 1323 ); 1324 } 1325 const { currentOperation, parentId, batchId } = item; 1326 dispatch({ 1327 type: Type.Cancel, 1328 id, 1329 error 1330 }); 1331 dispatch.removeItem(id); 1332 dispatch.revokeBlobUrls(id); 1333 if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate) { 1334 for (const pending of select2.getPendingImageProcessing()) { 1335 dispatch.processItem(pending.id); 1336 } 1337 } 1338 if (currentOperation === OperationType.Upload) { 1339 for (const pending of select2.getPendingUploads()) { 1340 dispatch.processItem(pending.id); 1341 } 1342 } 1343 if (currentOperation === OperationType.TranscodeGif) { 1344 for (const pending of select2.getPendingVideoProcessing()) { 1345 dispatch.processItem(pending.id); 1346 } 1347 } 1348 if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate || currentOperation === OperationType.TranscodeImage) { 1349 maybeRecycleVipsWorker(select2.getActiveImageProcessingCount()); 1350 } 1351 if (parentId) { 1352 const parentItem = select2.getItem(parentId); 1353 if (parentItem) { 1354 const isOptionalCompanion = item.additionalData?.image_size === "animated_video" || item.additionalData?.image_size === "animated_video_poster"; 1355 if (select2.hasPendingItemsByParentId(parentId)) { 1356 if (parentItem.operations && parentItem.operations.length > 0) { 1357 dispatch.processItem(parentId); 1358 } 1359 } else if (parentItem.subSizes && parentItem.subSizes.length > 0 || isOptionalCompanion) { 1360 if (parentItem.operations && parentItem.operations.length > 0) { 1361 dispatch.processItem(parentId); 1362 } 1363 } else { 1364 const parentAttachmentId = parentItem.attachment?.id; 1365 const { mediaDelete } = select2.getSettings(); 1366 if (parentAttachmentId && mediaDelete) { 1367 mediaDelete(parentAttachmentId).catch(() => { 1368 }); 1369 } 1370 await dispatch.cancelItem( 1371 parentId, 1372 new UploadError({ 1373 code: error instanceof UploadError && error.code || ErrorCode.GENERAL, 1374 message: error?.message || (0, import_i18n4.__)("The image could not be uploaded."), 1375 file: parentItem.file, 1376 cause: error instanceof Error ? error : void 0 1377 }) 1378 ); 1379 } 1380 } 1381 } 1382 if (batchId && select2.isBatchUploaded(batchId)) { 1383 debug(`Batch completed: $batchId}`); 1384 item.onBatchSuccess?.(); 1385 } 1386 }; 1387 } 1388 function retryItem(id) { 1389 return async ({ select: select2, dispatch }) => { 1390 const item = select2.getItem(id); 1391 if (!item) { 1392 return; 1393 } 1394 if (!item.error) { 1395 return; 1396 } 1397 dispatch({ 1398 type: Type.RetryItem, 1399 id 1400 }); 1401 dispatch.processItem(id); 1402 }; 1403 } 1404 function scheduleRetry(id, error) { 1405 return async ({ select: select2, dispatch }) => { 1406 const item = select2.getItem(id); 1407 if (!item) { 1408 return; 1409 } 1410 const settings = select2.getSettings(); 1411 const retrySettings = settings.retry; 1412 if (!retrySettings) { 1413 return; 1414 } 1415 const currentRetryCount = item.retryCount ?? 0; 1416 const delay = calculateRetryDelay({ 1417 attempt: currentRetryCount + 1, 1418 initialDelay: retrySettings.initialRetryDelayMs, 1419 maxDelay: retrySettings.maxRetryDelayMs, 1420 multiplier: retrySettings.backoffMultiplier, 1421 jitter: retrySettings.retryJitter 1422 }); 1423 const timerId = setTimeout(() => { 1424 retryTimers.delete(id); 1425 dispatch.executeRetry(id); 1426 }, delay); 1427 retryTimers.set(id, timerId); 1428 dispatch({ 1429 type: Type.ScheduleRetry, 1430 id, 1431 error, 1432 retryCount: currentRetryCount, 1433 nextRetryTimestamp: Date.now() + delay 1434 }); 1435 }; 1436 } 1437 function executeRetry(id) { 1438 return async ({ select: select2, dispatch }) => { 1439 const item = select2.getItem(id); 1440 if (!item || item.status !== ItemStatus.PendingRetry) { 1441 return; 1442 } 1443 if (select2.isPaused()) { 1444 return; 1445 } 1446 dispatch({ 1447 type: Type.RetryItem, 1448 id 1449 }); 1450 dispatch.processItem(id); 1451 }; 1452 } 1453 1454 // packages/upload-media/build-module/store/private-actions.mjs 1455 var private_actions_exports = {}; 1456 __export(private_actions_exports, { 1457 addItem: () => addItem, 1458 addSideloadItem: () => addSideloadItem, 1459 detectUltraHdr: () => detectUltraHdr, 1460 finalizeItem: () => finalizeItem, 1461 finishOperation: () => finishOperation, 1462 generateThumbnails: () => generateThumbnails, 1463 getTranscodeImageOperation: () => getTranscodeImageOperation, 1464 pauseItem: () => pauseItem, 1465 pauseQueue: () => pauseQueue, 1466 prepareItem: () => prepareItem, 1467 processItem: () => processItem, 1468 removeItem: () => removeItem, 1469 resizeCropItem: () => resizeCropItem, 1470 resumeQueue: () => resumeQueue, 1471 revokeBlobUrls: () => revokeBlobUrls, 1472 rotateItem: () => rotateItem, 1473 sideloadItem: () => sideloadItem, 1474 transcodeGifItem: () => transcodeGifItem, 1475 transcodeImageItem: () => transcodeImageItem, 1476 updateItemProgress: () => updateItemProgress, 1477 updateSettings: () => updateSettings, 1478 uploadItem: () => uploadItem 1479 }); 1480 var import_blob = __toESM(require_blob(), 1); 1481 var import_i18n6 = __toESM(require_i18n(), 1); 1482 1483 // packages/upload-media/build-module/heic-parser.mjs 1484 var Reader = class { 1485 view; 1486 buffer; 1487 pos; 1488 constructor(buffer, offset = 0) { 1489 this.buffer = buffer; 1490 this.view = new DataView(buffer); 1491 this.pos = offset; 1492 } 1493 u8() { 1494 const v = this.view.getUint8(this.pos); 1495 this.pos += 1; 1496 return v; 1497 } 1498 u16() { 1499 const v = this.view.getUint16(this.pos); 1500 this.pos += 2; 1501 return v; 1502 } 1503 u32() { 1504 const v = this.view.getUint32(this.pos); 1505 this.pos += 4; 1506 return v; 1507 } 1508 u64() { 1509 const hi = this.view.getUint32(this.pos); 1510 const lo = this.view.getUint32(this.pos + 4); 1511 this.pos += 8; 1512 return hi * 4294967296 + lo; 1513 } 1514 /** 1515 * Read a variable-width unsigned integer (0, 4 or 8 bytes). 1516 * 1517 * @param size Byte width to read (0, 4, or 8). 1518 */ 1519 uN(size) { 1520 if (size === 0) { 1521 return 0; 1522 } 1523 if (size === 4) { 1524 return this.u32(); 1525 } 1526 if (size === 8) { 1527 return this.u64(); 1528 } 1529 throw new Error(`Unsupported uint size: $size}`); 1530 } 1531 str(len) { 1532 let s = ""; 1533 for (let i = 0; i < len; i++) { 1534 s += String.fromCharCode(this.view.getUint8(this.pos + i)); 1535 } 1536 this.pos += len; 1537 return s; 1538 } 1539 bytes(len) { 1540 const b = new Uint8Array(this.buffer, this.pos, len); 1541 this.pos += len; 1542 return new Uint8Array(b); 1543 } 1544 }; 1545 function readBox(r) { 1546 if (r.pos + 8 > r.view.byteLength) { 1547 return null; 1548 } 1549 const offset = r.pos; 1550 let size = r.u32(); 1551 const type = r.str(4); 1552 let headerSize = 8; 1553 if (size === 1) { 1554 size = r.u64(); 1555 headerSize = 16; 1556 } else if (size === 0) { 1557 size = r.view.byteLength - offset; 1558 } 1559 return { type, offset, size, headerSize }; 1560 } 1561 function findBoxes(r, start, end) { 1562 const boxes = []; 1563 r.pos = start; 1564 while (r.pos < end) { 1565 const box = readBox(r); 1566 if (!box || box.size < 8) { 1567 break; 1568 } 1569 boxes.push(box); 1570 r.pos = box.offset + box.size; 1571 } 1572 return boxes; 1573 } 1574 function findBox(r, start, end, type) { 1575 r.pos = start; 1576 while (r.pos < end) { 1577 const box = readBox(r); 1578 if (!box || box.size < 8) { 1579 break; 1580 } 1581 if (box.type === type) { 1582 return box; 1583 } 1584 r.pos = box.offset + box.size; 1585 } 1586 return void 0; 1587 } 1588 function parsePitm(r, box) { 1589 r.pos = box.offset + box.headerSize; 1590 const version = r.u8(); 1591 r.pos += 3; 1592 return version === 0 ? r.u16() : r.u32(); 1593 } 1594 function parseIloc(r, box) { 1595 r.pos = box.offset + box.headerSize; 1596 const version = r.u8(); 1597 r.pos += 3; 1598 const byte1 = r.u8(); 1599 const offsetSize = byte1 >> 4 & 15; 1600 const lengthSize = byte1 & 15; 1601 const byte2 = r.u8(); 1602 const baseOffsetSize = byte2 >> 4 & 15; 1603 const indexSize = version >= 1 ? byte2 & 15 : 0; 1604 const itemCount = version < 2 ? r.u16() : r.u32(); 1605 const items = /* @__PURE__ */ new Map(); 1606 for (let i = 0; i < itemCount; i++) { 1607 const itemId = version < 2 ? r.u16() : r.u32(); 1608 let constructionMethod = 0; 1609 if (version === 1 || version === 2) { 1610 const cm = r.u16(); 1611 constructionMethod = cm & 15; 1612 } 1613 r.u16(); 1614 const baseOffset = r.uN(baseOffsetSize); 1615 const extentCount = r.u16(); 1616 const extents = []; 1617 for (let j = 0; j < extentCount; j++) { 1618 if (version >= 1) { 1619 r.uN(indexSize); 1620 } 1621 const extOffset = r.uN(offsetSize); 1622 const extLength = r.uN(lengthSize); 1623 extents.push({ 1624 offset: baseOffset + extOffset, 1625 length: extLength 1626 }); 1627 } 1628 items.set(itemId, { constructionMethod, extents }); 1629 } 1630 return items; 1631 } 1632 function parseIpma(r, box) { 1633 r.pos = box.offset + box.headerSize; 1634 const vf = r.u32(); 1635 const version = vf >>> 24; 1636 const flags = vf & 16777215; 1637 const largeIndex = (flags & 1) !== 0; 1638 const entryCount = r.u32(); 1639 const associations = /* @__PURE__ */ new Map(); 1640 for (let i = 0; i < entryCount; i++) { 1641 const itemId = version < 1 ? r.u16() : r.u32(); 1642 const assocCount = r.u8(); 1643 const indices = []; 1644 for (let j = 0; j < assocCount; j++) { 1645 if (largeIndex) { 1646 indices.push(r.u16() & 32767); 1647 } else { 1648 indices.push(r.u8() & 127); 1649 } 1650 } 1651 associations.set(itemId, indices); 1652 } 1653 return associations; 1654 } 1655 function parseIspe(r, box) { 1656 r.pos = box.offset + box.headerSize + 4; 1657 return { width: r.u32(), height: r.u32() }; 1658 } 1659 function parseIrot(r, box) { 1660 r.pos = box.offset + box.headerSize; 1661 return (r.u8() & 3) * 90; 1662 } 1663 function parseIinf(r, box) { 1664 r.pos = box.offset + box.headerSize; 1665 const version = r.u8(); 1666 r.pos += 3; 1667 const entryCount = version === 0 ? r.u16() : r.u32(); 1668 const itemTypes = /* @__PURE__ */ new Map(); 1669 const entriesStart = r.pos; 1670 const boxEnd = box.offset + box.size; 1671 const infeBoxes = findBoxes(r, entriesStart, boxEnd); 1672 for (let i = 0; i < Math.min(entryCount, infeBoxes.length); i++) { 1673 const infe = infeBoxes[i]; 1674 if (infe.type !== "infe") { 1675 continue; 1676 } 1677 r.pos = infe.offset + infe.headerSize; 1678 const infeVersion = r.u8(); 1679 r.pos += 3; 1680 if (infeVersion >= 2) { 1681 const itemId = infeVersion === 2 ? r.u16() : r.u32(); 1682 r.u16(); 1683 const itemType = r.str(4); 1684 itemTypes.set(itemId, itemType); 1685 } 1686 } 1687 return itemTypes; 1688 } 1689 function parseIref(r, box, refType) { 1690 r.pos = box.offset + box.headerSize; 1691 const version = r.u8(); 1692 r.pos += 3; 1693 const refs = /* @__PURE__ */ new Map(); 1694 const boxEnd = box.offset + box.size; 1695 while (r.pos < boxEnd) { 1696 const refBox = readBox(r); 1697 if (!refBox || refBox.size < 8) { 1698 break; 1699 } 1700 r.pos = refBox.offset + refBox.headerSize; 1701 const fromId = version === 0 ? r.u16() : r.u32(); 1702 const refCount = r.u16(); 1703 const toIds = []; 1704 for (let i = 0; i < refCount; i++) { 1705 toIds.push(version === 0 ? r.u16() : r.u32()); 1706 } 1707 if (refBox.type === refType) { 1708 refs.set(fromId, toIds); 1709 } 1710 r.pos = refBox.offset + refBox.size; 1711 } 1712 return refs; 1713 } 1714 function reverseBits32(n) { 1715 n = n >>> 1 & 1431655765 | (n & 1431655765) << 1; 1716 n = n >>> 2 & 858993459 | (n & 858993459) << 2; 1717 n = n >>> 4 & 252645135 | (n & 252645135) << 4; 1718 n = n >>> 8 & 16711935 | (n & 16711935) << 8; 1719 n = n >>> 16 | n << 16; 1720 return n >>> 0; 1721 } 1722 function buildCodecString(r, recordOffset) { 1723 r.pos = recordOffset; 1724 r.u8(); 1725 const byte1 = r.u8(); 1726 const profileSpace = byte1 >> 6 & 3; 1727 const tierFlag = byte1 >> 5 & 1; 1728 const profileIdc = byte1 & 31; 1729 const compatFlags = r.u32(); 1730 const constraintBytes = r.bytes(6); 1731 const levelIdc = r.u8(); 1732 const spacePrefix = profileSpace > 0 ? String.fromCharCode(64 + profileSpace) : ""; 1733 const compatHex = reverseBits32(compatFlags).toString(16).toUpperCase(); 1734 const tierChar = tierFlag ? "H" : "L"; 1735 let lastNonZero = -1; 1736 for (let i = 5; i >= 0; i--) { 1737 if (constraintBytes[i] !== 0) { 1738 lastNonZero = i; 1739 break; 1740 } 1741 } 1742 let constraintStr = ""; 1743 if (lastNonZero >= 0) { 1744 const parts = []; 1745 for (let i = 0; i <= lastNonZero; i++) { 1746 parts.push(constraintBytes[i].toString(16).toUpperCase()); 1747 } 1748 constraintStr = "." + parts.join("."); 1749 } 1750 return `hvc1.$spacePrefix}$profileIdc}.$compatHex}.$tierChar}$levelIdc}$constraintStr}`; 1751 } 1752 function readItemData(buffer, loc, idatOffset) { 1753 const baseOffset = loc.constructionMethod === 1 ? idatOffset : 0; 1754 for (const ext of loc.extents) { 1755 if (baseOffset + ext.offset + ext.length > buffer.byteLength) { 1756 throw new Error( 1757 "HEIC item data extends past the end of the file" 1758 ); 1759 } 1760 } 1761 if (loc.extents.length === 1) { 1762 const ext = loc.extents[0]; 1763 const start = baseOffset + ext.offset; 1764 return new Uint8Array(buffer.slice(start, start + ext.length)); 1765 } 1766 let totalLength = 0; 1767 for (const ext of loc.extents) { 1768 totalLength += ext.length; 1769 } 1770 const data = new Uint8Array(totalLength); 1771 let pos = 0; 1772 for (const ext of loc.extents) { 1773 const start = baseOffset + ext.offset; 1774 data.set( 1775 new Uint8Array(buffer.slice(start, start + ext.length)), 1776 pos 1777 ); 1778 pos += ext.length; 1779 } 1780 return data; 1781 } 1782 function findHvcProperties(propIndices, properties) { 1783 let hvcCBox; 1784 let ispeBox; 1785 let irotBox; 1786 for (const idx of propIndices) { 1787 if (idx < 1 || idx > properties.length) { 1788 continue; 1789 } 1790 const prop = properties[idx - 1]; 1791 if (prop.type === "hvcC" && !hvcCBox) { 1792 hvcCBox = prop; 1793 } 1794 if (prop.type === "ispe" && !ispeBox) { 1795 ispeBox = prop; 1796 } 1797 if (prop.type === "irot" && !irotBox) { 1798 irotBox = prop; 1799 } 1800 } 1801 if (!hvcCBox) { 1802 throw new Error("No HEVC configuration (hvcC) found"); 1803 } 1804 if (!ispeBox) { 1805 throw new Error("No image dimensions (ispe) found"); 1806 } 1807 return { hvcCBox, ispeBox, irotBox }; 1808 } 1809 function parseHeic(buffer) { 1810 const r = new Reader(buffer); 1811 const fileEnd = buffer.byteLength; 1812 const metaBox = findBox(r, 0, fileEnd, "meta"); 1813 if (!metaBox) { 1814 throw new Error("No meta box found in HEIC file"); 1815 } 1816 const metaChildStart = metaBox.offset + metaBox.headerSize + 4; 1817 const metaEnd = metaBox.offset + metaBox.size; 1818 const children = findBoxes(r, metaChildStart, metaEnd); 1819 const pitmBox = children.find((b) => b.type === "pitm"); 1820 const ilocBox = children.find((b) => b.type === "iloc"); 1821 const iprpBox = children.find((b) => b.type === "iprp"); 1822 const iinfBox = children.find((b) => b.type === "iinf"); 1823 const irefBox = children.find((b) => b.type === "iref"); 1824 const idatBox = children.find((b) => b.type === "idat"); 1825 const idatOffset = idatBox ? idatBox.offset + idatBox.headerSize : 0; 1826 if (!pitmBox || !ilocBox || !iprpBox) { 1827 throw new Error("Missing required boxes (pitm, iloc, iprp) in HEIC"); 1828 } 1829 const primaryId = parsePitm(r, pitmBox); 1830 const locations = parseIloc(r, ilocBox); 1831 const iprpStart = iprpBox.offset + iprpBox.headerSize; 1832 const iprpEnd = iprpBox.offset + iprpBox.size; 1833 const iprpChildren = findBoxes(r, iprpStart, iprpEnd); 1834 const ipcoBox = iprpChildren.find((b) => b.type === "ipco"); 1835 const ipmaBox = iprpChildren.find((b) => b.type === "ipma"); 1836 if (!ipcoBox || !ipmaBox) { 1837 throw new Error("Missing ipco or ipma in HEIC properties"); 1838 } 1839 const allAssoc = parseIpma(r, ipmaBox); 1840 const ipcoStart = ipcoBox.offset + ipcoBox.headerSize; 1841 const ipcoEnd = ipcoBox.offset + ipcoBox.size; 1842 const properties = findBoxes(r, ipcoStart, ipcoEnd); 1843 let primaryItemType = "hvc1"; 1844 if (iinfBox) { 1845 const itemTypes = parseIinf(r, iinfBox); 1846 const t = itemTypes.get(primaryId); 1847 if (t) { 1848 primaryItemType = t; 1849 } 1850 } 1851 if (primaryItemType === "grid") { 1852 return parseGridImage( 1853 r, 1854 buffer, 1855 primaryId, 1856 locations, 1857 allAssoc, 1858 properties, 1859 irefBox, 1860 idatOffset 1861 ); 1862 } 1863 const primaryLoc = locations.get(primaryId); 1864 if (!primaryLoc || primaryLoc.extents.length === 0) { 1865 throw new Error(`No location data for primary item $primaryId}`); 1866 } 1867 const primaryPropIndices = allAssoc.get(primaryId); 1868 if (!primaryPropIndices || primaryPropIndices.length === 0) { 1869 throw new Error("No property associations for primary item"); 1870 } 1871 const { hvcCBox, ispeBox, irotBox } = findHvcProperties( 1872 primaryPropIndices, 1873 properties 1874 ); 1875 const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize; 1876 const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize; 1877 const description = new Uint8Array( 1878 buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize) 1879 ); 1880 const codecString = buildCodecString(r, hvcCDataStart); 1881 const { width, height } = parseIspe(r, ispeBox); 1882 const rotation = irotBox ? parseIrot(r, irotBox) : 0; 1883 return { 1884 codecString, 1885 description, 1886 tiles: [ 1887 { 1888 data: readItemData(buffer, primaryLoc, idatOffset), 1889 x: 0, 1890 y: 0 1891 } 1892 ], 1893 tileWidth: width, 1894 tileHeight: height, 1895 outputWidth: width, 1896 outputHeight: height, 1897 rotation, 1898 exifOrientation: rotation === 0 ? getUnappliedExifOrientation(buffer) : 1 1899 }; 1900 } 1901 function parseGridImage(r, buffer, gridItemId, locations, allAssoc, properties, irefBox, idatOffset) { 1902 const gridLoc = locations.get(gridItemId); 1903 if (!gridLoc || gridLoc.extents.length === 0) { 1904 throw new Error("No location data for grid item"); 1905 } 1906 const gridData = readItemData(buffer, gridLoc, idatOffset); 1907 const largeFields = gridData.length > 1 && (gridData[1] & 1) !== 0; 1908 const minGridSize = largeFields ? 12 : 8; 1909 if (gridData.length < minGridSize) { 1910 throw new Error( 1911 `Grid descriptor too short: $gridData.length} bytes` 1912 ); 1913 } 1914 const rows = gridData[2] + 1; 1915 const columns = gridData[3] + 1; 1916 const gv = new DataView(gridData.buffer, gridData.byteOffset); 1917 let outputWidth; 1918 let outputHeight; 1919 if (largeFields) { 1920 outputWidth = gv.getUint32(4); 1921 outputHeight = gv.getUint32(8); 1922 } else { 1923 outputWidth = gv.getUint16(4); 1924 outputHeight = gv.getUint16(6); 1925 } 1926 if (!irefBox) { 1927 throw new Error("Grid image requires iref box"); 1928 } 1929 const dimgRefs = parseIref(r, irefBox, "dimg"); 1930 const tileItemIds = dimgRefs.get(gridItemId); 1931 if (!tileItemIds || tileItemIds.length === 0) { 1932 throw new Error("No tile references found for grid item"); 1933 } 1934 const expectedTiles = rows * columns; 1935 if (tileItemIds.length < expectedTiles) { 1936 throw new Error( 1937 `Grid expects $expectedTiles} tiles but found $tileItemIds.length}` 1938 ); 1939 } 1940 const firstTileProps = allAssoc.get(tileItemIds[0]); 1941 if (!firstTileProps || firstTileProps.length === 0) { 1942 throw new Error("No property associations for tile item"); 1943 } 1944 const { hvcCBox, ispeBox } = findHvcProperties( 1945 firstTileProps, 1946 properties 1947 ); 1948 const gridProps = allAssoc.get(gridItemId) || []; 1949 let irotBox; 1950 for (const idx of gridProps) { 1951 if (idx >= 1 && idx <= properties.length) { 1952 const prop = properties[idx - 1]; 1953 if (prop.type === "irot") { 1954 irotBox = prop; 1955 break; 1956 } 1957 } 1958 } 1959 const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize; 1960 const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize; 1961 const description = new Uint8Array( 1962 buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize) 1963 ); 1964 const codecString = buildCodecString(r, hvcCDataStart); 1965 const { width: tileWidth, height: tileHeight } = parseIspe(r, ispeBox); 1966 const tiles = []; 1967 for (let row = 0; row < rows; row++) { 1968 for (let col = 0; col < columns; col++) { 1969 const tileIdx = row * columns + col; 1970 const tileId = tileItemIds[tileIdx]; 1971 const tileLoc = locations.get(tileId); 1972 if (!tileLoc || tileLoc.extents.length === 0) { 1973 throw new Error(`No location data for tile item $tileId}`); 1974 } 1975 tiles.push({ 1976 data: readItemData(buffer, tileLoc, idatOffset), 1977 x: col * tileWidth, 1978 y: row * tileHeight 1979 }); 1980 } 1981 } 1982 const rotation = irotBox ? parseIrot(r, irotBox) : 0; 1983 return { 1984 codecString, 1985 description, 1986 tiles, 1987 tileWidth, 1988 tileHeight, 1989 outputWidth, 1990 outputHeight, 1991 rotation, 1992 exifOrientation: rotation === 0 ? getUnappliedExifOrientation(buffer) : 1 1993 }; 1994 } 1995 function readTiffOrientation(payload) { 1996 if (payload.length < 8) { 1997 return 1; 1998 } 1999 const view = new DataView( 2000 payload.buffer, 2001 payload.byteOffset, 2002 payload.byteLength 2003 ); 2004 let tiffStart = 0; 2005 const firstWord = view.getUint16(0); 2006 if (firstWord !== 18761 && firstWord !== 19789) { 2007 tiffStart = view.getUint32(0) + 4; 2008 } 2009 if (tiffStart + 8 > payload.length) { 2010 return 1; 2011 } 2012 const byteOrder = view.getUint16(tiffStart); 2013 let little; 2014 if (byteOrder === 18761) { 2015 little = true; 2016 } else if (byteOrder === 19789) { 2017 little = false; 2018 } else { 2019 return 1; 2020 } 2021 const ifd0 = tiffStart + view.getUint32(tiffStart + 4, little); 2022 if (ifd0 + 2 > payload.length) { 2023 return 1; 2024 } 2025 const entryCount = view.getUint16(ifd0, little); 2026 for (let i = 0; i < entryCount; i++) { 2027 const entry = ifd0 + 2 + i * 12; 2028 if (entry + 12 > payload.length) { 2029 break; 2030 } 2031 if (view.getUint16(entry, little) === 274) { 2032 const value = view.getUint16(entry + 8, little); 2033 return value >= 1 && value <= 8 ? value : 1; 2034 } 2035 } 2036 return 1; 2037 } 2038 function findMeta(r) { 2039 const metaBox = findBox(r, 0, r.view.byteLength, "meta"); 2040 if (!metaBox) { 2041 return null; 2042 } 2043 const start = metaBox.offset + metaBox.headerSize + 4; 2044 const end = metaBox.offset + metaBox.size; 2045 return { box: metaBox, children: findBoxes(r, start, end) }; 2046 } 2047 function parseExifOrientation(buffer) { 2048 try { 2049 const r = new Reader(buffer); 2050 const meta = findMeta(r); 2051 if (!meta) { 2052 return 1; 2053 } 2054 const iinfBox = meta.children.find((b) => b.type === "iinf"); 2055 const ilocBox = meta.children.find((b) => b.type === "iloc"); 2056 if (!iinfBox || !ilocBox) { 2057 return 1; 2058 } 2059 const itemTypes = parseIinf(r, iinfBox); 2060 let exifItemId; 2061 for (const [id, type] of itemTypes) { 2062 if (type === "Exif") { 2063 exifItemId = id; 2064 break; 2065 } 2066 } 2067 if (exifItemId === void 0) { 2068 return 1; 2069 } 2070 const loc = parseIloc(r, ilocBox).get(exifItemId); 2071 if (!loc || loc.extents.length === 0) { 2072 return 1; 2073 } 2074 const idatBox = meta.children.find((b) => b.type === "idat"); 2075 const idatOffset = idatBox ? idatBox.offset + idatBox.headerSize : 0; 2076 return readTiffOrientation(readItemData(buffer, loc, idatOffset)); 2077 } catch { 2078 return 1; 2079 } 2080 } 2081 function hasNativeTransform(r) { 2082 const meta = findMeta(r); 2083 if (!meta) { 2084 return false; 2085 } 2086 const iprp = meta.children.find((b) => b.type === "iprp"); 2087 if (!iprp) { 2088 return false; 2089 } 2090 const ipco = findBox( 2091 r, 2092 iprp.offset + iprp.headerSize, 2093 iprp.offset + iprp.size, 2094 "ipco" 2095 ); 2096 if (!ipco) { 2097 return false; 2098 } 2099 const start = ipco.offset + ipco.headerSize; 2100 const end = ipco.offset + ipco.size; 2101 return Boolean( 2102 findBox(r, start, end, "irot") || findBox(r, start, end, "imir") 2103 ); 2104 } 2105 function getUnappliedExifOrientation(buffer) { 2106 try { 2107 if (hasNativeTransform(new Reader(buffer))) { 2108 return 1; 2109 } 2110 } catch { 2111 return 1; 2112 } 2113 return parseExifOrientation(buffer); 2114 } 2115 2116 // packages/upload-media/build-module/heic-support.mjs 2117 var import_i18n5 = __toESM(require_i18n(), 1); 2118 function detectBrowserFamily() { 2119 if (typeof navigator === "undefined") { 2120 return null; 2121 } 2122 const brands = navigator.userAgentData?.brands; 2123 if (brands?.length) { 2124 if (brands.some(({ brand }) => /Chromium/i.test(brand))) { 2125 return "chromium"; 2126 } 2127 } 2128 const userAgent = navigator.userAgent || ""; 2129 if (/Firefox|FxiOS/i.test(userAgent)) { 2130 return "firefox"; 2131 } 2132 if (/Chrome|Chromium|CriOS|Edg|OPR/i.test(userAgent)) { 2133 return "chromium"; 2134 } 2135 if (/Safari/i.test(userAgent)) { 2136 return "safari"; 2137 } 2138 return null; 2139 } 2140 function detectPlatform() { 2141 if (typeof navigator === "undefined") { 2142 return "other"; 2143 } 2144 const platform = navigator.userAgentData?.platform || navigator.userAgent || ""; 2145 if (/iPhone|iPad|iPod|iOS/i.test(platform)) { 2146 return "other"; 2147 } 2148 if (/macOS|Mac OS X|Macintosh/i.test(platform)) { 2149 return "macos"; 2150 } 2151 if (/Windows/i.test(platform)) { 2152 return "windows"; 2153 } 2154 if (/Android|CrOS|Chrome OS/i.test(platform)) { 2155 return "other"; 2156 } 2157 if (/Linux|X11/i.test(platform)) { 2158 return "linux"; 2159 } 2160 return "other"; 2161 } 2162 function getBrowserName() { 2163 if (detectBrowserFamily() === "chromium") { 2164 const brands = navigator.userAgentData?.brands ?? []; 2165 const userAgent = navigator.userAgent || ""; 2166 if (brands.some(({ brand }) => /Edge/i.test(brand)) || /Edg\//i.test(userAgent)) { 2167 return "Edge"; 2168 } 2169 if (brands.some(({ brand }) => /Opera/i.test(brand)) || /OPR\//i.test(userAgent)) { 2170 return "Opera"; 2171 } 2172 return "Chrome"; 2173 } 2174 switch (detectBrowserFamily()) { 2175 case "firefox": 2176 return "Firefox"; 2177 case "safari": 2178 return "Safari"; 2179 default: 2180 return null; 2181 } 2182 } 2183 function getHeicConversionAdvice() { 2184 const platform = detectPlatform(); 2185 const family = detectBrowserFamily(); 2186 if (platform === "macos") { 2187 if (family === "chromium") { 2188 return (0, import_i18n5.__)( 2189 "Safari usually can, or you can upload a JPEG instead." 2190 ); 2191 } 2192 if (family !== "safari") { 2193 return (0, import_i18n5.__)( 2194 "Safari or Chrome usually can, or you can upload a JPEG instead." 2195 ); 2196 } 2197 } 2198 if (platform === "windows" && family === "firefox") { 2199 return (0, import_i18n5.__)("Chrome or Edge might, or you can upload a JPEG instead."); 2200 } 2201 return (0, import_i18n5.__)("You can upload a JPEG instead."); 2202 } 2203 function getHeicUnsupportedMessage() { 2204 const platform = detectPlatform(); 2205 const family = detectBrowserFamily(); 2206 const browserName = getBrowserName(); 2207 let cause; 2208 if (platform === "linux") { 2209 cause = (0, import_i18n5.__)( 2210 "HEIC photos can't be decoded on Linux, so unfortunately we couldn't convert this one." 2211 ); 2212 } else if (family === "firefox") { 2213 cause = (0, import_i18n5.__)( 2214 "Firefox can't read HEIC photos, so we couldn't convert this one." 2215 ); 2216 } else if (browserName && platform === "windows") { 2217 cause = (0, import_i18n5.sprintf)( 2218 /* translators: %s: browser name, e.g. "Chrome". */ 2219 (0, import_i18n5.__)( 2220 "%s couldn't decode HEIC on this PC, so we couldn't convert this one." 2221 ), 2222 browserName 2223 ); 2224 } else if (browserName && platform === "macos") { 2225 cause = (0, import_i18n5.sprintf)( 2226 /* translators: %s: browser name, e.g. "Safari". */ 2227 (0, import_i18n5.__)( 2228 "%s couldn't decode HEIC on this Mac, so we couldn't convert this one." 2229 ), 2230 browserName 2231 ); 2232 } else if (browserName) { 2233 cause = (0, import_i18n5.sprintf)( 2234 /* translators: %s: browser name, e.g. "Chrome". */ 2235 (0, import_i18n5.__)( 2236 "%s couldn't decode HEIC on this device, so we couldn't convert this one." 2237 ), 2238 browserName 2239 ); 2240 } else { 2241 cause = (0, import_i18n5.__)( 2242 "This browser can't read HEIC photos, so we couldn't convert this one." 2243 ); 2244 } 2245 return `$cause} $getHeicConversionAdvice()}`; 2246 } 2247 2248 // packages/upload-media/build-module/canvas-utils.mjs 2249 var IMAGE_DECODER_TIMEOUT = 15e3; 2250 var HeicUnsupportedError = class extends Error { 2251 }; 2252 async function canvasConvertToJpeg(file, quality = 0.82, encode) { 2253 const canvas = await decodeToCanvas(file); 2254 const jpegBlob = await encodeCanvas(canvas, quality, encode); 2255 return new File([jpegBlob], `$getFileBasename(file.name)}.jpg`, { 2256 type: "image/jpeg" 2257 }); 2258 } 2259 async function encodeCanvas(canvas, quality, encode) { 2260 if (encode) { 2261 try { 2262 const encoded = await encode(canvas, quality); 2263 if (encoded) { 2264 return encoded; 2265 } 2266 } catch { 2267 } 2268 } 2269 return canvas.convertToBlob({ type: "image/jpeg", quality }); 2270 } 2271 async function decodeToCanvas(file) { 2272 try { 2273 const bitmap = await createImageBitmap(file); 2274 try { 2275 const canvas = new OffscreenCanvas(bitmap.width, bitmap.height); 2276 const ctx = canvas.getContext("2d"); 2277 if (!ctx) { 2278 throw new Error("Could not get canvas 2d context"); 2279 } 2280 ctx.drawImage(bitmap, 0, 0); 2281 return canvas; 2282 } finally { 2283 bitmap.close(); 2284 } 2285 } catch { 2286 } 2287 if (typeof ImageDecoder !== "undefined") { 2288 const supported = await ImageDecoder.isTypeSupported(file.type); 2289 if (supported) { 2290 const decoder = new ImageDecoder({ 2291 type: file.type, 2292 data: file.stream() 2293 }); 2294 let videoFrame; 2295 let timeoutId; 2296 let timedOut = false; 2297 try { 2298 const decoded = await Promise.race([ 2299 decoder.decode(), 2300 new Promise((_resolve, reject) => { 2301 timeoutId = setTimeout(() => { 2302 timedOut = true; 2303 decoder.close(); 2304 reject( 2305 new Error("ImageDecoder decode timed out") 2306 ); 2307 }, IMAGE_DECODER_TIMEOUT); 2308 }) 2309 ]); 2310 videoFrame = decoded.image; 2311 } catch (error) { 2312 if (!timedOut) { 2313 throw error; 2314 } 2315 } finally { 2316 clearTimeout(timeoutId); 2317 if (!timedOut) { 2318 decoder.close(); 2319 } 2320 } 2321 if (videoFrame) { 2322 try { 2323 const canvas = new OffscreenCanvas( 2324 videoFrame.displayWidth, 2325 videoFrame.displayHeight 2326 ); 2327 const ctx = canvas.getContext("2d"); 2328 if (!ctx) { 2329 throw new Error("Could not get canvas 2d context"); 2330 } 2331 ctx.drawImage(videoFrame, 0, 0); 2332 return canvas; 2333 } finally { 2334 videoFrame.close(); 2335 } 2336 } 2337 } 2338 } 2339 let heicData; 2340 try { 2341 heicData = parseHeic(await file.arrayBuffer()); 2342 } catch (error) { 2343 throw new Error("The HEIC file could not be parsed", { 2344 cause: error 2345 }); 2346 } 2347 if (typeof VideoDecoder !== "undefined") { 2348 let supported = false; 2349 try { 2350 const support = await VideoDecoder.isConfigSupported({ 2351 codec: heicData.codecString 2352 }); 2353 supported = support.supported === true; 2354 } catch { 2355 } 2356 if (supported) { 2357 const canvas = new OffscreenCanvas( 2358 heicData.outputWidth, 2359 heicData.outputHeight 2360 ); 2361 const ctx = canvas.getContext("2d"); 2362 if (!ctx) { 2363 throw new Error("Could not get canvas 2d context"); 2364 } 2365 for (const tile of heicData.tiles) { 2366 const frame = await decodeHevcFrame( 2367 heicData.codecString, 2368 heicData.description, 2369 heicData.tileWidth, 2370 heicData.tileHeight, 2371 tile.data 2372 ); 2373 try { 2374 ctx.drawImage(frame, tile.x, tile.y); 2375 } finally { 2376 frame.close(); 2377 } 2378 } 2379 return heicData.rotation !== 0 ? applyRotation(canvas, heicData.rotation) : applyExifOrientation(canvas, heicData.exifOrientation); 2380 } 2381 } 2382 throw new HeicUnsupportedError(getHeicUnsupportedMessage()); 2383 } 2384 function applyRotation(source, rotation) { 2385 if (rotation === 0) { 2386 return source; 2387 } 2388 const swap = rotation === 90 || rotation === 270; 2389 const w = swap ? source.height : source.width; 2390 const h = swap ? source.width : source.height; 2391 const rotated = new OffscreenCanvas(w, h); 2392 const ctx = rotated.getContext("2d"); 2393 if (!ctx) { 2394 return source; 2395 } 2396 ctx.translate(w / 2, h / 2); 2397 ctx.rotate(-rotation * Math.PI / 180); 2398 ctx.drawImage(source, -source.width / 2, -source.height / 2); 2399 return rotated; 2400 } 2401 function applyExifOrientation(source, orientation) { 2402 if (orientation <= 1 || orientation > 8) { 2403 return source; 2404 } 2405 const { width: sw, height: sh } = source; 2406 const swap = orientation >= 5; 2407 const out = new OffscreenCanvas(swap ? sh : sw, swap ? sw : sh); 2408 const ctx = out.getContext("2d"); 2409 if (!ctx) { 2410 return source; 2411 } 2412 switch (orientation) { 2413 case 2: 2414 ctx.transform(-1, 0, 0, 1, sw, 0); 2415 break; 2416 case 3: 2417 ctx.transform(-1, 0, 0, -1, sw, sh); 2418 break; 2419 case 4: 2420 ctx.transform(1, 0, 0, -1, 0, sh); 2421 break; 2422 case 5: 2423 ctx.transform(0, 1, 1, 0, 0, 0); 2424 break; 2425 case 6: 2426 ctx.transform(0, 1, -1, 0, sh, 0); 2427 break; 2428 case 7: 2429 ctx.transform(0, -1, -1, 0, sh, sw); 2430 break; 2431 case 8: 2432 ctx.transform(0, -1, 1, 0, 0, sw); 2433 break; 2434 } 2435 ctx.drawImage(source, 0, 0); 2436 return out; 2437 } 2438 function decodeHevcFrame(codec, description, width, height, data) { 2439 return new Promise((resolve, reject) => { 2440 const decoder = new VideoDecoder({ 2441 output: (frame) => { 2442 decoder.close(); 2443 resolve(frame); 2444 }, 2445 error: (e) => { 2446 if (decoder.state !== "closed") { 2447 decoder.close(); 2448 } 2449 reject(e); 2450 } 2451 }); 2452 decoder.configure({ 2453 codec, 2454 codedWidth: width, 2455 codedHeight: height, 2456 description 2457 }); 2458 decoder.decode( 2459 new EncodedVideoChunk({ 2460 type: "key", 2461 timestamp: 0, 2462 data 2463 }) 2464 ); 2465 decoder.flush().catch((e) => { 2466 if (decoder.state !== "closed") { 2467 decoder.close(); 2468 } 2469 reject(e); 2470 }); 2471 }); 2472 } 2473 2474 // packages/upload-media/build-module/get-image-dimensions.mjs 2475 var MAX_HEADER_BYTES = 512 * 1024; 2476 function parseJpeg(view) { 2477 let offset = 2; 2478 while (offset < view.byteLength) { 2479 if (view.getUint8(offset) !== 255) { 2480 return null; 2481 } 2482 while (offset < view.byteLength && view.getUint8(offset) === 255) { 2483 offset++; 2484 } 2485 if (offset >= view.byteLength) { 2486 return null; 2487 } 2488 const marker = view.getUint8(offset); 2489 offset++; 2490 if (marker === 1 || marker >= 208 && marker <= 217) { 2491 continue; 2492 } 2493 if (marker === 218) { 2494 return null; 2495 } 2496 if (offset + 2 > view.byteLength) { 2497 return null; 2498 } 2499 const segmentLength = view.getUint16(offset); 2500 if (segmentLength < 2) { 2501 return null; 2502 } 2503 const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204; 2504 if (isStartOfFrame) { 2505 if (offset + 7 > view.byteLength) { 2506 return null; 2507 } 2508 const height = view.getUint16(offset + 3); 2509 const width = view.getUint16(offset + 5); 2510 const interlaced = marker === 194 || marker === 198 || marker === 202 || marker === 206; 2511 return { width, height, interlaced }; 2512 } 2513 offset += segmentLength; 2514 } 2515 return null; 2516 } 2517 function parsePng(view) { 2518 if (view.byteLength < 29) { 2519 return null; 2520 } 2521 const isIhdr = view.getUint8(12) === 73 && // I 2522 view.getUint8(13) === 72 && // H 2523 view.getUint8(14) === 68 && // D 2524 view.getUint8(15) === 82; 2525 if (!isIhdr) { 2526 return null; 2527 } 2528 const width = view.getUint32(16); 2529 const height = view.getUint32(20); 2530 const interlaceMethod = view.getUint8(28); 2531 return { width, height, interlaced: interlaceMethod !== 0 }; 2532 } 2533 async function getImageDimensions(file) { 2534 try { 2535 const headerBytes = Math.min(file.size, MAX_HEADER_BYTES); 2536 const buffer = await file.slice(0, headerBytes).arrayBuffer(); 2537 const view = new DataView(buffer); 2538 if (view.byteLength >= 3 && view.getUint16(0) === 65496) { 2539 return parseJpeg(view); 2540 } 2541 if (view.byteLength >= 8 && view.getUint32(0) === 2303741511 && view.getUint32(4) === 218765834) { 2542 return parsePng(view); 2543 } 2544 return null; 2545 } catch { 2546 return null; 2547 } 2548 } 2549 2550 // packages/upload-media/build-module/stub-file.mjs 2551 var StubFile = class extends File { 2552 constructor(fileName = "stub-file") { 2553 super([], fileName); 2554 } 2555 }; 2556 2557 // packages/upload-media/build-module/store/private-actions.mjs 2558 var DEFAULT_OUTPUT_QUALITY = 0.82; 2559 var ultraHdrItems = /* @__PURE__ */ new Set(); 2560 function addItem({ 2561 file: fileOrBlob, 2562 batchId, 2563 onChange, 2564 onSuccess, 2565 onBatchSuccess, 2566 onError, 2567 additionalData = {}, 2568 sourceUrl, 2569 sourceAttachmentId, 2570 abortController, 2571 operations 2572 }) { 2573 return async ({ dispatch }) => { 2574 const itemId = v4_default(); 2575 const file = convertBlobToFile(fileOrBlob); 2576 let blobUrl; 2577 if (!(file instanceof StubFile)) { 2578 blobUrl = (0, import_blob.createBlobURL)(file); 2579 dispatch({ 2580 type: Type.CacheBlobUrl, 2581 id: itemId, 2582 blobUrl 2583 }); 2584 } 2585 dispatch({ 2586 type: Type.Add, 2587 item: { 2588 id: itemId, 2589 batchId, 2590 status: ItemStatus.Processing, 2591 sourceFile: cloneFile(file), 2592 file, 2593 attachment: { 2594 url: blobUrl 2595 }, 2596 additionalData: { 2597 generate_sub_sizes: false, 2598 ...additionalData 2599 }, 2600 onChange, 2601 onSuccess, 2602 onBatchSuccess, 2603 onError, 2604 sourceUrl, 2605 sourceAttachmentId, 2606 abortController: abortController || new AbortController(), 2607 operations: Array.isArray(operations) ? operations : [OperationType.Prepare] 2608 } 2609 }); 2610 dispatch.processItem(itemId); 2611 }; 2612 } 2613 function addSideloadItem({ 2614 file, 2615 onChange, 2616 additionalData, 2617 operations, 2618 batchId, 2619 parentId 2620 }) { 2621 return ({ dispatch }) => { 2622 const itemId = v4_default(); 2623 dispatch({ 2624 type: Type.Add, 2625 item: { 2626 id: itemId, 2627 batchId, 2628 status: ItemStatus.Processing, 2629 sourceFile: cloneFile(file), 2630 file, 2631 onChange, 2632 additionalData: { 2633 ...additionalData 2634 }, 2635 parentId, 2636 operations: Array.isArray(operations) ? operations : [OperationType.Prepare], 2637 abortController: new AbortController() 2638 } 2639 }); 2640 dispatch.processItem(itemId); 2641 }; 2642 } 2643 function processItem(id) { 2644 return async ({ select: select2, dispatch }) => { 2645 if (select2.isPaused()) { 2646 return; 2647 } 2648 const item = select2.getItem(id); 2649 if (!item) { 2650 return; 2651 } 2652 if (item.currentOperation) { 2653 return; 2654 } 2655 const { 2656 attachment, 2657 onChange, 2658 onSuccess, 2659 onBatchSuccess, 2660 batchId, 2661 parentId 2662 } = item; 2663 const operation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0]; 2664 const operationArgs = Array.isArray(item.operations?.[0]) ? item.operations[0][1] : void 0; 2665 if (operation === OperationType.Upload) { 2666 const settings = select2.getSettings(); 2667 const activeCount = select2.getActiveUploadCount(); 2668 if (activeCount >= settings.maxConcurrentUploads) { 2669 return; 2670 } 2671 } 2672 if (operation === OperationType.ResizeCrop || operation === OperationType.Rotate) { 2673 const settings = select2.getSettings(); 2674 const activeCount = select2.getActiveImageProcessingCount(); 2675 if (activeCount >= settings.maxConcurrentImageProcessing) { 2676 return; 2677 } 2678 } 2679 if (operation === OperationType.TranscodeGif) { 2680 const activeCount = select2.getActiveVideoProcessingCount(); 2681 if (activeCount >= 1) { 2682 return; 2683 } 2684 } 2685 if (attachment) { 2686 const isHeicUrl = attachment.url && /\.hei[cf]$/i.test(attachment.url); 2687 if (!isHeicUrl) { 2688 onChange?.([attachment]); 2689 } 2690 } 2691 if (!operation) { 2692 if (parentId || !parentId && !select2.hasPendingItemsByParentId(id)) { 2693 if (attachment) { 2694 onSuccess?.([attachment]); 2695 } 2696 dispatch.removeItem(id); 2697 dispatch.revokeBlobUrls(id); 2698 if (batchId && select2.isBatchUploaded(batchId)) { 2699 onBatchSuccess?.(); 2700 } 2701 } 2702 if (parentId && batchId && select2.isBatchUploaded(batchId)) { 2703 const parentItem = select2.getItem(parentId); 2704 if (!parentItem) { 2705 return; 2706 } 2707 if (parentItem.operations && parentItem.operations.length > 0) { 2708 dispatch.processItem(parentId); 2709 return; 2710 } 2711 if (attachment) { 2712 parentItem.onSuccess?.([attachment]); 2713 } 2714 dispatch.removeItem(parentId); 2715 dispatch.revokeBlobUrls(parentId); 2716 if (parentItem.batchId && select2.isBatchUploaded(parentItem.batchId)) { 2717 parentItem.onBatchSuccess?.(); 2718 } 2719 } 2720 return; 2721 } 2722 if (operation === OperationType.Finalize && select2.hasPendingItemsByParentId(id)) { 2723 return; 2724 } 2725 dispatch({ 2726 type: Type.OperationStart, 2727 id, 2728 operation 2729 }); 2730 debug( 2731 `Starting operation $operation} for $item.file.name} (item $item.id})` 2732 ); 2733 switch (operation) { 2734 case OperationType.Prepare: 2735 dispatch.prepareItem(item.id); 2736 break; 2737 case OperationType.ResizeCrop: 2738 dispatch.resizeCropItem( 2739 item.id, 2740 operationArgs 2741 ); 2742 break; 2743 case OperationType.Rotate: 2744 dispatch.rotateItem( 2745 item.id, 2746 operationArgs 2747 ); 2748 break; 2749 case OperationType.TranscodeImage: 2750 dispatch.transcodeImageItem( 2751 item.id, 2752 operationArgs 2753 ); 2754 break; 2755 case OperationType.TranscodeGif: 2756 dispatch.transcodeGifItem( 2757 item.id, 2758 operationArgs 2759 ); 2760 break; 2761 case OperationType.Upload: 2762 if (item.parentId) { 2763 dispatch.sideloadItem(id); 2764 } else { 2765 dispatch.uploadItem(id); 2766 } 2767 break; 2768 case OperationType.ThumbnailGeneration: 2769 dispatch.generateThumbnails(id); 2770 break; 2771 case OperationType.Finalize: 2772 dispatch.finalizeItem(id); 2773 break; 2774 case OperationType.DetectUltraHdr: 2775 dispatch.detectUltraHdr(id); 2776 break; 2777 } 2778 }; 2779 } 2780 function pauseQueue() { 2781 return { 2782 type: Type.PauseQueue 2783 }; 2784 } 2785 function resumeQueue() { 2786 return async ({ select: select2, dispatch }) => { 2787 dispatch({ 2788 type: Type.ResumeQueue 2789 }); 2790 for (const item of select2.getAllItems()) { 2791 if (item.status === ItemStatus.PendingRetry) { 2792 dispatch.executeRetry(item.id); 2793 } else { 2794 dispatch.processItem(item.id); 2795 } 2796 } 2797 }; 2798 } 2799 function pauseItem(id) { 2800 return async ({ dispatch }) => { 2801 dispatch({ 2802 type: Type.PauseItem, 2803 id 2804 }); 2805 }; 2806 } 2807 function removeItem(id) { 2808 return async ({ select: select2, dispatch }) => { 2809 const item = select2.getItem(id); 2810 if (!item) { 2811 return; 2812 } 2813 ultraHdrItems.delete(id); 2814 clearRetryTimer(id); 2815 dispatch({ 2816 type: Type.Remove, 2817 id 2818 }); 2819 if (select2.getAllItems().length === 0) { 2820 terminateVipsWorker(); 2821 terminateVideoConversionWorker(); 2822 } 2823 }; 2824 } 2825 function finishOperation(id, updates) { 2826 return async ({ select: select2, dispatch }) => { 2827 const item = select2.getItem(id); 2828 const previousOperation = item?.currentOperation; 2829 dispatch({ 2830 type: Type.OperationFinish, 2831 id, 2832 item: updates 2833 }); 2834 dispatch.processItem(id); 2835 if (previousOperation === OperationType.Upload) { 2836 const pendingUploads = select2.getPendingUploads(); 2837 for (const pendingItem of pendingUploads) { 2838 dispatch.processItem(pendingItem.id); 2839 } 2840 } 2841 if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate) { 2842 const pendingItems = select2.getPendingImageProcessing(); 2843 for (const pendingItem of pendingItems) { 2844 dispatch.processItem(pendingItem.id); 2845 } 2846 } 2847 if (previousOperation === OperationType.TranscodeGif) { 2848 const pendingItems = select2.getPendingVideoProcessing(); 2849 for (const pendingItem of pendingItems) { 2850 dispatch.processItem(pendingItem.id); 2851 } 2852 } 2853 if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate || previousOperation === OperationType.TranscodeImage) { 2854 maybeRecycleVipsWorker(select2.getActiveImageProcessingCount()); 2855 } 2856 }; 2857 } 2858 var VALID_IMAGE_FORMATS = ["jpeg", "webp", "avif", "png", "gif"]; 2859 function isValidImageFormat(format) { 2860 return VALID_IMAGE_FORMATS.includes(format); 2861 } 2862 async function getTranscodeImageOperation(file, outputMimeType, interlaced = false, quality = DEFAULT_OUTPUT_QUALITY) { 2863 if (file.type === "image/png" && outputMimeType === "image/jpeg") { 2864 const blobUrl = (0, import_blob.createBlobURL)(file); 2865 try { 2866 const hasAlpha = await vipsHasTransparency(blobUrl); 2867 if (hasAlpha) { 2868 return null; 2869 } 2870 } catch { 2871 return null; 2872 } finally { 2873 (0, import_blob.revokeBlobURL)(blobUrl); 2874 } 2875 } 2876 const formatPart = outputMimeType.split("/")[1]; 2877 if (!isValidImageFormat(formatPart)) { 2878 return null; 2879 } 2880 return [ 2881 OperationType.TranscodeImage, 2882 { 2883 outputFormat: formatPart, 2884 outputQuality: quality, 2885 interlaced 2886 } 2887 ]; 2888 } 2889 function prepareItem(id) { 2890 return async ({ select: select2, dispatch }) => { 2891 const item = select2.getItem(id); 2892 if (!item) { 2893 return; 2894 } 2895 const { file } = item; 2896 const operations = []; 2897 const settings = select2.getSettings(); 2898 if (file.type === "image/gif" && settings.gifConvert !== false && typeof ImageDecoder !== "undefined" && typeof VideoEncoder !== "undefined") { 2899 let isAnimated = false; 2900 try { 2901 isAnimated = isAnimatedGif(await file.arrayBuffer()); 2902 } catch { 2903 isAnimated = false; 2904 } 2905 if (isAnimated) { 2906 let hasTransparency = false; 2907 const blobUrl = (0, import_blob.createBlobURL)(file); 2908 try { 2909 hasTransparency = await vipsHasTransparency(blobUrl); 2910 } catch { 2911 hasTransparency = true; 2912 } finally { 2913 (0, import_blob.revokeBlobURL)(blobUrl); 2914 } 2915 if (!hasTransparency) { 2916 operations.push( 2917 OperationType.Upload, 2918 OperationType.ThumbnailGeneration, 2919 OperationType.Finalize 2920 ); 2921 dispatch({ 2922 type: Type.AddOperations, 2923 id, 2924 operations 2925 }); 2926 dispatch.finishOperation(id, { 2927 animatedGifFile: item.file 2928 }); 2929 return; 2930 } 2931 } 2932 } 2933 let heicJpeg = null; 2934 const isHeic = await isHeicFile(file); 2935 const isMisnamedHeic = isHeic && !HEIC_MIME_TYPES.includes(file.type); 2936 const isImage = file.type.startsWith("image/") || isHeic; 2937 const isVipsSupported = !isHeic && CLIENT_SIDE_SUPPORTED_MIME_TYPES.includes(file.type); 2938 const heicFile = isMisnamedHeic ? new File([file], `$getFileBasename(file.name)}.heic`, { 2939 type: HEIC_MIME_TYPES[0], 2940 lastModified: file.lastModified 2941 }) : file; 2942 let tooLargeForClient = false; 2943 if (isImage && isVipsSupported) { 2944 const dimensions = await getImageDimensions(file); 2945 if (dimensions && exceedsClientProcessingMemory(dimensions)) { 2946 tooLargeForClient = true; 2947 } 2948 } 2949 if (file.type === "image/jpeg" && !isHeic && !tooLargeForClient) { 2950 operations.push(OperationType.DetectUltraHdr); 2951 } 2952 if (isImage && isVipsSupported && !tooLargeForClient) { 2953 operations.push( 2954 OperationType.Upload, 2955 OperationType.ThumbnailGeneration, 2956 OperationType.Finalize 2957 ); 2958 } else if (isImage && isHeic) { 2959 const encode = isClientSideMediaSupported() ? (canvas, quality) => vipsEncodeCanvasAsJpeg(id, canvas, heicFile, quality) : void 0; 2960 try { 2961 heicJpeg = await canvasConvertToJpeg( 2962 heicFile, 2963 settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY, 2964 encode 2965 ); 2966 } catch (error) { 2967 const unsupported = error instanceof HeicUnsupportedError; 2968 dispatch.cancelItem( 2969 id, 2970 new UploadError({ 2971 code: unsupported ? ErrorCode.HEIC_DECODE_ERROR : ErrorCode.IMAGE_TRANSCODING_ERROR, 2972 message: unsupported ? getHeicUnsupportedMessage() : (0, import_i18n6.__)( 2973 "This HEIC image could not be converted. Try converting it to JPEG before uploading." 2974 ), 2975 file, 2976 cause: error instanceof Error ? error : void 0 2977 }) 2978 ); 2979 return; 2980 } 2981 operations.push( 2982 OperationType.Upload, 2983 OperationType.ThumbnailGeneration, 2984 OperationType.Finalize 2985 ); 2986 } else { 2987 operations.push(OperationType.Upload); 2988 } 2989 dispatch({ 2990 type: Type.AddOperations, 2991 id, 2992 operations 2993 }); 2994 let updates; 2995 if (isHeic && heicJpeg) { 2996 const vipsAvailable = isClientSideMediaSupported(); 2997 updates = { 2998 file: heicJpeg, 2999 sourceFile: heicJpeg, 3000 originalHeicFile: heicFile, 3001 additionalData: { 3002 ...item.additionalData, 3003 generate_sub_sizes: !vipsAvailable, 3004 convert_format: true 3005 } 3006 }; 3007 } else if (!isVipsSupported || !isImage || tooLargeForClient) { 3008 updates = { 3009 additionalData: { 3010 ...item.additionalData, 3011 generate_sub_sizes: true, 3012 convert_format: true 3013 } 3014 }; 3015 } else { 3016 updates = { 3017 additionalData: { 3018 ...item.additionalData, 3019 generate_sub_sizes: false 3020 } 3021 }; 3022 } 3023 dispatch.finishOperation(id, updates); 3024 }; 3025 } 3026 function detectUltraHdr(id) { 3027 return async ({ select: select2, dispatch }) => { 3028 const item = select2.getItem(id); 3029 if (!item) { 3030 return; 3031 } 3032 let info; 3033 try { 3034 const buffer = await item.file.arrayBuffer(); 3035 info = await vipsGetUltraHdrInfo(buffer); 3036 } catch { 3037 } 3038 if (info) { 3039 ultraHdrItems.add(id); 3040 } 3041 dispatch.finishOperation(id, {}); 3042 }; 3043 } 3044 function uploadItem(id) { 3045 return async ({ select: select2, dispatch }) => { 3046 const item = select2.getItem(id); 3047 if (!item) { 3048 return; 3049 } 3050 const startTime = performance.now(); 3051 let finished = false; 3052 const finishUpload = (attachment) => { 3053 if (finished) { 3054 return; 3055 } 3056 finished = true; 3057 measure({ 3058 measureName: `Upload $item.file.name}`, 3059 startTime, 3060 tooltipText: item.file.name, 3061 properties: [ 3062 ["Item ID", item.id], 3063 ["File name", item.file.name] 3064 ] 3065 }); 3066 dispatch.finishOperation(id, { attachment }); 3067 }; 3068 select2.getSettings().mediaUpload({ 3069 filesList: [item.file], 3070 additionalData: item.additionalData, 3071 signal: item.abortController?.signal, 3072 // The queue's own items drive upload progress UI and save 3073 // locking; without this, consumers that track uploads themselves 3074 // (e.g. the editor's progress snackbar) would count this file a 3075 // second time. 3076 isTransportOnly: true, 3077 onFileChange: ([attachment]) => { 3078 if (attachment && !(0, import_blob.isBlobURL)(attachment.url)) { 3079 finishUpload(attachment); 3080 } 3081 }, 3082 onSuccess: ([attachment]) => { 3083 finishUpload(attachment); 3084 }, 3085 onError: (error) => { 3086 dispatch.cancelItem(id, error); 3087 } 3088 }); 3089 }; 3090 } 3091 function sideloadItem(id) { 3092 return async ({ select: select2, dispatch }) => { 3093 const item = select2.getItem(id); 3094 if (!item) { 3095 return; 3096 } 3097 const { post, ...additionalData } = item.additionalData; 3098 const mediaSideload = select2.getSettings().mediaSideload; 3099 if (!mediaSideload) { 3100 dispatch.finishOperation(id, {}); 3101 return; 3102 } 3103 const startTime = performance.now(); 3104 mediaSideload({ 3105 file: item.file, 3106 attachmentId: post, 3107 additionalData, 3108 signal: item.abortController?.signal, 3109 onSuccess: (subSize) => { 3110 measure({ 3111 measureName: `Sideload $item.file.name}`, 3112 startTime, 3113 tooltipText: item.file.name, 3114 properties: [ 3115 ["Item ID", item.id], 3116 ["File name", item.file.name] 3117 ] 3118 }); 3119 if (item.parentId) { 3120 dispatch({ 3121 type: Type.AccumulateSubSize, 3122 id: item.parentId, 3123 subSize 3124 }); 3125 } 3126 dispatch.finishOperation(id, {}); 3127 }, 3128 onError: (error) => { 3129 dispatch.cancelItem(id, error); 3130 } 3131 }); 3132 }; 3133 } 3134 function resizeCropItem(id, args) { 3135 return async ({ select: select2, dispatch }) => { 3136 const item = select2.getItem(id); 3137 if (!item) { 3138 return; 3139 } 3140 if (!args?.resize) { 3141 dispatch.finishOperation(id, { 3142 file: item.file 3143 }); 3144 return; 3145 } 3146 const startTime = performance.now(); 3147 const addSuffix = Boolean(item.parentId); 3148 const scaledSuffix = Boolean(args.isThresholdResize); 3149 const { 3150 imageStripMeta, 3151 imageMaxBitDepth, 3152 generateAnimatedImageSubsizes 3153 } = select2.getSettings(); 3154 try { 3155 const file = await vipsResizeImage( 3156 item.id, 3157 item.file, 3158 args.resize, 3159 { 3160 smartCrop: false, 3161 addSuffix, 3162 signal: item.abortController?.signal, 3163 scaledSuffix, 3164 quality: args.quality, 3165 stripMeta: imageStripMeta, 3166 maxBitdepth: imageMaxBitDepth, 3167 preserveAnimation: false !== generateAnimatedImageSubsizes 3168 } 3169 ); 3170 measure({ 3171 measureName: `ResizeCrop $item.file.name}`, 3172 startTime, 3173 tooltipText: item.file.name, 3174 properties: [ 3175 ["Item ID", item.id], 3176 ["File name", item.file.name] 3177 ] 3178 }); 3179 const blobUrl = (0, import_blob.createBlobURL)(file); 3180 dispatch({ 3181 type: Type.CacheBlobUrl, 3182 id, 3183 blobUrl 3184 }); 3185 dispatch.finishOperation(id, { 3186 file, 3187 attachment: { 3188 url: blobUrl 3189 } 3190 }); 3191 } catch (error) { 3192 dispatch.cancelItem( 3193 id, 3194 new UploadError({ 3195 code: ErrorCode.IMAGE_TRANSCODING_ERROR, 3196 message: (0, import_i18n6.__)( 3197 "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading." 3198 ), 3199 file: item.file, 3200 cause: error instanceof Error ? error : void 0 3201 }) 3202 ); 3203 } 3204 }; 3205 } 3206 function rotateItem(id, args) { 3207 return async ({ select: select2, dispatch }) => { 3208 const item = select2.getItem(id); 3209 if (!item) { 3210 return; 3211 } 3212 if (!args?.orientation || args.orientation === 1) { 3213 dispatch.finishOperation(id, { 3214 file: item.file 3215 }); 3216 return; 3217 } 3218 const startTime = performance.now(); 3219 try { 3220 const file = await vipsRotateImage( 3221 item.id, 3222 item.file, 3223 args.orientation, 3224 item.abortController?.signal 3225 ); 3226 measure({ 3227 measureName: `Rotate $item.file.name}`, 3228 startTime, 3229 tooltipText: item.file.name, 3230 properties: [ 3231 ["Item ID", item.id], 3232 ["File name", item.file.name] 3233 ] 3234 }); 3235 const blobUrl = (0, import_blob.createBlobURL)(file); 3236 dispatch({ 3237 type: Type.CacheBlobUrl, 3238 id, 3239 blobUrl 3240 }); 3241 dispatch.finishOperation(id, { 3242 file, 3243 attachment: { 3244 url: blobUrl 3245 } 3246 }); 3247 } catch (error) { 3248 dispatch.cancelItem( 3249 id, 3250 new UploadError({ 3251 code: ErrorCode.IMAGE_ROTATION_ERROR, 3252 message: (0, import_i18n6.__)( 3253 "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading." 3254 ), 3255 file: item.file, 3256 cause: error instanceof Error ? error : void 0 3257 }) 3258 ); 3259 } 3260 }; 3261 } 3262 function transcodeImageItem(id, args) { 3263 return async ({ select: select2, dispatch }) => { 3264 const item = select2.getItem(id); 3265 if (!item) { 3266 return; 3267 } 3268 if (!args?.outputFormat) { 3269 dispatch.finishOperation(id, { 3270 file: item.file 3271 }); 3272 return; 3273 } 3274 const startTime = performance.now(); 3275 const outputMimeType = `image/$args.outputFormat}`; 3276 const quality = args.outputQuality ?? DEFAULT_OUTPUT_QUALITY; 3277 const interlaced = args.interlaced ?? false; 3278 const { imageStripMeta, imageMaxBitDepth } = select2.getSettings(); 3279 try { 3280 const file = await vipsConvertImageFormat( 3281 item.id, 3282 item.file, 3283 outputMimeType, 3284 { 3285 quality, 3286 interlaced, 3287 stripMeta: imageStripMeta, 3288 maxBitdepth: imageMaxBitDepth 3289 } 3290 ); 3291 measure({ 3292 measureName: `Transcode $item.file.name}`, 3293 startTime, 3294 tooltipText: item.file.name, 3295 properties: [ 3296 ["Item ID", item.id], 3297 ["File name", item.file.name] 3298 ] 3299 }); 3300 const blobUrl = (0, import_blob.createBlobURL)(file); 3301 dispatch({ 3302 type: Type.CacheBlobUrl, 3303 id, 3304 blobUrl 3305 }); 3306 dispatch.finishOperation(id, { 3307 file, 3308 attachment: { 3309 url: blobUrl 3310 } 3311 }); 3312 } catch (error) { 3313 dispatch.cancelItem( 3314 id, 3315 new UploadError({ 3316 code: ErrorCode.MEDIA_TRANSCODING_ERROR, 3317 message: "Image could not be transcoded to the target format", 3318 file: item.file, 3319 cause: error instanceof Error ? error : void 0 3320 }) 3321 ); 3322 } 3323 }; 3324 } 3325 function transcodeGifItem(id, args) { 3326 return async ({ select: select2, dispatch }) => { 3327 const item = select2.getItem(id); 3328 if (!item) { 3329 return; 3330 } 3331 const outputFormat = args?.outputFormat ?? "mp4"; 3332 const outputMimeType = `video/$outputFormat}`; 3333 const gifFile = item.file; 3334 try { 3335 const file = await convertGifToVideo( 3336 item.id, 3337 gifFile, 3338 outputMimeType, 3339 { 3340 timeout: args?.timeout, 3341 maxTotalPixels: args?.maxTotalPixels 3342 } 3343 ); 3344 dispatch.finishOperation(id, { file }); 3345 dispatch.addSideloadItem({ 3346 file: gifFile, 3347 batchId: v4_default(), 3348 parentId: item.parentId, 3349 additionalData: { 3350 post: item.additionalData?.post, 3351 image_size: "animated_video_poster", 3352 convert_format: false 3353 }, 3354 operations: [ 3355 [ 3356 OperationType.TranscodeImage, 3357 { 3358 outputFormat: "jpeg", 3359 outputQuality: DEFAULT_OUTPUT_QUALITY, 3360 interlaced: false 3361 } 3362 ], 3363 OperationType.Upload 3364 ] 3365 }); 3366 } catch (error) { 3367 if (isUnsupportedConversionError(error)) { 3368 if (isSizeLimitConversionError(error)) { 3369 debug( 3370 `Skipping GIF to video conversion: $error instanceof Error ? error.message : error}` 3371 ); 3372 } 3373 dispatch.cancelItem( 3374 id, 3375 new Error("Animated GIF conversion unsupported"), 3376 true 3377 ); 3378 return; 3379 } 3380 if (isConversionTimeoutError(error)) { 3381 debug( 3382 `GIF to video conversion timed out; keeping the original GIF only: $error instanceof Error ? error.message : error}` 3383 ); 3384 dispatch.cancelItem( 3385 id, 3386 new Error("Animated GIF conversion timed out"), 3387 true 3388 ); 3389 return; 3390 } 3391 console.error( 3392 "[video-conversion] GIF to video conversion failed:", 3393 error 3394 ); 3395 dispatch.cancelItem( 3396 id, 3397 new UploadError({ 3398 code: ErrorCode.GIF_TRANSCODING_ERROR, 3399 message: "Animated GIF could not be converted to video", 3400 file: item.file, 3401 cause: error instanceof Error ? error : void 0 3402 }), 3403 true 3404 ); 3405 } 3406 }; 3407 } 3408 function generateThumbnails(id) { 3409 return async ({ select: select2, dispatch }) => { 3410 const item = select2.getItem(id); 3411 if (!item) { 3412 return; 3413 } 3414 if (!item.attachment) { 3415 dispatch.finishOperation(id, {}); 3416 return; 3417 } 3418 const attachment = item.attachment; 3419 const settings = select2.getSettings(); 3420 if (item.originalHeicFile && attachment.id) { 3421 dispatch.addSideloadItem({ 3422 file: item.originalHeicFile, 3423 batchId: v4_default(), 3424 parentId: item.id, 3425 additionalData: { 3426 post: attachment.id, 3427 image_size: "source_original", 3428 convert_format: false 3429 }, 3430 operations: [OperationType.Upload] 3431 }); 3432 } 3433 if (item.animatedGifFile && attachment.id) { 3434 const outputFormat = settings.videoOutputFormat === "video/webm" ? "webm" : "mp4"; 3435 dispatch.addSideloadItem({ 3436 file: item.animatedGifFile, 3437 batchId: v4_default(), 3438 parentId: item.id, 3439 additionalData: { 3440 post: attachment.id, 3441 image_size: "animated_video", 3442 convert_format: false 3443 }, 3444 operations: [ 3445 [ 3446 OperationType.TranscodeGif, 3447 { 3448 outputFormat 3449 } 3450 ], 3451 OperationType.Upload 3452 ] 3453 }); 3454 } 3455 let exifOrientation = attachment.exif_orientation || 1; 3456 const sourceType = item.sourceFile.type; 3457 const isHeifFamily = sourceType === "image/avif" || sourceType === "image/heif"; 3458 let needsClientRotation = false; 3459 if (isHeifFamily) { 3460 exifOrientation = getUnappliedExifOrientation( 3461 await item.sourceFile.arrayBuffer() 3462 ); 3463 needsClientRotation = exifOrientation !== 1; 3464 } 3465 let rotatedSource; 3466 { 3467 const needsRotation = exifOrientation !== 1 && !item.file.name.includes("-scaled"); 3468 if ((needsRotation || needsClientRotation) && attachment.id) { 3469 try { 3470 rotatedSource = await vipsRotateImage( 3471 item.id, 3472 item.sourceFile, 3473 exifOrientation, 3474 item.abortController?.signal 3475 ); 3476 } catch { 3477 console.warn( 3478 "Failed to rotate image, continuing with thumbnails" 3479 ); 3480 } 3481 } 3482 if (needsRotation && rotatedSource && attachment.id) { 3483 dispatch.addSideloadItem({ 3484 file: rotatedSource, 3485 batchId: v4_default(), 3486 parentId: item.id, 3487 additionalData: { 3488 post: attachment.id, 3489 image_size: "original", 3490 convert_format: false 3491 }, 3492 operations: [OperationType.Upload] 3493 }); 3494 } 3495 } 3496 if (!item.parentId && attachment.missing_image_sizes && attachment.missing_image_sizes.length > 0) { 3497 const allImageSizes = settings.allImageSizes || {}; 3498 const sizesToGenerate = attachment.missing_image_sizes; 3499 const thumbnailSource = needsClientRotation && rotatedSource ? rotatedSource : item.sourceFile; 3500 const file = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource; 3501 const batchId = v4_default(); 3502 const isUltraHdr = ultraHdrItems.has(item.id); 3503 const outputMimeType = attachment.image_output_format; 3504 const interlaced = attachment.image_save_progressive ?? false; 3505 const imageQuality = attachment.image_quality; 3506 const fallbackQuality = settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY; 3507 const defaultQuality = typeof imageQuality?.default === "number" ? imageQuality.default / 100 : fallbackQuality; 3508 const qualityForSize = (sizeName) => { 3509 const sized = imageQuality?.sizes?.[sizeName]; 3510 if (typeof sized === "number") { 3511 return sized / 100; 3512 } 3513 return defaultQuality; 3514 }; 3515 let thumbnailTranscodeOperation = null; 3516 if (!isUltraHdr && outputMimeType) { 3517 thumbnailTranscodeOperation = await getTranscodeImageOperation( 3518 thumbnailSource, 3519 outputMimeType, 3520 interlaced, 3521 defaultQuality 3522 ); 3523 } 3524 const dimensionGroups = /* @__PURE__ */ new Map(); 3525 for (const name of sizesToGenerate) { 3526 const imageSize = allImageSizes[name]; 3527 if (!imageSize) { 3528 console.warn( 3529 `Image size "$name}" not found in configuration` 3530 ); 3531 continue; 3532 } 3533 const key = `$imageSize.width}x$imageSize.height}x$imageSize.crop}`; 3534 const group = dimensionGroups.get(key); 3535 if (group) { 3536 group.push(name); 3537 } else { 3538 dimensionGroups.set(key, [name]); 3539 } 3540 } 3541 for (const [, names] of dimensionGroups) { 3542 const imageSize = allImageSizes[names[0]]; 3543 const sizeQuality = qualityForSize(names[0]); 3544 const thumbnailOperations = [ 3545 [ 3546 OperationType.ResizeCrop, 3547 { resize: imageSize, quality: sizeQuality } 3548 ] 3549 ]; 3550 if (!isUltraHdr && thumbnailTranscodeOperation) { 3551 thumbnailOperations.push([ 3552 thumbnailTranscodeOperation[0], 3553 { 3554 ...thumbnailTranscodeOperation[1], 3555 outputQuality: sizeQuality 3556 } 3557 ]); 3558 } 3559 thumbnailOperations.push(OperationType.Upload); 3560 const imageSizeParam = names.length === 1 ? names[0] : names; 3561 dispatch.addSideloadItem({ 3562 file, 3563 batchId, 3564 parentId: item.id, 3565 additionalData: { 3566 // Sideloading does not use the parent post ID but the 3567 // attachment ID as the image sizes need to be added to it. 3568 post: attachment.id, 3569 image_size: imageSizeParam, 3570 convert_format: false 3571 }, 3572 operations: thumbnailOperations 3573 }); 3574 } 3575 { 3576 const { bigImageSizeThreshold } = settings; 3577 if (bigImageSizeThreshold && attachment.id) { 3578 const bitmap = await createImageBitmap(thumbnailSource); 3579 const needsScaling = bitmap.width > bigImageSizeThreshold || bitmap.height > bigImageSizeThreshold; 3580 bitmap.close(); 3581 if (needsScaling) { 3582 const sourceForScaled = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource; 3583 const scaledOperations = [ 3584 [ 3585 OperationType.ResizeCrop, 3586 { 3587 resize: { 3588 width: bigImageSizeThreshold, 3589 height: bigImageSizeThreshold 3590 }, 3591 isThresholdResize: true, 3592 quality: defaultQuality 3593 } 3594 ] 3595 ]; 3596 if (!isUltraHdr && thumbnailTranscodeOperation) { 3597 scaledOperations.push( 3598 thumbnailTranscodeOperation 3599 ); 3600 } 3601 scaledOperations.push(OperationType.Upload); 3602 dispatch.addSideloadItem({ 3603 file: sourceForScaled, 3604 batchId, 3605 parentId: item.id, 3606 additionalData: { 3607 post: attachment.id, 3608 image_size: "scaled", 3609 convert_format: false 3610 }, 3611 operations: scaledOperations 3612 }); 3613 } 3614 } 3615 } 3616 } 3617 dispatch.finishOperation(id, {}); 3618 }; 3619 } 3620 function finalizeItem(id) { 3621 return async ({ select: select2, dispatch }) => { 3622 const item = select2.getItem(id); 3623 if (!item) { 3624 return; 3625 } 3626 const attachment = item.attachment; 3627 const { mediaFinalize } = select2.getSettings(); 3628 const updates = {}; 3629 if (attachment?.id && mediaFinalize) { 3630 try { 3631 const updatedAttachment = await mediaFinalize( 3632 attachment.id, 3633 item.subSizes || [] 3634 ); 3635 if (updatedAttachment) { 3636 updates.attachment = updatedAttachment; 3637 } 3638 } catch (error) { 3639 console.warn("Media finalization failed:", error); 3640 dispatch.cancelItem( 3641 id, 3642 new UploadError({ 3643 code: ErrorCode.MEDIA_FINALIZE_ERROR, 3644 message: (0, import_i18n6.__)("Could not finalize the upload."), 3645 file: item.file 3646 }) 3647 ); 3648 return; 3649 } 3650 } 3651 dispatch.finishOperation(id, updates); 3652 }; 3653 } 3654 function revokeBlobUrls(id) { 3655 return async ({ select: select2, dispatch }) => { 3656 const blobUrls = select2.getBlobUrls(id); 3657 for (const blobUrl of blobUrls) { 3658 (0, import_blob.revokeBlobURL)(blobUrl); 3659 } 3660 dispatch({ 3661 type: Type.RevokeBlobUrls, 3662 id 3663 }); 3664 }; 3665 } 3666 function updateItemProgress(id, progress) { 3667 return async ({ dispatch }) => { 3668 dispatch({ 3669 type: Type.UpdateProgress, 3670 id, 3671 progress 3672 }); 3673 }; 3674 } 3675 function updateSettings(settings) { 3676 return { 3677 type: Type.UpdateSettings, 3678 settings 3679 }; 3680 } 3681 3682 // packages/upload-media/build-module/lock-unlock.mjs 3683 var import_private_apis = __toESM(require_private_apis(), 1); 3684 var { lock, unlock } = (0, import_private_apis.__dangerousOptInToUnstableAPIsOnlyForCoreModules)( 3685 "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.", 3686 "@wordpress/upload-media" 3687 ); 3688 3689 // packages/upload-media/build-module/store/index.mjs 3690 var storeConfig = { 3691 reducer: reducer_default, 3692 selectors: selectors_exports, 3693 actions: actions_exports 3694 }; 3695 var store = (0, import_data.createReduxStore)(STORE_NAME, { 3696 reducer: reducer_default, 3697 selectors: selectors_exports, 3698 actions: actions_exports 3699 }); 3700 if (!(0, import_data.select)(store)) { 3701 (0, import_data.register)(store); 3702 } 3703 unlock(store).registerPrivateActions(private_actions_exports); 3704 unlock(store).registerPrivateSelectors(private_selectors_exports); 3705 3706 // packages/upload-media/build-module/components/provider/index.mjs 3707 var import_element2 = __toESM(require_element(), 1); 3708 var import_data3 = __toESM(require_data(), 1); 3709 3710 // packages/upload-media/build-module/components/provider/with-registry-provider.mjs 3711 var import_element = __toESM(require_element(), 1); 3712 var import_data2 = __toESM(require_data(), 1); 3713 var import_compose = __toESM(require_compose(), 1); 3714 var import_jsx_runtime = __toESM(require_jsx_runtime(), 1); 3715 function getSubRegistry(subRegistries, registry, useSubRegistry) { 3716 if (!useSubRegistry) { 3717 return registry; 3718 } 3719 let subRegistry = subRegistries.get(registry); 3720 if (!subRegistry) { 3721 subRegistry = (0, import_data2.createRegistry)({}, registry); 3722 subRegistry.registerStore(STORE_NAME, storeConfig); 3723 subRegistries.set(registry, subRegistry); 3724 } 3725 return subRegistry; 3726 } 3727 var withRegistryProvider = (0, import_compose.createHigherOrderComponent)( 3728 (WrappedComponent) => ({ useSubRegistry = true, ...props }) => { 3729 const registry = (0, import_data2.useRegistry)(); 3730 const [subRegistries] = (0, import_element.useState)(() => /* @__PURE__ */ new WeakMap()); 3731 const subRegistry = getSubRegistry( 3732 subRegistries, 3733 registry, 3734 useSubRegistry 3735 ); 3736 if (subRegistry === registry) { 3737 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { registry, ...props }); 3738 } 3739 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_data2.RegistryProvider, { value: subRegistry, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { registry: subRegistry, ...props }) }); 3740 }, 3741 "withRegistryProvider" 3742 ); 3743 var with_registry_provider_default = withRegistryProvider; 3744 3745 // packages/upload-media/build-module/components/provider/index.mjs 3746 var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1); 3747 var MediaUploadProvider = with_registry_provider_default((props) => { 3748 const { children, settings } = props; 3749 const { updateSettings: updateSettings2 } = unlock((0, import_data3.useDispatch)(store)); 3750 (0, import_element2.useEffect)(() => { 3751 updateSettings2(settings); 3752 }, [settings, updateSettings2]); 3753 return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }); 3754 }); 3755 var provider_default = MediaUploadProvider; 3756 3757 // packages/upload-media/build-module/error-messages.mjs 3758 var import_i18n7 = __toESM(require_i18n(), 1); 3759 function getErrorMessage(code, fileName) { 3760 const messages = { 3761 [ErrorCode.EMPTY_FILE]: { 3762 title: (0, import_i18n7.__)("Empty file"), 3763 description: (0, import_i18n7.sprintf)( 3764 /* translators: %s: file name */ 3765 (0, import_i18n7.__)('"%s" is empty.'), 3766 fileName 3767 ), 3768 action: (0, import_i18n7.__)("Please choose a different file.") 3769 }, 3770 [ErrorCode.SIZE_ABOVE_LIMIT]: { 3771 title: (0, import_i18n7.__)("File too large"), 3772 description: (0, import_i18n7.sprintf)( 3773 /* translators: %s: file name */ 3774 (0, import_i18n7.__)('"%s" exceeds the maximum upload size.'), 3775 fileName 3776 ), 3777 action: (0, import_i18n7.__)("Please reduce the file size and try again.") 3778 }, 3779 [ErrorCode.MIME_TYPE_NOT_SUPPORTED]: { 3780 title: (0, import_i18n7.__)("Unsupported file type"), 3781 description: (0, import_i18n7.sprintf)( 3782 /* translators: %s: file name */ 3783 (0, import_i18n7.__)('"%s" is not a supported file type.'), 3784 fileName 3785 ), 3786 action: (0, import_i18n7.__)("Please upload a different file format.") 3787 }, 3788 [ErrorCode.MIME_TYPE_NOT_ALLOWED_FOR_USER]: { 3789 title: (0, import_i18n7.__)("File type not allowed"), 3790 description: (0, import_i18n7.sprintf)( 3791 /* translators: %s: file name */ 3792 (0, import_i18n7.__)('You are not allowed to upload "%s".'), 3793 fileName 3794 ), 3795 action: (0, import_i18n7.__)("Please contact your site administrator.") 3796 }, 3797 [ErrorCode.HEIC_DECODE_ERROR]: { 3798 title: (0, import_i18n7.__)("HEIC decode failed"), 3799 description: (0, import_i18n7.sprintf)( 3800 /* translators: %s: file name */ 3801 (0, import_i18n7.__)('Failed to decode HEIC file "%s".'), 3802 fileName 3803 ), 3804 action: getHeicConversionAdvice() 3805 }, 3806 [ErrorCode.IMAGE_TRANSCODING_ERROR]: { 3807 title: (0, import_i18n7.__)("Image processing failed"), 3808 description: (0, import_i18n7.sprintf)( 3809 /* translators: %s: file name */ 3810 (0, import_i18n7.__)('Failed to process "%s".'), 3811 fileName 3812 ), 3813 action: (0, import_i18n7.__)("The image may be corrupted. Try a different file.") 3814 }, 3815 [ErrorCode.IMAGE_ROTATION_ERROR]: { 3816 title: (0, import_i18n7.__)("Image rotation failed"), 3817 description: (0, import_i18n7.sprintf)( 3818 /* translators: %s: file name */ 3819 (0, import_i18n7.__)('Failed to rotate "%s".'), 3820 fileName 3821 ), 3822 action: (0, import_i18n7.__)("The image may be corrupted. Try a different file.") 3823 }, 3824 [ErrorCode.MEDIA_TRANSCODING_ERROR]: { 3825 title: (0, import_i18n7.__)("Media processing failed"), 3826 description: (0, import_i18n7.sprintf)( 3827 /* translators: %s: file name */ 3828 (0, import_i18n7.__)('Failed to convert "%s" to the target format.'), 3829 fileName 3830 ), 3831 action: (0, import_i18n7.__)("The file may be corrupted. Try a different file.") 3832 }, 3833 [ErrorCode.MEDIA_FINALIZE_ERROR]: { 3834 title: (0, import_i18n7.__)("Upload failed"), 3835 description: (0, import_i18n7.sprintf)( 3836 /* translators: %s: file name */ 3837 (0, import_i18n7.__)('Could not finalize the upload of "%s".'), 3838 fileName 3839 ), 3840 action: (0, import_i18n7.__)("Please try again.") 3841 }, 3842 [ErrorCode.GENERAL]: { 3843 title: (0, import_i18n7.__)("Upload failed"), 3844 description: (0, import_i18n7.sprintf)( 3845 /* translators: %s: file name */ 3846 (0, import_i18n7.__)('Failed to upload "%s".'), 3847 fileName 3848 ), 3849 action: (0, import_i18n7.__)("Please try again.") 3850 } 3851 }; 3852 return messages[code] || { 3853 title: (0, import_i18n7.__)("Upload failed"), 3854 description: (0, import_i18n7.sprintf)( 3855 /* translators: %s: file name */ 3856 (0, import_i18n7.__)('Failed to upload "%s".'), 3857 fileName 3858 ), 3859 action: (0, import_i18n7.__)("Please try again.") 3860 }; 3861 } 3862 return __toCommonJS(index_exports); 3863 })(); 3864 (window.wp ||= {}).uploadMedia = wp.uploadMedia; 3865 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sun Nov 1 08:20:35 2026 | Cross-referenced by PHPXref |