Fixes #6 by implementing link unfurling
This commit is contained in:
parent
b5ba23130b
commit
3217f2afc3
@ -39,6 +39,7 @@ let vm = new VM({
|
||||
clearTimeout,
|
||||
setInterval,
|
||||
URL,
|
||||
window: {},
|
||||
clearInterval,
|
||||
fetch: require(`${nodeModulesPath}/node-fetch`),
|
||||
WebSocket: require(`${nodeModulesPath}/ws`),
|
||||
|
@ -11,8 +11,16 @@ let pendingRequests = new Map<
|
||||
}
|
||||
>();
|
||||
|
||||
let isWorker = false;
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
// @ts-ignore
|
||||
window = {};
|
||||
isWorker = true;
|
||||
}
|
||||
|
||||
function workerPostMessage(msg: ControllerMessage) {
|
||||
if (typeof window !== "undefined" && window.parent !== window) {
|
||||
if (!isWorker && window.parent !== window) {
|
||||
window.parent.postMessage(msg, "*");
|
||||
} else {
|
||||
self.postMessage(msg);
|
||||
|
@ -319,3 +319,26 @@ functions:
|
||||
name: "UI: Hide BHS"
|
||||
key: "Ctrl-Alt-b"
|
||||
mac: "Cmd-Alt-b"
|
||||
|
||||
# Link unfurl infrastructure
|
||||
unfurlLink:
|
||||
path: ./link.ts:unfurlCommand
|
||||
command:
|
||||
name: "Link: Unfurl"
|
||||
key: "Ctrl-Shift-u"
|
||||
mac: "Cmd-Shift-u"
|
||||
contexts:
|
||||
- NakedURL
|
||||
unfurlExec:
|
||||
env: server
|
||||
path: ./link.ts:unfurlExec
|
||||
|
||||
# Title-based link unfurl
|
||||
titleUnfurlOptions:
|
||||
path: ./link.ts:titleUnfurlOptions
|
||||
events:
|
||||
- unfurl:options
|
||||
titleUnfurl:
|
||||
path: ./link.ts:titleUnfurl
|
||||
events:
|
||||
- unfurl:title-unfurl
|
||||
|
79
packages/plugs/core/link.ts
Normal file
79
packages/plugs/core/link.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { nodeAtPos } from "@silverbulletmd/common/tree";
|
||||
import {
|
||||
filterBox,
|
||||
flashNotification,
|
||||
getCursor,
|
||||
getText,
|
||||
replaceRange,
|
||||
} from "@silverbulletmd/plugos-silverbullet-syscall/editor";
|
||||
import { parseMarkdown } from "@silverbulletmd/plugos-silverbullet-syscall/markdown";
|
||||
import { dispatch as dispatchEvent } from "@plugos/plugos-syscall/event";
|
||||
import { invokeFunction } from "@silverbulletmd/plugos-silverbullet-syscall/system";
|
||||
|
||||
type UnfurlOption = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export async function unfurlCommand() {
|
||||
let mdTree = await parseMarkdown(await getText());
|
||||
let nakedUrlNode = nodeAtPos(mdTree, await getCursor());
|
||||
let url = nakedUrlNode!.children![0].text!;
|
||||
console.log("Got URL to unfurl", url);
|
||||
let optionResponses = await dispatchEvent("unfurl:options", url);
|
||||
let options: UnfurlOption[] = [];
|
||||
for (let resp of optionResponses) {
|
||||
options.push(...resp);
|
||||
}
|
||||
let selectedUnfurl: any = await filterBox(
|
||||
"Unfurl",
|
||||
options,
|
||||
"Select the unfurl strategy of your choice"
|
||||
);
|
||||
if (!selectedUnfurl) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let replacement = await invokeFunction(
|
||||
"server",
|
||||
"unfurlExec",
|
||||
selectedUnfurl.id,
|
||||
url
|
||||
);
|
||||
await replaceRange(nakedUrlNode?.from!, nakedUrlNode?.to!, replacement);
|
||||
} catch (e: any) {
|
||||
await flashNotification(e.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
export async function titleUnfurlOptions(url: string): Promise<UnfurlOption[]> {
|
||||
return [
|
||||
{
|
||||
id: "title-unfurl",
|
||||
name: "Extract title",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// Run on the server because plugs will likely rely on fetch for this
|
||||
export async function unfurlExec(id: string, url: string): Promise<string> {
|
||||
let replacement = await dispatchEvent(`unfurl:${id}`, url);
|
||||
return replacement[0];
|
||||
}
|
||||
|
||||
const titleRegex = /<title[^>]*>\s*([^<]+)\s*<\/title\s*>/i;
|
||||
|
||||
export async function titleUnfurl(url: string): Promise<string> {
|
||||
let response = await fetch(url);
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
console.error("Unfurl failed", await response.text());
|
||||
throw new Error(`Failed to fetch: ${await response.statusText}`);
|
||||
}
|
||||
let body = await response.text();
|
||||
let match = titleRegex.exec(body);
|
||||
if (match) {
|
||||
return `[${match[1]}](${url})`;
|
||||
} else {
|
||||
throw new Error("No title found");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user