100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
/**
|
|
* Previews links to this site's own dump, user and playlist pages, as
|
|
* `parsePagePath` reads them, from the database, for `rich-content-service.ts`. No request goes out, so this works
|
|
* even when the site runs on a private host that `fetchWithTimeout` refuses.
|
|
*
|
|
* @module
|
|
*/
|
|
|
|
import type { RichContent } from "../../../shared/dump.ts";
|
|
import type { RichContentProvider } from "./provider.ts";
|
|
import { getDumpByPath } from "../../services/dump-service.ts";
|
|
import { resolveUsername } from "../../services/user-service.ts";
|
|
import { getPlaylistByPath } from "../../services/playlist-service.ts";
|
|
import { APIException } from "../../lib/api-exception.ts";
|
|
import { PUBLIC_URL, THEME_COLOR } from "../../config.ts";
|
|
import { isSelfUrl } from "../../lib/self-url.ts";
|
|
import { parsePagePath } from "../../../shared/paths.ts";
|
|
|
|
/**
|
|
* Gives a link to this site without a thumbnail a placeholder in the site's
|
|
* icon and color.
|
|
*/
|
|
const SELF_BRANDING = {
|
|
siteName: "gerbeur",
|
|
faviconUrl: `${PUBLIC_URL}/apple-touch-icon.png`,
|
|
accentColor: THEME_COLOR,
|
|
} as const;
|
|
|
|
/**
|
|
* Comes before the generic provider, and claims what `isSelfUrl` accepts. A
|
|
* profile's tab previews as the profile. Its `fetch` rejects with a 404
|
|
* `APIException` for a missing page, a private dump or a private playlist:
|
|
* the preview is stored in the linking dump, which others may see.
|
|
*/
|
|
export const selfProvider: RichContentProvider = {
|
|
name: "self",
|
|
|
|
matches(url: string): boolean {
|
|
try {
|
|
return isSelfUrl(new URL(url));
|
|
} catch {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
fetch(url: string): Promise<RichContent> {
|
|
// matches() let only these paths through.
|
|
const page = parsePagePath(new URL(url).pathname)!;
|
|
const user = resolveUsername(page.username);
|
|
|
|
if (page.kind === "dump") {
|
|
const dump = getDumpByPath(user.id, page.slug);
|
|
let thumbnailUrl: string | undefined;
|
|
if (dump.kind === "file" && dump.fileMime?.startsWith("image/")) {
|
|
thumbnailUrl = `${PUBLIC_URL}/api/dumps/${dump.id}/file`;
|
|
} else if (dump.richContent?.thumbnailUrl) {
|
|
thumbnailUrl = dump.richContent.thumbnailUrl;
|
|
}
|
|
return Promise.resolve({
|
|
type: "generic",
|
|
url,
|
|
...SELF_BRANDING,
|
|
title: dump.title,
|
|
description: dump.comment,
|
|
thumbnailUrl,
|
|
});
|
|
}
|
|
|
|
if (page.kind === "playlist") {
|
|
const playlist = getPlaylistByPath(user.id, page.slug);
|
|
if (!playlist.isPublic) {
|
|
throw new APIException(404, "Playlist not found");
|
|
}
|
|
const thumbnailUrl = playlist.imageMime
|
|
? `${PUBLIC_URL}/api/playlists/${playlist.id}/cover`
|
|
: undefined;
|
|
return Promise.resolve({
|
|
type: "generic",
|
|
url,
|
|
...SELF_BRANDING,
|
|
title: playlist.title,
|
|
description: playlist.description,
|
|
thumbnailUrl,
|
|
});
|
|
}
|
|
|
|
const thumbnailUrl = user.avatarMime
|
|
? `${PUBLIC_URL}/api/users/${user.id}/avatar`
|
|
: undefined;
|
|
return Promise.resolve({
|
|
type: "generic",
|
|
url,
|
|
...SELF_BRANDING,
|
|
title: user.username,
|
|
description: user.description,
|
|
thumbnailUrl,
|
|
});
|
|
},
|
|
};
|