diff --git a/src/config/default.docunotion.config.ts b/src/config/default.docunotion.config.ts
index ee3dad4..6029250 100644
--- a/src/config/default.docunotion.config.ts
+++ b/src/config/default.docunotion.config.ts
@@ -1,9 +1,4 @@
-import {
- gifEmbed,
- imgurGifEmbed,
- vimeoEmbed,
- youtubeEmbed,
-} from "../plugins/embedTweaks";
+import { gifEmbed, imgurGifEmbed } from "../plugins/embedTweaks";
import { standardImageTransformer } from "../images";
import { standardInternalLinkConversion } from "../plugins/internalLinks";
import { standardCalloutTransformer } from "../plugins/CalloutTransformer";
@@ -13,6 +8,7 @@ import { standardEscapeHtmlBlockModifier } from "../plugins/EscapeHtmlBlockModif
import { standardHeadingTransformer } from "../plugins/HeadingTransformer";
import { standardNumberedListTransformer } from "../plugins/NumberedListTransformer";
import { standardTableTransformer } from "../plugins/TableTransformer";
+import { standardVideoTransformer } from "../plugins/VideoTransformer";
import { standardExternalLinkConversion } from "../plugins/externalLinks";
import { IDocuNotionConfig } from "./configuration";
@@ -30,6 +26,7 @@ const defaultConfig: IDocuNotionConfig = {
standardCalloutTransformer,
standardTableTransformer,
standardNumberedListTransformer,
+ standardVideoTransformer,
// Link modifiers, which are special because they can read metadata from all the pages in order to figure out the correct url
standardInternalLinkConversion,
@@ -38,8 +35,6 @@ const defaultConfig: IDocuNotionConfig = {
// Regexps plus javascript `import`s that operate on the Markdown output
imgurGifEmbed,
gifEmbed,
- youtubeEmbed,
- vimeoEmbed,
],
};
diff --git a/src/plugins/VideoTransformer.spec.ts b/src/plugins/VideoTransformer.spec.ts
new file mode 100644
index 0000000..4433af8
--- /dev/null
+++ b/src/plugins/VideoTransformer.spec.ts
@@ -0,0 +1,87 @@
+import { setLogLevel } from "../log";
+import { NotionBlock } from "../types";
+import { standardVideoTransformer } from "./VideoTransformer";
+import { blocksToMarkdown } from "./pluginTestRun";
+
+test("youtube embedded", async () => {
+ const config = { plugins: [standardVideoTransformer] };
+ const result = await blocksToMarkdown(config, [
+ {
+ object: "block",
+ type: "video",
+ video: {
+ caption: [
+ {
+ type: "text",
+ text: {
+ content: "A video about editing in Notion",
+ link: null,
+ },
+ plain_text: "A video about editing in Notion",
+ href: null,
+ },
+ ],
+ type: "external",
+ external: { url: "https://www.youtube.com/watch?v=FXIrojSK3Jo" },
+ },
+ } as unknown as NotionBlock,
+ ]);
+ expect(result).toContain(`import ReactPlayer from "react-player";`);
+ expect(result).toContain(
+ ``
+ );
+});
+
+test("vimeo embedded", async () => {
+ setLogLevel("verbose");
+ const config = { plugins: [standardVideoTransformer] };
+ const result = await blocksToMarkdown(config, [
+ {
+ object: "block",
+ type: "video",
+ video: {
+ caption: [],
+ type: "external",
+ external: { url: "https://vimeo.com/4613611xx" },
+ },
+ } as unknown as NotionBlock,
+ ]);
+ expect(result).toContain(`import ReactPlayer from "react-player";`);
+ expect(result).toContain(
+ ``
+ );
+});
+
+test("video link, not embedded", async () => {
+ setLogLevel("verbose");
+ const config = { plugins: [standardVideoTransformer] };
+ const result = await blocksToMarkdown(config, [
+ {
+ object: "block",
+ type: "paragraph",
+ paragraph: {
+ rich_text: [
+ {
+ type: "text",
+ text: {
+ content: "https://vimeo.com/4613611xx",
+ link: {
+ url: "https://vimeo.com/4613611xx",
+ },
+ },
+ annotations: {
+ code: false,
+ },
+ plain_text: "https://vimeo.com/4613611xx",
+ href: "https://vimeo.com/4613611xx",
+ },
+ ],
+ color: "default",
+ },
+ } as unknown as NotionBlock,
+ ]);
+ expect(result).toContain(
+ "[https://vimeo.com/4613611xx](https://vimeo.com/4613611xx)"
+ );
+ expect(result).not.toContain(`import`);
+});
diff --git a/src/plugins/VideoTransformer.ts b/src/plugins/VideoTransformer.ts
new file mode 100644
index 0000000..3151956
--- /dev/null
+++ b/src/plugins/VideoTransformer.ts
@@ -0,0 +1,29 @@
+import { VideoBlockObjectResponse } from "@notionhq/client/build/src/api-endpoints";
+import { IDocuNotionContext, IPlugin } from "./pluginTypes";
+import { warning } from "../log";
+import { NotionBlock } from "../types";
+
+export const standardVideoTransformer: IPlugin = {
+ name: "video",
+ notionToMarkdownTransforms: [
+ {
+ type: "video",
+ getStringFromBlock: (
+ context: IDocuNotionContext,
+ block: NotionBlock
+ ): string => {
+ const video = (block as VideoBlockObjectResponse).video;
+ if (video.type === "external") {
+ if (!context.imports) context.imports = [];
+ context.imports.push(`import ReactPlayer from "react-player";`);
+ return ``;
+ } else {
+ warning(
+ `[standardVideoTransformer] Found Notion "video" block with type ${video.type}. The best docu-notion can do for now is ignore it.`
+ );
+ }
+ return "";
+ },
+ },
+ ],
+};
diff --git a/src/plugins/embedTweaks.spec.ts b/src/plugins/embedTweaks.spec.ts
index 2491f21..1084a0c 100644
--- a/src/plugins/embedTweaks.spec.ts
+++ b/src/plugins/embedTweaks.spec.ts
@@ -2,65 +2,7 @@ import { NotionBlock } from "../types";
import { IPlugin } from "./pluginTypes";
import { setLogLevel } from "../log";
import { blocksToMarkdown } from "./pluginTestRun";
-import {
- gifEmbed,
- imgurGifEmbed,
- vimeoEmbed,
- youtubeEmbed,
-} from "./embedTweaks";
-
-test("youtube", async () => {
- const config = { plugins: [youtubeEmbed] };
- const result = await blocksToMarkdown(config, [
- {
- object: "block",
- id: "e6ddd1d4-36d4-4925-94c1-5dff4662c1f3",
- has_children: false,
- archived: false,
- type: "video",
- video: {
- caption: [
- {
- type: "text",
- text: {
- content: "A video about editing in Notion",
- link: null,
- },
- plain_text: "A video about editing in Notion",
- href: null,
- },
- ],
- type: "external",
- external: { url: "https://www.youtube.com/watch?v=FXIrojSK3Jo" },
- },
- } as unknown as NotionBlock,
- ]);
- expect(result).toContain(`import ReactPlayer from "react-player";`);
- expect(result).toContain(
- ``
- );
-});
-
-test("vimeo", async () => {
- setLogLevel("verbose");
- const config = { plugins: [vimeoEmbed] };
- const result = await blocksToMarkdown(config, [
- {
- object: "block",
- id: "39ff83a3-2fb5-4411-a715-960656a177ff",
- type: "video",
- video: {
- caption: [],
- type: "external",
- external: { url: "https://vimeo.com/4613611xx" },
- },
- } as unknown as NotionBlock,
- ]);
- expect(result).toContain(`import ReactPlayer from "react-player";`);
- expect(result).toContain(
- ``
- );
-});
+import { gifEmbed, imgurGifEmbed } from "./embedTweaks";
test("imgur", async () => {
setLogLevel("verbose");
diff --git a/src/plugins/embedTweaks.ts b/src/plugins/embedTweaks.ts
index 4111cdb..455abde 100644
--- a/src/plugins/embedTweaks.ts
+++ b/src/plugins/embedTweaks.ts
@@ -22,26 +22,3 @@ export const imgurGifEmbed: IPlugin = {
},
],
};
-export const youtubeEmbed: IPlugin = {
- name: "youtube",
- regexMarkdownModifications: [
- {
- regex: /\[.*\]\((.*youtube\.com\/watch.*)\)/, //youtube.com/watch
- imports: [`import ReactPlayer from "react-player";`],
- replacementPattern: ``,
- },
- ],
-};
-export const vimeoEmbed: IPlugin = {
- name: "vimeo",
- regexMarkdownModifications: [
- {
- regex: /\[.*\]\((https:\/\/.*vimeo.*)\)/,
- // we use to have the following, but the above should handle both the player an not-player urls.
- //regex: /\[.*\]\((.*player\.vimeo.*)\)/gm, // player.vimeo
-
- imports: [`import ReactPlayer from "react-player";`],
- replacementPattern: ``,
- },
- ],
-};
diff --git a/src/plugins/externalLinks.spec.ts b/src/plugins/externalLinks.spec.ts
index 578d8f6..9ba7298 100644
--- a/src/plugins/externalLinks.spec.ts
+++ b/src/plugins/externalLinks.spec.ts
@@ -1,5 +1,4 @@
-import { setLogLevel, verbose } from "../log";
-import { NotionPage } from "../NotionPage";
+import { setLogLevel } from "../log";
import { oneBlockToMarkdown } from "./pluginTestRun";
import { standardExternalLinkConversion } from "./externalLinks";
@@ -15,6 +14,22 @@ test("links turned into bookmarks", async () => {
expect(results.trim()).toBe("[https://github.com](https://github.com)");
});
+test("video links turned into bookmarks", async () => {
+ setLogLevel("debug");
+ const results = await getMarkdown({
+ object: "block",
+ type: "bookmark",
+ bookmark: {
+ caption: [],
+ url: "https://vimeo.com/4613611xx",
+ },
+ });
+ expect(results).toContain(
+ "[https://vimeo.com/4613611xx](https://vimeo.com/4613611xx)"
+ );
+ expect(results).not.toContain(`import`);
+});
+
test("external link inside callout", async () => {
const results = await getMarkdown({
type: "callout",
diff --git a/src/plugins/pluginTypes.ts b/src/plugins/pluginTypes.ts
index 7c3eb5c..065d690 100644
--- a/src/plugins/pluginTypes.ts
+++ b/src/plugins/pluginTypes.ts
@@ -53,7 +53,9 @@ export type IRegexMarkdownModification = {
// normally, anything in code blocks is will be ignored. If you want to make changes inside of code blocks, set this to true.
includeCodeBlocks?: boolean;
- // If the output is creating things like react elements, you can import their definitions here
+ // If the output is creating things like react elements, you can append their import definitions
+ // to this array so they get added to the page.
+ // e.g. mod.imports.push(`import ReactPlayer from "react-player";`);
imports?: string[];
};
@@ -74,4 +76,9 @@ export type IDocuNotionContext = {
convertNotionLinkToLocalDocusaurusLink: (url: string) => string | undefined;
pages: NotionPage[];
counts: ICounts;
+
+ // If the output is creating things like react elements, you can append their import definitions
+ // to this array so they get added to the page.
+ // e.g. context.imports.push(`import ReactPlayer from "react-player";`);
+ imports?: string[];
};
diff --git a/src/transform.ts b/src/transform.ts
index 94cb21a..20d7281 100644
--- a/src/transform.ts
+++ b/src/transform.ts
@@ -56,15 +56,14 @@ export async function getMarkdownFromNotionBlocks(
//console.log("markdown after link fixes", markdown);
// simple regex-based tweaks. These are usually related to docusaurus
- const { imports, body } = await doTransformsOnMarkdown(
- context,
- config,
- markdown
- );
+ const body = await doTransformsOnMarkdown(context, config, markdown);
// console.log("markdown after regex fixes", markdown);
// console.log("body after regex", body);
+ const uniqueImports = [...new Set(context.imports)];
+ const imports = uniqueImports.join("\n");
+ context.imports = []; // reset for next page
return `${imports}\n${body}`;
}
@@ -106,7 +105,6 @@ async function doTransformsOnMarkdown(
let body = input;
//console.log("body before regex: " + body);
let match;
- const imports = new Set();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const mod of regexMods) {
@@ -143,15 +141,16 @@ async function doTransformsOnMarkdown(
body =
precedingPart +
partStartingFromThisMatch.replace(original, replacement);
+
// add any library imports
- mod.imports?.forEach(imp => imports.add(imp));
+ if (!context.imports) context.imports = [];
+ context.imports.push(...(mod.imports || []));
}
}
}
}
logDebug("doTransformsOnMarkdown", "body after regex: " + body);
- const uniqueImports = [...new Set(imports)];
- return { body, imports: [...uniqueImports].join("\n") };
+ return body;
}
async function doNotionToMarkdown(