OverviewFilesCommitsIssuesDocsReleasesPeers

ollama_semantic_function_calling / ollamatools-new / keet / node_modules / @holepunchto / keet-link-preview / index.js

104 lines · javascript ref:
import fastMetaTags, { userAgent } from 'fast-meta-tags'

export default async function getLinkPreview(url, opt) {
  if (url.startsWith('http://')) url = 'https' + url.slice(4)

  const data = await fastMetaTags(url, opt)
  if (data === null) return null

  const preview = parse(data)
  const image = getImage(data)
  preview.file = await getFile(image, opt)

  return preview
}

function parse(data) {
  return {
    url: data.url,
    favicon: data.favicon,
    title: getTitle(data),
    name: getSiteName(data),
    description: getDescription(data)
  }
}

function getSiteName(data) {
  return (
    getMetaContent(data.meta, {
      name: 'og:site_name',
      property: 'og:site_name',
    }) || getUrlDomain(data.url)
  )
}

function getTitle(data) {
  return getMetaContent(data.meta, { name: 'og:title', property: 'og:title' }) || data.title
}

function getDescription(data) {
  return getMetaContent(data.meta, { name: 'description', property: 'og:description' })
}

function getImage(data) {
  return getMetaContent(data.meta, { name: 'og:image', property: 'og:image' })
}

async function getFile(src, opt) {
  if (!src) return null
  return opt?.noBuffer
    ? { src, name: toFilename(src, null), buffer: null }
    : await getFileBuffer(src, opt)
}

async function getFileBuffer(src, opt) {
  try {
    const res = await fetch(src, {
      headers: {
        Accept: '*/*',
        'User-Agent': opt?.userAgent || userAgent,
      },
    })
    if (!res.ok) return null

    const type = res.headers.get('Content-Type')

    return { src, type, name: toFilename(src, type), buffer: await res.arrayBuffer() }
  } catch {
    return null
  }
}

function getUrlDomain(url) {
  try {
    const parsedUrl = new URL(url)
    return parsedUrl.hostname
  } catch (error) {
    return null
  }
}

function getMetaContent(meta, filter) {
  const entries = Object.entries(filter)

  return meta.find((m) => {
    for (const [k, v] of entries) {
      if (m[k] === v) return true
    }
  })?.content
}

function toFilename(url, type) {
  switch (type) {
    case 'image/png':
      return 'preview.png'
    case 'image/jpg':
    case 'image/jpeg':
      return 'preview.jpeg'
    case 'image/gif':
      return 'preview.gif'
  }

  return decodeURIComponent(url?.split('/').pop())
}