Parcourir la source

fix crossorigin posters (fix #947)

Gildas il y a 3 ans
Parent
commit
f85ec7862e
2 fichiers modifiés avec 58 ajouts et 1 suppressions
  1. 49 0
      src/single-file/single-file-core.js
  2. 9 1
      src/single-file/single-file-helper.js

+ 49 - 0
src/single-file/single-file-core.js

@@ -113,6 +113,7 @@ const STAGES = [{
 		{ action: "resolveStyleAttributeURLs" }
 		{ action: "resolveStyleAttributeURLs" }
 	],
 	],
 	parallel: [
 	parallel: [
+		{ option: "blockVideos", action: "insertMissingVideoPosters" },
 		{ action: "resolveStylesheetURLs" },
 		{ action: "resolveStylesheetURLs" },
 		{ option: "!removeFrames", action: "resolveFrameURLs" },
 		{ option: "!removeFrames", action: "resolveFrameURLs" },
 		{ action: "resolveHtmlImportURLs" }
 		{ action: "resolveHtmlImportURLs" }
@@ -959,6 +960,54 @@ class Processor {
 		});
 		});
 	}
 	}
 
 
+	async insertMissingVideoPosters() {
+		await Promise.all(Array.from(this.doc.querySelectorAll("video[src], video > source[src]")).map(async element => {
+			let videoElement;
+			if (element.tagName == "VIDEO") {
+				videoElement = element;
+			} else {
+				videoElement = element.parentElement;
+			}
+			if (!videoElement.poster) {
+				const attributeValue = videoElement.getAttribute(util.VIDEO_ATTRIBUTE_NAME);
+				if (attributeValue) {
+					const videoData = this.options.videos[Number(attributeValue)];
+					const src = videoData.src || videoElement.src;
+					if (src) {
+						const temporaryVideoElement = this.doc.createElement("video");
+						temporaryVideoElement.src = src;
+						temporaryVideoElement.style.setProperty("width", videoData.size.pxWidth + "px", "important");
+						temporaryVideoElement.style.setProperty("height", videoData.size.pxHeight + "px", "important");
+						temporaryVideoElement.style.setProperty("display", "none", "important");
+						temporaryVideoElement.crossOrigin = "anonymous";
+						const canvasElement = this.doc.createElement("canvas");
+						const context = canvasElement.getContext("2d");
+						this.options.doc.body.appendChild(temporaryVideoElement);
+						return new Promise(resolve => {
+							temporaryVideoElement.currentTime = videoData.currentTime;
+							temporaryVideoElement.oncanplay = () => {
+								canvasElement.width = videoData.size.pxWidth;
+								canvasElement.height = videoData.size.pxHeight;
+								context.drawImage(temporaryVideoElement, 0, 0, canvasElement.width, canvasElement.height);
+								try {
+									videoElement.poster = canvasElement.toDataURL("image/png", "");
+								} catch (error) {
+									// ignored
+								}
+								temporaryVideoElement.remove();
+								resolve();
+							};
+							temporaryVideoElement.onerror = () => {
+								temporaryVideoElement.remove();
+								resolve();
+							};
+						});
+					}
+				}
+			}
+		}));
+	}
+
 	resolveStyleAttributeURLs() {
 	resolveStyleAttributeURLs() {
 		this.doc.querySelectorAll("[style]").forEach(element => {
 		this.doc.querySelectorAll("[style]").forEach(element => {
 			let styleContent = element.getAttribute("style");
 			let styleContent = element.getAttribute("style");

+ 9 - 1
src/single-file/single-file-helper.js

@@ -290,7 +290,15 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
 		const src = element.currentSrc;
 		const src = element.currentSrc;
 		if (src && !src.startsWith("blob:") && !src.startsWith("data:")) {
 		if (src && !src.startsWith("blob:") && !src.startsWith("data:")) {
 			const positionParent = win.getComputedStyle(element.parentNode).getPropertyValue("position");
 			const positionParent = win.getComputedStyle(element.parentNode).getPropertyValue("position");
-			data.videos.push({ positionParent, src });
+			data.videos.push({
+				positionParent,
+				src,
+				size: {
+					pxWidth: element.clientWidth,
+					pxHeight: element.clientHeight
+				},
+				currentTime: element.currentTime
+			});
 			element.setAttribute(VIDEO_ATTRIBUTE_NAME, data.videos.length - 1);
 			element.setAttribute(VIDEO_ATTRIBUTE_NAME, data.videos.length - 1);
 		}
 		}
 		if (!element.poster) {
 		if (!element.poster) {