UNPKG

@jrmc/adonis-attachment

Version:

Turn any field on your Lucid model to an attachment data type

98 lines (97 loc) 3.48 kB
/** * @jrmc/adonis-attachment * * @license MIT * @copyright Jeremy Chaufourier <jeremy@chaufourier.fr> */ import logger from '@adonisjs/core/services/logger'; import attachmentManager from '../../../services/main.js'; import { streamToTempFile } from '../../utils/helpers.js'; export default class VariantGeneratorService { async generate({ attachments, options, filters }) { const variants = []; const variantKeys = this.#getVariantKeysToProcess(options, filters); for (const key of variantKeys) { const converter = await this.#getConverter(key); if (!converter) continue; for (const attachment of attachments) { const variant = await this.generateVariant({ key, attachment, converter }); if (variant) { variants.push(variant); } } } return variants; } async generateVariant({ key, attachment, converter }) { try { const input = await this.#prepareInput(attachment); const output = await this.#convertFile(input, converter); if (!output) { // throw new errors.E_CANNOT_PATH_BY_CONVERTER() logger.warn(`Converter returned no output for key: ${key}`); return null; } const variant = await attachment.createVariant(key, output); await this.#processBlurhash(variant, converter); await attachmentManager.write(variant); return variant; } catch (error) { logger.error(`Failed to generate variant ${key} for attachment: ${error.message}`); return null; } } #getVariantKeysToProcess(options, filters) { if (!options.variants) return []; return options.variants.filter(key => filters?.variants === undefined || filters.variants.includes(key)); } async #getConverter(key) { try { return await attachmentManager.getConverter(key); } catch (error) { logger.error(`Failed to get converter for key ${key}: ${error.message}`); return null; } } async #prepareInput(attachment) { if (attachment.input) { return attachment.input; } const stream = await attachment.getStream(); return await streamToTempFile(stream); } async #convertFile(input, converter) { if (!converter.handle) { throw new Error('Converter handle method is required'); } if (!converter.options) { throw new Error('Converter options are required'); } return await converter.handle({ input, options: converter.options, }); } async #processBlurhash(variant, converter) { const blurhashConfig = converter.options?.blurhash; if (!blurhashConfig) return; const shouldGenerate = typeof blurhashConfig === 'boolean' ? blurhashConfig : blurhashConfig.enabled === true; if (!shouldGenerate) return; try { const options = typeof blurhashConfig !== 'boolean' ? blurhashConfig : undefined; await variant.generateBlurhash(options); } catch (error) { logger.error(`Blurhash generation failed: ${error.message}`); } } }