diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index 15e3f67f..e8f39407 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -17,11 +17,11 @@ */ import { Config, Embed, EmbedType } from "@spacebar/util"; -import fetch, { RequestInit } from "node-fetch"; import * as cheerio from "cheerio"; -import probe from "probe-image-size"; import crypto from "crypto"; +import fetch, { RequestInit } from "node-fetch"; import { yellow } from "picocolors"; +import probe from "probe-image-size"; export const DEFAULT_FETCH_OPTIONS: RequestInit = { redirect: "follow", @@ -85,6 +85,7 @@ export const getMetaDescriptions = (text: string) => { const $ = cheerio.load(text); return { + type: getMeta($, "og:type"), title: getMeta($, "og:title") || $("title").first().text(), provider_name: getMeta($, "og:site_name"), author: getMeta($, "article:author"), @@ -96,6 +97,8 @@ export const getMetaDescriptions = (text: string) => { height: parseInt(getMeta($, "og:image:height") || "0"), url: getMeta($, "og:url"), youtube_embed: getMeta($, "og:video:secure_url"), + + $, }; }; @@ -116,7 +119,7 @@ const genericImageHandler = async (url: URL): Promise => { method: "HEAD", }); - let width, height, image; + let width: number, height: number, image: string | undefined; if (type.headers.get("content-type")?.indexOf("image") !== -1) { const result = await probe(url.href); @@ -181,9 +184,16 @@ export const EmbedHandlers: { return null; } + let embedType = EmbedType.link; + if (metas.type == "article") embedType = EmbedType.article; + if (metas.type == "object") embedType = EmbedType.article; // github + if (metas.type == "rich") embedType = EmbedType.rich; + + if (metas.width < 400) embedType = EmbedType.link; + return { url: url.href, - type: EmbedType.link, + type: embedType, title: metas.title, thumbnail: { width: metas.width, @@ -210,9 +220,7 @@ export const EmbedHandlers: { // TODO: facebook // have to use their APIs or something because they don't send the metas in initial html - "twitter.com": (url: URL) => { - return EmbedHandlers["www.twitter.com"](url); - }, + "twitter.com": (url) => EmbedHandlers["www.twitter.com"](url), "www.twitter.com": async (url: URL) => { const token = Config.get().external.twitter; if (!token) return null; @@ -345,15 +353,15 @@ export const EmbedHandlers: { }; }, - "pixiv.net": (url: URL) => { - return EmbedHandlers["www.pixiv.net"](url); - }, + // TODO: docs: Pixiv won't work without Imagor + "pixiv.net": (url) => EmbedHandlers["www.pixiv.net"](url), "www.pixiv.net": async (url: URL) => { const response = await doFetch(url); if (!response) return null; const metas = getMetaDescriptions(await response.text()); - // TODO: doesn't show images. think it's a bug in the cdn + if (!metas.image) return null; + return { url: url.href, type: EmbedType.image, @@ -407,9 +415,7 @@ export const EmbedHandlers: { }; }, - "reddit.com": (url: URL) => { - return EmbedHandlers["www.reddit.com"](url); - }, + "reddit.com": (url) => EmbedHandlers["www.reddit.com"](url), "www.reddit.com": async (url: URL) => { const res = await EmbedHandlers["default"](url); return { @@ -420,12 +426,9 @@ export const EmbedHandlers: { }, }; }, - "youtu.be": (url: URL) => { - return EmbedHandlers["www.youtube.com"](url); - }, - "youtube.com": (url: URL) => { - return EmbedHandlers["www.youtube.com"](url); - }, + + "youtu.be": (url) => EmbedHandlers["www.youtube.com"](url), + "youtube.com": (url) => EmbedHandlers["www.youtube.com"](url), "www.youtube.com": async (url: URL): Promise => { const response = await doFetch(url); if (!response) return null; @@ -466,6 +469,36 @@ export const EmbedHandlers: { }; }, + "www.xkcd.com": (url) => EmbedHandlers["xkcd.com"](url), + "xkcd.com": async (url) => { + const response = await doFetch(url); + if (!response) return null; + + const metas = getMetaDescriptions(await response.text()); + const hoverText = metas.$("#comic img").attr("title"); + + if (!metas.image) return null; + + const { width, height } = await probe(metas.image); + + return { + url: url.href, + type: EmbedType.rich, + title: `xkcd: ${metas.title}`, + image: { + width, + height, + url: metas.image, + proxy_url: getProxyUrl(new URL(metas.image), width, height), + }, + footer: hoverText + ? { + text: hoverText, + } + : undefined, + }; + }, + // the url is an image from this instance self: async (url: URL): Promise => { const result = await probe(url.href);