Skip to content

Commit

Permalink
Merge pull request #67 from sillsdev/60-change-video-embed
Browse files Browse the repository at this point in the history
fix: Use video player only for embedded videos (#60)
  • Loading branch information
andrew-polk authored Aug 11, 2023
2 parents 2ad2ab1 + 047bafd commit 4606aff
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 102 deletions.
11 changes: 3 additions & 8 deletions src/config/default.docunotion.config.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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";

Expand All @@ -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,
Expand All @@ -38,8 +35,6 @@ const defaultConfig: IDocuNotionConfig = {
// Regexps plus javascript `import`s that operate on the Markdown output
imgurGifEmbed,
gifEmbed,
youtubeEmbed,
vimeoEmbed,
],
};

Expand Down
87 changes: 87 additions & 0 deletions src/plugins/VideoTransformer.spec.ts
Original file line number Diff line number Diff line change
@@ -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(
`<ReactPlayer controls url="https://www.youtube.com/watch?v=FXIrojSK3Jo" />`
);
});

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(
`<ReactPlayer controls url="https://vimeo.com/4613611xx" />`
);
});

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`);
});
29 changes: 29 additions & 0 deletions src/plugins/VideoTransformer.ts
Original file line number Diff line number Diff line change
@@ -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 `<ReactPlayer controls url="${video.external.url}" />`;
} else {
warning(
`[standardVideoTransformer] Found Notion "video" block with type ${video.type}. The best docu-notion can do for now is ignore it.`
);
}
return "";
},
},
],
};
60 changes: 1 addition & 59 deletions src/plugins/embedTweaks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
`<ReactPlayer controls url="https://www.youtube.com/watch?v=FXIrojSK3Jo" />`
);
});

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(
`<ReactPlayer controls url="https://vimeo.com/4613611xx" />`
);
});
import { gifEmbed, imgurGifEmbed } from "./embedTweaks";

test("imgur", async () => {
setLogLevel("verbose");
Expand Down
23 changes: 0 additions & 23 deletions src/plugins/embedTweaks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: `<ReactPlayer controls url="$1" />`,
},
],
};
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: `<ReactPlayer controls url="$1" />`,
},
],
};
19 changes: 17 additions & 2 deletions src/plugins/externalLinks.spec.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -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",
Expand Down
9 changes: 8 additions & 1 deletion src/plugins/pluginTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
};

Expand All @@ -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[];
};
17 changes: 8 additions & 9 deletions src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`;
}

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

// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const mod of regexMods) {
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit 4606aff

Please sign in to comment.