diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 40 | ||||
-rw-r--r-- | src/server/ApiManagers/UploadManager.ts | 53 |
2 files changed, 52 insertions, 41 deletions
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index bcbd65258..6ec48ca89 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -22,6 +22,7 @@ import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./VideoBox.scss"; import { documentSchema } from "../../../fields/documentSchemas"; +import { Networking } from "../../Network"; const path = require('path'); export const timeSchema = createSchema({ @@ -118,29 +119,38 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD b.isLinkButton = true; this.props.addDocument?.(b); DocUtils.MakeLink({ doc: b }, { doc: this.rootDoc }, "video snapshot"); + Networking.PostToServer("/youtubeScreenshot", { + id: this.youtubeVideoId, + timecode: this.layoutDoc.currentTimecode + }).then(response => { + this.props.removeDocument?.(b); + this.createRealSummaryLink(response.accessPaths.agnostic.client); + }); } else { //convert to desired file format const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' // if you want to preview the captured image, const filename = path.basename(encodeURIComponent("snapshot" + StrCast(this.rootDoc.title).replace(/\..*$/, "") + "_" + (this.layoutDoc.currentTimecode || 0).toString().replace(/\./, "_"))); - VideoBox.convertDataUri(dataUrl, filename).then(returnedFilename => { - if (returnedFilename) { - const url = this.choosePath(Utils.prepend(returnedFilename)); - const imageSummary = Docs.Create.ImageDocument(url, { - _nativeWidth: this.layoutDoc._nativeWidth, _nativeHeight: this.layoutDoc._nativeHeight, - x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 0), - _width: 150, _height: height / width * 150, title: "--snapshot" + (this.layoutDoc.currentTimecode || 0) + " image-" - }); - Doc.GetProto(imageSummary)["data-nativeWidth"] = this.layoutDoc._nativeWidth; - Doc.GetProto(imageSummary)["data-nativeHeight"] = this.layoutDoc._nativeHeight; - imageSummary.isLinkButton = true; - this.props.addDocument?.(imageSummary); - DocUtils.MakeLink({ doc: imageSummary }, { doc: this.rootDoc }, "video snapshot"); - } - }); + VideoBox.convertDataUri(dataUrl, filename).then(this.createRealSummaryLink); } } + private createRealSummaryLink = (relative: string) => { + const url = this.choosePath(Utils.prepend(relative)); + const width = (this.layoutDoc._width || 0); + const height = (this.layoutDoc._height || 0); + const imageSummary = Docs.Create.ImageDocument(url, { + _nativeWidth: this.layoutDoc._nativeWidth, _nativeHeight: this.layoutDoc._nativeHeight, + x: (this.layoutDoc.x || 0) + width, y: (this.layoutDoc.y || 0), + _width: 150, _height: height / width * 150, title: "--snapshot" + (this.layoutDoc.currentTimecode || 0) + " image-" + }); + Doc.GetProto(imageSummary)["data-nativeWidth"] = this.layoutDoc._nativeWidth; + Doc.GetProto(imageSummary)["data-nativeHeight"] = this.layoutDoc._nativeHeight; + imageSummary.isLinkButton = true; + this.props.addDocument?.(imageSummary); + DocUtils.MakeLink({ doc: imageSummary }, { doc: this.rootDoc }, "video snapshot"); + } + @action updateTimecode = () => { this.player && (this.layoutDoc.currentTimecode = this.player.currentTime); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 06c2e516d..1ab81803f 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -68,34 +68,34 @@ export default class UploadManager extends ApiManager { method: Method.POST, subscription: new RouteSubscriber("youtubeScreenshot"), secureHandler: async ({ req, res }) => { - const { url, t } = req.query; - const parseUrl = (url: string) => { - url = decodeURIComponent(url) - if (!/^(?:f|ht)tps?\:\/\//.test(url)) { - url = 'http://' + url - } - return url; - } - let targetUrl: string; - if (!url || !t || !isWebUri(targetUrl = parseUrl(url as string))) { - return res.send(); - } - const buffer = await captureYoutubeScreenshot(targetUrl, t as string); + const { id, timecode } = req.body; + const convert = (raw: string) => { + const number = Math.floor(Number(raw)); + const seconds = number % 60; + const minutes = (number - seconds) / 60; + return `${minutes}m${seconds}s`; + }; + const suffix = timecode ? `&t=${convert(timecode)}` : ``; + const targetUrl = `https://www.youtube.com/watch?v=${id}${suffix}`; + const buffer = await captureYoutubeScreenshot(targetUrl); if (!buffer) { return res.send(); } - const resolvedName = `${targetUrl}@${t}.png`; + const resolvedName = `youtube_capture_${id}_${suffix}.png`; const resolvedPath = serverPathToFile(Directory.images, resolvedName); - writeFile(resolvedPath, buffer, async error => { - if (error) { - return res.send(); - } - await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images)); - res.send({ - accessPaths: { - agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName) + return new Promise<void>(resolve => { + writeFile(resolvedPath, buffer, async error => { + if (error) { + return res.send(); } - } as Upload.FileInformation); + await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images)); + res.send({ + accessPaths: { + agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName) + } + } as Upload.FileInformation); + resolve(); + }); }); } }); @@ -284,17 +284,18 @@ export default class UploadManager extends ApiManager { * * On failure, returns undefined. */ -async function captureYoutubeScreenshot(targetUrl: string, t: string): Promise<Opt<Buffer>> { +async function captureYoutubeScreenshot(targetUrl: string): Promise<Opt<Buffer>> { const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); - await page.goto(targetUrl + '&t=' + t, { waitUntil: 'networkidle0' }); + await page.goto(targetUrl, { waitUntil: 'networkidle0' }); // hide youtube player controls. await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as any).style.display = 'none'); - const buffer = await (await page.$('.html5-video-player'))?.screenshot({ encoding: "binary" }); + const videoPlayer = await page.$('.html5-video-player'); + const buffer = await videoPlayer?.screenshot({ encoding: "binary" }); await browser.close(); return buffer; |