1
0
mirror of https://github.com/spacebarchat/server.git synced 2024-09-20 01:31:34 +02:00

xkcd embed handler and improved generic handler

This commit is contained in:
Madeline 2023-09-02 23:47:40 +10:00
parent 09f5b4f0bb
commit c64a115729
No known key found for this signature in database
GPG Key ID: 1958E017C36F2E47

View File

@ -17,11 +17,11 @@
*/ */
import { Config, Embed, EmbedType } from "@spacebar/util"; import { Config, Embed, EmbedType } from "@spacebar/util";
import fetch, { RequestInit } from "node-fetch";
import * as cheerio from "cheerio"; import * as cheerio from "cheerio";
import probe from "probe-image-size";
import crypto from "crypto"; import crypto from "crypto";
import fetch, { RequestInit } from "node-fetch";
import { yellow } from "picocolors"; import { yellow } from "picocolors";
import probe from "probe-image-size";
export const DEFAULT_FETCH_OPTIONS: RequestInit = { export const DEFAULT_FETCH_OPTIONS: RequestInit = {
redirect: "follow", redirect: "follow",
@ -85,6 +85,7 @@ export const getMetaDescriptions = (text: string) => {
const $ = cheerio.load(text); const $ = cheerio.load(text);
return { return {
type: getMeta($, "og:type"),
title: getMeta($, "og:title") || $("title").first().text(), title: getMeta($, "og:title") || $("title").first().text(),
provider_name: getMeta($, "og:site_name"), provider_name: getMeta($, "og:site_name"),
author: getMeta($, "article:author"), author: getMeta($, "article:author"),
@ -96,6 +97,8 @@ export const getMetaDescriptions = (text: string) => {
height: parseInt(getMeta($, "og:image:height") || "0"), height: parseInt(getMeta($, "og:image:height") || "0"),
url: getMeta($, "og:url"), url: getMeta($, "og:url"),
youtube_embed: getMeta($, "og:video:secure_url"), youtube_embed: getMeta($, "og:video:secure_url"),
$,
}; };
}; };
@ -116,7 +119,7 @@ const genericImageHandler = async (url: URL): Promise<Embed | null> => {
method: "HEAD", method: "HEAD",
}); });
let width, height, image; let width: number, height: number, image: string | undefined;
if (type.headers.get("content-type")?.indexOf("image") !== -1) { if (type.headers.get("content-type")?.indexOf("image") !== -1) {
const result = await probe(url.href); const result = await probe(url.href);
@ -181,9 +184,16 @@ export const EmbedHandlers: {
return null; 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 { return {
url: url.href, url: url.href,
type: EmbedType.link, type: embedType,
title: metas.title, title: metas.title,
thumbnail: { thumbnail: {
width: metas.width, width: metas.width,
@ -210,9 +220,7 @@ export const EmbedHandlers: {
// TODO: facebook // TODO: facebook
// have to use their APIs or something because they don't send the metas in initial html // have to use their APIs or something because they don't send the metas in initial html
"twitter.com": (url: URL) => { "twitter.com": (url) => EmbedHandlers["www.twitter.com"](url),
return EmbedHandlers["www.twitter.com"](url);
},
"www.twitter.com": async (url: URL) => { "www.twitter.com": async (url: URL) => {
const token = Config.get().external.twitter; const token = Config.get().external.twitter;
if (!token) return null; if (!token) return null;
@ -345,15 +353,15 @@ export const EmbedHandlers: {
}; };
}, },
"pixiv.net": (url: URL) => { // TODO: docs: Pixiv won't work without Imagor
return EmbedHandlers["www.pixiv.net"](url); "pixiv.net": (url) => EmbedHandlers["www.pixiv.net"](url),
},
"www.pixiv.net": async (url: URL) => { "www.pixiv.net": async (url: URL) => {
const response = await doFetch(url); const response = await doFetch(url);
if (!response) return null; if (!response) return null;
const metas = getMetaDescriptions(await response.text()); 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 { return {
url: url.href, url: url.href,
type: EmbedType.image, type: EmbedType.image,
@ -407,9 +415,7 @@ export const EmbedHandlers: {
}; };
}, },
"reddit.com": (url: URL) => { "reddit.com": (url) => EmbedHandlers["www.reddit.com"](url),
return EmbedHandlers["www.reddit.com"](url);
},
"www.reddit.com": async (url: URL) => { "www.reddit.com": async (url: URL) => {
const res = await EmbedHandlers["default"](url); const res = await EmbedHandlers["default"](url);
return { return {
@ -420,12 +426,9 @@ export const EmbedHandlers: {
}, },
}; };
}, },
"youtu.be": (url: URL) => {
return EmbedHandlers["www.youtube.com"](url); "youtu.be": (url) => EmbedHandlers["www.youtube.com"](url),
}, "youtube.com": (url) => EmbedHandlers["www.youtube.com"](url),
"youtube.com": (url: URL) => {
return EmbedHandlers["www.youtube.com"](url);
},
"www.youtube.com": async (url: URL): Promise<Embed | null> => { "www.youtube.com": async (url: URL): Promise<Embed | null> => {
const response = await doFetch(url); const response = await doFetch(url);
if (!response) return null; 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 // the url is an image from this instance
self: async (url: URL): Promise<Embed | null> => { self: async (url: URL): Promise<Embed | null> => {
const result = await probe(url.href); const result = await probe(url.href);