import { Link } from '../MdToHtml'; import { toForwardSlashes } from '@joplin/utils/path'; import { LinkIndexes } from './rules/link_close'; import { RendererTheme } from '../types'; import { AllHtmlEntities as Entities } from 'html-entities'; const htmlentities = new Entities().encode; export interface Options { audioPlayerEnabled: boolean; videoPlayerEnabled: boolean; autoplayVideo?: boolean; pdfViewerEnabled: boolean; useCustomPdfViewer: boolean; noteId: string; vendorDir: string; theme: RendererTheme; } function resourceUrl(resourceFullPath: string): string { if ( resourceFullPath.indexOf('http://') === 0 || resourceFullPath.indexOf('https://') === 0 || resourceFullPath.indexOf('joplin-content://') === 0 || resourceFullPath.indexOf('file://') === 0 || // On web, resources are loaded as blob URLs. resourceFullPath.startsWith('blob:null/') ) { return resourceFullPath; } return `file://${toForwardSlashes(resourceFullPath)}`; } const resourceHash = (link: string) => { // Preserve certain #hash strings when rendering resources. // These patterns can be used to customize the starting/ending points for // audio/video/PDF embeds: const patterns = [ // Starting PDF page /#page=\d+$/, // Staring/ending playback time /#t=[0-9:,]+$/, ]; for (const pattern of patterns) { const match = link.match(pattern); if (match) { return match[0]; } } return ''; }; export default function(link: Link, options: Options, linkIndexes: LinkIndexes) { const resource = link.resource; if (!link.resourceReady || !resource || !resource.mime) return ''; const escapedResourcePath = htmlentities( resourceUrl(link.resourceFullPath) + resourceHash(link.href), ); const escapedMime = htmlentities(resource.mime); const escapedTitle = htmlentities(resource.title || resource.mime); const resourceIdAttribute = resource.id ? ` data-resource-id="${htmlentities(resource.id)}"` : ''; if (options.videoPlayerEnabled && resource.mime.indexOf('video/') === 0) { const playbackAttributes = options.autoplayVideo ? 'autoplay muted playsinline preload="auto"' : 'preload="metadata"'; return ` `; } if (options.audioPlayerEnabled && resource.mime.indexOf('audio/') === 0) { // We want to support both audio/x-flac and audio/flac MIME types, but chromium only supports audio/flac // https://github.com/laurent22/joplin/issues/6434 const escapedAudioMime = escapedMime === 'audio/x-flac' ? 'audio/flac' : escapedMime; return ` `; } if (options.pdfViewerEnabled && resource.mime === 'application/pdf') { if (options.useCustomPdfViewer) { const resourceId = resource.id; let anchorPageNo = null; let id = `${options.noteId}.${resourceId}`; if (linkIndexes && linkIndexes[resourceId]) { linkIndexes[resourceId]++; } else { linkIndexes[resourceId] = 1; } id += `.${linkIndexes[resourceId]}`; if (link.href.indexOf('#') > 0) { anchorPageNo = Number(link.href.split('#').pop()); if (anchorPageNo < 1) anchorPageNo = null; } const src = `${options.vendorDir}/lib/@joplin/pdf-viewer/index.html`; return ``; } return ``; } return ''; }