From 358f9e266ef264442aea1e2c7d5d959a19f7624c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 22 Jul 2022 14:11:30 -0400
Subject: adjusted native dim scaling slightly combining props.scaling and
 props.ContentScaling into props.NativeDimScaling and fixing some resizing
 behaviors for fitWidth freeformviews and native-sized text boxes.   Also
 fixed clicking on presboxe elements to not drag.

---
 src/client/views/nodes/VideoBox.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index b1f7d8023..681f7c5b2 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -898,7 +898,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
 
-    scaling = () => this.props.scaling?.() || 1;
+    scaling = () => this.props.NativeDimScaling?.() || 1;
 
     panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100;
     panelHeight = () => (this.layoutDoc._fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100);
@@ -911,7 +911,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             .scale(100 / this.heightPercent);
     };
 
-    marqueeFitScaling = () => ((this.props.scaling?.() || 1) * this.heightPercent) / 100;
+    marqueeFitScaling = () => ((this.props.NativeDimScaling?.() || 1) * this.heightPercent) / 100;
     marqueeOffset = () => [((this.panelWidth() / 2) * (1 - this.heightPercent / 100)) / (this.heightPercent / 100), 0];
 
     timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`];
@@ -1124,7 +1124,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                             ScreenToLocalTransform={this.screenToLocalTransform}
                             docFilters={this.timelineDocFilter}
                             select={emptyFunction}
-                            scaling={returnOne}
+                            NativeDimScaling={returnOne}
                             whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
-- 
cgit v1.2.3-70-g09d2


From b830a5dc8df82886a9304ebe02fe93cdf1c0b521 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Jul 2022 14:10:32 -0400
Subject: fixed video thumbnail generation to have a lock that prevents
 multiple attempts to create the thumbnails at the same time.  fixed
 ImageUpload to catch resize errors and not crash the server.

---
 .../collections/CollectionStackedTimeline.tsx      |   9 +-
 src/client/views/nodes/VideoBox.tsx                |  16 +-
 src/server/ApiManagers/UploadManager.ts            | 556 +++++++++++----------
 3 files changed, 297 insertions(+), 284 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 714d8421a..52126884a 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -2,7 +2,7 @@ import React = require('react');
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
-import { Doc, DocListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { listSpec } from '../../../fields/Schema';
@@ -289,10 +289,9 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
             this._hoverTime = this.toTimeline(clientX - rect.x, rect.width);
             if (this.dataDoc.thumbnails) {
                 const nearest = Math.floor((this._hoverTime / this.props.rawDuration) * VideoBox.numThumbnails);
-                const thumbnails = Cast(this.dataDoc.thumbnails, listSpec('string'), []);
-                const imgField = thumbnails && thumbnails.length > 0 ? new ImageField(thumbnails[nearest]) : new ImageField('');
-                const src = imgField && imgField.url.href ? imgField.url.href.replace('.png', '_s.png') : '';
-                this._thumbnail = src ? src : undefined;
+                const thumbnails = StrListCast(this.dataDoc.thumbnails);
+                const imgField = thumbnails?.length > 0 ? new ImageField(thumbnails[nearest]) : undefined;
+                this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_s.png') : undefined;
             }
         }
     };
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 681f7c5b2..4af4d2020 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -418,31 +418,29 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // extracts video thumbnails and saves them as field of doc
     getVideoThumbnails = () => {
-        const video = document.createElement('video');
+        if (this.dataDoc.thumbnails !== undefined) return;
+        this.dataDoc.thumbnails = new List<string>();
         const thumbnailPromises: Promise<any>[] = [];
+        const video = document.createElement('video');
 
-        video.onloadedmetadata = () => {
-            video.currentTime = 0;
-        };
+        video.onloadedmetadata = () => (video.currentTime = 0);
 
         video.onseeked = () => {
             const canvas = document.createElement('canvas');
             canvas.height = video.videoHeight;
             canvas.width = video.videoWidth;
             const ctx = canvas.getContext('2d');
-            ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
+            ctx?.drawImage(video, 0, 0, canvas.width, canvas.height, 0, 0, 25, 25);
             const imgUrl = canvas.toDataURL();
             const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, '');
             const encodedFilename = encodeURIComponent('thumbnail' + retitled + '_' + video.currentTime.toString().replace(/\./, '_'));
             const filename = basename(encodedFilename);
-            thumbnailPromises.push(VideoBox.convertDataUri(imgUrl, filename));
+            thumbnailPromises?.push(VideoBox.convertDataUri(imgUrl, filename, true));
             const newTime = video.currentTime + video.duration / (VideoBox.numThumbnails - 1);
             if (newTime < video.duration) {
                 video.currentTime = newTime;
             } else {
-                Promise.all(thumbnailPromises).then(thumbnails => {
-                    this.dataDoc.thumbnails = new List<string>(thumbnails);
-                });
+                Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc.thumbnails = new List<string>(thumbnails)));
             }
         };
 
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 332ba3d35..787e331c5 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -1,291 +1,308 @@
-import ApiManager, { Registration } from "./ApiManager";
-import { Method, _success } from "../RouteManager";
+import ApiManager, { Registration } from './ApiManager';
+import { Method, _success } from '../RouteManager';
 import * as formidable from 'formidable';
 import v4 = require('uuid/v4');
 const AdmZip = require('adm-zip');
-import { extname, basename, dirname, } from 'path';
-import { createReadStream, createWriteStream, unlink, writeFile } from "fs";
-import { publicDirectory, filesDirectory } from "..";
-import { Database } from "../database";
-import { DashUploadUtils, InjectSize, SizeSuffix } from "../DashUploadUtils";
+import { extname, basename, dirname } from 'path';
+import { createReadStream, createWriteStream, unlink, writeFile } from 'fs';
+import { publicDirectory, filesDirectory } from '..';
+import { Database } from '../database';
+import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils';
 import * as sharp from 'sharp';
-import { AcceptableMedia, Upload } from "../SharedMediaTypes";
-import { normalize } from "path";
-import RouteSubscriber from "../RouteSubscriber";
+import { AcceptableMedia, Upload } from '../SharedMediaTypes';
+import { normalize } from 'path';
+import RouteSubscriber from '../RouteSubscriber';
 const imageDataUri = require('image-data-uri');
-import { SolrManager } from "./SearchManager";
+import { SolrManager } from './SearchManager';
 const fs = require('fs');
 
 export enum Directory {
-      parsed_files = "parsed_files",
-      images = "images",
-      videos = "videos",
-      pdfs = "pdfs",
-      text = "text",
-      pdf_thumbnails = "pdf_thumbnails",
-      audio = "audio",
-      csv = "csv",
+    parsed_files = 'parsed_files',
+    images = 'images',
+    videos = 'videos',
+    pdfs = 'pdfs',
+    text = 'text',
+    pdf_thumbnails = 'pdf_thumbnails',
+    audio = 'audio',
+    csv = 'csv',
 }
 
 export function serverPathToFile(directory: Directory, filename: string) {
-      return normalize(`${filesDirectory}/${directory}/${filename}`);
+    return normalize(`${filesDirectory}/${directory}/${filename}`);
 }
 
 export function pathToDirectory(directory: Directory) {
-      return normalize(`${filesDirectory}/${directory}`);
+    return normalize(`${filesDirectory}/${directory}`);
 }
 
 export function clientPathToFile(directory: Directory, filename: string) {
-      return `/files/${directory}/${filename}`;
+    return `/files/${directory}/${filename}`;
 }
 
 export default class UploadManager extends ApiManager {
-
     protected initialize(register: Registration): void {
-          
-            register({
-                  method: Method.POST,
-                  subscription: "/concatVideos",
-              secureHandler: async ({ req, res }) => {
-                    // req.body contains the array of server paths to the videos
-                    _success(res, await DashUploadUtils.concatVideos(req.body));
-                  }
-            });
-
-            register({
-                  method: Method.POST,
-                  subscription: "/uploadFormData",
-                  secureHandler: async ({ req, res }) => {
-                        const form = new formidable.IncomingForm();
-                        form.keepExtensions = true;
-                        form.uploadDir = pathToDirectory(Directory.parsed_files);
-                        return new Promise<void>(resolve => {
-                            form.parse(req, async (_err, _fields, files) => {
-                                    const results: Upload.FileResponse[] = [];
-                                    for (const key in files) {
-                                          const f = files[key];
-                                          if (!Array.isArray(f)) {
-                                                const result = await DashUploadUtils.upload(f);
-                                                result && !(result.result instanceof Error) && results.push(result);
-                                          }
-                                    }
-                                    _success(res, results);
-                                    resolve();
-                              });
-                        });
-                  }
-            });
-
-            register({
-                  method: Method.POST,
-                  subscription: "/uploadYoutubeVideo",
-                  secureHandler: async ({ req, res }) => {
-                        //req.readableBuffer.head.data
-                        return new Promise<void>(async resolve => {
-                              req.addListener("data", async (args) => {
-                                    console.log(args);
-                                    const payload = String.fromCharCode.apply(String, args);
-                                    const videoId = JSON.parse(payload).videoId;
-                                    const results: Upload.FileResponse[] = [];
-                                    const result = await DashUploadUtils.uploadYoutube(videoId);
-                                    result && !(result.result instanceof Error) && results.push(result);
-                                    _success(res, results);
-                                    resolve();
-                              });
-                        });
-                  }
-            });
+        register({
+            method: Method.POST,
+            subscription: '/concatVideos',
+            secureHandler: async ({ req, res }) => {
+                // req.body contains the array of server paths to the videos
+                _success(res, await DashUploadUtils.concatVideos(req.body));
+            },
+        });
 
-            register({
-                  method: Method.POST,
-                  subscription: new RouteSubscriber("youtubeScreenshot"),
-                  secureHandler: async ({ req, res }) => {
-                        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();
+        register({
+            method: Method.POST,
+            subscription: '/uploadFormData',
+            secureHandler: async ({ req, res }) => {
+                const form = new formidable.IncomingForm();
+                form.keepExtensions = true;
+                form.uploadDir = pathToDirectory(Directory.parsed_files);
+                return new Promise<void>(resolve => {
+                    form.parse(req, async (_err, _fields, files) => {
+                        const results: Upload.FileResponse[] = [];
+                        for (const key in files) {
+                            const f = files[key];
+                            if (!Array.isArray(f)) {
+                                const result = await DashUploadUtils.upload(f);
+                                result && !(result.result instanceof Error) && results.push(result);
+                            }
                         }
-                        const resolvedName = `youtube_capture_${id}_${suffix}.png`;
-                        const resolvedPath = serverPathToFile(Directory.images, resolvedName);
-                        return new Promise<void>(resolve => {
-                              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)
-                                          }
-                                    } as Upload.FileInformation);
-                                    resolve();
-                              });
-                        });
-                  }
-            });
+                        _success(res, results);
+                        resolve();
+                    });
+                });
+            },
+        });
 
-            register({
-                  method: Method.POST,
-                  subscription: "/uploadRemoteImage",
-                  secureHandler: async ({ req, res }) => {
+        register({
+            method: Method.POST,
+            subscription: '/uploadYoutubeVideo',
+            secureHandler: async ({ req, res }) => {
+                //req.readableBuffer.head.data
+                return new Promise<void>(async resolve => {
+                    req.addListener('data', async args => {
+                        console.log(args);
+                        const payload = String.fromCharCode.apply(String, args);
+                        const videoId = JSON.parse(payload).videoId;
+                        const results: Upload.FileResponse[] = [];
+                        const result = await DashUploadUtils.uploadYoutube(videoId);
+                        result && !(result.result instanceof Error) && results.push(result);
+                        _success(res, results);
+                        resolve();
+                    });
+                });
+            },
+        });
 
-                        const { sources } = req.body;
-                        if (Array.isArray(sources)) {
-                              const results = await Promise.all(sources.map(source => DashUploadUtils.UploadImage(source)));
-                              return res.send(results);
+        register({
+            method: Method.POST,
+            subscription: new RouteSubscriber('youtubeScreenshot'),
+            secureHandler: async ({ req, res }) => {
+                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 = `youtube_capture_${id}_${suffix}.png`;
+                const resolvedPath = serverPathToFile(Directory.images, resolvedName);
+                return new Promise<void>(resolve => {
+                    writeFile(resolvedPath, buffer, async error => {
+                        if (error) {
+                            return res.send();
                         }
-                        res.send();
-                  }
-            });
+                        await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images));
+                        res.send({
+                            accessPaths: {
+                                agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName),
+                            },
+                        } as Upload.FileInformation);
+                        resolve();
+                    });
+                });
+            },
+        });
 
-            register({
-                  method: Method.POST,
-                  subscription: "/uploadDoc",
-                  secureHandler: ({ req, res }) => {
+        register({
+            method: Method.POST,
+            subscription: '/uploadRemoteImage',
+            secureHandler: async ({ req, res }) => {
+                const { sources } = req.body;
+                if (Array.isArray(sources)) {
+                    const results = await Promise.all(sources.map(source => DashUploadUtils.UploadImage(source)));
+                    return res.send(results);
+                }
+                res.send();
+            },
+        });
 
-                        const form = new formidable.IncomingForm();
-                        form.keepExtensions = true;
-                        // let path = req.body.path;
-                        const ids: { [id: string]: string } = {};
-                        let remap = true;
-                        const getId = (id: string): string => {
-                              if (!remap) return id;
-                              if (id.endsWith("Proto")) return id;
-                              if (id in ids) {
-                                    return ids[id];
-                              } else {
-                                    return ids[id] = v4();
-                              }
-                        };
-                        const mapFn = (doc: any) => {
-                              if (doc.id) {
-                                    doc.id = getId(doc.id);
-                              }
-                              for (const key in doc.fields) {
-                                    if (!doc.fields.hasOwnProperty(key)) { continue; }
-                                    const field = doc.fields[key];
-                                    if (field === undefined || field === null) { continue; }
+        register({
+            method: Method.POST,
+            subscription: '/uploadDoc',
+            secureHandler: ({ req, res }) => {
+                const form = new formidable.IncomingForm();
+                form.keepExtensions = true;
+                // let path = req.body.path;
+                const ids: { [id: string]: string } = {};
+                let remap = true;
+                const getId = (id: string): string => {
+                    if (!remap) return id;
+                    if (id.endsWith('Proto')) return id;
+                    if (id in ids) {
+                        return ids[id];
+                    } else {
+                        return (ids[id] = v4());
+                    }
+                };
+                const mapFn = (doc: any) => {
+                    if (doc.id) {
+                        doc.id = getId(doc.id);
+                    }
+                    for (const key in doc.fields) {
+                        if (!doc.fields.hasOwnProperty(key)) {
+                            continue;
+                        }
+                        const field = doc.fields[key];
+                        if (field === undefined || field === null) {
+                            continue;
+                        }
 
-                                    if (field.__type === "Doc") {
-                                          mapFn(field);
-                                    } else if (field.__type === "proxy" || field.__type === "prefetch_proxy") {
-                                          field.fieldId = getId(field.fieldId);
-                                    } else if (field.__type === "script" || field.__type === "computed") {
-                                          if (field.captures) {
-                                                field.captures.fieldId = getId(field.captures.fieldId);
-                                          }
-                                    } else if (field.__type === "list") {
-                                          mapFn(field);
-                                    } else if (typeof field === "string") {
-                                          const re = /("(?:dataD|d)ocumentId"\s*:\s*")([\w\-]*)"/g;
-                                          doc.fields[key] = (field as any).replace(re, (match: any, p1: string, p2: string) => {
-                                                return `${p1}${getId(p2)}"`;
-                                          });
-                                    } else if (field.__type === "RichTextField") {
-                                          const re = /("href"\s*:\s*")(.*?)"/g;
-                                          field.Data = field.Data.replace(re, (match: any, p1: string, p2: string) => {
-                                                return `${p1}${getId(p2)}"`;
-                                          });
-                                    }
-                              }
-                        };
-                        return new Promise<void>(resolve => {
-                              form.parse(req, async (_err, fields, files) => {
-                                    remap = fields.remap !== "false";
-                                    let id: string = "";
+                        if (field.__type === 'Doc') {
+                            mapFn(field);
+                        } else if (field.__type === 'proxy' || field.__type === 'prefetch_proxy') {
+                            field.fieldId = getId(field.fieldId);
+                        } else if (field.__type === 'script' || field.__type === 'computed') {
+                            if (field.captures) {
+                                field.captures.fieldId = getId(field.captures.fieldId);
+                            }
+                        } else if (field.__type === 'list') {
+                            mapFn(field);
+                        } else if (typeof field === 'string') {
+                            const re = /("(?:dataD|d)ocumentId"\s*:\s*")([\w\-]*)"/g;
+                            doc.fields[key] = (field as any).replace(re, (match: any, p1: string, p2: string) => {
+                                return `${p1}${getId(p2)}"`;
+                            });
+                        } else if (field.__type === 'RichTextField') {
+                            const re = /("href"\s*:\s*")(.*?)"/g;
+                            field.Data = field.Data.replace(re, (match: any, p1: string, p2: string) => {
+                                return `${p1}${getId(p2)}"`;
+                            });
+                        }
+                    }
+                };
+                return new Promise<void>(resolve => {
+                    form.parse(req, async (_err, fields, files) => {
+                        remap = fields.remap !== 'false';
+                        let id: string = '';
+                        try {
+                            for (const name in files) {
+                                const f = files[name];
+                                const path_2 = Array.isArray(f) ? '' : f.path;
+                                const zip = new AdmZip(path_2);
+                                zip.getEntries().forEach((entry: any) => {
+                                    if (!entry.entryName.startsWith('files/')) return;
+                                    let directory = dirname(entry.entryName) + '/';
+                                    const extension = extname(entry.entryName);
+                                    const base = basename(entry.entryName).split('.')[0];
                                     try {
-                                          for (const name in files) {
-                                                const f = files[name];
-                                                const path_2 = Array.isArray(f) ? "" : f.path;
-                                                const zip = new AdmZip(path_2);
-                                                zip.getEntries().forEach((entry: any) => {
-                                                      if (!entry.entryName.startsWith("files/")) return;
-                                                      let directory = dirname(entry.entryName) + "/";
-                                                      const extension = extname(entry.entryName);
-                                                      const base = basename(entry.entryName).split(".")[0];
-                                                      try {
-                                                            zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
-                                                            directory = "/" + directory;
-
-                                                            createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_o" + extension));
-                                                            createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_s" + extension));
-                                                            createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_m" + extension));
-                                                            createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_l" + extension));
-                                                      } catch (e) {
-                                                            console.log(e);
-                                                      }
-                                                });
-                                                const json = zip.getEntry("doc.json");
-                                                try {
-                                                      const data = JSON.parse(json.getData().toString("utf8"));
-                                                      const datadocs = data.docs;
-                                                      id = getId(data.id);
-                                                      const docs = Object.keys(datadocs).map(key => datadocs[key]);
-                                                      docs.forEach(mapFn);
-                                                      await Promise.all(docs.map((doc: any) => new Promise<void>(res => {
-                                                            Database.Instance.replace(doc.id, doc, (err, r) => {
-                                                                  err && console.log(err);
-                                                                  res();
-                                                            }, true);
-                                                      })));
-                                                } catch (e) { console.log(e); }
-                                                unlink(path_2, () => { });
-                                          }
-                                          SolrManager.update();
-                                          res.send(JSON.stringify(id || "error"));
-                                    } catch (e) { console.log(e); }
-                                    resolve();
-                              });
-                        });
-                  }
-            });
-
-            register({
-                  method: Method.POST,
-                  subscription: "/inspectImage",
-                  secureHandler: async ({ req, res }) => {
+                                        zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
+                                        directory = '/' + directory;
 
-                        const { source } = req.body;
-                        if (typeof source === "string") {
-                              return res.send(await DashUploadUtils.InspectImage(source));
+                                        createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + '_o' + extension));
+                                        createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + '_s' + extension));
+                                        createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + '_m' + extension));
+                                        createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + '_l' + extension));
+                                    } catch (e) {
+                                        console.log(e);
+                                    }
+                                });
+                                const json = zip.getEntry('doc.json');
+                                try {
+                                    const data = JSON.parse(json.getData().toString('utf8'));
+                                    const datadocs = data.docs;
+                                    id = getId(data.id);
+                                    const docs = Object.keys(datadocs).map(key => datadocs[key]);
+                                    docs.forEach(mapFn);
+                                    await Promise.all(
+                                        docs.map(
+                                            (doc: any) =>
+                                                new Promise<void>(res => {
+                                                    Database.Instance.replace(
+                                                        doc.id,
+                                                        doc,
+                                                        (err, r) => {
+                                                            err && console.log(err);
+                                                            res();
+                                                        },
+                                                        true
+                                                    );
+                                                })
+                                        )
+                                    );
+                                } catch (e) {
+                                    console.log(e);
+                                }
+                                unlink(path_2, () => {});
+                            }
+                            SolrManager.update();
+                            res.send(JSON.stringify(id || 'error'));
+                        } catch (e) {
+                            console.log(e);
                         }
-                        res.send({});
-                  }
-            });
+                        resolve();
+                    });
+                });
+            },
+        });
+
+        register({
+            method: Method.POST,
+            subscription: '/inspectImage',
+            secureHandler: async ({ req, res }) => {
+                const { source } = req.body;
+                if (typeof source === 'string') {
+                    return res.send(await DashUploadUtils.InspectImage(source));
+                }
+                res.send({});
+            },
+        });
 
         register({
             method: Method.POST,
-            subscription: "/uploadURI",
+            subscription: '/uploadURI',
             secureHandler: ({ req, res }) => {
                 const uri = req.body.uri;
                 const filename = req.body.name;
                 const origSuffix = req.body.nosuffix ? SizeSuffix.None : SizeSuffix.Original;
                 const deleteFiles = req.body.replaceRootFilename;
                 if (!uri || !filename) {
-                    res.status(401).send("incorrect parameters specified");
+                    res.status(401).send('incorrect parameters specified');
                     return;
                 }
                 if (deleteFiles) {
-                    const path = serverPathToFile(Directory.images, "");
+                    const path = serverPathToFile(Directory.images, '');
                     const regex = new RegExp(`${deleteFiles}.*`);
-                    fs.readdirSync(path).filter((f: any) => regex.test(f)).map((f: any) => fs.unlinkSync(path + f));
+                    fs.readdirSync(path)
+                        .filter((f: any) => regex.test(f))
+                        .map((f: any) => fs.unlinkSync(path + f));
                 }
                 return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
                     const ext = extname(savedName).toLowerCase();
                     const { pngs, jpgs } = AcceptableMedia;
-                    const resizers = !origSuffix ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium }] : [
-                        { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Small },
-                        { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium },
-                        { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Large },
-                    ];
+                    const resizers = !origSuffix
+                        ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium }]
+                        : [
+                              { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Small },
+                              { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Medium },
+                              { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: SizeSuffix.Large },
+                          ];
                     let isImage = false;
                     if (pngs.includes(ext)) {
                         resizers.forEach(element => {
@@ -301,49 +318,48 @@ export default class UploadManager extends ApiManager {
                     if (isImage) {
                         resizers.forEach(resizer => {
                             const path = serverPathToFile(Directory.images, InjectSize(filename, resizer.suffix) + ext);
-                            createReadStream(savedName).on("error", e => console.log("Resizing read:" + e))
+                            createReadStream(savedName)
+                                .on('error', e => console.log('Resizing read:' + e))
                                 .pipe(resizer.resizer)
-                                .pipe(createWriteStream(path).on("error", e => console.log("Resizing write: " + e)));
+                                .on('error', e => console.log('Resizing write: ' + e))
+                                .pipe(createWriteStream(path).on('error', e => console.log('Resizing write: ' + e)));
                         });
-
-                              }
-                              res.send(clientPathToFile(Directory.images, filename + ext));
-                        });
-                  }
-            });
-
-      }
-
+                    }
+                    res.send(clientPathToFile(Directory.images, filename + ext));
+                });
+            },
+        });
+    }
 }
 function delay(ms: number) {
-      return new Promise(resolve => setTimeout(resolve, ms));
+    return new Promise(resolve => setTimeout(resolve, ms));
 }
 /**
  * On success, returns a buffer containing the bytes of a screenshot
  * of the video (optionally, at a timecode) specified by @param targetUrl.
- * 
+ *
  * On failure, returns undefined.
  */
 async function captureYoutubeScreenshot(targetUrl: string) {
-      // const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
-      // const page = await browser.newPage();
-      // // await page.setViewport({ width: 1920, height: 1080 });
+    // 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, { waitUntil: 'domcontentloaded' as any });
+    // // await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any });
 
-      // const videoPlayer = await page.$('.html5-video-player');
-      // videoPlayer && await page.focus("video");
-      // await delay(7000);
-      // const ad = await page.$('.ytp-ad-skip-button-text');
-      // await ad?.click();
-      // await videoPlayer?.click();
-      // await delay(1000);
-      // // hide youtube player controls.
-      // await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
+    // const videoPlayer = await page.$('.html5-video-player');
+    // videoPlayer && await page.focus("video");
+    // await delay(7000);
+    // const ad = await page.$('.ytp-ad-skip-button-text');
+    // await ad?.click();
+    // await videoPlayer?.click();
+    // await delay(1000);
+    // // hide youtube player controls.
+    // await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
 
-      // const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
-      // await browser.close();
+    // const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
+    // await browser.close();
 
-      // return buffer;
-      return null;
-}
\ No newline at end of file
+    // return buffer;
+    return null;
+}
-- 
cgit v1.2.3-70-g09d2


From fe5b49705069eebccec22e6cad29b007a60e3bec Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 28 Jul 2022 14:22:58 -0400
Subject: from last

---
 src/client/views/collections/CollectionStackedTimeline.tsx |  2 +-
 src/client/views/nodes/VideoBox.tsx                        | 11 ++++-------
 2 files changed, 5 insertions(+), 8 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 52126884a..48e3abbc7 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -291,7 +291,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 const nearest = Math.floor((this._hoverTime / this.props.rawDuration) * VideoBox.numThumbnails);
                 const thumbnails = StrListCast(this.dataDoc.thumbnails);
                 const imgField = thumbnails?.length > 0 ? new ImageField(thumbnails[nearest]) : undefined;
-                this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_s.png') : undefined;
+                this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_m.png') : undefined;
             }
         }
     };
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 4af4d2020..a3d501153 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -427,15 +427,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
         video.onseeked = () => {
             const canvas = document.createElement('canvas');
-            canvas.height = video.videoHeight;
-            canvas.width = video.videoWidth;
-            const ctx = canvas.getContext('2d');
-            ctx?.drawImage(video, 0, 0, canvas.width, canvas.height, 0, 0, 25, 25);
-            const imgUrl = canvas.toDataURL();
+            canvas.height = 100;
+            canvas.width = 100;
+            canvas.getContext('2d')?.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, 100, 100);
             const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, '');
             const encodedFilename = encodeURIComponent('thumbnail' + retitled + '_' + video.currentTime.toString().replace(/\./, '_'));
-            const filename = basename(encodedFilename);
-            thumbnailPromises?.push(VideoBox.convertDataUri(imgUrl, filename, true));
+            thumbnailPromises?.push(VideoBox.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true));
             const newTime = video.currentTime + video.duration / (VideoBox.numThumbnails - 1);
             if (newTime < video.duration) {
                 video.currentTime = newTime;
-- 
cgit v1.2.3-70-g09d2

