Rewrite thumbnail/image generation for embeds
This commit is contained in:
parent
fb7409947c
commit
e64c34adea
@ -16,7 +16,7 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Config, Embed, EmbedType } from "@spacebar/util";
|
import { Config, Embed, EmbedImage, EmbedType } from "@spacebar/util";
|
||||||
import * as cheerio from "cheerio";
|
import * as cheerio from "cheerio";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import fetch, { RequestInit } from "node-fetch";
|
import fetch, { RequestInit } from "node-fetch";
|
||||||
@ -35,6 +35,20 @@ export const DEFAULT_FETCH_OPTIONS: RequestInit = {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makeEmbedImage = (
|
||||||
|
url: string | undefined,
|
||||||
|
width: number | undefined,
|
||||||
|
height: number | undefined,
|
||||||
|
): Required<EmbedImage> | undefined => {
|
||||||
|
if (!url || !width || !height) return undefined;
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
proxy_url: getProxyUrl(new URL(url), width, height),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
let hasWarnedAboutImagor = false;
|
let hasWarnedAboutImagor = false;
|
||||||
|
|
||||||
export const getProxyUrl = (
|
export const getProxyUrl = (
|
||||||
@ -82,6 +96,15 @@ const getMeta = ($: cheerio.CheerioAPI, name: string): string | undefined => {
|
|||||||
return ret.trim().length == 0 ? undefined : ret;
|
return ret.trim().length == 0 ? undefined : ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tryParseInt = (str: string | undefined) => {
|
||||||
|
if (!str) return undefined;
|
||||||
|
try {
|
||||||
|
return parseInt(str);
|
||||||
|
} catch (e) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getMetaDescriptions = (text: string) => {
|
export const getMetaDescriptions = (text: string) => {
|
||||||
const $ = cheerio.load(text);
|
const $ = cheerio.load(text);
|
||||||
|
|
||||||
@ -94,8 +117,8 @@ export const getMetaDescriptions = (text: string) => {
|
|||||||
image: getMeta($, "og:image") || getMeta($, "twitter:image"),
|
image: getMeta($, "og:image") || getMeta($, "twitter:image"),
|
||||||
image_fallback: $(`image`).attr("src"),
|
image_fallback: $(`image`).attr("src"),
|
||||||
video_fallback: $(`video`).attr("src"),
|
video_fallback: $(`video`).attr("src"),
|
||||||
width: parseInt(getMeta($, "og:image:width") || "0"),
|
width: tryParseInt(getMeta($, "og:image:width")),
|
||||||
height: parseInt(getMeta($, "og:image:height") || "0"),
|
height: tryParseInt(getMeta($, "og:image:height")),
|
||||||
url: getMeta($, "og:url"),
|
url: getMeta($, "og:url"),
|
||||||
youtube_embed: getMeta($, "og:video:secure_url"),
|
youtube_embed: getMeta($, "og:video:secure_url"),
|
||||||
|
|
||||||
@ -120,13 +143,11 @@ const genericImageHandler = async (url: URL): Promise<Embed | null> => {
|
|||||||
method: "HEAD",
|
method: "HEAD",
|
||||||
});
|
});
|
||||||
|
|
||||||
let width: number, height: number, image: string | undefined;
|
let image;
|
||||||
|
|
||||||
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);
|
||||||
width = result.width;
|
image = makeEmbedImage(url.href, result.width, result.height);
|
||||||
height = result.height;
|
|
||||||
image = url.href;
|
|
||||||
} else if (type.headers.get("content-type")?.indexOf("video") !== -1) {
|
} else if (type.headers.get("content-type")?.indexOf("video") !== -1) {
|
||||||
// TODO
|
// TODO
|
||||||
return null;
|
return null;
|
||||||
@ -135,22 +156,19 @@ const genericImageHandler = async (url: URL): Promise<Embed | null> => {
|
|||||||
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());
|
||||||
width = metas.width;
|
image = makeEmbedImage(
|
||||||
height = metas.height;
|
metas.image || metas.image_fallback,
|
||||||
image = metas.image || metas.image_fallback;
|
metas.width,
|
||||||
|
metas.height,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!width || !height || !image) return null;
|
if (!image) return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: url.href,
|
url: url.href,
|
||||||
type: EmbedType.image,
|
type: EmbedType.image,
|
||||||
thumbnail: {
|
thumbnail: image,
|
||||||
width: width,
|
|
||||||
height: height,
|
|
||||||
url: url.href,
|
|
||||||
proxy_url: getProxyUrl(new URL(image), width, height),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -176,13 +194,15 @@ export const EmbedHandlers: {
|
|||||||
|
|
||||||
if (!metas.image) metas.image = metas.image_fallback;
|
if (!metas.image) metas.image = metas.image_fallback;
|
||||||
|
|
||||||
|
let image: Required<EmbedImage> | undefined;
|
||||||
|
|
||||||
if (metas.image && (!metas.width || !metas.height)) {
|
if (metas.image && (!metas.width || !metas.height)) {
|
||||||
const result = await probe(metas.image);
|
const result = await probe(metas.image);
|
||||||
metas.width = result.width;
|
image = makeEmbedImage(metas.image, result.width, result.height);
|
||||||
metas.height = result.height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metas.image && (!metas.title || !metas.description)) {
|
if (!image && (!metas.title || !metas.description)) {
|
||||||
|
// we don't have any content to display
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,24 +211,11 @@ export const EmbedHandlers: {
|
|||||||
if (metas.type == "object") embedType = EmbedType.article; // github
|
if (metas.type == "object") embedType = EmbedType.article; // github
|
||||||
if (metas.type == "rich") embedType = EmbedType.rich;
|
if (metas.type == "rich") embedType = EmbedType.rich;
|
||||||
|
|
||||||
if (metas.width && metas.width < 400) embedType = EmbedType.link;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: url.href,
|
url: url.href,
|
||||||
type: embedType,
|
type: embedType,
|
||||||
title: metas.title,
|
title: metas.title,
|
||||||
thumbnail: {
|
thumbnail: image,
|
||||||
width: metas.width,
|
|
||||||
height: metas.height,
|
|
||||||
url: metas.image,
|
|
||||||
proxy_url: metas.image
|
|
||||||
? getProxyUrl(
|
|
||||||
new URL(metas.image),
|
|
||||||
metas.width,
|
|
||||||
metas.height,
|
|
||||||
)
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
description: metas.description,
|
description: metas.description,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -340,14 +347,7 @@ export const EmbedHandlers: {
|
|||||||
type: EmbedType.link,
|
type: EmbedType.link,
|
||||||
title: metas.title,
|
title: metas.title,
|
||||||
description: metas.description,
|
description: metas.description,
|
||||||
thumbnail: {
|
thumbnail: makeEmbedImage(metas.image, 640, 640),
|
||||||
width: 640,
|
|
||||||
height: 640,
|
|
||||||
proxy_url: metas.image
|
|
||||||
? getProxyUrl(new URL(metas.image), 640, 640)
|
|
||||||
: undefined,
|
|
||||||
url: metas.image,
|
|
||||||
},
|
|
||||||
provider: {
|
provider: {
|
||||||
url: "https://spotify.com",
|
url: "https://spotify.com",
|
||||||
name: "Spotify",
|
name: "Spotify",
|
||||||
@ -369,18 +369,11 @@ export const EmbedHandlers: {
|
|||||||
type: EmbedType.image,
|
type: EmbedType.image,
|
||||||
title: metas.title,
|
title: metas.title,
|
||||||
description: metas.description,
|
description: metas.description,
|
||||||
image: {
|
image: makeEmbedImage(
|
||||||
width: metas.width,
|
metas.image || metas.image_fallback,
|
||||||
height: metas.height,
|
metas.width,
|
||||||
url: url.href,
|
metas.height,
|
||||||
proxy_url: metas.image
|
),
|
||||||
? getProxyUrl(
|
|
||||||
new URL(metas.image),
|
|
||||||
metas.width,
|
|
||||||
metas.height,
|
|
||||||
)
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
provider: {
|
provider: {
|
||||||
url: "https://pixiv.net",
|
url: "https://pixiv.net",
|
||||||
name: "Pixiv",
|
name: "Pixiv",
|
||||||
@ -437,37 +430,31 @@ export const EmbedHandlers: {
|
|||||||
const metas = getMetaDescriptions(await response.text());
|
const metas = getMetaDescriptions(await response.text());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
video: {
|
video: makeEmbedImage(
|
||||||
// TODO: does this adjust with aspect ratio?
|
metas.youtube_embed,
|
||||||
width: metas.width,
|
metas.width,
|
||||||
height: metas.height,
|
metas.height,
|
||||||
url: metas.youtube_embed,
|
),
|
||||||
},
|
|
||||||
url: url.href,
|
url: url.href,
|
||||||
type: EmbedType.video,
|
type: metas.youtube_embed ? EmbedType.video : EmbedType.link,
|
||||||
title: metas.title,
|
title: metas.title,
|
||||||
thumbnail: {
|
thumbnail: makeEmbedImage(
|
||||||
width: metas.width,
|
metas.image || metas.image_fallback,
|
||||||
height: metas.height,
|
metas.width,
|
||||||
url: metas.image,
|
metas.height,
|
||||||
proxy_url: metas.image
|
),
|
||||||
? getProxyUrl(
|
|
||||||
new URL(metas.image),
|
|
||||||
metas.width,
|
|
||||||
metas.height,
|
|
||||||
)
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
provider: {
|
provider: {
|
||||||
url: "https://www.youtube.com",
|
url: "https://www.youtube.com",
|
||||||
name: "YouTube",
|
name: "YouTube",
|
||||||
},
|
},
|
||||||
description: metas.description,
|
description: metas.description,
|
||||||
color: 16711680,
|
color: 16711680,
|
||||||
author: {
|
author: metas.author
|
||||||
name: metas.author,
|
? {
|
||||||
// TODO: author channel url
|
name: metas.author,
|
||||||
},
|
// TODO: author channel url
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -487,12 +474,7 @@ export const EmbedHandlers: {
|
|||||||
url: url.href,
|
url: url.href,
|
||||||
type: EmbedType.rich,
|
type: EmbedType.rich,
|
||||||
title: `xkcd: ${metas.title}`,
|
title: `xkcd: ${metas.title}`,
|
||||||
image: {
|
image: makeEmbedImage(metas.image, width, height),
|
||||||
width,
|
|
||||||
height,
|
|
||||||
url: metas.image,
|
|
||||||
proxy_url: getProxyUrl(new URL(metas.image), width, height),
|
|
||||||
},
|
|
||||||
footer: hoverText
|
footer: hoverText
|
||||||
? {
|
? {
|
||||||
text: hoverText,
|
text: hoverText,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user