simple-photo-gallery 2.0.11-rc.9 → 2.0.12
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/assets/fonts/dejavu/DejaVuSans-Bold.ttf +0 -0
- package/assets/fonts/dejavu/LICENSE.txt +78 -0
- package/dist/index.cjs +149 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +146 -87
- package/dist/index.js.map +1 -1
- package/dist/lib/browser.cjs +29 -0
- package/dist/lib/browser.cjs.map +1 -0
- package/dist/lib/browser.d.cts +8 -0
- package/dist/lib/browser.d.ts +8 -0
- package/dist/lib/browser.js +23 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/index.cjs +47 -2
- package/dist/lib/index.cjs.map +1 -1
- package/dist/lib/index.js +46 -2
- package/dist/lib/index.js.map +1 -1
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import process4, { stdout } from 'process';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { LogLevels, createConsola } from 'consola';
|
|
5
5
|
import { execSync, spawn } from 'child_process';
|
|
6
6
|
import fs8, { promises } from 'fs';
|
|
7
|
-
import
|
|
7
|
+
import path from 'path';
|
|
8
8
|
import { Buffer } from 'buffer';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
9
10
|
import sharp2 from 'sharp';
|
|
10
11
|
import { encode } from 'blurhash';
|
|
11
12
|
import { GalleryDataSchema, GalleryDataDeprecatedSchema } from '@simple-photo-gallery/common';
|
|
@@ -76,10 +77,42 @@ async function generateBlurHash(imagePath, componentX = 4, componentY = 3) {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
// src/modules/build/utils/index.ts
|
|
79
|
-
|
|
80
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
81
|
+
var SOCIAL_CARD_FONT_RELATIVE_PATH = path.join("assets", "fonts", "dejavu", "DejaVuSans-Bold.ttf");
|
|
82
|
+
var socialCardFontBase64;
|
|
83
|
+
function resolveFromCurrentDir(...segments) {
|
|
84
|
+
return path.resolve(__dirname, ...segments);
|
|
85
|
+
}
|
|
86
|
+
function findSocialCardFontPath() {
|
|
87
|
+
const fontCandidates = [
|
|
88
|
+
resolveFromCurrentDir("../../../../", SOCIAL_CARD_FONT_RELATIVE_PATH),
|
|
89
|
+
path.resolve(__dirname, "../", SOCIAL_CARD_FONT_RELATIVE_PATH),
|
|
90
|
+
path.resolve(__dirname, "../../", SOCIAL_CARD_FONT_RELATIVE_PATH),
|
|
91
|
+
path.resolve(process4.cwd(), SOCIAL_CARD_FONT_RELATIVE_PATH),
|
|
92
|
+
path.resolve(process4.cwd(), "../", SOCIAL_CARD_FONT_RELATIVE_PATH)
|
|
93
|
+
];
|
|
94
|
+
for (const candidate of fontCandidates) {
|
|
95
|
+
if (fs8.existsSync(candidate)) {
|
|
96
|
+
return candidate;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function getSocialCardFontBase64() {
|
|
102
|
+
if (socialCardFontBase64 !== void 0) {
|
|
103
|
+
return socialCardFontBase64;
|
|
104
|
+
}
|
|
105
|
+
const fontPath = findSocialCardFontPath();
|
|
106
|
+
if (!fontPath) {
|
|
107
|
+
socialCardFontBase64 = null;
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
socialCardFontBase64 = fs8.readFileSync(fontPath).toString("base64");
|
|
111
|
+
return socialCardFontBase64;
|
|
112
|
+
}
|
|
80
113
|
async function createGallerySocialMediaCardImage(headerPhotoPath, title, ouputPath, ui) {
|
|
81
114
|
ui?.start(`Creating social media card image`);
|
|
82
|
-
const headerBasename =
|
|
115
|
+
const headerBasename = path.basename(headerPhotoPath, path.extname(headerPhotoPath));
|
|
83
116
|
if (fs8.existsSync(ouputPath)) {
|
|
84
117
|
ui?.success(`Social media card image already exists`);
|
|
85
118
|
return headerBasename;
|
|
@@ -88,11 +121,21 @@ async function createGallerySocialMediaCardImage(headerPhotoPath, title, ouputPa
|
|
|
88
121
|
const resizedImageBuffer = await image.resize(1200, 631, { fit: "cover" }).jpeg({ quality: 90 }).toBuffer();
|
|
89
122
|
const outputPath = ouputPath;
|
|
90
123
|
await sharp2(resizedImageBuffer).toFile(outputPath);
|
|
124
|
+
const fontBase64 = getSocialCardFontBase64();
|
|
125
|
+
const fontFace = fontBase64 ? `
|
|
126
|
+
@font-face {
|
|
127
|
+
font-family: 'DejaVu Sans';
|
|
128
|
+
src: url('data:font/ttf;base64,${fontBase64}') format('truetype');
|
|
129
|
+
font-weight: 700;
|
|
130
|
+
font-style: normal;
|
|
131
|
+
}` : "";
|
|
132
|
+
const fontFamily = fontBase64 ? "'DejaVu Sans', Arial, sans-serif" : "Arial, sans-serif";
|
|
91
133
|
const svgText = `
|
|
92
134
|
<svg width="1200" height="631" xmlns="http://www.w3.org/2000/svg">
|
|
93
135
|
<defs>
|
|
94
136
|
<style>
|
|
95
|
-
|
|
137
|
+
${fontFace}
|
|
138
|
+
.title { font-family: ${fontFamily}; font-size: 96px; font-weight: bold; fill: white; stroke: black; stroke-width: 5; paint-order: stroke; text-anchor: middle; }
|
|
96
139
|
</style>
|
|
97
140
|
</defs>
|
|
98
141
|
<text x="600" y="250" class="title">${title}</text>
|
|
@@ -106,7 +149,7 @@ async function createGallerySocialMediaCardImage(headerPhotoPath, title, ouputPa
|
|
|
106
149
|
async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
107
150
|
ui?.start(`Creating optimized header images`);
|
|
108
151
|
const image = await loadImage(headerPhotoPath);
|
|
109
|
-
const headerBasename =
|
|
152
|
+
const headerBasename = path.basename(headerPhotoPath, path.extname(headerPhotoPath));
|
|
110
153
|
const generatedFiles = [];
|
|
111
154
|
ui?.debug("Generating blurhash for header image");
|
|
112
155
|
const blurHash = await generateBlurHash(headerPhotoPath);
|
|
@@ -115,22 +158,22 @@ async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
|
115
158
|
ui?.debug(`Creating landscape header image ${width}`);
|
|
116
159
|
const avifFilename = `${headerBasename}_landscape_${width}.avif`;
|
|
117
160
|
const jpgFilename = `${headerBasename}_landscape_${width}.jpg`;
|
|
118
|
-
if (fs8.existsSync(
|
|
161
|
+
if (fs8.existsSync(path.join(outputFolder, avifFilename))) {
|
|
119
162
|
ui?.debug(`Landscape header image ${width} AVIF already exists`);
|
|
120
163
|
} else {
|
|
121
164
|
await cropAndResizeImage(
|
|
122
165
|
image.clone(),
|
|
123
|
-
|
|
166
|
+
path.join(outputFolder, avifFilename),
|
|
124
167
|
width,
|
|
125
168
|
width * landscapeYFactor,
|
|
126
169
|
"avif"
|
|
127
170
|
);
|
|
128
171
|
}
|
|
129
172
|
generatedFiles.push(avifFilename);
|
|
130
|
-
if (fs8.existsSync(
|
|
173
|
+
if (fs8.existsSync(path.join(outputFolder, jpgFilename))) {
|
|
131
174
|
ui?.debug(`Landscape header image ${width} JPG already exists`);
|
|
132
175
|
} else {
|
|
133
|
-
await cropAndResizeImage(image.clone(),
|
|
176
|
+
await cropAndResizeImage(image.clone(), path.join(outputFolder, jpgFilename), width, width * landscapeYFactor, "jpg");
|
|
134
177
|
}
|
|
135
178
|
generatedFiles.push(jpgFilename);
|
|
136
179
|
}
|
|
@@ -139,16 +182,16 @@ async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
|
139
182
|
ui?.debug(`Creating portrait header image ${width}`);
|
|
140
183
|
const avifFilename = `${headerBasename}_portrait_${width}.avif`;
|
|
141
184
|
const jpgFilename = `${headerBasename}_portrait_${width}.jpg`;
|
|
142
|
-
if (fs8.existsSync(
|
|
185
|
+
if (fs8.existsSync(path.join(outputFolder, avifFilename))) {
|
|
143
186
|
ui?.debug(`Portrait header image ${width} AVIF already exists`);
|
|
144
187
|
} else {
|
|
145
|
-
await cropAndResizeImage(image.clone(),
|
|
188
|
+
await cropAndResizeImage(image.clone(), path.join(outputFolder, avifFilename), width, width * portraitYFactor, "avif");
|
|
146
189
|
}
|
|
147
190
|
generatedFiles.push(avifFilename);
|
|
148
|
-
if (fs8.existsSync(
|
|
191
|
+
if (fs8.existsSync(path.join(outputFolder, jpgFilename))) {
|
|
149
192
|
ui?.debug(`Portrait header image ${width} JPG already exists`);
|
|
150
193
|
} else {
|
|
151
|
-
await cropAndResizeImage(image.clone(),
|
|
194
|
+
await cropAndResizeImage(image.clone(), path.join(outputFolder, jpgFilename), width, width * portraitYFactor, "jpg");
|
|
152
195
|
}
|
|
153
196
|
generatedFiles.push(jpgFilename);
|
|
154
197
|
}
|
|
@@ -181,12 +224,12 @@ function cleanupOldHeaderImages(outputFolder, currentHeaderBasename, ui) {
|
|
|
181
224
|
const landscapeMatch = file.match(/^(.+)_landscape_\d+\.(avif|jpg)$/);
|
|
182
225
|
const portraitMatch = file.match(/^(.+)_portrait_\d+\.(avif|jpg)$/);
|
|
183
226
|
if (landscapeMatch && landscapeMatch[1] !== currentHeaderBasename) {
|
|
184
|
-
const filePath =
|
|
227
|
+
const filePath = path.join(outputFolder, file);
|
|
185
228
|
ui?.debug(`Deleting old landscape header image: ${file}`);
|
|
186
229
|
fs8.unlinkSync(filePath);
|
|
187
230
|
deletedCount++;
|
|
188
231
|
} else if (portraitMatch && portraitMatch[1] !== currentHeaderBasename) {
|
|
189
|
-
const filePath =
|
|
232
|
+
const filePath = path.join(outputFolder, file);
|
|
190
233
|
ui?.debug(`Deleting old portrait header image: ${file}`);
|
|
191
234
|
fs8.unlinkSync(filePath);
|
|
192
235
|
deletedCount++;
|
|
@@ -200,7 +243,7 @@ function cleanupOldHeaderImages(outputFolder, currentHeaderBasename, ui) {
|
|
|
200
243
|
}
|
|
201
244
|
function findGalleries(basePath, recursive) {
|
|
202
245
|
const galleryDirs = [];
|
|
203
|
-
const galleryJsonPath =
|
|
246
|
+
const galleryJsonPath = path.join(basePath, "gallery", "gallery.json");
|
|
204
247
|
if (fs8.existsSync(galleryJsonPath)) {
|
|
205
248
|
galleryDirs.push(basePath);
|
|
206
249
|
}
|
|
@@ -209,7 +252,7 @@ function findGalleries(basePath, recursive) {
|
|
|
209
252
|
const entries = fs8.readdirSync(basePath, { withFileTypes: true });
|
|
210
253
|
for (const entry of entries) {
|
|
211
254
|
if (entry.isDirectory() && entry.name !== "gallery") {
|
|
212
|
-
const subPath =
|
|
255
|
+
const subPath = path.join(basePath, entry.name);
|
|
213
256
|
const subResults = findGalleries(subPath, recursive);
|
|
214
257
|
galleryDirs.push(...subResults);
|
|
215
258
|
}
|
|
@@ -268,20 +311,20 @@ function migrateGalleryJson(deprecatedGalleryData, galleryJsonPath, ui) {
|
|
|
268
311
|
ui.start("Old gallery.json format detected. Migrating gallery.json to the new data format.");
|
|
269
312
|
let mediaBasePath;
|
|
270
313
|
const imagePath = deprecatedGalleryData.sections[0].images[0].path;
|
|
271
|
-
if (imagePath && imagePath !==
|
|
272
|
-
mediaBasePath =
|
|
314
|
+
if (imagePath && imagePath !== path.join("..", path.basename(imagePath))) {
|
|
315
|
+
mediaBasePath = path.resolve(path.join(path.dirname(galleryJsonPath)), path.dirname(imagePath));
|
|
273
316
|
}
|
|
274
317
|
const sections = deprecatedGalleryData.sections.map((section) => ({
|
|
275
318
|
...section,
|
|
276
319
|
images: section.images.map((image) => ({
|
|
277
320
|
...image,
|
|
278
321
|
path: void 0,
|
|
279
|
-
filename:
|
|
322
|
+
filename: path.basename(image.path)
|
|
280
323
|
}))
|
|
281
324
|
}));
|
|
282
325
|
const galleryData = {
|
|
283
326
|
...deprecatedGalleryData,
|
|
284
|
-
headerImage:
|
|
327
|
+
headerImage: path.basename(deprecatedGalleryData.headerImage),
|
|
285
328
|
sections,
|
|
286
329
|
mediaBasePath
|
|
287
330
|
};
|
|
@@ -293,7 +336,7 @@ function migrateGalleryJson(deprecatedGalleryData, galleryJsonPath, ui) {
|
|
|
293
336
|
return galleryData;
|
|
294
337
|
}
|
|
295
338
|
function getMediaFileType(fileName) {
|
|
296
|
-
const ext =
|
|
339
|
+
const ext = path.extname(fileName).toLowerCase();
|
|
297
340
|
if (IMAGE_EXTENSIONS.has(ext)) return "image";
|
|
298
341
|
if (VIDEO_EXTENSIONS.has(ext)) return "video";
|
|
299
342
|
return null;
|
|
@@ -321,7 +364,7 @@ async function scanDirectory(dirPath, ui) {
|
|
|
321
364
|
mediaFiles.push(mediaFile);
|
|
322
365
|
}
|
|
323
366
|
} else if (entry.isDirectory() && entry.name !== "gallery") {
|
|
324
|
-
subGalleryDirectories.push(
|
|
367
|
+
subGalleryDirectories.push(path.join(dirPath, entry.name));
|
|
325
368
|
}
|
|
326
369
|
}
|
|
327
370
|
} catch (error) {
|
|
@@ -356,13 +399,13 @@ async function getGallerySettingsFromUser(galleryName, defaultImage, ui) {
|
|
|
356
399
|
});
|
|
357
400
|
return { title, description, url, headerImage };
|
|
358
401
|
}
|
|
359
|
-
async function createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalleries = [], useDefaultSettings, ui) {
|
|
360
|
-
const galleryDir =
|
|
361
|
-
const isSameLocation =
|
|
402
|
+
async function createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalleries = [], useDefaultSettings, ctaBanner, ui) {
|
|
403
|
+
const galleryDir = path.dirname(galleryJsonPath);
|
|
404
|
+
const isSameLocation = path.relative(scanPath, path.join(galleryDir, "..")) === "";
|
|
362
405
|
const mediaBasePath = isSameLocation ? void 0 : scanPath;
|
|
363
406
|
const relativeSubGalleries = subGalleries.map((subGallery) => ({
|
|
364
407
|
...subGallery,
|
|
365
|
-
headerImage: subGallery.headerImage ?
|
|
408
|
+
headerImage: subGallery.headerImage ? path.relative(galleryDir, subGallery.headerImage) : ""
|
|
366
409
|
}));
|
|
367
410
|
let galleryData = {
|
|
368
411
|
title: "My Gallery",
|
|
@@ -378,14 +421,15 @@ async function createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalle
|
|
|
378
421
|
subGalleries: {
|
|
379
422
|
title: "Sub Galleries",
|
|
380
423
|
galleries: relativeSubGalleries
|
|
381
|
-
}
|
|
424
|
+
},
|
|
425
|
+
...ctaBanner !== void 0 && { ctaBanner }
|
|
382
426
|
};
|
|
383
427
|
if (!useDefaultSettings) {
|
|
384
428
|
galleryData = {
|
|
385
429
|
...galleryData,
|
|
386
430
|
...await getGallerySettingsFromUser(
|
|
387
|
-
|
|
388
|
-
|
|
431
|
+
path.basename(path.join(galleryDir, "..")),
|
|
432
|
+
path.basename(mediaFiles[0]?.filename || ""),
|
|
389
433
|
ui
|
|
390
434
|
)
|
|
391
435
|
};
|
|
@@ -393,8 +437,8 @@ async function createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalle
|
|
|
393
437
|
await promises.writeFile(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
394
438
|
}
|
|
395
439
|
async function galleryExists(outputPath) {
|
|
396
|
-
const galleryPath =
|
|
397
|
-
const galleryJsonPath =
|
|
440
|
+
const galleryPath = path.join(outputPath, "gallery");
|
|
441
|
+
const galleryJsonPath = path.join(galleryPath, "gallery.json");
|
|
398
442
|
try {
|
|
399
443
|
await promises.access(galleryJsonPath);
|
|
400
444
|
return true;
|
|
@@ -402,7 +446,7 @@ async function galleryExists(outputPath) {
|
|
|
402
446
|
return false;
|
|
403
447
|
}
|
|
404
448
|
}
|
|
405
|
-
async function processDirectory(scanPath, outputPath, recursive, useDefaultSettings, force, ui) {
|
|
449
|
+
async function processDirectory(scanPath, outputPath, recursive, useDefaultSettings, force, ctaBanner, ui) {
|
|
406
450
|
ui.start(`Scanning ${scanPath}`);
|
|
407
451
|
let totalFiles = 0;
|
|
408
452
|
let totalGalleries = 1;
|
|
@@ -413,10 +457,11 @@ async function processDirectory(scanPath, outputPath, recursive, useDefaultSetti
|
|
|
413
457
|
for (const subGalleryDir of subGalleryDirectories) {
|
|
414
458
|
const result2 = await processDirectory(
|
|
415
459
|
subGalleryDir,
|
|
416
|
-
|
|
460
|
+
path.join(outputPath, path.basename(subGalleryDir)),
|
|
417
461
|
recursive,
|
|
418
462
|
useDefaultSettings,
|
|
419
463
|
force,
|
|
464
|
+
ctaBanner,
|
|
420
465
|
ui
|
|
421
466
|
);
|
|
422
467
|
totalFiles += result2.totalFiles;
|
|
@@ -427,8 +472,8 @@ async function processDirectory(scanPath, outputPath, recursive, useDefaultSetti
|
|
|
427
472
|
}
|
|
428
473
|
}
|
|
429
474
|
if (mediaFiles.length > 0 || subGalleries.length > 0) {
|
|
430
|
-
const galleryPath =
|
|
431
|
-
const galleryJsonPath =
|
|
475
|
+
const galleryPath = path.join(outputPath, "gallery");
|
|
476
|
+
const galleryJsonPath = path.join(galleryPath, "gallery.json");
|
|
432
477
|
const exists = await galleryExists(outputPath);
|
|
433
478
|
if (exists && !force) {
|
|
434
479
|
const shouldOverride = await ui.prompt(`Gallery already exists at ${galleryJsonPath}. Do you want to override it?`, {
|
|
@@ -442,7 +487,7 @@ async function processDirectory(scanPath, outputPath, recursive, useDefaultSetti
|
|
|
442
487
|
}
|
|
443
488
|
try {
|
|
444
489
|
await promises.mkdir(galleryPath, { recursive: true });
|
|
445
|
-
await createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalleries, useDefaultSettings, ui);
|
|
490
|
+
await createGalleryJson(mediaFiles, galleryJsonPath, scanPath, subGalleries, useDefaultSettings, ctaBanner, ui);
|
|
446
491
|
ui.success(
|
|
447
492
|
`Create gallery with ${mediaFiles.length} files and ${subGalleries.length} subgalleries at: ${galleryJsonPath}`
|
|
448
493
|
);
|
|
@@ -453,20 +498,28 @@ async function processDirectory(scanPath, outputPath, recursive, useDefaultSetti
|
|
|
453
498
|
}
|
|
454
499
|
const result = { totalFiles, totalGalleries };
|
|
455
500
|
if (mediaFiles.length > 0 || subGalleries.length > 0) {
|
|
456
|
-
const dirName =
|
|
501
|
+
const dirName = path.basename(scanPath);
|
|
457
502
|
result.subGallery = {
|
|
458
503
|
title: capitalizeTitle(dirName),
|
|
459
504
|
headerImage: mediaFiles[0]?.filename || "",
|
|
460
|
-
path:
|
|
505
|
+
path: path.join("..", dirName)
|
|
461
506
|
};
|
|
462
507
|
}
|
|
463
508
|
return result;
|
|
464
509
|
}
|
|
465
510
|
async function init(options, ui) {
|
|
466
511
|
try {
|
|
467
|
-
const scanPath =
|
|
468
|
-
const outputPath = options.gallery ?
|
|
469
|
-
const result = await processDirectory(
|
|
512
|
+
const scanPath = path.resolve(options.photos);
|
|
513
|
+
const outputPath = options.gallery ? path.resolve(options.gallery) : scanPath;
|
|
514
|
+
const result = await processDirectory(
|
|
515
|
+
scanPath,
|
|
516
|
+
outputPath,
|
|
517
|
+
options.recursive,
|
|
518
|
+
options.default,
|
|
519
|
+
options.force,
|
|
520
|
+
options.ctaBanner,
|
|
521
|
+
ui
|
|
522
|
+
);
|
|
470
523
|
ui.box(
|
|
471
524
|
`Created ${result.totalGalleries} ${result.totalGalleries === 1 ? "gallery" : "galleries"} with ${result.totalFiles} media ${result.totalFiles === 1 ? "file" : "files"}`
|
|
472
525
|
);
|
|
@@ -581,7 +634,7 @@ async function processImage(imagePath, thumbnailPath, thumbnailPathRetina, thumb
|
|
|
581
634
|
const blurHash = await generateBlurHash(thumbnailPath);
|
|
582
635
|
return {
|
|
583
636
|
type: "image",
|
|
584
|
-
filename:
|
|
637
|
+
filename: path.basename(imagePath),
|
|
585
638
|
alt: description,
|
|
586
639
|
width: imageDimensions.width,
|
|
587
640
|
height: imageDimensions.height,
|
|
@@ -612,7 +665,7 @@ async function processVideo(videoPath, thumbnailPath, thumbnailPathRetina, thumb
|
|
|
612
665
|
const blurHash = await generateBlurHash(thumbnailPath);
|
|
613
666
|
return {
|
|
614
667
|
type: "video",
|
|
615
|
-
filename:
|
|
668
|
+
filename: path.basename(videoPath),
|
|
616
669
|
alt: void 0,
|
|
617
670
|
width: videoDimensions.width,
|
|
618
671
|
height: videoDimensions.height,
|
|
@@ -628,11 +681,11 @@ async function processVideo(videoPath, thumbnailPath, thumbnailPathRetina, thumb
|
|
|
628
681
|
}
|
|
629
682
|
async function processMediaFile(mediaFile, mediaBasePath, thumbnailsPath, thumbnailSize, ui) {
|
|
630
683
|
try {
|
|
631
|
-
const filePath =
|
|
684
|
+
const filePath = path.resolve(path.join(mediaBasePath, mediaFile.filename));
|
|
632
685
|
const fileName = mediaFile.filename;
|
|
633
|
-
const fileNameWithoutExt =
|
|
686
|
+
const fileNameWithoutExt = path.parse(fileName).name;
|
|
634
687
|
const thumbnailFileName = `${fileNameWithoutExt}.avif`;
|
|
635
|
-
const thumbnailPath =
|
|
688
|
+
const thumbnailPath = path.join(thumbnailsPath, thumbnailFileName);
|
|
636
689
|
const thumbnailPathRetina = thumbnailPath.replace(".avif", "@2x.avif");
|
|
637
690
|
const lastMediaTimestamp = mediaFile.lastMediaTimestamp ? new Date(mediaFile.lastMediaTimestamp) : void 0;
|
|
638
691
|
const verbose = ui.level === LogLevels.debug;
|
|
@@ -658,8 +711,14 @@ async function processMediaFile(mediaFile, mediaBasePath, thumbnailsPath, thumbn
|
|
|
658
711
|
}
|
|
659
712
|
updatedMediaFile.filename = mediaFile.filename;
|
|
660
713
|
if (updatedMediaFile.thumbnail) {
|
|
661
|
-
updatedMediaFile.thumbnail.path =
|
|
662
|
-
updatedMediaFile.thumbnail.pathRetina =
|
|
714
|
+
updatedMediaFile.thumbnail.path = path.basename(thumbnailPath);
|
|
715
|
+
updatedMediaFile.thumbnail.pathRetina = path.basename(thumbnailPathRetina);
|
|
716
|
+
if (mediaFile.thumbnail?.baseUrl) {
|
|
717
|
+
updatedMediaFile.thumbnail.baseUrl = mediaFile.thumbnail.baseUrl;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (mediaFile.url) {
|
|
721
|
+
updatedMediaFile.url = mediaFile.url;
|
|
663
722
|
}
|
|
664
723
|
return updatedMediaFile;
|
|
665
724
|
} catch (error) {
|
|
@@ -668,14 +727,14 @@ async function processMediaFile(mediaFile, mediaBasePath, thumbnailsPath, thumbn
|
|
|
668
727
|
}
|
|
669
728
|
}
|
|
670
729
|
async function processGalleryThumbnails(galleryDir, ui) {
|
|
671
|
-
const galleryJsonPath =
|
|
672
|
-
const thumbnailsPath =
|
|
730
|
+
const galleryJsonPath = path.join(galleryDir, "gallery", "gallery.json");
|
|
731
|
+
const thumbnailsPath = path.join(galleryDir, "gallery", "images");
|
|
673
732
|
ui.start(`Creating thumbnails: ${galleryDir}`);
|
|
674
733
|
try {
|
|
675
734
|
fs8.mkdirSync(thumbnailsPath, { recursive: true });
|
|
676
735
|
const galleryData = parseGalleryJson(galleryJsonPath, ui);
|
|
677
736
|
const thumbnailSize = galleryData.thumbnailSize || DEFAULT_THUMBNAIL_SIZE;
|
|
678
|
-
const mediaBasePath = galleryData.mediaBasePath ??
|
|
737
|
+
const mediaBasePath = galleryData.mediaBasePath ?? path.join(galleryDir);
|
|
679
738
|
let processedCount = 0;
|
|
680
739
|
for (const section of galleryData.sections) {
|
|
681
740
|
for (const [index, mediaFile] of section.images.entries()) {
|
|
@@ -722,8 +781,8 @@ function copyPhotos(galleryData, galleryDir, ui) {
|
|
|
722
781
|
for (const section of galleryData.sections) {
|
|
723
782
|
for (const image of section.images) {
|
|
724
783
|
if (galleryData.mediaBasePath) {
|
|
725
|
-
const sourcePath =
|
|
726
|
-
const destPath =
|
|
784
|
+
const sourcePath = path.join(galleryData.mediaBasePath, image.filename);
|
|
785
|
+
const destPath = path.join(galleryDir, image.filename);
|
|
727
786
|
ui.debug(`Copying photo to ${destPath}`);
|
|
728
787
|
fs8.copyFileSync(sourcePath, destPath);
|
|
729
788
|
}
|
|
@@ -762,17 +821,17 @@ async function scanAndAppendNewFiles(galleryDir, galleryJsonPath, galleryData, u
|
|
|
762
821
|
}
|
|
763
822
|
async function buildGallery(galleryDir, templateDir, scan, shouldCreateThumbnails, ui, baseUrl, thumbsBaseUrl) {
|
|
764
823
|
ui.start(`Building gallery ${galleryDir}`);
|
|
765
|
-
const galleryJsonPath =
|
|
824
|
+
const galleryJsonPath = path.join(galleryDir, "gallery", "gallery.json");
|
|
766
825
|
let galleryData = parseGalleryJson(galleryJsonPath, ui);
|
|
767
826
|
if (scan) {
|
|
768
827
|
galleryData = await scanAndAppendNewFiles(galleryDir, galleryJsonPath, galleryData, ui);
|
|
769
828
|
}
|
|
770
|
-
const socialMediaCardImagePath =
|
|
829
|
+
const socialMediaCardImagePath = path.join(galleryDir, "gallery", "images", "social-media-card.jpg");
|
|
771
830
|
const mediaBasePath = galleryData.mediaBasePath;
|
|
772
831
|
const mediaBaseUrl = baseUrl || galleryData.mediaBaseUrl;
|
|
773
|
-
const headerImagePath = mediaBasePath ?
|
|
774
|
-
const imagesFolder =
|
|
775
|
-
const currentHeaderBasename =
|
|
832
|
+
const headerImagePath = mediaBasePath ? path.join(mediaBasePath, galleryData.headerImage) : path.resolve(galleryDir, galleryData.headerImage);
|
|
833
|
+
const imagesFolder = path.join(galleryDir, "gallery", "images");
|
|
834
|
+
const currentHeaderBasename = path.basename(headerImagePath, path.extname(headerImagePath));
|
|
776
835
|
if (shouldCreateThumbnails) {
|
|
777
836
|
if (!fs8.existsSync(imagesFolder)) {
|
|
778
837
|
fs8.mkdirSync(imagesFolder, { recursive: true });
|
|
@@ -815,7 +874,7 @@ async function buildGallery(galleryDir, templateDir, scan, shouldCreateThumbnail
|
|
|
815
874
|
}
|
|
816
875
|
if (!galleryData.metadata.image) {
|
|
817
876
|
ui.debug("Updating gallery.json with social media card URL");
|
|
818
|
-
galleryData.metadata.image = thumbsBaseUrl ? `${thumbsBaseUrl}/${
|
|
877
|
+
galleryData.metadata.image = thumbsBaseUrl ? `${thumbsBaseUrl}/${path.basename(socialMediaCardImagePath)}` : `${galleryData.url || ""}/${path.relative(galleryDir, socialMediaCardImagePath)}`;
|
|
819
878
|
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
820
879
|
}
|
|
821
880
|
if (shouldCreateThumbnails) {
|
|
@@ -823,20 +882,20 @@ async function buildGallery(galleryDir, templateDir, scan, shouldCreateThumbnail
|
|
|
823
882
|
}
|
|
824
883
|
ui.debug("Building gallery from template");
|
|
825
884
|
try {
|
|
826
|
-
|
|
827
|
-
|
|
885
|
+
process4.env.GALLERY_JSON_PATH = galleryJsonPath;
|
|
886
|
+
process4.env.GALLERY_OUTPUT_DIR = path.join(galleryDir, "gallery");
|
|
828
887
|
execSync("npx astro build", { cwd: templateDir, stdio: ui.level === LogLevels.debug ? "inherit" : "ignore" });
|
|
829
888
|
} catch (error) {
|
|
830
889
|
ui.error(`Build failed for ${galleryDir}`);
|
|
831
890
|
throw error;
|
|
832
891
|
}
|
|
833
|
-
const outputDir =
|
|
834
|
-
const buildDir =
|
|
892
|
+
const outputDir = path.join(galleryDir, "gallery");
|
|
893
|
+
const buildDir = path.join(outputDir, "_build");
|
|
835
894
|
ui.debug(`Copying build output to ${outputDir}`);
|
|
836
895
|
fs8.cpSync(buildDir, outputDir, { recursive: true });
|
|
837
896
|
ui.debug("Moving index.html to gallery directory");
|
|
838
|
-
fs8.copyFileSync(
|
|
839
|
-
fs8.rmSync(
|
|
897
|
+
fs8.copyFileSync(path.join(outputDir, "index.html"), path.join(galleryDir, "index.html"));
|
|
898
|
+
fs8.rmSync(path.join(outputDir, "index.html"));
|
|
840
899
|
ui.debug("Cleaning up build directory");
|
|
841
900
|
fs8.rmSync(buildDir, { recursive: true, force: true });
|
|
842
901
|
ui.success(`Gallery built successfully`);
|
|
@@ -849,12 +908,12 @@ async function build(options, ui) {
|
|
|
849
908
|
return { processedGalleryCount: 0 };
|
|
850
909
|
}
|
|
851
910
|
const themePath = await import.meta.resolve("@simple-photo-gallery/theme-modern/package.json");
|
|
852
|
-
const themeDir =
|
|
911
|
+
const themeDir = path.dirname(new URL(themePath).pathname);
|
|
853
912
|
let totalGalleries = 0;
|
|
854
913
|
for (const dir of galleryDirs) {
|
|
855
|
-
const baseUrl = options.baseUrl ? `${options.baseUrl}${
|
|
856
|
-
const thumbsBaseUrl = options.thumbsBaseUrl ? `${options.thumbsBaseUrl}${
|
|
857
|
-
await buildGallery(
|
|
914
|
+
const baseUrl = options.baseUrl ? `${options.baseUrl}${path.relative(options.gallery, dir)}` : void 0;
|
|
915
|
+
const thumbsBaseUrl = options.thumbsBaseUrl ? `${options.thumbsBaseUrl}${path.relative(options.gallery, dir)}` : void 0;
|
|
916
|
+
await buildGallery(path.resolve(dir), themeDir, options.scan, options.thumbnails, ui, baseUrl, thumbsBaseUrl);
|
|
858
917
|
++totalGalleries;
|
|
859
918
|
}
|
|
860
919
|
ui.box(`Built ${totalGalleries} ${totalGalleries === 1 ? "gallery" : "galleries"} successfully`);
|
|
@@ -870,7 +929,7 @@ async function build(options, ui) {
|
|
|
870
929
|
}
|
|
871
930
|
async function cleanGallery(galleryDir, ui) {
|
|
872
931
|
let filesRemoved = 0;
|
|
873
|
-
const indexHtmlPath =
|
|
932
|
+
const indexHtmlPath = path.join(galleryDir, "index.html");
|
|
874
933
|
if (fs8.existsSync(indexHtmlPath)) {
|
|
875
934
|
try {
|
|
876
935
|
fs8.rmSync(indexHtmlPath);
|
|
@@ -880,7 +939,7 @@ async function cleanGallery(galleryDir, ui) {
|
|
|
880
939
|
ui?.warn(`Failed to remove index.html: ${error}`);
|
|
881
940
|
}
|
|
882
941
|
}
|
|
883
|
-
const galleryPath =
|
|
942
|
+
const galleryPath = path.join(galleryDir, "gallery");
|
|
884
943
|
if (fs8.existsSync(galleryPath)) {
|
|
885
944
|
try {
|
|
886
945
|
fs8.rmSync(galleryPath, { recursive: true, force: true });
|
|
@@ -899,7 +958,7 @@ async function cleanGallery(galleryDir, ui) {
|
|
|
899
958
|
}
|
|
900
959
|
async function clean(options, ui) {
|
|
901
960
|
try {
|
|
902
|
-
const basePath =
|
|
961
|
+
const basePath = path.resolve(options.gallery);
|
|
903
962
|
if (!fs8.existsSync(basePath)) {
|
|
904
963
|
ui.error(`Directory does not exist: ${basePath}`);
|
|
905
964
|
return { processedGalleryCount: 0 };
|
|
@@ -948,7 +1007,7 @@ var ApiTelemetryClient = class {
|
|
|
948
1007
|
axios.post(this.endpoint, event, {
|
|
949
1008
|
headers: {
|
|
950
1009
|
"content-type": "application/json",
|
|
951
|
-
"user-agent": `simple-photo-gallery/${event.packageVersion} (${
|
|
1010
|
+
"user-agent": `simple-photo-gallery/${event.packageVersion} (${process4.platform}; ${process4.arch})`
|
|
952
1011
|
}
|
|
953
1012
|
});
|
|
954
1013
|
} catch {
|
|
@@ -985,11 +1044,11 @@ var TelemetryService = class {
|
|
|
985
1044
|
if (override) {
|
|
986
1045
|
return override === "1";
|
|
987
1046
|
}
|
|
988
|
-
if (
|
|
1047
|
+
if (process4.env.CI || process4.env.DO_NOT_TRACK) {
|
|
989
1048
|
return false;
|
|
990
1049
|
}
|
|
991
|
-
if (
|
|
992
|
-
return
|
|
1050
|
+
if (process4.env.SPG_TELEMETRY) {
|
|
1051
|
+
return process4.env.SPG_TELEMETRY === "1";
|
|
993
1052
|
}
|
|
994
1053
|
const stored = this.getStoredPreference();
|
|
995
1054
|
if (stored === void 0) {
|
|
@@ -1031,7 +1090,7 @@ var TelemetryService = class {
|
|
|
1031
1090
|
durationMs: now - startedAt,
|
|
1032
1091
|
packageName: this.packageName,
|
|
1033
1092
|
packageVersion: this.packageVersion,
|
|
1034
|
-
nodeVersion:
|
|
1093
|
+
nodeVersion: process4.version,
|
|
1035
1094
|
osPlatform: os.platform(),
|
|
1036
1095
|
osRelease: os.release(),
|
|
1037
1096
|
osArch: os.arch(),
|
|
@@ -1065,7 +1124,7 @@ var TelemetryService = class {
|
|
|
1065
1124
|
/** Returns the telemetry client. */
|
|
1066
1125
|
getClient() {
|
|
1067
1126
|
if (!this.client) {
|
|
1068
|
-
switch (
|
|
1127
|
+
switch (process4.env.SPG_TELEMETRY_PROVIDER) {
|
|
1069
1128
|
case "none": {
|
|
1070
1129
|
this.client = void 0;
|
|
1071
1130
|
break;
|
|
@@ -1157,7 +1216,7 @@ async function waitForUpdateCheck(checkPromise) {
|
|
|
1157
1216
|
// package.json
|
|
1158
1217
|
var package_default = {
|
|
1159
1218
|
name: "simple-photo-gallery",
|
|
1160
|
-
version: "2.0.
|
|
1219
|
+
version: "2.0.12"};
|
|
1161
1220
|
|
|
1162
1221
|
// src/index.ts
|
|
1163
1222
|
var program = new Command();
|
|
@@ -1199,7 +1258,7 @@ function withCommandContext(handler) {
|
|
|
1199
1258
|
} catch (error) {
|
|
1200
1259
|
ui.debug(error);
|
|
1201
1260
|
errorInfo = error instanceof Error ? { name: error.name, message: error.message } : { name: "UnknownError", message: String(error) };
|
|
1202
|
-
|
|
1261
|
+
process4.exitCode = 1;
|
|
1203
1262
|
}
|
|
1204
1263
|
const updateInfo = await waitForUpdateCheck(updateCheckPromise);
|
|
1205
1264
|
if (updateInfo) {
|
|
@@ -1221,14 +1280,14 @@ function withCommandContext(handler) {
|
|
|
1221
1280
|
program.command("init").description("Initialize a gallery by scaning a folder for images and videos").option(
|
|
1222
1281
|
"-p, --photos <path>",
|
|
1223
1282
|
"Path to the folder where the photos are stored. Default: current working directory",
|
|
1224
|
-
|
|
1283
|
+
process4.cwd()
|
|
1225
1284
|
).option(
|
|
1226
1285
|
"-g, --gallery <path>",
|
|
1227
1286
|
"Path to the directory where the gallery will be initialized. Default: same directory as the photos folder"
|
|
1228
|
-
).option("-r, --recursive", "Recursively create galleries from all photos subdirectories", false).option("-d, --default", "Use default gallery settings instead of asking the user", false).option("-f, --force", "Force override existing galleries without asking", false).action(withCommandContext((options, ui) => init(options, ui)));
|
|
1229
|
-
program.command("thumbnails").description("Create thumbnails for all media files in the gallery").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory",
|
|
1230
|
-
program.command("build").description("Build the HTML gallery in the specified directory").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory",
|
|
1231
|
-
program.command("clean").description("Remove all gallery files and folders (index.html, gallery/)").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory",
|
|
1287
|
+
).option("-r, --recursive", "Recursively create galleries from all photos subdirectories", false).option("-d, --default", "Use default gallery settings instead of asking the user", false).option("-f, --force", "Force override existing galleries without asking", false).option("--cta-banner", "Add a Simple Photo Gallery call-to-action banner to the end of the gallery", false).action(withCommandContext((options, ui) => init(options, ui)));
|
|
1288
|
+
program.command("thumbnails").description("Create thumbnails for all media files in the gallery").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory", process4.cwd()).option("-r, --recursive", "Scan subdirectories recursively", false).action(withCommandContext((options, ui) => thumbnails(options, ui)));
|
|
1289
|
+
program.command("build").description("Build the HTML gallery in the specified directory").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory", process4.cwd()).option("-r, --recursive", "Scan subdirectories recursively", false).option("-b, --base-url <url>", "Base URL where the photos are hosted").option("-t, --thumbs-base-url <url>", "Base URL where the thumbnails are hosted").option("--no-thumbnails", "Skip creating thumbnails when building the gallery", true).option("--no-scan", "Do not scan for new photos when building the gallery", true).action(withCommandContext((options, ui) => build(options, ui)));
|
|
1290
|
+
program.command("clean").description("Remove all gallery files and folders (index.html, gallery/)").option("-g, --gallery <path>", "Path to the directory of the gallery. Default: current working directory", process4.cwd()).option("-r, --recursive", "Clean subdirectories recursively", false).action(withCommandContext((options, ui) => clean(options, ui)));
|
|
1232
1291
|
program.command("telemetry").description("Manage anonymous telemetry preferences. Use 1 to enable, 0 to disable, or no argument to check status").option("-s, --state <state>", "Enable (1) or disable (0) telemetry", parseTelemetryOption).action(withCommandContext((options, ui) => telemetry(options, ui, telemetryService)));
|
|
1233
1292
|
program.parse();
|
|
1234
1293
|
//# sourceMappingURL=index.js.map
|