import { format } from 'date-fns'; import { parse } from 'yaml'; import formatTemplate from 'template-format'; import slugify from '#/utils/slugify.js'; import ellipsis from '#/utils/ellipsis.js'; const genderMap = { f: 'female', m: 'male', t: 'transsexual', o: 'other', u: null, }; const propProcessors = { ...Object.fromEntries(Object.entries({ // aliases shoot: 'shootId', }).map(([key, alias]) => [key, (sceneInfo) => sceneInfo[alias]])), link: (sceneInfo, _options, env) => `${env.origin}/scene/${sceneInfo.id}/${sceneInfo.slug}`, channel: (sceneInfo) => sceneInfo.channel?.name || sceneInfo.network?.name, network: (sceneInfo) => sceneInfo.network?.name || sceneInfo.channel?.name, actors: (sceneInfo, options) => { const genders = (options.genders || 'fmtou').split('').map((genderKey) => genderMap[genderKey]); return sceneInfo.actors .filter((actor) => genders.includes(actor.gender)) .map((actor) => { const curatedActor = { ...actor, age: actor.ageThen, ageNow: actor.age, g: actor.gender?.charAt(0), G: actor.gender?.charAt(0).toUpperCase(), dateOfBirth: actor.dateOfBirth && format(actor.dateOfBirth, 'yyyy-MM-dd'), }; if (options.format) { return formatTemplate(options.format, Object.fromEntries(Object.entries(curatedActor).map(([key, value]) => [key, value ?? '']))); // don't render `null` } if (options.details) { return options.details .map((parentDetail) => { if (parentDetail.details) { // already nested return { ...parentDetail, details: parentDetail.details.map((detail) => { if (detail.key) { return detail; } return { key: detail }; }), }; } if (parentDetail.key) { return { details: [parentDetail], }; } return { details: [{ key: parentDetail }], }; }) .map((parentDetail) => { const curatedDetails = parentDetail.details .filter((detail) => !!curatedActor[detail.key]) .map((detail) => { if (detail.wrap) { return `${detail.wrap[0]}${curatedActor[detail.key]}${detail.wrap[1]}`; } return curatedActor[detail.key]; }) .join(parentDetail.delimiter ?? ' '); if (parentDetail.wrap) { return `${parentDetail.wrap[0]}${curatedDetails}${parentDetail.wrap[1]}`; } return curatedDetails; }) .filter((parentDetail) => !!parentDetail) .join(options.detailDelimiter ?? ' '); } return actor.name; }); }, tags: (sceneInfo, options) => sceneInfo.tags ?.filter((tag) => { if (options.include && !options.include.includes(tag.slug)) { return false; } if (options.exclude?.includes(tag.slug)) { return false; } if (options.priority && tag.priority < options.priority) { return false; } return true; }) .map((tag) => tag.name), movie: (sceneInfo) => sceneInfo.movies?.[0]?.title, date: (sceneInfo, options) => { const dateFormat = options.format || 'yyyy-MM-dd'; if (sceneInfo.date) { return format(sceneInfo.date, dateFormat); } if (options.fallbackToAdded && sceneInfo.effectiveDate) { return format(sceneInfo.effectiveDate, dateFormat); } return null; }, createdAt: (sceneInfo, options) => format(sceneInfo.createdAt, options.format || 'yyyy-MM-dd'), }; function curateValue(value, item) { return [].concat(value) // account for both arrays (actors, tags) and strings (title, channel) .filter((listValue) => !!listValue) .slice(0, item.limit || Infinity) .map((listValue) => (item.slugify ? slugify(listValue, item.slugify) : listValue)) .map((listValue) => ellipsis(listValue, item.slice || Infinity, item.ellipsis || '')) .map((listValue) => `${item.wrap?.[0] || ''}${listValue}${item.wrap?.[1] || ''}`) .join(item.delimit || ', '); } function traverseTemplate(chain, release, env, { delimit = ' ' } = {}) { const results = chain.reduce((result, item) => { const keys = typeof item === 'string' ? item : item.key; if ((item.channels && !item.channels.includes(release.channel?.slug)) || item.notChannels?.includes(release.channel?.slug)) { return result; } if ((item.networks && !item.networks.includes(release.network?.slug)) || item.notNetworks?.includes(release.network?.slug)) { return result; } if (item.text) { return result.concat(curateValue(item.text, item)); } if (keys) { const value = keys.split('|').reduce((acc, key) => acc || propProcessors[key]?.(release, typeof item === 'string' ? { key } : item, env) || release[key], null); return result.concat(curateValue(value, item)); } if (item.items) { const group = traverseTemplate(item.items, release, env, { delimit: item.delimit, }); return result.concat(curateValue(group, item)); } return result; }, []); if (results.length > 0) { // return `${wrap[0] || ''}${results.filter(Boolean).join(delimit)}${wrap[1] || ''}`; return results.filter(Boolean).join(delimit); } return ''; } export default function processSummaryTemplate(template, release, env) { const chain = parse(template); return traverseTemplate(chain, release, env); }