11import fs from 'node:fs/promises' ;
22import path from 'node:path' ;
33import sharp from 'sharp' ;
4+ import { config } from './config.js' ;
45
56const IMG_EXTS = new Set ( [ '.jpg' , '.jpeg' , '.png' , '.webp' , '.tif' , '.tiff' , '.bmp' ] ) ;
67
@@ -11,12 +12,12 @@ function parseArgs(argv) {
1112 if ( a . startsWith ( '--quality=' ) ) opts . quality = Number ( a . split ( '=' ) [ 1 ] ) || 75 ;
1213 else args . push ( a ) ;
1314 }
14- if ( args . length < 2 ) {
15- console . error ( 'Usage: node gen-webp-sizes.mjs <inputDir> <outputDir > [--quality=75]' ) ;
15+ if ( args . length < 1 ) {
16+ console . error ( 'Usage: node gen-webp-sizes.mjs <inputDirInsideContent > [--quality=75]' ) ;
1617 process . exit ( 1 ) ;
1718 }
18- const [ inputDir , outputDir ] = args . map ( p => path . resolve ( p ) ) ;
19- return { inputDir, outputDir , ...opts } ;
19+ const inputDir = path . resolve ( args [ 0 ] ) ;
20+ return { inputDir, ...opts } ;
2021}
2122
2223async function ensureDir ( dir ) {
@@ -49,10 +50,10 @@ function targetWidthsFor(originalWidth) {
4950 return targets ;
5051}
5152
52- function outPathFor ( inputDir , outputDir , absFile , width ) {
53- const rel = path . relative ( inputDir , absFile ) ;
54- const { dir, name } = path . parse ( rel ) ;
55- const outDir = path . join ( outputDir , dir ) ;
53+ function outPathFor ( contentRoot , imagesRoot , absFile , width ) {
54+ const relFromContent = path . relative ( contentRoot , absFile ) ;
55+ const { dir, name } = path . parse ( relFromContent ) ;
56+ const outDir = path . join ( imagesRoot , dir ) ;
5657 const outFile = path . join ( outDir , `${ name } -${ width } .webp` ) ;
5758 return { outDir, outFile } ;
5859}
@@ -67,7 +68,7 @@ async function fileNewerOrEqual(a, b) {
6768 }
6869}
6970
70- async function processImage ( absIn , inputDir , outputDir , quality ) {
71+ async function processImage ( absIn , contentRoot , imagesRoot , quality ) {
7172 const buf = await fs . readFile ( absIn ) ;
7273 const img = sharp ( buf ) . rotate ( ) ; // honor EXIF orientation
7374 const meta = await img . metadata ( ) ;
@@ -79,7 +80,7 @@ async function processImage(absIn, inputDir, outputDir, quality) {
7980 let created = 0 ;
8081 await Promise . all (
8182 targets . map ( async ( w ) => {
82- const { outDir, outFile } = outPathFor ( inputDir , outputDir , absIn , w ) ;
83+ const { outDir, outFile } = outPathFor ( contentRoot , imagesRoot , absIn , w ) ;
8384 await ensureDir ( outDir ) ;
8485
8586 // Skip if up-to-date
@@ -92,23 +93,34 @@ async function processImage(absIn, inputDir, outputDir, quality) {
9293 . toFile ( outFile ) ;
9394
9495 created += 1 ;
95- console . log ( `✓ ${ path . relative ( inputDir , absIn ) } -> ${ path . relative ( outputDir , outFile ) } ` ) ;
96+ console . log ( `✓ ${ path . relative ( contentRoot , absIn ) } -> ${ path . relative ( imagesRoot , outFile ) } ` ) ;
9697 } )
9798 ) ;
9899
99100 return { created, skipped : targets . length === 0 ? 1 : 0 } ;
100101}
101102
102103async function main ( ) {
103- const { inputDir, outputDir, quality } = parseArgs ( process . argv ) ;
104- await ensureDir ( outputDir ) ;
104+ const { inputDir, quality } = parseArgs ( process . argv ) ;
105+
106+ const contentRoot = path . resolve ( config . content_path ) ;
107+ const imagesRoot = path . join ( config . rootdir , 'public' , 'images' ) ;
108+
109+ const normInput = inputDir . replaceAll ( '\\' , '/' ) ;
110+ const normContent = contentRoot . replaceAll ( '\\' , '/' ) ;
111+ if ( ! normInput . startsWith ( normContent ) ) {
112+ console . error ( `Input directory must be inside content root: ${ contentRoot } ` ) ;
113+ process . exit ( 1 ) ;
114+ }
115+
116+ await ensureDir ( imagesRoot ) ;
105117
106118 let total = 0 , created = 0 , skipped = 0 ;
107- for await ( const f of walk ( inputDir , outputDir ) ) {
119+ for await ( const f of walk ( inputDir , imagesRoot ) ) {
108120 if ( ! isImageFile ( f ) ) continue ;
109121 total ++ ;
110122 try {
111- const res = await processImage ( f , inputDir , outputDir , quality ) ;
123+ const res = await processImage ( f , contentRoot , imagesRoot , quality ) ;
112124 created += res . created ;
113125 skipped += res . skipped ;
114126 } catch ( e ) {
0 commit comments