Skip to content

Commit 047bafd

Browse files
committed
fix: Use video player only for embedded videos (#60)
1 parent 2ad2ab1 commit 047bafd

File tree

8 files changed

+153
-102
lines changed

8 files changed

+153
-102
lines changed

src/config/default.docunotion.config.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
gifEmbed,
3-
imgurGifEmbed,
4-
vimeoEmbed,
5-
youtubeEmbed,
6-
} from "../plugins/embedTweaks";
1+
import { gifEmbed, imgurGifEmbed } from "../plugins/embedTweaks";
72
import { standardImageTransformer } from "../images";
83
import { standardInternalLinkConversion } from "../plugins/internalLinks";
94
import { standardCalloutTransformer } from "../plugins/CalloutTransformer";
@@ -13,6 +8,7 @@ import { standardEscapeHtmlBlockModifier } from "../plugins/EscapeHtmlBlockModif
138
import { standardHeadingTransformer } from "../plugins/HeadingTransformer";
149
import { standardNumberedListTransformer } from "../plugins/NumberedListTransformer";
1510
import { standardTableTransformer } from "../plugins/TableTransformer";
11+
import { standardVideoTransformer } from "../plugins/VideoTransformer";
1612
import { standardExternalLinkConversion } from "../plugins/externalLinks";
1713
import { IDocuNotionConfig } from "./configuration";
1814

@@ -30,6 +26,7 @@ const defaultConfig: IDocuNotionConfig = {
3026
standardCalloutTransformer,
3127
standardTableTransformer,
3228
standardNumberedListTransformer,
29+
standardVideoTransformer,
3330

3431
// Link modifiers, which are special because they can read metadata from all the pages in order to figure out the correct url
3532
standardInternalLinkConversion,
@@ -38,8 +35,6 @@ const defaultConfig: IDocuNotionConfig = {
3835
// Regexps plus javascript `import`s that operate on the Markdown output
3936
imgurGifEmbed,
4037
gifEmbed,
41-
youtubeEmbed,
42-
vimeoEmbed,
4338
],
4439
};
4540

src/plugins/VideoTransformer.spec.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { setLogLevel } from "../log";
2+
import { NotionBlock } from "../types";
3+
import { standardVideoTransformer } from "./VideoTransformer";
4+
import { blocksToMarkdown } from "./pluginTestRun";
5+
6+
test("youtube embedded", async () => {
7+
const config = { plugins: [standardVideoTransformer] };
8+
const result = await blocksToMarkdown(config, [
9+
{
10+
object: "block",
11+
type: "video",
12+
video: {
13+
caption: [
14+
{
15+
type: "text",
16+
text: {
17+
content: "A video about editing in Notion",
18+
link: null,
19+
},
20+
plain_text: "A video about editing in Notion",
21+
href: null,
22+
},
23+
],
24+
type: "external",
25+
external: { url: "https://www.youtube.com/watch?v=FXIrojSK3Jo" },
26+
},
27+
} as unknown as NotionBlock,
28+
]);
29+
expect(result).toContain(`import ReactPlayer from "react-player";`);
30+
expect(result).toContain(
31+
`<ReactPlayer controls url="https://www.youtube.com/watch?v=FXIrojSK3Jo" />`
32+
);
33+
});
34+
35+
test("vimeo embedded", async () => {
36+
setLogLevel("verbose");
37+
const config = { plugins: [standardVideoTransformer] };
38+
const result = await blocksToMarkdown(config, [
39+
{
40+
object: "block",
41+
type: "video",
42+
video: {
43+
caption: [],
44+
type: "external",
45+
external: { url: "https://vimeo.com/4613611xx" },
46+
},
47+
} as unknown as NotionBlock,
48+
]);
49+
expect(result).toContain(`import ReactPlayer from "react-player";`);
50+
expect(result).toContain(
51+
`<ReactPlayer controls url="https://vimeo.com/4613611xx" />`
52+
);
53+
});
54+
55+
test("video link, not embedded", async () => {
56+
setLogLevel("verbose");
57+
const config = { plugins: [standardVideoTransformer] };
58+
const result = await blocksToMarkdown(config, [
59+
{
60+
object: "block",
61+
type: "paragraph",
62+
paragraph: {
63+
rich_text: [
64+
{
65+
type: "text",
66+
text: {
67+
content: "https://vimeo.com/4613611xx",
68+
link: {
69+
url: "https://vimeo.com/4613611xx",
70+
},
71+
},
72+
annotations: {
73+
code: false,
74+
},
75+
plain_text: "https://vimeo.com/4613611xx",
76+
href: "https://vimeo.com/4613611xx",
77+
},
78+
],
79+
color: "default",
80+
},
81+
} as unknown as NotionBlock,
82+
]);
83+
expect(result).toContain(
84+
"[https://vimeo.com/4613611xx](https://vimeo.com/4613611xx)"
85+
);
86+
expect(result).not.toContain(`import`);
87+
});

src/plugins/VideoTransformer.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { VideoBlockObjectResponse } from "@notionhq/client/build/src/api-endpoints";
2+
import { IDocuNotionContext, IPlugin } from "./pluginTypes";
3+
import { warning } from "../log";
4+
import { NotionBlock } from "../types";
5+
6+
export const standardVideoTransformer: IPlugin = {
7+
name: "video",
8+
notionToMarkdownTransforms: [
9+
{
10+
type: "video",
11+
getStringFromBlock: (
12+
context: IDocuNotionContext,
13+
block: NotionBlock
14+
): string => {
15+
const video = (block as VideoBlockObjectResponse).video;
16+
if (video.type === "external") {
17+
if (!context.imports) context.imports = [];
18+
context.imports.push(`import ReactPlayer from "react-player";`);
19+
return `<ReactPlayer controls url="${video.external.url}" />`;
20+
} else {
21+
warning(
22+
`[standardVideoTransformer] Found Notion "video" block with type ${video.type}. The best docu-notion can do for now is ignore it.`
23+
);
24+
}
25+
return "";
26+
},
27+
},
28+
],
29+
};

src/plugins/embedTweaks.spec.ts

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,7 @@ import { NotionBlock } from "../types";
22
import { IPlugin } from "./pluginTypes";
33
import { setLogLevel } from "../log";
44
import { blocksToMarkdown } from "./pluginTestRun";
5-
import {
6-
gifEmbed,
7-
imgurGifEmbed,
8-
vimeoEmbed,
9-
youtubeEmbed,
10-
} from "./embedTweaks";
11-
12-
test("youtube", async () => {
13-
const config = { plugins: [youtubeEmbed] };
14-
const result = await blocksToMarkdown(config, [
15-
{
16-
object: "block",
17-
id: "e6ddd1d4-36d4-4925-94c1-5dff4662c1f3",
18-
has_children: false,
19-
archived: false,
20-
type: "video",
21-
video: {
22-
caption: [
23-
{
24-
type: "text",
25-
text: {
26-
content: "A video about editing in Notion",
27-
link: null,
28-
},
29-
plain_text: "A video about editing in Notion",
30-
href: null,
31-
},
32-
],
33-
type: "external",
34-
external: { url: "https://www.youtube.com/watch?v=FXIrojSK3Jo" },
35-
},
36-
} as unknown as NotionBlock,
37-
]);
38-
expect(result).toContain(`import ReactPlayer from "react-player";`);
39-
expect(result).toContain(
40-
`<ReactPlayer controls url="https://www.youtube.com/watch?v=FXIrojSK3Jo" />`
41-
);
42-
});
43-
44-
test("vimeo", async () => {
45-
setLogLevel("verbose");
46-
const config = { plugins: [vimeoEmbed] };
47-
const result = await blocksToMarkdown(config, [
48-
{
49-
object: "block",
50-
id: "39ff83a3-2fb5-4411-a715-960656a177ff",
51-
type: "video",
52-
video: {
53-
caption: [],
54-
type: "external",
55-
external: { url: "https://vimeo.com/4613611xx" },
56-
},
57-
} as unknown as NotionBlock,
58-
]);
59-
expect(result).toContain(`import ReactPlayer from "react-player";`);
60-
expect(result).toContain(
61-
`<ReactPlayer controls url="https://vimeo.com/4613611xx" />`
62-
);
63-
});
5+
import { gifEmbed, imgurGifEmbed } from "./embedTweaks";
646

657
test("imgur", async () => {
668
setLogLevel("verbose");

src/plugins/embedTweaks.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,3 @@ export const imgurGifEmbed: IPlugin = {
2222
},
2323
],
2424
};
25-
export const youtubeEmbed: IPlugin = {
26-
name: "youtube",
27-
regexMarkdownModifications: [
28-
{
29-
regex: /\[.*\]\((.*youtube\.com\/watch.*)\)/, //youtube.com/watch
30-
imports: [`import ReactPlayer from "react-player";`],
31-
replacementPattern: `<ReactPlayer controls url="$1" />`,
32-
},
33-
],
34-
};
35-
export const vimeoEmbed: IPlugin = {
36-
name: "vimeo",
37-
regexMarkdownModifications: [
38-
{
39-
regex: /\[.*\]\((https:\/\/.*vimeo.*)\)/,
40-
// we use to have the following, but the above should handle both the player an not-player urls.
41-
//regex: /\[.*\]\((.*player\.vimeo.*)\)/gm, // player.vimeo
42-
43-
imports: [`import ReactPlayer from "react-player";`],
44-
replacementPattern: `<ReactPlayer controls url="$1" />`,
45-
},
46-
],
47-
};

src/plugins/externalLinks.spec.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { setLogLevel, verbose } from "../log";
2-
import { NotionPage } from "../NotionPage";
1+
import { setLogLevel } from "../log";
32
import { oneBlockToMarkdown } from "./pluginTestRun";
43
import { standardExternalLinkConversion } from "./externalLinks";
54

@@ -15,6 +14,22 @@ test("links turned into bookmarks", async () => {
1514
expect(results.trim()).toBe("[https://github.com](https://github.com)");
1615
});
1716

17+
test("video links turned into bookmarks", async () => {
18+
setLogLevel("debug");
19+
const results = await getMarkdown({
20+
object: "block",
21+
type: "bookmark",
22+
bookmark: {
23+
caption: [],
24+
url: "https://vimeo.com/4613611xx",
25+
},
26+
});
27+
expect(results).toContain(
28+
"[https://vimeo.com/4613611xx](https://vimeo.com/4613611xx)"
29+
);
30+
expect(results).not.toContain(`import`);
31+
});
32+
1833
test("external link inside callout", async () => {
1934
const results = await getMarkdown({
2035
type: "callout",

src/plugins/pluginTypes.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ export type IRegexMarkdownModification = {
5353
// normally, anything in code blocks is will be ignored. If you want to make changes inside of code blocks, set this to true.
5454
includeCodeBlocks?: boolean;
5555

56-
// If the output is creating things like react elements, you can import their definitions here
56+
// If the output is creating things like react elements, you can append their import definitions
57+
// to this array so they get added to the page.
58+
// e.g. mod.imports.push(`import ReactPlayer from "react-player";`);
5759
imports?: string[];
5860
};
5961

@@ -74,4 +76,9 @@ export type IDocuNotionContext = {
7476
convertNotionLinkToLocalDocusaurusLink: (url: string) => string | undefined;
7577
pages: NotionPage[];
7678
counts: ICounts;
79+
80+
// If the output is creating things like react elements, you can append their import definitions
81+
// to this array so they get added to the page.
82+
// e.g. context.imports.push(`import ReactPlayer from "react-player";`);
83+
imports?: string[];
7784
};

src/transform.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,14 @@ export async function getMarkdownFromNotionBlocks(
5656
//console.log("markdown after link fixes", markdown);
5757

5858
// simple regex-based tweaks. These are usually related to docusaurus
59-
const { imports, body } = await doTransformsOnMarkdown(
60-
context,
61-
config,
62-
markdown
63-
);
59+
const body = await doTransformsOnMarkdown(context, config, markdown);
6460

6561
// console.log("markdown after regex fixes", markdown);
6662
// console.log("body after regex", body);
6763

64+
const uniqueImports = [...new Set(context.imports)];
65+
const imports = uniqueImports.join("\n");
66+
context.imports = []; // reset for next page
6867
return `${imports}\n${body}`;
6968
}
7069

@@ -106,7 +105,6 @@ async function doTransformsOnMarkdown(
106105
let body = input;
107106
//console.log("body before regex: " + body);
108107
let match;
109-
const imports = new Set<string>();
110108

111109
// eslint-disable-next-line @typescript-eslint/no-unused-vars
112110
for (const mod of regexMods) {
@@ -143,15 +141,16 @@ async function doTransformsOnMarkdown(
143141
body =
144142
precedingPart +
145143
partStartingFromThisMatch.replace(original, replacement);
144+
146145
// add any library imports
147-
mod.imports?.forEach(imp => imports.add(imp));
146+
if (!context.imports) context.imports = [];
147+
context.imports.push(...(mod.imports || []));
148148
}
149149
}
150150
}
151151
}
152152
logDebug("doTransformsOnMarkdown", "body after regex: " + body);
153-
const uniqueImports = [...new Set(imports)];
154-
return { body, imports: [...uniqueImports].join("\n") };
153+
return body;
155154
}
156155

157156
async function doNotionToMarkdown(

0 commit comments

Comments
 (0)