diff --git a/videomaker.js b/videomaker.js index 3ecc12f..f56e319 100644 --- a/videomaker.js +++ b/videomaker.js @@ -107,13 +107,21 @@ async function render(job) { await QR.toFile(qrFile, 'https://' + link, { width: Math.round(Math.min(w, h) * 0.34), margin: 1, color: { dark: '#061c17', light: '#ffffff' } }); const F = font(); const portrait = h > w; const big = Math.round(Math.min(w, h) * (portrait ? 0.075 : 0.07)), mid = Math.round(big * 0.62), small = Math.round(big * 0.48); const qrSize = Math.round(Math.min(w, h) * 0.34); - const yTitle = Math.round(h * (portrait ? 0.18 : 0.14)), yQr = Math.round(h * (portrait ? 0.30 : 0.30)), yName = yQr + qrSize + Math.round(h * 0.03), yLink = yName + mid + Math.round(h * 0.015), yFoot = h - Math.round(h * 0.08); + // every line is sized to fit 90% of the frame width (DejaVu Bold averages ~0.62em per glyph); portrait splits the long lines in two + const maxW = Math.round(w * 0.9); const fit = (t, max) => Math.max(18, Math.min(max, Math.floor(maxW / (t.length * 0.62)))); + const titles = portrait ? ['Join my line', 'on InstantAdPay'] : ['Join my line on InstantAdPay']; + const foots = portrait ? ['Free to join. Paid in the same transaction.', 'Not investment advice.'] : ['Free to join. Paid in the same transaction. Not investment advice.']; + const bigS = Math.min(...titles.map(t => fit(t, big))), midS = fit('@' + job.username, mid), smallS = fit(link, small), footS = Math.min(...foots.map(t => fit(t, Math.round(small * 0.8)))); + const yTitle = Math.round(h * (portrait ? 0.16 : 0.14)), yQr = Math.round(h * 0.30), yName = yQr + qrSize + Math.round(h * 0.03), yLink = yName + midS + Math.round(h * 0.015), yFootEnd = h - Math.round(h * 0.08); + const draw = (t, color, size, y) => 'drawtext=fontfile=' + F + ":text='" + ffText(t) + "':fontcolor=" + color + ':fontsize=' + size + ':x=(w-text_w)/2:y=' + y; + const steps = []; + titles.forEach((t, i) => steps.push(draw(t, '0x43e8c3', bigS, yTitle + Math.round(i * bigS * 1.2)))); + steps.push(draw('@' + job.username, '0xffffff', midS, yName)); + steps.push(draw(link, '0xffd15c', smallS, yLink)); + foots.forEach((t, i) => steps.push(draw(t, '0x8fd8c4', footS, yFootEnd - Math.round((foots.length - 1 - i) * footS * 1.35)))); const filters = [ '[0:v][1:v]overlay=(W-w)/2:' + yQr + '[b]', - '[b]drawtext=fontfile=' + F + ":text='" + ffText('Join my line on InstantAdPay') + "':fontcolor=0x43e8c3:fontsize=" + big + ':x=(w-text_w)/2:y=' + yTitle + '[c]', - '[c]drawtext=fontfile=' + F + ":text='" + ffText('@' + job.username) + "':fontcolor=0xffffff:fontsize=" + mid + ':x=(w-text_w)/2:y=' + yName + '[d]', - '[d]drawtext=fontfile=' + F + ":text='" + ffText(link) + "':fontcolor=0xffd15c:fontsize=" + small + ':x=(w-text_w)/2:y=' + yLink + '[e]', - '[e]drawtext=fontfile=' + F + ":text='" + ffText('Free to join. Paid in the same transaction. Not investment advice.') + "':fontcolor=0x8fd8c4:fontsize=" + Math.round(small * 0.8) + ':x=(w-text_w)/2:y=' + yFoot + ',format=yuv420p[v]' + '[b]' + steps.join(',') + ',format=yuv420p[v]' ].join(';'); await run('ffmpeg', ['-y', '-loglevel', 'error', '-f', 'lavfi', '-i', 'color=c=0x061c17:s=' + w + 'x' + h + ':r=30:d=4.5', '-i', qrFile, '-f', 'lavfi', '-i', 'anullsrc=r=44100:cl=stereo', '-filter_complex', filters, '-map', '[v]', '-map', '2:a', '-t', '4.5', '-c:v', 'libx264', '-preset', 'veryfast', '-crf', '24', '-c:a', 'aac', '-shortest', endFile], 120000); await run('ffmpeg', ['-y', '-loglevel', 'error', '-i', srcFile, '-i', endFile, '-filter_complex',