Skip to content

Commit b5d539e

Browse files
committed
feat: initial video and gif embedding
1 parent 3162ce2 commit b5d539e

File tree

3 files changed

+111
-22
lines changed

3 files changed

+111
-22
lines changed

.vscode/settings.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"callouts"
88
],
99
"workbench.colorCustomizations": {
10-
"statusBar.noFolderBackground": "#49d6a0",
11-
"statussBar.prominentBackground": "#49d6a0"
10+
"statusBar.background": "#d649ca",
11+
"statusBar.noFolderBackground": "#d649ca",
12+
"statussBar.prominentBackground": "#d649ca"
1213
}
1314
}

src/DocusaurusTweaks.ts

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,99 @@
1-
const notionCalloutPattern = />\s(||💡||🔥)\s(.*)\n/gmu;
2-
const calloutsToAdmonitions = {
3-
/* prettier-ignore */ "ℹ️": "note",
4-
"💡": "tip",
5-
"❗": "info",
6-
"⚠️": "caution",
7-
"🔥": "danger",
8-
};
9-
10-
export function tweakForDocusaurus(input: string): string {
1+
import chalk from "chalk";
2+
3+
export function tweakForDocusaurus(input: string): {
4+
body: string;
5+
imports: string;
6+
} {
7+
const output = notionCalloutsToAdmonitions(input);
8+
const { body, imports } = notionEmbedsToMDX(output);
9+
return { body, imports };
10+
}
11+
// In Notion, you can embed videos & such. To show these
12+
// in Docusaurus, we have to
13+
// * switch to .MDX instead of just .MD
14+
// * import the required react libraries
15+
// * insert some JSX for each embed
16+
function notionEmbedsToMDX(input: string): {
17+
body: string;
18+
imports: string;
19+
} {
20+
/* Note: the notion api tells us that the embedded type is video, but this information is lost by the time
21+
we got through notion-to-md:
22+
{
23+
...
24+
"type": "video",
25+
"video": {
26+
"caption": [],
27+
"type": "external",
28+
"external": {
29+
"url": "https://www.youtube.com/watch?v=FXIrojSK3Jo"
30+
}
31+
}
32+
},
33+
34+
For now, we're just using this regex to notice youtube and vimeo.
35+
*/
36+
37+
// NOTE: currently notion-to-md seems to be dropping the "Caption" entirely.
38+
39+
const video = {
40+
import: `import ReactPlayer from "react-player";`,
41+
output: `<ReactPlayer controls url="$1" />`,
42+
};
43+
const gif = {
44+
import: `import GifPlayer from "react-gif-player";`,
45+
output: `<GifPlayer gif="$1" />`,
46+
};
47+
const embeds = {
48+
youtube: {
49+
regex: /\[.*\]\((.*youtube\.com\/watch.*)\)/gm, //youtube.com/watch
50+
...video,
51+
},
52+
vimeo: {
53+
regex: /\[.*\]\((.*player\.vimeo.*)\)/gm, // player.vimeo
54+
...video,
55+
},
56+
imgur: {
57+
regex: /\[embed\]\((.*imgur\.com\/.*)\)/gm, // imgur.com
58+
...gif,
59+
},
60+
gifExtension: {
61+
// ending in .gif. I once saw a gif coming form Notion that wasn't a full
62+
// url, which wouldn't work, hence the "http" requirement
63+
regex: /\[.*\]\((http.*(\.(gif|GIF)))\)/gm,
64+
...gif,
65+
},
66+
};
67+
68+
let body = input;
69+
let match;
70+
const imports = new Set<string>();
71+
72+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
73+
for (const [k, v] of Object.entries(embeds)) {
74+
while ((match = v.regex.exec(input)) !== null) {
75+
const string = match[0];
76+
const url = match[1];
77+
console.log(chalk.green(`${string} --> ${v.output.replace("$1", url)}`));
78+
body = body.replace(string, v.output.replace("$1", url));
79+
imports.add(v.import);
80+
}
81+
}
82+
83+
return { body, imports: [...imports].join("\n") };
84+
}
85+
86+
// In Notion, you can make a callout and change its emoji. We map 5 of these
87+
// to the 5 Docusaurus admonition styles.
88+
function notionCalloutsToAdmonitions(input: string): string {
89+
const notionCalloutPattern = />\s(||💡||🔥)\s(.*)\n/gmu;
90+
const calloutsToAdmonitions = {
91+
/* prettier-ignore */ "ℹ️": "note",
92+
"💡": "tip",
93+
"❗": "info",
94+
"⚠️": "caution",
95+
"🔥": "danger",
96+
};
1197
let output = input;
1298
let match;
1399
while ((match = notionCalloutPattern.exec(input)) !== null) {

src/pull.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,24 +160,26 @@ async function outputPage(page: NotionPage) {
160160

161161
const mdBlocks = await notionToMarkdown.blocksToMarkdown(blocks);
162162

163-
// if (page.nameOrTitle === "Bananas") {
163+
// if (page.nameOrTitle.startsWith("Embed")) {
164164
// console.log(JSON.stringify(blocks, null, 2));
165165
// console.log(JSON.stringify(mdBlocks, null, 2));
166166
// }
167-
let markdown = "---\n";
168-
markdown += `title: ${page.nameOrTitle}\n`;
169-
markdown += `sidebar_position: ${currentSidebarPosition}\n`;
170-
markdown += `slug: ${page.slug ?? ""}\n`;
171-
if (page.keywords) markdown += `keywords: [${page.keywords}]\n`;
167+
let frontmatter = "---\n";
168+
frontmatter += `title: ${page.nameOrTitle}\n`;
169+
frontmatter += `sidebar_position: ${currentSidebarPosition}\n`;
170+
frontmatter += `slug: ${page.slug ?? ""}\n`;
171+
if (page.keywords) frontmatter += `keywords: [${page.keywords}]\n`;
172172

173-
markdown += "---\n\n";
174-
markdown += notionToMarkdown.toMarkdownString(mdBlocks);
173+
frontmatter += "---\n";
174+
175+
let markdown = notionToMarkdown.toMarkdownString(mdBlocks);
175176

176177
markdown = convertInternalLinks(markdown);
177178

178-
markdown = tweakForDocusaurus(markdown);
179+
const { body, imports } = tweakForDocusaurus(markdown);
180+
const output = `${frontmatter}\n${imports}\n${body}`;
179181

180-
fs.writeFileSync(path, markdown, {});
182+
fs.writeFileSync(path, output, {});
181183
}
182184

183185
async function outputImages(

0 commit comments

Comments
 (0)