Skip to content

Commit

Permalink
feat: support video by url only
Browse files Browse the repository at this point in the history
  • Loading branch information
v8tenko committed Nov 6, 2024
1 parent 0d670f4 commit 3d2469d
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 37 deletions.
7 changes: 0 additions & 7 deletions src/transform/plugins/video/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ export enum VideoService {
url = 'url',
}

export type Service = {
csp?: Record<string, string[]>;
extract(url: string): string;
};

export type Services = [VideoService, Service][];

export const defaults: VideoFullOptions = {
videoUrl,
youtube: {width: 640, height: 390},
Expand Down
19 changes: 12 additions & 7 deletions src/transform/plugins/video/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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) {
Expand All @@ -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 ??= {};
Expand Down
19 changes: 10 additions & 9 deletions src/transform/plugins/video/parsers.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -53,7 +54,7 @@ export function rutubeParser(url: string) {

const urlParser = (url: string) => url;

const supportedServices = Object.entries({
const supportedServices = {
osf: {
extract: mfrParser,
},
Expand All @@ -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;
}
7 changes: 7 additions & 0 deletions src/transform/plugins/video/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export type VideoServicesOptions = {
};
};

export type Service = {
csp?: Record<string, string[]>;
extract(url: string): string;
};

export type Services = Record<VideoService, Service>;

export type VideoFullOptions = VideoServicesOptions & {
videoUrl: VideoUrlFn;
};
Expand Down
2 changes: 1 addition & 1 deletion test/data/video/video-fixtures.txt
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ Coverage. Line Breaks
.
@[vine](MhQ2lvg29Un) @[vine](MhQ2lvg29Un)
.
<p>@<a href="MhQ2lvg29Un">vine</a> <div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item vine-player" type="text/html" width="600" height="600" src="https://vine.co/v/MhQ2lvg29Un/embed/simple" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div></p>
<p><div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item vine-player" type="text/html" width="600" height="600" src="https://vine.co/v/MhQ2lvg29Un/embed/simple" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div><div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item vine-player" type="text/html" width="600" height="600" src="https://vine.co/v/MhQ2lvg29Un/embed/simple" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div></p>
.
.
@[vine](MhQ2lvg29Un)
Expand Down
26 changes: 13 additions & 13 deletions test/video.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)',
Expand All @@ -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 )',
Expand All @@ -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 )',
Expand All @@ -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)',
Expand All @@ -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)',
Expand All @@ -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)',
Expand Down

0 comments on commit 3d2469d

Please sign in to comment.