process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0' import * as path from 'path' import * as pMap from 'p-map' import { resolve } from '@plastichub/osr-cli-commons/fs' import { files } from '@plastichub/osr-cli-commons/glob' import { sync as exists } from '@plastichub/fs/exists' import { sync as read } from '@plastichub/fs/read' import { logger as _logger } from '@plastichub/core/debug' import * as ExifReader from 'exifreader' import { translateText } from '@plastichub/osr-i18n/lib/translate' import { resize, getResizePatterns, format, getFormats, meta } from '@plastichub/osr-media/lib/media/images' import { I18N_STORE, OSR_ROOT, PRODUCT_CONFIG, PRODUCT_ROOT, RETAIL_MEDIA_CACHE } from './config' import { GalleryImage } from './images' const logger = _logger('ph-site') const IMAGES_GLOB = '*.+(JPG|jpg|png|PNG|gif)' export const productGallery = async (grunt, assetPath, product, lang, dstLanguage): Promise => { product = '' + product const root = resolve(PRODUCT_ROOT()) const productConfig: any = read(PRODUCT_CONFIG(product), "json") if (!productConfig) { logger.error('Product config not found !' + product) return } const mediaPath = `${root}/${product}/${assetPath}/` if (!exists(mediaPath)) { return [] } const galleryFiles = files(mediaPath, IMAGES_GLOB, { cwd: mediaPath, absolute: false }) if (!galleryFiles) { return } const removeBufferValues = (obj: any): any => { for (const key in obj) { const val = obj[key] if (Buffer.isBuffer(val)) { } if (Buffer.isBuffer(val)) { delete obj[key]; } else if (typeof val === 'object') { removeBufferValues(val); } } return obj; } const removeArrayValues = (obj: any): any => { for (const key in obj) { if (key == 'id') { delete obj[key] } if (Array.isArray(obj[key]) || Buffer.isBuffer(obj[key])) { delete obj[key]; } else if (typeof obj[key] === 'object') { removeArrayValues(obj[key]); } } return obj; } const removeEmptyObjects = (obj: any): any => { for (const key in obj) { if (typeof obj[key] === 'object' || (key == 'value' && typeof obj[key] === 'number' && obj[key] === 0 || key == 'base64') ) { obj[key] = removeEmptyObjects(obj[key]); if (Object.keys(obj[key]).length === 0) { delete obj[key]; } } } return obj; } const removeArrays = (obj: any): any => { for (const key in obj) { if (key == 'description' && typeof obj[key] === 'string' && obj[key].split(',').length > 2) { try { if (Buffer.isBuffer(Buffer.from(obj[key].split(',')))) delete obj[key] } catch (e) { } } else if (typeof obj[key] === 'object') { removeArrays(obj[key]); } } return obj; } return await pMap(galleryFiles, async (file: string) => { const parts = path.parse(file) const filePath = path.join(mediaPath, file) let imageMeta: any = await meta(filePath) const exifRaw: any = await ExifReader.load(filePath) const title = exifRaw?.title?.description || '' const keywords = exifRaw?.['LastKeywordXMP']?.description || exifRaw?.iptc?.Keywords?.description || '' const exifDescription = exifRaw?.['ImageDescription']?.description || '' const width = exifRaw?.['Image Width']?.value const height = exifRaw?.['Image Height']?.value const lon = exifRaw?.['GPSLongitude']?.description const lat = exifRaw?.['GPSLatitude']?.description const description = exifDescription || exifRaw?.iptc?.['Caption/Abstract'].description || '' imageMeta.exif = exifRaw imageMeta = removeBufferValues(imageMeta) imageMeta = removeArrayValues(imageMeta) imageMeta = removeArrays(imageMeta) imageMeta = removeEmptyObjects(imageMeta) delete imageMeta.xmp delete imageMeta.icc delete imageMeta.exif.icc delete imageMeta.exif.xmp delete imageMeta.exif.iptc const keywordsTranslated = await translateText(keywords || '', lang, dstLanguage,{ store: I18N_STORE(OSR_ROOT(), dstLanguage) }) const assetUrl = (filePath) => `[[OSR_MACHINES_ASSETS_URL]]/[[product_relative]]/${assetPath}/${filePath}` const ret: GalleryImage = { name: path.parse(file).name, url: assetUrl(file), thumb: assetUrl(`/20/webp/${parts.name}.webp`), responsive: assetUrl(`/webp/${parts.name}.webp`), meta: imageMeta || "", keywords: keywords.split(',').map((k) => k.trim()), description, alt: `${description} - ${keywordsTranslated || ''}`, width, height, title } return ret }) } export const compileProductAssets = async (grunt, product_root, srcLang, dstLanguage) => { logger.info('Resize Product Media Assets ', product_root); await resize(getResizePatterns(product_root, 'drawings')) await format(getFormats(product_root, 'drawings'), { png: false, cache: RETAIL_MEDIA_CACHE }) await resize(getResizePatterns(product_root, 'renderings')) await format(getFormats(product_root, 'renderings'), { png: false, cache: RETAIL_MEDIA_CACHE }) await resize(getResizePatterns(product_root, 'renderings/20')) await format(getFormats(product_root, 'renderings/20'), { png: false, cache: RETAIL_MEDIA_CACHE }) await resize(getResizePatterns(product_root, 'media/gallery')) await format(getFormats(product_root, 'media/gallery'), { png: false, cache: RETAIL_MEDIA_CACHE }) await resize(getResizePatterns(product_root, 'media/gallery/20')) await format(getFormats(product_root, 'media/gallery/20'), { png: false, cache: RETAIL_MEDIA_CACHE }) }