Created
October 11, 2024 04:51
-
-
Save AlanGreyjoy/5de6ab4ac533a6841bce0ff141707053 to your computer and use it in GitHub Desktop.
Node.js Link Preview Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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