simple-photo-gallery 2.0.10 → 2.0.11-rc.10
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/index.cjs +1250 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.js +82 -163
- package/dist/index.js.map +1 -1
- package/dist/lib/index.cjs +166 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +97 -0
- package/dist/lib/index.d.ts +97 -0
- package/dist/lib/index.js +148 -0
- package/dist/lib/index.js.map +1 -0
- package/package.json +20 -4
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import path7 from 'path';
|
|
|
8
8
|
import { Buffer } from 'buffer';
|
|
9
9
|
import sharp2 from 'sharp';
|
|
10
10
|
import { encode } from 'blurhash';
|
|
11
|
+
import { GalleryDataSchema, GalleryDataDeprecatedSchema } from '@simple-photo-gallery/common';
|
|
11
12
|
import ExifReader from 'exifreader';
|
|
12
|
-
import { z } from 'zod';
|
|
13
13
|
import ffprobe from 'node-ffprobe';
|
|
14
14
|
import os from 'os';
|
|
15
15
|
import Conf from 'conf';
|
|
@@ -46,22 +46,6 @@ async function cropAndResizeImage(image, outputPath, width, height, format = "av
|
|
|
46
46
|
withoutEnlargement: true
|
|
47
47
|
}).toFormat(format).toFile(outputPath);
|
|
48
48
|
}
|
|
49
|
-
async function getImageDescription(imagePath) {
|
|
50
|
-
try {
|
|
51
|
-
const tags = await ExifReader.load(imagePath);
|
|
52
|
-
if (tags.description?.description) return tags.description.description;
|
|
53
|
-
if (tags.ImageDescription?.description) return tags.ImageDescription.description;
|
|
54
|
-
if (tags.UserComment && typeof tags.UserComment === "object" && tags.UserComment !== null && "description" in tags.UserComment) {
|
|
55
|
-
return tags.UserComment.description;
|
|
56
|
-
}
|
|
57
|
-
if (tags.ExtDescrAccessibility?.description) return tags.ExtDescrAccessibility.description;
|
|
58
|
-
if (tags["Caption/Abstract"]?.description) return tags["Caption/Abstract"].description;
|
|
59
|
-
if (tags.XPTitle?.description) return tags.XPTitle.description;
|
|
60
|
-
if (tags.XPComment?.description) return tags.XPComment.description;
|
|
61
|
-
} catch {
|
|
62
|
-
return void 0;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
49
|
async function createImageThumbnails(image, metadata, outputPath, outputPathRetina, size) {
|
|
66
50
|
const originalWidth = metadata.width || 0;
|
|
67
51
|
const originalHeight = metadata.height || 0;
|
|
@@ -94,10 +78,10 @@ async function generateBlurHash(imagePath, componentX = 4, componentY = 3) {
|
|
|
94
78
|
// src/modules/build/utils/index.ts
|
|
95
79
|
path7.dirname(new URL(import.meta.url).pathname);
|
|
96
80
|
async function createGallerySocialMediaCardImage(headerPhotoPath, title, ouputPath, ui) {
|
|
97
|
-
ui
|
|
81
|
+
ui?.start(`Creating social media card image`);
|
|
98
82
|
const headerBasename = path7.basename(headerPhotoPath, path7.extname(headerPhotoPath));
|
|
99
83
|
if (fs8.existsSync(ouputPath)) {
|
|
100
|
-
ui
|
|
84
|
+
ui?.success(`Social media card image already exists`);
|
|
101
85
|
return headerBasename;
|
|
102
86
|
}
|
|
103
87
|
const image = await loadImage(headerPhotoPath);
|
|
@@ -116,23 +100,23 @@ async function createGallerySocialMediaCardImage(headerPhotoPath, title, ouputPa
|
|
|
116
100
|
`;
|
|
117
101
|
const finalImageBuffer = await sharp2(resizedImageBuffer).composite([{ input: Buffer.from(svgText), top: 0, left: 0 }]).jpeg({ quality: 90 }).toBuffer();
|
|
118
102
|
await sharp2(finalImageBuffer).toFile(outputPath);
|
|
119
|
-
ui
|
|
103
|
+
ui?.success(`Created social media card image successfully`);
|
|
120
104
|
return headerBasename;
|
|
121
105
|
}
|
|
122
106
|
async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
123
|
-
ui
|
|
107
|
+
ui?.start(`Creating optimized header images`);
|
|
124
108
|
const image = await loadImage(headerPhotoPath);
|
|
125
109
|
const headerBasename = path7.basename(headerPhotoPath, path7.extname(headerPhotoPath));
|
|
126
110
|
const generatedFiles = [];
|
|
127
|
-
ui
|
|
111
|
+
ui?.debug("Generating blurhash for header image");
|
|
128
112
|
const blurHash = await generateBlurHash(headerPhotoPath);
|
|
129
113
|
const landscapeYFactor = 3 / 4;
|
|
130
114
|
for (const width of HEADER_IMAGE_LANDSCAPE_WIDTHS) {
|
|
131
|
-
ui
|
|
115
|
+
ui?.debug(`Creating landscape header image ${width}`);
|
|
132
116
|
const avifFilename = `${headerBasename}_landscape_${width}.avif`;
|
|
133
117
|
const jpgFilename = `${headerBasename}_landscape_${width}.jpg`;
|
|
134
118
|
if (fs8.existsSync(path7.join(outputFolder, avifFilename))) {
|
|
135
|
-
ui
|
|
119
|
+
ui?.debug(`Landscape header image ${width} AVIF already exists`);
|
|
136
120
|
} else {
|
|
137
121
|
await cropAndResizeImage(
|
|
138
122
|
image.clone(),
|
|
@@ -144,7 +128,7 @@ async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
|
144
128
|
}
|
|
145
129
|
generatedFiles.push(avifFilename);
|
|
146
130
|
if (fs8.existsSync(path7.join(outputFolder, jpgFilename))) {
|
|
147
|
-
ui
|
|
131
|
+
ui?.debug(`Landscape header image ${width} JPG already exists`);
|
|
148
132
|
} else {
|
|
149
133
|
await cropAndResizeImage(image.clone(), path7.join(outputFolder, jpgFilename), width, width * landscapeYFactor, "jpg");
|
|
150
134
|
}
|
|
@@ -152,23 +136,23 @@ async function createOptimizedHeaderImage(headerPhotoPath, outputFolder, ui) {
|
|
|
152
136
|
}
|
|
153
137
|
const portraitYFactor = 4 / 3;
|
|
154
138
|
for (const width of HEADER_IMAGE_PORTRAIT_WIDTHS) {
|
|
155
|
-
ui
|
|
139
|
+
ui?.debug(`Creating portrait header image ${width}`);
|
|
156
140
|
const avifFilename = `${headerBasename}_portrait_${width}.avif`;
|
|
157
141
|
const jpgFilename = `${headerBasename}_portrait_${width}.jpg`;
|
|
158
142
|
if (fs8.existsSync(path7.join(outputFolder, avifFilename))) {
|
|
159
|
-
ui
|
|
143
|
+
ui?.debug(`Portrait header image ${width} AVIF already exists`);
|
|
160
144
|
} else {
|
|
161
145
|
await cropAndResizeImage(image.clone(), path7.join(outputFolder, avifFilename), width, width * portraitYFactor, "avif");
|
|
162
146
|
}
|
|
163
147
|
generatedFiles.push(avifFilename);
|
|
164
148
|
if (fs8.existsSync(path7.join(outputFolder, jpgFilename))) {
|
|
165
|
-
ui
|
|
149
|
+
ui?.debug(`Portrait header image ${width} JPG already exists`);
|
|
166
150
|
} else {
|
|
167
151
|
await cropAndResizeImage(image.clone(), path7.join(outputFolder, jpgFilename), width, width * portraitYFactor, "jpg");
|
|
168
152
|
}
|
|
169
153
|
generatedFiles.push(jpgFilename);
|
|
170
154
|
}
|
|
171
|
-
ui
|
|
155
|
+
ui?.success(`Created optimized header image successfully`);
|
|
172
156
|
return { headerBasename, generatedFiles, blurHash };
|
|
173
157
|
}
|
|
174
158
|
function hasOldHeaderImages(outputFolder, currentHeaderBasename) {
|
|
@@ -186,9 +170,9 @@ function hasOldHeaderImages(outputFolder, currentHeaderBasename) {
|
|
|
186
170
|
return false;
|
|
187
171
|
}
|
|
188
172
|
function cleanupOldHeaderImages(outputFolder, currentHeaderBasename, ui) {
|
|
189
|
-
ui
|
|
173
|
+
ui?.start(`Cleaning up old header images`);
|
|
190
174
|
if (!fs8.existsSync(outputFolder)) {
|
|
191
|
-
ui
|
|
175
|
+
ui?.debug(`Output folder ${outputFolder} does not exist, skipping cleanup`);
|
|
192
176
|
return;
|
|
193
177
|
}
|
|
194
178
|
const files = fs8.readdirSync(outputFolder);
|
|
@@ -198,20 +182,20 @@ function cleanupOldHeaderImages(outputFolder, currentHeaderBasename, ui) {
|
|
|
198
182
|
const portraitMatch = file.match(/^(.+)_portrait_\d+\.(avif|jpg)$/);
|
|
199
183
|
if (landscapeMatch && landscapeMatch[1] !== currentHeaderBasename) {
|
|
200
184
|
const filePath = path7.join(outputFolder, file);
|
|
201
|
-
ui
|
|
185
|
+
ui?.debug(`Deleting old landscape header image: ${file}`);
|
|
202
186
|
fs8.unlinkSync(filePath);
|
|
203
187
|
deletedCount++;
|
|
204
188
|
} else if (portraitMatch && portraitMatch[1] !== currentHeaderBasename) {
|
|
205
189
|
const filePath = path7.join(outputFolder, file);
|
|
206
|
-
ui
|
|
190
|
+
ui?.debug(`Deleting old portrait header image: ${file}`);
|
|
207
191
|
fs8.unlinkSync(filePath);
|
|
208
192
|
deletedCount++;
|
|
209
193
|
}
|
|
210
194
|
}
|
|
211
195
|
if (deletedCount > 0) {
|
|
212
|
-
ui
|
|
196
|
+
ui?.success(`Deleted ${deletedCount} old header image(s)`);
|
|
213
197
|
} else {
|
|
214
|
-
ui
|
|
198
|
+
ui?.debug(`No old header images to clean up`);
|
|
215
199
|
}
|
|
216
200
|
}
|
|
217
201
|
function findGalleries(basePath, recursive) {
|
|
@@ -253,89 +237,6 @@ function parseTelemetryOption(value) {
|
|
|
253
237
|
}
|
|
254
238
|
return value;
|
|
255
239
|
}
|
|
256
|
-
var ThumbnailSchema = z.object({
|
|
257
|
-
path: z.string(),
|
|
258
|
-
pathRetina: z.string(),
|
|
259
|
-
width: z.number(),
|
|
260
|
-
height: z.number(),
|
|
261
|
-
blurHash: z.string().optional()
|
|
262
|
-
});
|
|
263
|
-
var MediaFileSchema = z.object({
|
|
264
|
-
type: z.enum(["image", "video"]),
|
|
265
|
-
filename: z.string(),
|
|
266
|
-
alt: z.string().optional(),
|
|
267
|
-
width: z.number(),
|
|
268
|
-
height: z.number(),
|
|
269
|
-
thumbnail: ThumbnailSchema.optional(),
|
|
270
|
-
lastMediaTimestamp: z.string().optional()
|
|
271
|
-
});
|
|
272
|
-
var MediaFileDeprecatedSchema = z.object({
|
|
273
|
-
type: z.enum(["image", "video"]),
|
|
274
|
-
path: z.string(),
|
|
275
|
-
alt: z.string().optional(),
|
|
276
|
-
width: z.number(),
|
|
277
|
-
height: z.number(),
|
|
278
|
-
thumbnail: ThumbnailSchema.optional(),
|
|
279
|
-
lastMediaTimestamp: z.string().optional()
|
|
280
|
-
});
|
|
281
|
-
var GallerySectionSchema = z.object({
|
|
282
|
-
title: z.string().optional(),
|
|
283
|
-
description: z.string().optional(),
|
|
284
|
-
images: z.array(MediaFileSchema)
|
|
285
|
-
});
|
|
286
|
-
var GallerySectionDeprecatedSchema = z.object({
|
|
287
|
-
title: z.string().optional(),
|
|
288
|
-
description: z.string().optional(),
|
|
289
|
-
images: z.array(MediaFileDeprecatedSchema)
|
|
290
|
-
});
|
|
291
|
-
var SubGallerySchema = z.object({
|
|
292
|
-
title: z.string(),
|
|
293
|
-
headerImage: z.string(),
|
|
294
|
-
path: z.string()
|
|
295
|
-
});
|
|
296
|
-
var GalleryMetadataSchema = z.object({
|
|
297
|
-
image: z.string().optional(),
|
|
298
|
-
imageWidth: z.number().optional(),
|
|
299
|
-
imageHeight: z.number().optional(),
|
|
300
|
-
ogUrl: z.string().optional(),
|
|
301
|
-
ogType: z.string().optional(),
|
|
302
|
-
ogSiteName: z.string().optional(),
|
|
303
|
-
twitterSite: z.string().optional(),
|
|
304
|
-
twitterCreator: z.string().optional(),
|
|
305
|
-
author: z.string().optional(),
|
|
306
|
-
keywords: z.string().optional(),
|
|
307
|
-
canonicalUrl: z.string().optional(),
|
|
308
|
-
language: z.string().optional(),
|
|
309
|
-
robots: z.string().optional()
|
|
310
|
-
});
|
|
311
|
-
var GalleryDataSchema = z.object({
|
|
312
|
-
title: z.string(),
|
|
313
|
-
description: z.string(),
|
|
314
|
-
mediaBasePath: z.string().optional(),
|
|
315
|
-
url: z.string().optional(),
|
|
316
|
-
headerImage: z.string(),
|
|
317
|
-
headerImageBlurHash: z.string().optional(),
|
|
318
|
-
thumbnailSize: z.number().optional(),
|
|
319
|
-
metadata: GalleryMetadataSchema,
|
|
320
|
-
mediaBaseUrl: z.string().optional(),
|
|
321
|
-
analyticsScript: z.string().optional(),
|
|
322
|
-
sections: z.array(GallerySectionSchema),
|
|
323
|
-
subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
|
|
324
|
-
});
|
|
325
|
-
var GalleryDataDeprecatedSchema = z.object({
|
|
326
|
-
title: z.string(),
|
|
327
|
-
description: z.string(),
|
|
328
|
-
url: z.string().optional(),
|
|
329
|
-
headerImage: z.string(),
|
|
330
|
-
thumbnailSize: z.number().optional(),
|
|
331
|
-
metadata: GalleryMetadataSchema,
|
|
332
|
-
mediaBaseUrl: z.string().optional(),
|
|
333
|
-
analyticsScript: z.string().optional(),
|
|
334
|
-
sections: z.array(GallerySectionDeprecatedSchema),
|
|
335
|
-
subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
// src/utils/gallery.ts
|
|
339
240
|
function parseGalleryJson(galleryJsonPath, ui) {
|
|
340
241
|
let galleryContent;
|
|
341
242
|
try {
|
|
@@ -582,6 +483,22 @@ async function getFileMtime(filePath) {
|
|
|
582
483
|
const stats = await promises.stat(filePath);
|
|
583
484
|
return stats.mtime;
|
|
584
485
|
}
|
|
486
|
+
async function getImageDescription(image) {
|
|
487
|
+
try {
|
|
488
|
+
const tags = await ExifReader.load(image);
|
|
489
|
+
if (tags.description?.description) return tags.description.description;
|
|
490
|
+
if (tags.ImageDescription?.description) return tags.ImageDescription.description;
|
|
491
|
+
if (tags.UserComment && typeof tags.UserComment === "object" && tags.UserComment !== null && "description" in tags.UserComment) {
|
|
492
|
+
return tags.UserComment.description;
|
|
493
|
+
}
|
|
494
|
+
if (tags.ExtDescrAccessibility?.description) return tags.ExtDescrAccessibility.description;
|
|
495
|
+
if (tags["Caption/Abstract"]?.description) return tags["Caption/Abstract"].description;
|
|
496
|
+
if (tags.XPTitle?.description) return tags.XPTitle.description;
|
|
497
|
+
if (tags.XPComment?.description) return tags.XPComment.description;
|
|
498
|
+
} catch {
|
|
499
|
+
return void 0;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
585
502
|
async function getVideoDimensions(filePath) {
|
|
586
503
|
const data = await ffprobe(filePath);
|
|
587
504
|
const videoStream = data.streams.find((stream) => stream.codec_type === "video");
|
|
@@ -709,17 +626,14 @@ async function processVideo(videoPath, thumbnailPath, thumbnailPathRetina, thumb
|
|
|
709
626
|
lastMediaTimestamp: fileMtime.toISOString()
|
|
710
627
|
};
|
|
711
628
|
}
|
|
712
|
-
async function processMediaFile(mediaFile, mediaBasePath,
|
|
629
|
+
async function processMediaFile(mediaFile, mediaBasePath, thumbnailsPath, thumbnailSize, ui) {
|
|
713
630
|
try {
|
|
714
631
|
const filePath = path7.resolve(path7.join(mediaBasePath, mediaFile.filename));
|
|
715
632
|
const fileName = mediaFile.filename;
|
|
716
633
|
const fileNameWithoutExt = path7.parse(fileName).name;
|
|
717
|
-
const galleryJsonDir = path7.join(galleryDir, "gallery");
|
|
718
634
|
const thumbnailFileName = `${fileNameWithoutExt}.avif`;
|
|
719
635
|
const thumbnailPath = path7.join(thumbnailsPath, thumbnailFileName);
|
|
720
636
|
const thumbnailPathRetina = thumbnailPath.replace(".avif", "@2x.avif");
|
|
721
|
-
const relativeThumbnailPath = path7.relative(galleryJsonDir, thumbnailPath);
|
|
722
|
-
const relativeThumbnailRetinaPath = path7.relative(galleryJsonDir, thumbnailPathRetina);
|
|
723
637
|
const lastMediaTimestamp = mediaFile.lastMediaTimestamp ? new Date(mediaFile.lastMediaTimestamp) : void 0;
|
|
724
638
|
const verbose = ui.level === LogLevels.debug;
|
|
725
639
|
ui.debug(` Processing ${mediaFile.type}: ${fileName}`);
|
|
@@ -744,8 +658,8 @@ async function processMediaFile(mediaFile, mediaBasePath, galleryDir, thumbnails
|
|
|
744
658
|
}
|
|
745
659
|
updatedMediaFile.filename = mediaFile.filename;
|
|
746
660
|
if (updatedMediaFile.thumbnail) {
|
|
747
|
-
updatedMediaFile.thumbnail.path =
|
|
748
|
-
updatedMediaFile.thumbnail.pathRetina =
|
|
661
|
+
updatedMediaFile.thumbnail.path = path7.basename(thumbnailPath);
|
|
662
|
+
updatedMediaFile.thumbnail.pathRetina = path7.basename(thumbnailPathRetina);
|
|
749
663
|
}
|
|
750
664
|
return updatedMediaFile;
|
|
751
665
|
} catch (error) {
|
|
@@ -765,14 +679,7 @@ async function processGalleryThumbnails(galleryDir, ui) {
|
|
|
765
679
|
let processedCount = 0;
|
|
766
680
|
for (const section of galleryData.sections) {
|
|
767
681
|
for (const [index, mediaFile] of section.images.entries()) {
|
|
768
|
-
section.images[index] = await processMediaFile(
|
|
769
|
-
mediaFile,
|
|
770
|
-
mediaBasePath,
|
|
771
|
-
galleryDir,
|
|
772
|
-
thumbnailsPath,
|
|
773
|
-
thumbnailSize,
|
|
774
|
-
ui
|
|
775
|
-
);
|
|
682
|
+
section.images[index] = await processMediaFile(mediaFile, mediaBasePath, thumbnailsPath, thumbnailSize, ui);
|
|
776
683
|
}
|
|
777
684
|
processedCount += section.images.length;
|
|
778
685
|
}
|
|
@@ -853,7 +760,7 @@ async function scanAndAppendNewFiles(galleryDir, galleryJsonPath, galleryData, u
|
|
|
853
760
|
}
|
|
854
761
|
return galleryData;
|
|
855
762
|
}
|
|
856
|
-
async function buildGallery(galleryDir, templateDir, scan, ui, baseUrl) {
|
|
763
|
+
async function buildGallery(galleryDir, templateDir, scan, shouldCreateThumbnails, ui, baseUrl, thumbsBaseUrl) {
|
|
857
764
|
ui.start(`Building gallery ${galleryDir}`);
|
|
858
765
|
const galleryJsonPath = path7.join(galleryDir, "gallery", "gallery.json");
|
|
859
766
|
let galleryData = parseGalleryJson(galleryJsonPath, ui);
|
|
@@ -866,26 +773,26 @@ async function buildGallery(galleryDir, templateDir, scan, ui, baseUrl) {
|
|
|
866
773
|
const headerImagePath = mediaBasePath ? path7.join(mediaBasePath, galleryData.headerImage) : path7.resolve(galleryDir, galleryData.headerImage);
|
|
867
774
|
const imagesFolder = path7.join(galleryDir, "gallery", "images");
|
|
868
775
|
const currentHeaderBasename = path7.basename(headerImagePath, path7.extname(headerImagePath));
|
|
869
|
-
if (
|
|
870
|
-
fs8.
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
fs8.
|
|
878
|
-
|
|
776
|
+
if (shouldCreateThumbnails) {
|
|
777
|
+
if (!fs8.existsSync(imagesFolder)) {
|
|
778
|
+
fs8.mkdirSync(imagesFolder, { recursive: true });
|
|
779
|
+
}
|
|
780
|
+
const headerImageChanged = hasOldHeaderImages(imagesFolder, currentHeaderBasename);
|
|
781
|
+
if (headerImageChanged) {
|
|
782
|
+
ui.info("Header image changed, cleaning up old assets");
|
|
783
|
+
cleanupOldHeaderImages(imagesFolder, currentHeaderBasename, ui);
|
|
784
|
+
if (fs8.existsSync(socialMediaCardImagePath)) {
|
|
785
|
+
fs8.unlinkSync(socialMediaCardImagePath);
|
|
786
|
+
ui.debug("Deleted old social media card");
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
await createGallerySocialMediaCardImage(headerImagePath, galleryData.title, socialMediaCardImagePath, ui);
|
|
790
|
+
const { blurHash } = await createOptimizedHeaderImage(headerImagePath, imagesFolder, ui);
|
|
791
|
+
if (galleryData.headerImageBlurHash !== blurHash) {
|
|
792
|
+
ui.debug("Updating gallery.json with header image blurhash");
|
|
793
|
+
galleryData.headerImageBlurHash = blurHash;
|
|
794
|
+
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
879
795
|
}
|
|
880
|
-
}
|
|
881
|
-
await createGallerySocialMediaCardImage(headerImagePath, galleryData.title, socialMediaCardImagePath, ui);
|
|
882
|
-
galleryData.metadata.image = galleryData.metadata.image || `${galleryData.url || ""}/${path7.relative(galleryDir, socialMediaCardImagePath)}`;
|
|
883
|
-
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
884
|
-
const { blurHash } = await createOptimizedHeaderImage(headerImagePath, imagesFolder, ui);
|
|
885
|
-
if (galleryData.headerImageBlurHash !== blurHash) {
|
|
886
|
-
ui.debug("Updating gallery.json with header image blurhash");
|
|
887
|
-
galleryData.headerImageBlurHash = blurHash;
|
|
888
|
-
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
889
796
|
}
|
|
890
797
|
if (!mediaBaseUrl && mediaBasePath) {
|
|
891
798
|
const shouldCopyPhotos = await ui.prompt("All photos need to be copied. Are you sure you want to continue?", {
|
|
@@ -901,7 +808,19 @@ async function buildGallery(galleryDir, templateDir, scan, ui, baseUrl) {
|
|
|
901
808
|
galleryData.mediaBaseUrl = mediaBaseUrl;
|
|
902
809
|
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
903
810
|
}
|
|
904
|
-
|
|
811
|
+
if (thumbsBaseUrl && galleryData.thumbsBaseUrl !== thumbsBaseUrl) {
|
|
812
|
+
ui.debug("Updating gallery.json with thumbsBaseUrl");
|
|
813
|
+
galleryData.thumbsBaseUrl = thumbsBaseUrl;
|
|
814
|
+
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
815
|
+
}
|
|
816
|
+
if (!galleryData.metadata.image) {
|
|
817
|
+
ui.debug("Updating gallery.json with social media card URL");
|
|
818
|
+
galleryData.metadata.image = thumbsBaseUrl ? `${thumbsBaseUrl}/${path7.basename(socialMediaCardImagePath)}` : `${galleryData.url || ""}/${path7.relative(galleryDir, socialMediaCardImagePath)}`;
|
|
819
|
+
fs8.writeFileSync(galleryJsonPath, JSON.stringify(galleryData, null, 2));
|
|
820
|
+
}
|
|
821
|
+
if (shouldCreateThumbnails) {
|
|
822
|
+
await processGalleryThumbnails(galleryDir, ui);
|
|
823
|
+
}
|
|
905
824
|
ui.debug("Building gallery from template");
|
|
906
825
|
try {
|
|
907
826
|
process3.env.GALLERY_JSON_PATH = galleryJsonPath;
|
|
@@ -923,7 +842,6 @@ async function buildGallery(galleryDir, templateDir, scan, ui, baseUrl) {
|
|
|
923
842
|
ui.success(`Gallery built successfully`);
|
|
924
843
|
}
|
|
925
844
|
async function build(options, ui) {
|
|
926
|
-
console.log("DBG: options", options);
|
|
927
845
|
try {
|
|
928
846
|
const galleryDirs = findGalleries(options.gallery, options.recursive);
|
|
929
847
|
if (galleryDirs.length === 0) {
|
|
@@ -935,7 +853,8 @@ async function build(options, ui) {
|
|
|
935
853
|
let totalGalleries = 0;
|
|
936
854
|
for (const dir of galleryDirs) {
|
|
937
855
|
const baseUrl = options.baseUrl ? `${options.baseUrl}${path7.relative(options.gallery, dir)}` : void 0;
|
|
938
|
-
|
|
856
|
+
const thumbsBaseUrl = options.thumbsBaseUrl ? `${options.thumbsBaseUrl}${path7.relative(options.gallery, dir)}` : void 0;
|
|
857
|
+
await buildGallery(path7.resolve(dir), themeDir, options.scan, options.thumbnails, ui, baseUrl, thumbsBaseUrl);
|
|
939
858
|
++totalGalleries;
|
|
940
859
|
}
|
|
941
860
|
ui.box(`Built ${totalGalleries} ${totalGalleries === 1 ? "gallery" : "galleries"} successfully`);
|
|
@@ -955,26 +874,26 @@ async function cleanGallery(galleryDir, ui) {
|
|
|
955
874
|
if (fs8.existsSync(indexHtmlPath)) {
|
|
956
875
|
try {
|
|
957
876
|
fs8.rmSync(indexHtmlPath);
|
|
958
|
-
ui
|
|
877
|
+
ui?.debug(`Removed: ${indexHtmlPath}`);
|
|
959
878
|
filesRemoved++;
|
|
960
879
|
} catch (error) {
|
|
961
|
-
ui
|
|
880
|
+
ui?.warn(`Failed to remove index.html: ${error}`);
|
|
962
881
|
}
|
|
963
882
|
}
|
|
964
883
|
const galleryPath = path7.join(galleryDir, "gallery");
|
|
965
884
|
if (fs8.existsSync(galleryPath)) {
|
|
966
885
|
try {
|
|
967
886
|
fs8.rmSync(galleryPath, { recursive: true, force: true });
|
|
968
|
-
ui
|
|
887
|
+
ui?.debug(`Removed directory: ${galleryPath}`);
|
|
969
888
|
filesRemoved++;
|
|
970
889
|
} catch (error) {
|
|
971
|
-
ui
|
|
890
|
+
ui?.warn(`Failed to remove gallery directory: ${error}`);
|
|
972
891
|
}
|
|
973
892
|
}
|
|
974
893
|
if (filesRemoved > 0) {
|
|
975
|
-
ui
|
|
894
|
+
ui?.success(`Cleaned gallery at: ${galleryDir}`);
|
|
976
895
|
} else {
|
|
977
|
-
ui
|
|
896
|
+
ui?.info(`No gallery files found at: ${galleryDir}`);
|
|
978
897
|
}
|
|
979
898
|
return { processedGalleryCount: filesRemoved };
|
|
980
899
|
}
|
|
@@ -1238,7 +1157,7 @@ async function waitForUpdateCheck(checkPromise) {
|
|
|
1238
1157
|
// package.json
|
|
1239
1158
|
var package_default = {
|
|
1240
1159
|
name: "simple-photo-gallery",
|
|
1241
|
-
version: "2.0.10"};
|
|
1160
|
+
version: "2.0.11-rc.10"};
|
|
1242
1161
|
|
|
1243
1162
|
// src/index.ts
|
|
1244
1163
|
var program = new Command();
|
|
@@ -1308,7 +1227,7 @@ program.command("init").description("Initialize a gallery by scaning a folder fo
|
|
|
1308
1227
|
"Path to the directory where the gallery will be initialized. Default: same directory as the photos folder"
|
|
1309
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)));
|
|
1310
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", process3.cwd()).option("-r, --recursive", "Scan subdirectories recursively", false).action(withCommandContext((options, ui) => thumbnails(options, ui)));
|
|
1311
|
-
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", process3.cwd()).option("-r, --recursive", "Scan subdirectories recursively", false).option("-b, --base-url <url>", "Base URL where the photos are hosted").option("--no-scan", "Do not scan for new photos when
|
|
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", process3.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)));
|
|
1312
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", process3.cwd()).option("-r, --recursive", "Clean subdirectories recursively", false).action(withCommandContext((options, ui) => clean(options, ui)));
|
|
1313
1232
|
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)));
|
|
1314
1233
|
program.parse();
|