@gallop.software/studio 0.1.71 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-3RI33B7A.mjs +27 -0
- package/dist/chunk-3RI33B7A.mjs.map +1 -0
- package/dist/chunk-CN5NRNWB.js +27 -0
- package/dist/chunk-CN5NRNWB.js.map +1 -0
- package/dist/handlers.d.mts +1 -1
- package/dist/handlers.d.ts +1 -1
- package/dist/handlers.js +146 -292
- package/dist/handlers.js.map +1 -1
- package/dist/handlers.mjs +135 -281
- package/dist/handlers.mjs.map +1 -1
- package/dist/index.d.mts +2 -25
- package/dist/index.d.ts +2 -25
- package/dist/index.js +6 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -36
- package/dist/index.mjs.map +1 -1
- package/dist/types-C9CMIJLW.d.mts +57 -0
- package/dist/types-C9CMIJLW.d.ts +57 -0
- package/package.json +1 -1
- package/dist/types-1m_7EjJU.d.mts +0 -79
- package/dist/types-1m_7EjJU.d.ts +0 -79
package/dist/handlers.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
+
|
|
3
|
+
var _chunkCN5NRNWBjs = require('./chunk-CN5NRNWB.js');
|
|
4
|
+
|
|
5
|
+
// src/handlers.ts
|
|
2
6
|
var _server = require('next/server');
|
|
3
7
|
var _fs = require('fs');
|
|
4
8
|
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
@@ -252,9 +256,9 @@ async function handleScan() {
|
|
|
252
256
|
const validFiles = [];
|
|
253
257
|
const imagesDir = _path2.default.join(process.cwd(), "public", "images");
|
|
254
258
|
const trackedPaths = /* @__PURE__ */ new Set();
|
|
255
|
-
for (const
|
|
256
|
-
for (const
|
|
257
|
-
trackedPaths.add(
|
|
259
|
+
for (const imageKey of Object.keys(meta)) {
|
|
260
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
261
|
+
trackedPaths.add(thumbPath);
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
async function scanDir(dir, relativePath = "") {
|
|
@@ -279,20 +283,20 @@ async function handleScan() {
|
|
|
279
283
|
}
|
|
280
284
|
}
|
|
281
285
|
await scanDir(imagesDir);
|
|
282
|
-
for (const [
|
|
283
|
-
|
|
284
|
-
|
|
286
|
+
for (const [imageKey, entry] of Object.entries(meta)) {
|
|
287
|
+
if (entry.s) continue;
|
|
288
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
289
|
+
const filePath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
285
290
|
try {
|
|
286
291
|
await _fs.promises.access(filePath);
|
|
287
292
|
} catch (e8) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
293
|
+
missingFiles.push(`${imageKey}: ${thumbPath}`);
|
|
294
|
+
break;
|
|
291
295
|
}
|
|
292
296
|
}
|
|
293
297
|
}
|
|
294
298
|
return _server.NextResponse.json({
|
|
295
|
-
totalInMeta: Object.keys(meta
|
|
299
|
+
totalInMeta: Object.keys(meta).length,
|
|
296
300
|
validFiles: validFiles.length,
|
|
297
301
|
untrackedFiles,
|
|
298
302
|
missingFiles
|
|
@@ -319,9 +323,6 @@ async function handleUpload(request) {
|
|
|
319
323
|
const isSvg = ext === ".svg";
|
|
320
324
|
const isProcessableImage = isImage && !isSvg;
|
|
321
325
|
const meta = await loadMeta();
|
|
322
|
-
if (!meta.images) {
|
|
323
|
-
meta.images = {};
|
|
324
|
-
}
|
|
325
326
|
let relativeDir = "";
|
|
326
327
|
if (targetPath === "public") {
|
|
327
328
|
relativeDir = "";
|
|
@@ -344,10 +345,10 @@ async function handleUpload(request) {
|
|
|
344
345
|
path: `public/${relativeDir ? relativeDir + "/" : ""}${fileName}`
|
|
345
346
|
});
|
|
346
347
|
}
|
|
347
|
-
const
|
|
348
|
-
if (meta
|
|
348
|
+
const imageKey = "/" + (relativeDir ? `${relativeDir}/${fileName}` : fileName);
|
|
349
|
+
if (meta[imageKey]) {
|
|
349
350
|
return _server.NextResponse.json(
|
|
350
|
-
{ error: `File '${
|
|
351
|
+
{ error: `File '${imageKey}' already exists in meta` },
|
|
351
352
|
{ status: 409 }
|
|
352
353
|
);
|
|
353
354
|
}
|
|
@@ -356,21 +357,10 @@ async function handleUpload(request) {
|
|
|
356
357
|
let originalWidth = 0;
|
|
357
358
|
let originalHeight = 0;
|
|
358
359
|
let blurhash = "";
|
|
359
|
-
let dominantColor = "#888888";
|
|
360
|
-
const sizes = {
|
|
361
|
-
full: { path: "", width: 0, height: 0 },
|
|
362
|
-
large: { path: "", width: 0, height: 0 },
|
|
363
|
-
medium: { path: "", width: 0, height: 0 },
|
|
364
|
-
small: { path: "", width: 0, height: 0 }
|
|
365
|
-
};
|
|
366
360
|
const originalPath = `/${relativeDir ? relativeDir + "/" : ""}${fileName}`;
|
|
367
361
|
if (isSvg) {
|
|
368
362
|
const fullPath = _path2.default.join(imagesPath, fileName);
|
|
369
363
|
await _fs.promises.writeFile(fullPath, buffer);
|
|
370
|
-
sizes.full = { path: `/images/${relativeDir ? relativeDir + "/" : ""}${fileName}`, width: 0, height: 0 };
|
|
371
|
-
sizes.large = { ...sizes.full };
|
|
372
|
-
sizes.medium = { ...sizes.full };
|
|
373
|
-
sizes.small = { ...sizes.full };
|
|
374
364
|
} else if (isProcessableImage) {
|
|
375
365
|
const sharpInstance = _sharp2.default.call(void 0, buffer);
|
|
376
366
|
const metadata = await sharpInstance.metadata();
|
|
@@ -384,11 +374,9 @@ async function handleUpload(request) {
|
|
|
384
374
|
} else {
|
|
385
375
|
await _sharp2.default.call(void 0, buffer).jpeg({ quality: 85 }).toFile(fullPath);
|
|
386
376
|
}
|
|
387
|
-
|
|
388
|
-
for (const [sizeName, sizeConfig] of Object.entries(DEFAULT_SIZES)) {
|
|
377
|
+
for (const [, sizeConfig] of Object.entries(DEFAULT_SIZES)) {
|
|
389
378
|
const { width: maxWidth, suffix } = sizeConfig;
|
|
390
379
|
if (originalWidth <= maxWidth) {
|
|
391
|
-
sizes[sizeName] = { ...sizes.full };
|
|
392
380
|
continue;
|
|
393
381
|
}
|
|
394
382
|
const ratio = originalHeight / originalWidth;
|
|
@@ -400,32 +388,18 @@ async function handleUpload(request) {
|
|
|
400
388
|
} else {
|
|
401
389
|
await _sharp2.default.call(void 0, buffer).resize(maxWidth, newHeight).jpeg({ quality: 80 }).toFile(sizePath);
|
|
402
390
|
}
|
|
403
|
-
sizes[sizeName] = {
|
|
404
|
-
path: `/images/${relativeDir ? relativeDir + "/" : ""}${sizeFileName}`,
|
|
405
|
-
width: maxWidth,
|
|
406
|
-
height: newHeight
|
|
407
|
-
};
|
|
408
391
|
}
|
|
409
392
|
const { data, info } = await _sharp2.default.call(void 0, buffer).resize(32, 32, { fit: "inside" }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
410
393
|
blurhash = _blurhash.encode.call(void 0, new Uint8ClampedArray(data), info.width, info.height, 4, 4);
|
|
411
|
-
const { dominant } = await _sharp2.default.call(void 0, buffer).stats();
|
|
412
|
-
dominantColor = `#${dominant.r.toString(16).padStart(2, "0")}${dominant.g.toString(16).padStart(2, "0")}${dominant.b.toString(16).padStart(2, "0")}`;
|
|
413
394
|
}
|
|
414
395
|
const entry = {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
height: originalHeight,
|
|
419
|
-
fileSize: buffer.length
|
|
420
|
-
},
|
|
421
|
-
sizes,
|
|
422
|
-
blurhash,
|
|
423
|
-
dominantColor,
|
|
424
|
-
cdn: null
|
|
396
|
+
w: originalWidth,
|
|
397
|
+
h: originalHeight,
|
|
398
|
+
blur: blurhash
|
|
425
399
|
};
|
|
426
|
-
meta
|
|
400
|
+
meta[originalPath] = entry;
|
|
427
401
|
await saveMeta(meta);
|
|
428
|
-
return _server.NextResponse.json({ success: true, imageKey:
|
|
402
|
+
return _server.NextResponse.json({ success: true, imageKey: originalPath, entry });
|
|
429
403
|
} catch (error) {
|
|
430
404
|
console.error("Failed to upload:", error);
|
|
431
405
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -451,27 +425,26 @@ async function handleDelete(request) {
|
|
|
451
425
|
const stats = await _fs.promises.stat(absolutePath);
|
|
452
426
|
if (stats.isDirectory()) {
|
|
453
427
|
await _fs.promises.rm(absolutePath, { recursive: true });
|
|
454
|
-
const prefix = itemPath.replace(/^public\/images\/?/, "").replace(/^public\/?/, "");
|
|
455
|
-
for (const key of Object.keys(meta
|
|
428
|
+
const prefix = "/" + itemPath.replace(/^public\/images\/?/, "").replace(/^public\/?/, "");
|
|
429
|
+
for (const key of Object.keys(meta)) {
|
|
456
430
|
if (key.startsWith(prefix)) {
|
|
457
|
-
delete meta
|
|
431
|
+
delete meta[key];
|
|
458
432
|
}
|
|
459
433
|
}
|
|
460
434
|
} else {
|
|
461
435
|
await _fs.promises.unlink(absolutePath);
|
|
462
436
|
const isInImagesFolder = itemPath.startsWith("public/images/");
|
|
463
437
|
if (!isInImagesFolder) {
|
|
464
|
-
const imageKey = itemPath.replace(/^public\//, "");
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const sizePath = _path2.default.join(process.cwd(), "public", sizeData.path);
|
|
438
|
+
const imageKey = "/" + itemPath.replace(/^public\//, "");
|
|
439
|
+
if (meta[imageKey]) {
|
|
440
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
441
|
+
const absoluteThumbPath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
469
442
|
try {
|
|
470
|
-
await _fs.promises.unlink(
|
|
443
|
+
await _fs.promises.unlink(absoluteThumbPath);
|
|
471
444
|
} catch (e9) {
|
|
472
445
|
}
|
|
473
446
|
}
|
|
474
|
-
delete meta
|
|
447
|
+
delete meta[imageKey];
|
|
475
448
|
}
|
|
476
449
|
}
|
|
477
450
|
}
|
|
@@ -518,38 +491,37 @@ async function handleSync(request) {
|
|
|
518
491
|
const synced = [];
|
|
519
492
|
const errors = [];
|
|
520
493
|
for (const imageKey of imageKeys) {
|
|
521
|
-
const entry = meta
|
|
494
|
+
const entry = meta[imageKey];
|
|
522
495
|
if (!entry) {
|
|
523
496
|
errors.push(`Image not found in meta: ${imageKey}`);
|
|
524
497
|
continue;
|
|
525
498
|
}
|
|
526
|
-
if (
|
|
499
|
+
if (entry.s) {
|
|
527
500
|
synced.push(imageKey);
|
|
528
501
|
continue;
|
|
529
502
|
}
|
|
530
503
|
try {
|
|
531
|
-
for (const
|
|
532
|
-
const localPath = _path2.default.join(process.cwd(), "public",
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
504
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
505
|
+
const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
506
|
+
try {
|
|
507
|
+
const fileBuffer = await _fs.promises.readFile(localPath);
|
|
508
|
+
await r2.send(
|
|
509
|
+
new (0, _clients3.PutObjectCommand)({
|
|
510
|
+
Bucket: bucketName,
|
|
511
|
+
Key: thumbPath.replace(/^\//, ""),
|
|
512
|
+
Body: fileBuffer,
|
|
513
|
+
ContentType: getContentType(thumbPath)
|
|
514
|
+
})
|
|
515
|
+
);
|
|
516
|
+
} catch (e10) {
|
|
517
|
+
}
|
|
542
518
|
}
|
|
543
|
-
entry.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
syncedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
547
|
-
};
|
|
548
|
-
for (const sizeData of Object.values(entry.sizes)) {
|
|
549
|
-
const localPath = _path2.default.join(process.cwd(), "public", sizeData.path);
|
|
519
|
+
entry.s = 1;
|
|
520
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
521
|
+
const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
550
522
|
try {
|
|
551
523
|
await _fs.promises.unlink(localPath);
|
|
552
|
-
} catch (
|
|
524
|
+
} catch (e11) {
|
|
553
525
|
}
|
|
554
526
|
}
|
|
555
527
|
synced.push(imageKey);
|
|
@@ -581,54 +553,24 @@ async function handleReprocess(request) {
|
|
|
581
553
|
for (const imageKey of imageKeys) {
|
|
582
554
|
try {
|
|
583
555
|
let buffer;
|
|
584
|
-
|
|
556
|
+
const entry = meta[imageKey];
|
|
585
557
|
const originalPath = _path2.default.join(process.cwd(), "public", imageKey);
|
|
586
558
|
try {
|
|
587
559
|
buffer = await _fs.promises.readFile(originalPath);
|
|
588
|
-
} catch (
|
|
589
|
-
if (entry) {
|
|
590
|
-
|
|
591
|
-
try {
|
|
592
|
-
buffer = await _fs.promises.readFile(entryOriginalPath);
|
|
593
|
-
} catch (e12) {
|
|
594
|
-
if (_optionalChain([entry, 'access', _9 => _9.cdn, 'optionalAccess', _10 => _10.synced])) {
|
|
595
|
-
buffer = await downloadFromCdn(entry.original.path);
|
|
596
|
-
} else {
|
|
597
|
-
throw new Error("Original not found locally and not on CDN");
|
|
598
|
-
}
|
|
599
|
-
}
|
|
560
|
+
} catch (e12) {
|
|
561
|
+
if (_optionalChain([entry, 'optionalAccess', _5 => _5.s])) {
|
|
562
|
+
buffer = await downloadFromCdn(imageKey);
|
|
600
563
|
} else {
|
|
601
564
|
throw new Error(`File not found: ${imageKey}`);
|
|
602
565
|
}
|
|
603
566
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
original: {
|
|
610
|
-
path: imageKey,
|
|
611
|
-
width: metadata.width || 0,
|
|
612
|
-
height: metadata.height || 0,
|
|
613
|
-
fileSize: stats.size
|
|
614
|
-
},
|
|
615
|
-
sizes: {
|
|
616
|
-
full: { path: "", width: 0, height: 0 },
|
|
617
|
-
large: { path: "", width: 0, height: 0 },
|
|
618
|
-
medium: { path: "", width: 0, height: 0 },
|
|
619
|
-
small: { path: "", width: 0, height: 0 }
|
|
620
|
-
},
|
|
621
|
-
blurhash: "",
|
|
622
|
-
dominantColor: "#000000",
|
|
623
|
-
cdn: null
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
const updatedEntry = await processImage(buffer, entry, imageKey);
|
|
627
|
-
meta.images[imageKey] = updatedEntry;
|
|
628
|
-
if (_optionalChain([entry, 'access', _11 => _11.cdn, 'optionalAccess', _12 => _12.synced])) {
|
|
629
|
-
await uploadToCdn(updatedEntry);
|
|
630
|
-
await deleteLocalFiles(updatedEntry);
|
|
567
|
+
const updatedEntry = await processImage(buffer, imageKey);
|
|
568
|
+
if (_optionalChain([entry, 'optionalAccess', _6 => _6.s])) {
|
|
569
|
+
updatedEntry.s = 1;
|
|
570
|
+
await uploadToCdn(imageKey);
|
|
571
|
+
await deleteLocalThumbnails(imageKey);
|
|
631
572
|
}
|
|
573
|
+
meta[imageKey] = updatedEntry;
|
|
632
574
|
processed.push(imageKey);
|
|
633
575
|
} catch (error) {
|
|
634
576
|
console.error(`Failed to reprocess ${imageKey}:`, error);
|
|
@@ -755,6 +697,7 @@ async function handleProcessAllStream() {
|
|
|
755
697
|
sendEvent({ type: "start", total });
|
|
756
698
|
for (let i = 0; i < allImages.length; i++) {
|
|
757
699
|
const { key, fullPath } = allImages[i];
|
|
700
|
+
const imageKey = "/" + key;
|
|
758
701
|
sendEvent({
|
|
759
702
|
type: "progress",
|
|
760
703
|
current: i + 1,
|
|
@@ -773,45 +716,18 @@ async function handleProcessAllStream() {
|
|
|
773
716
|
const fileName = _path2.default.basename(key);
|
|
774
717
|
const destPath = _path2.default.join(imagesPath, fileName);
|
|
775
718
|
await _fs.promises.writeFile(destPath, buffer);
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
width: 0,
|
|
781
|
-
height: 0,
|
|
782
|
-
fileSize: buffer.length
|
|
783
|
-
},
|
|
784
|
-
sizes: {
|
|
785
|
-
full: { path: sizePath, width: 0, height: 0 },
|
|
786
|
-
large: { path: sizePath, width: 0, height: 0 },
|
|
787
|
-
medium: { path: sizePath, width: 0, height: 0 },
|
|
788
|
-
small: { path: sizePath, width: 0, height: 0 }
|
|
789
|
-
},
|
|
790
|
-
blurhash: "",
|
|
791
|
-
dominantColor: "#888888",
|
|
792
|
-
cdn: null
|
|
719
|
+
meta[imageKey] = {
|
|
720
|
+
w: 0,
|
|
721
|
+
h: 0,
|
|
722
|
+
blur: ""
|
|
793
723
|
};
|
|
794
724
|
} else {
|
|
795
|
-
const existingEntry = meta
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
fileSize: buffer.length
|
|
802
|
-
},
|
|
803
|
-
sizes: {
|
|
804
|
-
full: { path: "", width: 0, height: 0 },
|
|
805
|
-
large: { path: "", width: 0, height: 0 },
|
|
806
|
-
medium: { path: "", width: 0, height: 0 },
|
|
807
|
-
small: { path: "", width: 0, height: 0 }
|
|
808
|
-
},
|
|
809
|
-
blurhash: "",
|
|
810
|
-
dominantColor: "#888888",
|
|
811
|
-
cdn: null
|
|
812
|
-
};
|
|
813
|
-
const processedEntry = await processImage(buffer, baseEntry, key);
|
|
814
|
-
meta.images[key] = processedEntry;
|
|
725
|
+
const existingEntry = meta[imageKey];
|
|
726
|
+
const processedEntry = await processImage(buffer, imageKey);
|
|
727
|
+
if (_optionalChain([existingEntry, 'optionalAccess', _7 => _7.s])) {
|
|
728
|
+
processedEntry.s = 1;
|
|
729
|
+
}
|
|
730
|
+
meta[imageKey] = processedEntry;
|
|
815
731
|
}
|
|
816
732
|
processed.push(key);
|
|
817
733
|
} catch (error) {
|
|
@@ -821,9 +737,9 @@ async function handleProcessAllStream() {
|
|
|
821
737
|
}
|
|
822
738
|
sendEvent({ type: "cleanup", message: "Removing orphaned thumbnails..." });
|
|
823
739
|
const trackedPaths = /* @__PURE__ */ new Set();
|
|
824
|
-
for (const
|
|
825
|
-
for (const
|
|
826
|
-
trackedPaths.add(
|
|
740
|
+
for (const imageKey of Object.keys(meta)) {
|
|
741
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
742
|
+
trackedPaths.add(thumbPath);
|
|
827
743
|
}
|
|
828
744
|
}
|
|
829
745
|
async function findOrphans(dir, relativePath = "") {
|
|
@@ -900,42 +816,16 @@ async function loadMeta() {
|
|
|
900
816
|
const metaPath = _path2.default.join(process.cwd(), "_data", "_meta.json");
|
|
901
817
|
try {
|
|
902
818
|
const content = await _fs.promises.readFile(metaPath, "utf-8");
|
|
903
|
-
|
|
904
|
-
if (parsed.images && typeof parsed.images === "object") {
|
|
905
|
-
return parsed;
|
|
906
|
-
}
|
|
907
|
-
return {
|
|
908
|
-
$schema: "https://gallop.software/schemas/studio-meta.json",
|
|
909
|
-
version: 1,
|
|
910
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
911
|
-
images: {}
|
|
912
|
-
};
|
|
819
|
+
return JSON.parse(content);
|
|
913
820
|
} catch (e18) {
|
|
914
|
-
return {
|
|
915
|
-
$schema: "https://gallop.software/schemas/studio-meta.json",
|
|
916
|
-
version: 1,
|
|
917
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
918
|
-
images: {}
|
|
919
|
-
};
|
|
821
|
+
return {};
|
|
920
822
|
}
|
|
921
823
|
}
|
|
922
824
|
async function saveMeta(meta) {
|
|
923
825
|
const dataDir = _path2.default.join(process.cwd(), "_data");
|
|
924
826
|
await _fs.promises.mkdir(dataDir, { recursive: true });
|
|
925
|
-
const lean = {};
|
|
926
|
-
for (const [key, entry] of Object.entries(meta.images)) {
|
|
927
|
-
const imagePath = _optionalChain([entry, 'access', _13 => _13.original, 'optionalAccess', _14 => _14.path]) || `/${key}`;
|
|
928
|
-
lean[imagePath] = {
|
|
929
|
-
w: _optionalChain([entry, 'access', _15 => _15.original, 'optionalAccess', _16 => _16.width]) || 0,
|
|
930
|
-
h: _optionalChain([entry, 'access', _17 => _17.original, 'optionalAccess', _18 => _18.height]) || 0,
|
|
931
|
-
blur: entry.blurhash || ""
|
|
932
|
-
};
|
|
933
|
-
if (_optionalChain([entry, 'access', _19 => _19.cdn, 'optionalAccess', _20 => _20.synced])) {
|
|
934
|
-
lean[imagePath].s = 1;
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
827
|
const metaPath = _path2.default.join(dataDir, "_meta.json");
|
|
938
|
-
await _fs.promises.writeFile(metaPath, JSON.stringify(
|
|
828
|
+
await _fs.promises.writeFile(metaPath, JSON.stringify(meta, null, 2));
|
|
939
829
|
}
|
|
940
830
|
function isImageFile(filename) {
|
|
941
831
|
const ext = _path2.default.extname(filename).toLowerCase();
|
|
@@ -967,22 +857,17 @@ function getContentType(filePath) {
|
|
|
967
857
|
return "application/octet-stream";
|
|
968
858
|
}
|
|
969
859
|
}
|
|
970
|
-
async function processImage(buffer,
|
|
860
|
+
async function processImage(buffer, imageKey) {
|
|
971
861
|
const sharpInstance = _sharp2.default.call(void 0, buffer);
|
|
972
862
|
const metadata = await sharpInstance.metadata();
|
|
973
863
|
const originalWidth = metadata.width || 0;
|
|
974
864
|
const originalHeight = metadata.height || 0;
|
|
975
|
-
const
|
|
976
|
-
const
|
|
977
|
-
const
|
|
865
|
+
const keyWithoutSlash = imageKey.startsWith("/") ? imageKey.slice(1) : imageKey;
|
|
866
|
+
const baseName = _path2.default.basename(keyWithoutSlash, _path2.default.extname(keyWithoutSlash));
|
|
867
|
+
const ext = _path2.default.extname(keyWithoutSlash).toLowerCase();
|
|
868
|
+
const imageDir = _path2.default.dirname(keyWithoutSlash);
|
|
978
869
|
const imagesPath = _path2.default.join(process.cwd(), "public", "images", imageDir === "." ? "" : imageDir);
|
|
979
870
|
await _fs.promises.mkdir(imagesPath, { recursive: true });
|
|
980
|
-
const sizes = {
|
|
981
|
-
full: { path: "", width: originalWidth, height: originalHeight },
|
|
982
|
-
large: { path: "", width: 0, height: 0 },
|
|
983
|
-
medium: { path: "", width: 0, height: 0 },
|
|
984
|
-
small: { path: "", width: 0, height: 0 }
|
|
985
|
-
};
|
|
986
871
|
const isPng = ext === ".png";
|
|
987
872
|
const outputExt = isPng ? ".png" : ".jpg";
|
|
988
873
|
const fullFileName = imageDir === "." ? `${baseName}${outputExt}` : `${imageDir}/${baseName}${outputExt}`;
|
|
@@ -992,11 +877,9 @@ async function processImage(buffer, entry, imageKey) {
|
|
|
992
877
|
} else {
|
|
993
878
|
await _sharp2.default.call(void 0, buffer).jpeg({ quality: 85 }).toFile(fullPath);
|
|
994
879
|
}
|
|
995
|
-
|
|
996
|
-
for (const [sizeName, sizeConfig] of Object.entries(DEFAULT_SIZES)) {
|
|
880
|
+
for (const [, sizeConfig] of Object.entries(DEFAULT_SIZES)) {
|
|
997
881
|
const { width: maxWidth, suffix } = sizeConfig;
|
|
998
882
|
if (originalWidth <= maxWidth) {
|
|
999
|
-
sizes[sizeName] = { ...sizes.full };
|
|
1000
883
|
continue;
|
|
1001
884
|
}
|
|
1002
885
|
const ratio = originalHeight / originalWidth;
|
|
@@ -1009,27 +892,13 @@ async function processImage(buffer, entry, imageKey) {
|
|
|
1009
892
|
} else {
|
|
1010
893
|
await _sharp2.default.call(void 0, buffer).resize(maxWidth, newHeight).jpeg({ quality: 80 }).toFile(sizePath);
|
|
1011
894
|
}
|
|
1012
|
-
sizes[sizeName] = {
|
|
1013
|
-
path: `/images/${sizeFilePath}`,
|
|
1014
|
-
width: maxWidth,
|
|
1015
|
-
height: newHeight
|
|
1016
|
-
};
|
|
1017
895
|
}
|
|
1018
896
|
const { data, info } = await _sharp2.default.call(void 0, buffer).resize(32, 32, { fit: "inside" }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
1019
897
|
const blurhash = _blurhash.encode.call(void 0, new Uint8ClampedArray(data), info.width, info.height, 4, 4);
|
|
1020
|
-
const { dominant } = await _sharp2.default.call(void 0, buffer).stats();
|
|
1021
|
-
const dominantColor = `#${dominant.r.toString(16).padStart(2, "0")}${dominant.g.toString(16).padStart(2, "0")}${dominant.b.toString(16).padStart(2, "0")}`;
|
|
1022
898
|
return {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
width: originalWidth,
|
|
1027
|
-
height: originalHeight,
|
|
1028
|
-
fileSize: buffer.length
|
|
1029
|
-
},
|
|
1030
|
-
sizes,
|
|
1031
|
-
blurhash,
|
|
1032
|
-
dominantColor
|
|
899
|
+
w: originalWidth,
|
|
900
|
+
h: originalHeight,
|
|
901
|
+
blur: blurhash
|
|
1033
902
|
};
|
|
1034
903
|
}
|
|
1035
904
|
async function downloadFromCdn(originalPath) {
|
|
@@ -1058,7 +927,7 @@ async function downloadFromCdn(originalPath) {
|
|
|
1058
927
|
}
|
|
1059
928
|
return Buffer.concat(chunks);
|
|
1060
929
|
}
|
|
1061
|
-
async function uploadToCdn(
|
|
930
|
+
async function uploadToCdn(imageKey) {
|
|
1062
931
|
const accountId = process.env.CLOUDFLARE_R2_ACCOUNT_ID;
|
|
1063
932
|
const accessKeyId = process.env.CLOUDFLARE_R2_ACCESS_KEY_ID;
|
|
1064
933
|
const secretAccessKey = process.env.CLOUDFLARE_R2_SECRET_ACCESS_KEY;
|
|
@@ -1071,25 +940,28 @@ async function uploadToCdn(entry) {
|
|
|
1071
940
|
endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
|
|
1072
941
|
credentials: { accessKeyId, secretAccessKey }
|
|
1073
942
|
});
|
|
1074
|
-
for (const
|
|
1075
|
-
const localPath = _path2.default.join(process.cwd(), "public",
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
943
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
944
|
+
const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
945
|
+
try {
|
|
946
|
+
const fileBuffer = await _fs.promises.readFile(localPath);
|
|
947
|
+
await r2.send(
|
|
948
|
+
new (0, _clients3.PutObjectCommand)({
|
|
949
|
+
Bucket: bucketName,
|
|
950
|
+
Key: thumbPath.replace(/^\//, ""),
|
|
951
|
+
Body: fileBuffer,
|
|
952
|
+
ContentType: getContentType(thumbPath)
|
|
953
|
+
})
|
|
954
|
+
);
|
|
955
|
+
} catch (e19) {
|
|
956
|
+
}
|
|
1085
957
|
}
|
|
1086
958
|
}
|
|
1087
|
-
async function
|
|
1088
|
-
for (const
|
|
1089
|
-
const localPath = _path2.default.join(process.cwd(), "public",
|
|
959
|
+
async function deleteLocalThumbnails(imageKey) {
|
|
960
|
+
for (const thumbPath of _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
961
|
+
const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
|
|
1090
962
|
try {
|
|
1091
963
|
await _fs.promises.unlink(localPath);
|
|
1092
|
-
} catch (
|
|
964
|
+
} catch (e20) {
|
|
1093
965
|
}
|
|
1094
966
|
}
|
|
1095
967
|
}
|
|
@@ -1111,7 +983,7 @@ async function handleCreateFolder(request) {
|
|
|
1111
983
|
try {
|
|
1112
984
|
await _fs.promises.access(folderPath);
|
|
1113
985
|
return _server.NextResponse.json({ error: "A folder with this name already exists" }, { status: 400 });
|
|
1114
|
-
} catch (
|
|
986
|
+
} catch (e21) {
|
|
1115
987
|
}
|
|
1116
988
|
await _fs.promises.mkdir(folderPath, { recursive: true });
|
|
1117
989
|
return _server.NextResponse.json({ success: true, path: _path2.default.join(safePath, sanitizedName) });
|
|
@@ -1139,13 +1011,13 @@ async function handleRename(request) {
|
|
|
1139
1011
|
}
|
|
1140
1012
|
try {
|
|
1141
1013
|
await _fs.promises.access(absoluteOldPath);
|
|
1142
|
-
} catch (
|
|
1014
|
+
} catch (e22) {
|
|
1143
1015
|
return _server.NextResponse.json({ error: "File or folder not found" }, { status: 404 });
|
|
1144
1016
|
}
|
|
1145
1017
|
try {
|
|
1146
1018
|
await _fs.promises.access(absoluteNewPath);
|
|
1147
1019
|
return _server.NextResponse.json({ error: "An item with this name already exists" }, { status: 400 });
|
|
1148
|
-
} catch (
|
|
1020
|
+
} catch (e23) {
|
|
1149
1021
|
}
|
|
1150
1022
|
const stats = await _fs.promises.stat(absoluteOldPath);
|
|
1151
1023
|
const isFile = stats.isFile();
|
|
@@ -1155,32 +1027,23 @@ async function handleRename(request) {
|
|
|
1155
1027
|
const meta = await loadMeta();
|
|
1156
1028
|
const oldRelativePath = safePath.replace(/^public\//, "");
|
|
1157
1029
|
const newRelativePath = _path2.default.join(_path2.default.dirname(oldRelativePath), sanitizedName);
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
const
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
const oldThumbPath = _path2.default.join(thumbnailDir, oldThumbName);
|
|
1172
|
-
const newThumbPath = _path2.default.join(thumbnailDir, newThumbName);
|
|
1173
|
-
try {
|
|
1174
|
-
await _fs.promises.rename(oldThumbPath, newThumbPath);
|
|
1175
|
-
sizeData.path = `/images/${oldDirRelative}/${newThumbName}`.replace(/\/+/g, "/");
|
|
1176
|
-
} catch (e23) {
|
|
1177
|
-
}
|
|
1030
|
+
const oldKey = "/" + oldRelativePath;
|
|
1031
|
+
const newKey = "/" + newRelativePath;
|
|
1032
|
+
if (meta[oldKey]) {
|
|
1033
|
+
const entry = meta[oldKey];
|
|
1034
|
+
const oldThumbPaths = _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, oldKey);
|
|
1035
|
+
const newThumbPaths = _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, newKey);
|
|
1036
|
+
for (let i = 0; i < oldThumbPaths.length; i++) {
|
|
1037
|
+
const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
|
|
1038
|
+
const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
|
|
1039
|
+
await _fs.promises.mkdir(_path2.default.dirname(newThumbPath), { recursive: true });
|
|
1040
|
+
try {
|
|
1041
|
+
await _fs.promises.rename(oldThumbPath, newThumbPath);
|
|
1042
|
+
} catch (e24) {
|
|
1178
1043
|
}
|
|
1179
|
-
const newKey = `/${newRelativePath}`;
|
|
1180
|
-
delete meta.images[key];
|
|
1181
|
-
meta.images[newKey] = entry;
|
|
1182
|
-
break;
|
|
1183
1044
|
}
|
|
1045
|
+
delete meta[oldKey];
|
|
1046
|
+
meta[newKey] = entry;
|
|
1184
1047
|
}
|
|
1185
1048
|
await saveMeta(meta);
|
|
1186
1049
|
}
|
|
@@ -1213,7 +1076,7 @@ async function handleMove(request) {
|
|
|
1213
1076
|
if (!destStats.isDirectory()) {
|
|
1214
1077
|
return _server.NextResponse.json({ error: "Destination is not a folder" }, { status: 400 });
|
|
1215
1078
|
}
|
|
1216
|
-
} catch (
|
|
1079
|
+
} catch (e25) {
|
|
1217
1080
|
return _server.NextResponse.json({ error: "Destination folder not found" }, { status: 404 });
|
|
1218
1081
|
}
|
|
1219
1082
|
const moved = [];
|
|
@@ -1231,7 +1094,7 @@ async function handleMove(request) {
|
|
|
1231
1094
|
}
|
|
1232
1095
|
try {
|
|
1233
1096
|
await _fs.promises.access(absolutePath);
|
|
1234
|
-
} catch (
|
|
1097
|
+
} catch (e26) {
|
|
1235
1098
|
errors.push(`${itemName} not found`);
|
|
1236
1099
|
continue;
|
|
1237
1100
|
}
|
|
@@ -1239,7 +1102,7 @@ async function handleMove(request) {
|
|
|
1239
1102
|
await _fs.promises.access(newAbsolutePath);
|
|
1240
1103
|
errors.push(`${itemName} already exists in destination`);
|
|
1241
1104
|
continue;
|
|
1242
|
-
} catch (
|
|
1105
|
+
} catch (e27) {
|
|
1243
1106
|
}
|
|
1244
1107
|
try {
|
|
1245
1108
|
await _fs.promises.rename(absolutePath, newAbsolutePath);
|
|
@@ -1247,33 +1110,24 @@ async function handleMove(request) {
|
|
|
1247
1110
|
if (stats.isFile() && isImageFile(itemName)) {
|
|
1248
1111
|
const oldRelativePath = safePath.replace(/^public\//, "");
|
|
1249
1112
|
const newRelativePath = _path2.default.join(safeDestination.replace(/^public\//, ""), itemName);
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
const
|
|
1258
|
-
const
|
|
1259
|
-
await _fs.promises.mkdir(
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
const oldThumbPath = _path2.default.join(oldThumbDir, thumbName);
|
|
1264
|
-
const newThumbPath = _path2.default.join(newThumbDir, thumbName);
|
|
1265
|
-
try {
|
|
1266
|
-
await _fs.promises.rename(oldThumbPath, newThumbPath);
|
|
1267
|
-
sizeData.path = `/images/${newDir}/${thumbName}`.replace(/\/+/g, "/");
|
|
1268
|
-
} catch (e27) {
|
|
1269
|
-
}
|
|
1113
|
+
const oldKey = "/" + oldRelativePath;
|
|
1114
|
+
const newKey = "/" + newRelativePath;
|
|
1115
|
+
if (meta[oldKey]) {
|
|
1116
|
+
const entry = meta[oldKey];
|
|
1117
|
+
const oldThumbPaths = _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, oldKey);
|
|
1118
|
+
const newThumbPaths = _chunkCN5NRNWBjs.getAllThumbnailPaths.call(void 0, newKey);
|
|
1119
|
+
for (let i = 0; i < oldThumbPaths.length; i++) {
|
|
1120
|
+
const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
|
|
1121
|
+
const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
|
|
1122
|
+
await _fs.promises.mkdir(_path2.default.dirname(newThumbPath), { recursive: true });
|
|
1123
|
+
try {
|
|
1124
|
+
await _fs.promises.rename(oldThumbPath, newThumbPath);
|
|
1125
|
+
} catch (e28) {
|
|
1270
1126
|
}
|
|
1271
|
-
const newKey = `/${newRelativePath}`;
|
|
1272
|
-
delete meta.images[key];
|
|
1273
|
-
meta.images[newKey] = entry;
|
|
1274
|
-
metaChanged = true;
|
|
1275
|
-
break;
|
|
1276
1127
|
}
|
|
1128
|
+
delete meta[oldKey];
|
|
1129
|
+
meta[newKey] = entry;
|
|
1130
|
+
metaChanged = true;
|
|
1277
1131
|
}
|
|
1278
1132
|
}
|
|
1279
1133
|
moved.push(itemPath);
|
|
@@ -1313,7 +1167,7 @@ async function handleListFolders() {
|
|
|
1313
1167
|
});
|
|
1314
1168
|
await scanDir(_path2.default.join(dir, entry.name), folderRelativePath, depth + 1);
|
|
1315
1169
|
}
|
|
1316
|
-
} catch (
|
|
1170
|
+
} catch (e29) {
|
|
1317
1171
|
}
|
|
1318
1172
|
}
|
|
1319
1173
|
folders.push({ path: "public", name: "public", depth: 0 });
|