/** * Previews SoundCloud links from their page, for `rich-content-service.ts`. * * @module */ import type { RichContent } from "../../../shared/dump.ts"; import type { RichContentProvider } from "./provider.ts"; import { parsePage } from "../html.ts"; import { fetchPage } from "../fetch.ts"; import { genericPreview } from "./generic.ts"; /** SoundCloud's own hosts, the short links' `on.` included. */ const SOUNDCLOUD_HOSTS = new Set([ "soundcloud.com", "www.soundcloud.com", "m.soundcloud.com", "on.soundcloud.com", ]); /** * Returns the soundcloud.com address of the page, which the embed player * takes: its `og:url`, or else the URL it was served from. A short link only * redirects, so it is never the answer; tracking parameters are dropped. */ function pageAddress(ogUrl: string | undefined, finalUrl: string): string { for (const raw of [ogUrl, finalUrl]) { if (!raw) continue; try { const url = new URL(raw); if ( !SOUNDCLOUD_HOSTS.has(url.hostname) || url.hostname === "on.soundcloud.com" ) continue; return `https://soundcloud.com${url.pathname}`; } catch { continue; } } return finalUrl; } /** * Claims SoundCloud's hosts, short links included, and builds the embed * player's URL from the page's address. */ export const soundcloudProvider: RichContentProvider = { name: "soundcloud", matches(url: string): boolean { try { return SOUNDCLOUD_HOSTS.has(new URL(url).hostname); } catch { return false; } }, async fetch(url: string): Promise { const fetched = await fetchPage(url); const page = fetched.html === undefined ? undefined : parsePage(fetched.html, fetched.url); const address = pageAddress(page?.meta("og:url"), fetched.url); return { ...(page ? genericPreview(page, url, fetched.url) : { url }), type: "soundcloud", siteName: "SoundCloud", embedUrl: `https://w.soundcloud.com/player/?url=${ encodeURIComponent(address) }&visual=true&auto_play=false`, }; }, };