Skip to content

Instantly share code, notes, and snippets.

@AlanGreyjoy
Created October 11, 2024 04:51
Show Gist options
  • Save AlanGreyjoy/5de6ab4ac533a6841bce0ff141707053 to your computer and use it in GitHub Desktop.
Save AlanGreyjoy/5de6ab4ac533a6841bce0ff141707053 to your computer and use it in GitHub Desktop.
Node.js Link Preview Generator
/**
* @fileoverview Custom Link Preview Service using Puppeteer
* @description Generates link previews by rendering webpages with Puppeteer
* @reviewed Alan Spurlock - 2024-03-20
*/
const puppeteer = require('puppeteer')
const logger = require('../../utils/logger') //Where ever you might have your logger!
/**
* Fetches a link preview and returns relevant metadata
* @param {string} url - The URL to generate a preview for
* @returns {Promise<Object>} An object containing title, description, image URL, and screenshot
*/
async function getLinkPreview(url) {
logger.info(`[LINK-PREVIEW] Fetching link preview for ${url}`)
let browser
try {
browser = await puppeteer.launch({ headless: 'new' })
const page = await browser.newPage()
// Set a reasonable viewport size
await page.setViewport({ width: 1280, height: 800 })
// Navigate to the URL
await page.goto(url, { waitUntil: 'networkidle0' })
// Extract metadata
const metadata = await page.evaluate(() => {
const getMetaContent = name => {
const element = document.querySelector(`meta[name="${name}"], meta[property="og:${name}"]`)
return element ? element.getAttribute('content') : null
}
return {
title: document.title || getMetaContent('title'),
description: getMetaContent('description'),
image: getMetaContent('image')
}
})
// If no image found in metadata, try to get the largest image on the page
if (!metadata.image) {
metadata.image = await page.evaluate(() => {
const images = Array.from(document.images)
if (images.length > 0) {
const largestImage = images.reduce((largest, image) =>
image.width * image.height > largest.width * largest.height ? image : largest
)
return largestImage.src
}
return null
})
}
// Take a screenshot
const screenshot = await page.screenshot({ encoding: 'base64' })
return {
...metadata,
screenshot: `data:image/png;base64,${screenshot}`
}
} catch (error) {
console.error('Error fetching link preview:', error.message)
return { title: '', description: '', image: '', screenshot: '' }
} finally {
if (browser) {
await browser.close()
}
}
}
module.exports = {
getLinkPreview
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment