From 3d2469d6f3239f17e5ab5823312d573be67ecab1 Mon Sep 17 00:00:00 2001
From: Gleb Voitenko
Date: Wed, 6 Nov 2024 13:42:42 +0300
Subject: [PATCH] feat: support video by url only
---
src/transform/plugins/video/const.ts | 7 -------
src/transform/plugins/video/index.ts | 19 ++++++++++++-------
src/transform/plugins/video/parsers.ts | 19 ++++++++++---------
src/transform/plugins/video/types.ts | 7 +++++++
test/data/video/video-fixtures.txt | 2 +-
test/video.test.ts | 26 +++++++++++++-------------
6 files changed, 43 insertions(+), 37 deletions(-)
diff --git a/src/transform/plugins/video/const.ts b/src/transform/plugins/video/const.ts
index 28f4b6f6..5f005c66 100644
--- a/src/transform/plugins/video/const.ts
+++ b/src/transform/plugins/video/const.ts
@@ -15,13 +15,6 @@ export enum VideoService {
url = 'url',
}
-export type Service = {
- csp?: Record;
- extract(url: string): string;
-};
-
-export type Services = [VideoService, Service][];
-
export const defaults: VideoFullOptions = {
videoUrl,
youtube: {width: 640, height: 390},
diff --git a/src/transform/plugins/video/index.ts b/src/transform/plugins/video/index.ts
index 82678616..9262740c 100644
--- a/src/transform/plugins/video/index.ts
+++ b/src/transform/plugins/video/index.ts
@@ -83,7 +83,7 @@ function tokenizeVideo(md: MarkdownIt, options: VideoFullOptions): Renderer.Rend
};
}
-const EMBED_REGEX = /@\[([a-zA-Z].+)]\([\s]*(.*?)[\s]*[)]/im;
+const EMBED_REGEX = /@\[([a-zA-Z]*?)]\([\s]*(.*?)[\s]*[)]/im;
function videoEmbed(md: MarkdownIt, _options: VideoFullOptions): ParserInline.RuleInline {
return (state, silent) => {
@@ -98,12 +98,11 @@ function videoEmbed(md: MarkdownIt, _options: VideoFullOptions): ParserInline.Ru
}
const match = EMBED_REGEX.exec(state.src.slice(state.pos, state.src.length));
-
if (!match || match.length < 3) {
return false;
}
- const service = match[1];
+ const service = match[1] || 'url';
const parsed = parseVideoUrl(service, match[2]);
if (parsed === false) {
@@ -126,13 +125,19 @@ function videoEmbed(md: MarkdownIt, _options: VideoFullOptions): ParserInline.Ru
const newState = new theState.md.inline.State(service, theState.md, theState.env, []);
newState.md.inline.tokenize(newState);
- const token = theState.push('video', '', 0);
- (token as VideoToken).videoID = videoID;
- (token as VideoToken).service = service;
+ const token = theState.push('video', '', 0) as VideoToken;
+
+ token.videoID = videoID;
+ token.service = service;
+
token.level = theState.level;
}
- theState.pos += theState.src.indexOf(')', theState.pos);
+ if (service === 'url') {
+ theState.pos = theState.src.indexOf(')', theState.pos) + 1;
+ } else {
+ theState.pos += theState.src.indexOf(')', theState.pos);
+ }
if (csp) {
state.env.meta ??= {};
diff --git a/src/transform/plugins/video/parsers.ts b/src/transform/plugins/video/parsers.ts
index 0a01d28d..46aa3a1b 100644
--- a/src/transform/plugins/video/parsers.ts
+++ b/src/transform/plugins/video/parsers.ts
@@ -1,4 +1,5 @@
-import {Services} from './const';
+import {VideoService} from './const';
+import {Services} from './types';
const ytRegex = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
export function youtubeParser(url: string) {
@@ -53,7 +54,7 @@ export function rutubeParser(url: string) {
const urlParser = (url: string) => url;
-const supportedServices = Object.entries({
+const supportedServices = {
osf: {
extract: mfrParser,
},
@@ -75,37 +76,37 @@ const supportedServices = Object.entries({
vk: {
extract: vkParser,
csp: {
- 'frame-src': 'https://vk.com/',
+ 'frame-src': ['https://vk.com/'],
},
},
rutube: {
extract: rutubeParser,
csp: {
- 'frame-src': 'https://rutube.ru/play/embed/',
+ 'frame-src': ['https://rutube.ru/play/embed/'],
},
},
url: {
extract: urlParser,
},
-}) as Services;
+} as Services;
export function parseVideoUrl(service: string, url: string) {
let videoID = '';
const normalizedService = service.toLowerCase();
- const parsed = supportedServices.find(([name]) => name === normalizedService);
+ const parsed = supportedServices[normalizedService as VideoService];
if (!parsed) {
return false;
}
- const [, videoParser] = parsed;
+ const {extract, csp} = parsed;
- videoID = videoParser.extract(url);
+ videoID = extract(url);
// If the videoID field is empty, regex currently make it the close parenthesis.
if (videoID === ')') {
videoID = '';
}
- return [videoID, videoParser.csp] as const;
+ return [videoID, csp] as const;
}
diff --git a/src/transform/plugins/video/types.ts b/src/transform/plugins/video/types.ts
index 73557c59..6b525bc5 100644
--- a/src/transform/plugins/video/types.ts
+++ b/src/transform/plugins/video/types.ts
@@ -17,6 +17,13 @@ export type VideoServicesOptions = {
};
};
+export type Service = {
+ csp?: Record;
+ extract(url: string): string;
+};
+
+export type Services = Record;
+
export type VideoFullOptions = VideoServicesOptions & {
videoUrl: VideoUrlFn;
};
diff --git a/test/data/video/video-fixtures.txt b/test/data/video/video-fixtures.txt
index b603792a..e4289550 100644
--- a/test/data/video/video-fixtures.txt
+++ b/test/data/video/video-fixtures.txt
@@ -325,7 +325,7 @@ Coverage. Line Breaks
.
@[vine](MhQ2lvg29Un) @[vine](MhQ2lvg29Un)
.
-@vine
+
.
.
@[vine](MhQ2lvg29Un)
diff --git a/test/video.test.ts b/test/video.test.ts
index e7618197..0973cedd 100644
--- a/test/video.test.ts
+++ b/test/video.test.ts
@@ -11,42 +11,42 @@ function preserveId(html: string) {
.replace(/new mfr\.Render\("\d+.\d+"/, 'new mfr.Render("1.2"');
}
-describe('md-video', function () {
+describe('md-video', () => {
const md = new MarkdownIt({}).use(video);
generate(path.join(__dirname, 'data/video/video-fixtures.txt'), md);
});
// Because the mfr iframe requires a random id these tests cannont be part of
// the markdown-it-testgen fixture
-describe('md-video-mfr', function () {
+describe('md-video-mfr', () => {
const md = new MarkdownIt({}).use(video);
- it('make sure normal iframe generates properly when empty', function () {
+ it('make sure normal iframe generates properly when empty', () => {
const renderedHtml = preserveId(md.render('@[osf]()'));
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with guid', function () {
+ it('make sure normal iframe generates properly with guid', () => {
const renderedHtml = preserveId(md.render('@[osf](xxxxx)'));
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with guid and line break', function () {
+ it('make sure normal iframe generates properly with guid and line break', () => {
const renderedHtml = preserveId(md.render('@[osf](xxxxx\n)'));
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with guid and extra space', function () {
+ it('make sure normal iframe generates properly with guid and extra space', () => {
const renderedHtml = preserveId(md.render('@[osf](xxxxx )'));
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with guid and two extra spaces', function () {
+ it('make sure normal iframe generates properly with guid and two extra spaces', () => {
const renderedHtml = preserveId(md.render('@[osf]( xxxxx )'));
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link', function () {
+ it('make sure normal iframe generates properly with link', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](https://mfr.osf.io/render?url=https://osf.io/xxxxx/?action=download%26mode=render)',
@@ -55,7 +55,7 @@ describe('md-video-mfr', function () {
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link and extra space', function () {
+ it('make sure normal iframe generates properly with link and extra space', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](https://mfr.osf.io/render?url=https://osf.io/xxxxx/?action=download%26mode=render )',
@@ -64,7 +64,7 @@ describe('md-video-mfr', function () {
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link and two extra spaces', function () {
+ it('make sure normal iframe generates properly with link and two extra spaces', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](https://mfr.osf.io/render?url=https://osf.io/xxxxx/?action=download%26mode=render )',
@@ -73,7 +73,7 @@ describe('md-video-mfr', function () {
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link to staging', function () {
+ it('make sure normal iframe generates properly with link to staging', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](https://mfr-staging3.osf.io/render?url=https://staging3.osf.io/xxxxx/?action=download%26mode=render)',
@@ -82,7 +82,7 @@ describe('md-video-mfr', function () {
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link to local', function () {
+ it('make sure normal iframe generates properly with link to local', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](https://localhost:7778/render?url=https://localhost:5000/xxxxx/?action=download%26mode=render)',
@@ -91,7 +91,7 @@ describe('md-video-mfr', function () {
expect(renderedHtml).toMatchSnapshot();
});
- it('make sure normal iframe generates properly with link to local ip', function () {
+ it('make sure normal iframe generates properly with link to local ip', () => {
const renderedHtml = preserveId(
md.render(
'@[osf](http://localhost:7778/render?mode=render&url=http://192.168.168.167:5000/y98tn/?action=download%26mode=render%26direct)',