snipify
Version:
A production-ready tool for capturing and processing web screenshots with Puppeteer and Sharp.
1 lines • 4.49 kB
JavaScript
;var e=require("fs/promises"),t=require("path"),i=require("puppeteer"),a=require("sharp"),r=require("url"),o="undefined"!=typeof document?document.currentScript:null;function n(e){return e&&e.__esModule?e:{default:e}}var s=n(a),l={desktop:{viewport:{width:1920,height:1080},userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64)...Chrome/121.0.0.0 Safari/537.36"},laptop:{viewport:{width:1366,height:768},userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64)...Chrome/121.0.0.0 Safari/537.36"},tablet:{viewport:{width:768,height:1024},userAgent:"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X)...Safari/604.1"},mobile:{viewport:{width:375,height:667},userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...Safari/604.1"},"mobile-large":{viewport:{width:414,height:896},userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)...Safari/604.1"}},u={thumbnail:{width:300,height:200},card:{width:400,height:300},"social-media":{width:1200,height:630},"instagram-post":{width:1080,height:1080},"instagram-story":{width:1080,height:1920},"youtube-thumbnail":{width:1280,height:720},"blog-header":{width:800,height:400},"email-banner":{width:600,height:200},"preview-small":{width:200,height:150},"preview-medium":{width:400,height:300},"preview-large":{width:800,height:600}},h=t.dirname(r.fileURLToPath("undefined"==typeof document?require("url").pathToFileURL(__filename).href:o&&"SCRIPT"===o.tagName.toUpperCase()&&o.src||new URL("index.js",document.baseURI).href));async function c({url:e,device:t="desktop",options:a={}}){const{outputPath:r,format:o,quality:n,fullPage:s,waitForSelector:u,delay:h,headless:c,blockResources:p,clip:g,fixedSize:f}=function(e={}){const{outputPath:t,format:i="png",quality:a=90,fullPage:r=!0,waitForSelector:o,delay:n=0,headless:s=!0,blockResources:l=!1,clip:u=null,fixedSize:h=null}=e;return{outputPath:t,format:i,quality:a,fullPage:r,waitForSelector:o,delay:n,headless:s,blockResources:l,clip:u,fixedSize:h}}(a);if(!l[t])throw new Error(`Unknown device preset: ${t}. Available: ${Object.keys(l).join(", ")}`);const m=await i.launch({headless:c,args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-web-security","--disable-features=VizDisplayCompositor"]});let y=null;try{y=await m.newPage();const{viewport:i,userAgent:a}=l[t];await y.setViewport(i),await y.setUserAgent(a),p&&(await y.setRequestInterception(!0),y.on("request",(e=>{try{const t=e.resourceType(),i=e.url();"media"===t||"image"===t&&(i.includes(".mp4")||i.includes(".webm"))||"websocket"===t||i.includes("analytics")||i.includes("tracking")?e.abort():e.continue()}catch{e.continue()}}))),await y.goto(e,{waitUntil:"networkidle0",timeout:3e4}),u&&await y.waitForSelector(u,{timeout:1e4}),h>0&&await new Promise((e=>setTimeout(e,h)));const c={fullPage:!g&&s,type:o,..."jpeg"===o&&{quality:n},...g&&{clip:g}};let S=await y.screenshot(c);return f&&(S=await w(Buffer.from(S),f,o,n)),r&&await d(Buffer.from(S),r),S}finally{y&&await y.close(),await m.close()}}async function d(i,a){try{const r=t.dirname(a);await e.mkdir(r,{recursive:!0}),await e.writeFile(a,i)}catch(e){throw new Error(`Failed to save screenshot: ${e.message}`)}}async function w(e,t,i="png",a=100){try{let r=s.default(e).resize(t.width,t.height,{fit:"cover",position:"top"});return"jpeg"===i?r=r.jpeg({quality:a}):"png"===i&&(r=r.png({compressionLevel:9})),await r.toBuffer()}catch(e){throw new Error(`Failed to resize image: ${e.message}`)}}async function p(e,t,i="png",a){const r=new URL(e).hostname.replace(/\./g,"-"),o=(new Date).toISOString().replace(/[:.]/g,"-").split("T")[0];let n="";return a&&("string"==typeof a?n=`-${a}`:a.width&&a.height&&(n=`-${a.width}x${a.height}`)),`screenshot-${r}-${t}${n}-${o}.${i}`}if("undefined"!=typeof window)throw new Error("Snipify can only be used in Node.js environments.");exports.DEVICE_PRESETS=l,exports.PRODUCTION_SIZES=u,exports.captureProductionScreenshots=async function({url:e,device:i="desktop",sizes:a=["thumbnail","card","social-media"],options:r={}}){const{outputDir:o=t.join(h,"screenshots"),format:n="png",quality:s=90}=r,l=[],g=await c({url:e,device:i,options:{...r,outputPath:void 0,fullPage:!0}});for(const r of a)try{const a=u[r];if(!a.width||!a.height)continue;const h=await w(Buffer.from(g),a,n,s),c=await p(e,i,n,r),f=t.join(o,c);await d(h,f),l.push({size:r,dimensions:a,buffer:h,path:f,fileSize:`${(h.length/1024).toFixed(2)} KB`})}catch(e){}return l},exports.captureScreenshot=c,exports.generateFilename=p;