UNPKG

@diplodoc/transform

Version:

A simple transformer of text in YFM (Yandex Flavored Markdown) to HTML

152 lines (125 loc) 5.25 kB
// Process @[youtube](youtubeVideoID) // Process @[vimeo](vimeoVideoID) // Process @[vine](vineVideoID) // Process @[prezi](preziID) // Process @[osf](guid) // Process @[yandex](videoID) // Process @[vk](videoID) // Process @[rutube](videoID) // Process @[url](fullLink) import type MarkdownIt from 'markdown-it'; // eslint-disable-next-line no-duplicate-imports import type {PluginWithOptions} from 'markdown-it'; import type ParserInline from 'markdown-it/lib/parser_inline'; import type Renderer from 'markdown-it/lib/renderer'; import type {VideoFullOptions, VideoPluginOptions, VideoToken} from './types'; import {append} from '../utils'; import {parseVideoUrl} from './parsers'; import {VideoService, defaults} from './const'; // eslint-disable-next-line valid-jsdoc /** * Video plugin for markdown-it. * Forked from https://github.com/CenterForOpenScience/markdown-it-video/tree/0.6.3 */ const video: PluginWithOptions<VideoPluginOptions> = (md, options) => { const theOptions: VideoFullOptions = {...defaults, ...options}; const theMd = md; theMd.renderer.rules.video = tokenizeVideo(theMd, theOptions); theMd.inline.ruler.before('emphasis', 'video', videoEmbed(theMd, theOptions)); }; function tokenizeVideo(md: MarkdownIt, options: VideoFullOptions): Renderer.RenderRule { return (tokens, idx) => { const videoID = md.utils.escapeHtml((tokens[idx] as VideoToken).videoID); const service = md.utils.escapeHtml((tokens[idx] as VideoToken).service).toLowerCase(); const checkUrl = /http(?:s?):\/\/(?:www\.)?[a-zA-Z0-9-:.]{1,}\/render(?:\/)?[a-zA-Z0-9.&;?=:%]{1,}url=http(?:s?):\/\/[a-zA-Z0-9 -:.]{1,}\/[a-zA-Z0-9]{1,5}\/\?[a-zA-Z0-9.=:%]{1,}/; let num; if (service === VideoService.Osf && videoID) { num = Math.random() * 0x10000; if (videoID.match(checkUrl)) { return ( '<div id="' + num + '" class="mfr mfr-file"></div><script>' + '$(document).ready(function () {new mfr.Render("' + num + '", "' + videoID + '");' + ' }); </script>' ); } return ( '<div id="' + num + '" class="mfr mfr-file"></div><script>' + '$(document).ready(function () {new mfr.Render("' + num + '", "https://mfr.osf.io/' + 'render?url=https://osf.io/' + videoID + '/?action=download%26mode=render");' + ' }); </script>' ); } const {width, height} = options[service as VideoService]; return videoID === '' ? '' : `<div class="embed-responsive embed-responsive-16by9"><iframe` + ` class="embed-responsive-item ${service}-player"` + ` type="text/html" width="${width}" height="${height}"` + ` src="${options.videoUrl(service, videoID, options)}"` + ` frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>`; }; } const EMBED_REGEX = /@\[([a-zA-Z]*?)]\([\s]*(.*?)[\s]*[)]/im; function videoEmbed(md: MarkdownIt, _options: VideoFullOptions): ParserInline.RuleInline { return (state, silent) => { const theState = state; const oldPos = state.pos; if ( state.src.charCodeAt(oldPos) !== 0x40 /* @ */ || state.src.charCodeAt(oldPos + 1) !== 0x5b /* [ */ ) { return false; } const match = EMBED_REGEX.exec(state.src.slice(state.pos, state.src.length)); if (!match || match.length < 3) { return false; } const service = match[1] || 'url'; const parsed = parseVideoUrl(service, match[2]); if (parsed === false) { return false; } const [videoID, csp] = parsed; const serviceStart = oldPos + 2; const serviceEnd = md.helpers.parseLinkLabel(state, oldPos + 1, false); // // We found the end of the link, and know for a fact it's a valid link; // so all that's left to do is to call tokenizer. // if (!silent) { theState.pos = serviceStart; // @ts-expect-error theState.service = theState.src.slice(serviceStart, serviceEnd); const newState = new theState.md.inline.State(service, theState.md, theState.env, []); newState.md.inline.tokenize(newState); const token = theState.push('video', '', 0) as VideoToken; token.videoID = videoID; token.service = service; token.level = theState.level; } if (service === 'url') { theState.pos = theState.src.indexOf(')', theState.pos) + 1; } else { theState.pos += theState.src.indexOf(')', theState.pos); } if (csp) { state.env.meta ??= {}; append(state.env.meta, 'csp', csp); } return true; }; } export = video;