52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
/**
|
|
* Previews SoundCloud links from their page's OG tags, for
|
|
* `rich-content-service.ts`.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import type { RichContent } from "../../../shared/dump.ts";
|
|
import type { RichContentProvider } from "./provider.ts";
|
|
import { extractOgTag } from "../html.ts";
|
|
import { fetchWithTimeout, readTextCapped } from "../fetch.ts";
|
|
|
|
/**
|
|
* Claims soundcloud.com only, not www. or m.soundcloud.com, and builds the
|
|
* embed player's URL from the link itself.
|
|
*/
|
|
export const soundcloudProvider: RichContentProvider = {
|
|
name: "soundcloud",
|
|
|
|
matches(url: string): boolean {
|
|
try {
|
|
return new URL(url).hostname === "soundcloud.com";
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
async fetch(url: string): Promise<RichContent> {
|
|
const res = await fetchWithTimeout(url);
|
|
const contentType = res.headers.get("content-type") ?? "";
|
|
|
|
if (!contentType.startsWith("text/html")) {
|
|
await res.body?.cancel();
|
|
return { type: "soundcloud", siteName: "SoundCloud", url };
|
|
}
|
|
|
|
const html = await readTextCapped(res);
|
|
|
|
return {
|
|
type: "soundcloud",
|
|
siteName: "SoundCloud",
|
|
url,
|
|
title: extractOgTag(html, "title"),
|
|
description: extractOgTag(html, "description"),
|
|
thumbnailUrl: extractOgTag(html, "image"),
|
|
embedUrl: `https://w.soundcloud.com/player/?url=${
|
|
encodeURIComponent(url)
|
|
}&visual=true&auto_play=false`,
|
|
};
|
|
},
|
|
};
|