aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/Network.ts15
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.scss33
-rw-r--r--src/client/views/nodes/RecordingBox/ProgressBar.tsx9
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx4
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.scss29
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx23
-rw-r--r--src/server/ApiManagers/UploadManager.ts28
-rw-r--r--src/server/DashUploadUtils.ts40
8 files changed, 136 insertions, 45 deletions
diff --git a/src/client/Network.ts b/src/client/Network.ts
index 1255e5ce0..2c6d9d711 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -19,7 +19,6 @@ export namespace Networking {
}
export async function UploadFilesToServer<T extends Upload.FileInformation = Upload.FileInformation>(files: File | File[]): Promise<Upload.FileResponse<T>[]> {
- console.log(files)
const formData = new FormData();
if (Array.isArray(files)) {
if (!files.length) {
@@ -36,6 +35,19 @@ export namespace Networking {
const response = await fetch("/uploadFormData", parameters);
return response.json();
}
+
+ export async function UploadSegmentsAndConcatenate<T extends Upload.FileInformation = Upload.FileInformation>(files: File | File[]): Promise<Upload.FileResponse<T>[]> {
+ console.log(files)
+ const formData = new FormData();
+ if (!Array.isArray(files) || !files.length) return [];
+ files.forEach(file => formData.append(Utils.GenerateGuid(), file));
+ const parameters = {
+ method: 'POST',
+ body: formData
+ };
+ const response = await fetch("/uploadVideosandConcatenate", parameters);
+ return response.json();
+ }
export async function UploadYoutubeToServer<T extends Upload.FileInformation = Upload.FileInformation>(videoId: string): Promise<Upload.FileResponse<T>[]> {
const parameters = {
@@ -46,5 +58,6 @@ export namespace Networking {
const response = await fetch("/uploadYoutubeVideo", parameters);
return response.json();
}
+
} \ No newline at end of file
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.scss b/src/client/views/nodes/RecordingBox/ProgressBar.scss
index 67f96033a..d387468c6 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.scss
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.scss
@@ -1,13 +1,17 @@
.progressbar {
touch-action: none;
+ vertical-align: middle;
+ text-align: center;
+
+ align-items: center;
position: absolute;
display: flex;
justify-content: flex-start;
- bottom: 10px;
- width: 80%;
+ bottom: 2px;
+ width: 99%;
height: 30px;
background-color: gray;
@@ -34,11 +38,24 @@
margin: 1px;
padding: 0;
cursor: pointer;
- transition-duration: .25s;
+ transition-duration: .5s;
+ user-select: none;
+ vertical-align: middle;
text-align: center;
}
+.segment-hide {
+ background-color: inherit;
+ text-align: center;
+ vertical-align: middle;
+ user-select: none;
+ // /* Hide the text. */
+ // text-indent: 100%;
+ // white-space: nowrap;
+ // overflow: hidden;
+}
+
.segment:first-child {
margin-left: 2px;
}
@@ -47,9 +64,17 @@
}
.segment:hover {
+ background-color: white;
+}
+
+.segment:hover, .segment-selected {
margin: 0px;
border: 4px solid red;
- background-color: black;
min-width: 10px;
border-radius: 2px;
}
+
+.segment-selected {
+ border: 4px solid grey;
+ background-color: red;
+}
diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
index b17d27d2e..34a771367 100644
--- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx
+++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx
@@ -27,7 +27,7 @@ export function ProgressBar(props: ProgressBarProps) {
useEffect(() => {
const segmentsJSX = ordered.map((vid, i) =>
- <div id={`segment-${i.toString()}`} className='segment' style={{ width: `${((vid.endTime - vid.startTime) / totalTime()) * 100}%`, backgroundColor: clicked === i ? 'inherit' : 'red', }}>{vid.order}</div>);
+ <div id={`segment-${i.toString()}`} className={ clicked === i ? 'segment-hide' : 'segment'} style={{ width: `${((vid.endTime - vid.startTime) / totalTime()) * 100}%` }}>{vid.order}</div>);
setSegments(segmentsJSX)
}, [clicked, ordered])
@@ -98,7 +98,8 @@ export function ProgressBar(props: ProgressBarProps) {
// clickedSegment.style.backgroundColor = `inherit`;
const dot = document.createElement("div")
- dot.classList.add("segment")
+ dot.classList.add("segment-selected")
+ dot.style.transitionDuration = '0s';
dot.style.position = 'absolute';
dot.style.zIndex = '999';
dot.style.width = `${rect.width}px`;
@@ -106,8 +107,8 @@ export function ProgressBar(props: ProgressBarProps) {
document.body.append(dot)
const dragSegment = (event: PointerEvent): void => {
// event.stopPropagation()
- dot.style.left = `${event.clientX - rect.width/2}px`;
- dot.style.top = `${event.clientY - rect.height/2}px`;
+ dot.style.left = `${event.clientX - rect.width/2}px`;
+ dot.style.top = `${event.clientY - rect.height/2}px`;
}
const updateSegmentOrder = (event: PointerEvent): void => {
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 159271223..68f3b3ad4 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -54,9 +54,9 @@ export class RecordingBox extends ViewBoxBaseComponent() {
}
render() {
- // console.log("Proto[Is]: ", this.rootDoc.proto?.[Id])
+ console.log("Proto[Is]: ", this.rootDoc.proto?.[Id])
return <div className="recordingBox" ref={this._ref}>
- {!this.result && <RecordingView setResult={this.setResult} setDuration={this.setVideoDuration} id={this.rootDoc.proto?.[Id]} />}
+ {!this.result && <RecordingView setResult={this.setResult} setDuration={this.setVideoDuration} id={this.rootDoc.proto?.[Id] || ''} />}
</div>;
}
}
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss
index 9b2f6d070..0b7b1918f 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.scss
+++ b/src/client/views/nodes/RecordingBox/RecordingView.scss
@@ -33,7 +33,7 @@ button {
}
.video-wrapper:hover .controls {
- bottom: 30px;
+ bottom: 34.5px;
transform: translateY(0%);
opacity: 100%;
}
@@ -43,8 +43,8 @@ button {
align-items: center;
justify-content: space-evenly;
position: absolute;
- padding: 14px;
- width: 100%;
+ // padding: 14px;
+ //width: 100%;
max-width: 500px;
// max-height: 20%;
flex-wrap: wrap;
@@ -56,7 +56,14 @@ button {
// transform: translateY(150%);
transition: all 0.3s ease-in-out;
// opacity: 0%;
- bottom: 30px;
+ bottom: 34.5px;
+ height: 60px;
+ right: 2px;
+ // bottom: -150px;
+}
+
+.controls:active {
+ bottom: 40px;
// bottom: -150px;
}
@@ -127,9 +134,8 @@ button {
.controls-inner-container {
display: flex;
flex-direction: row;
- justify-content: center;
- width: 100%;
-
+ align-content: center;
+ position: relative;
}
.record-button-wrapper {
@@ -180,14 +186,14 @@ button {
height: 100%;
display: flex;
flex-direction: row;
- align-items: center;
- position: absolute;
+ align-content: center;
+ position: relative;
top: 0;
bottom: 0;
&.video-edit-wrapper {
- right: 50% - 15;
+ // right: 50% - 15;
.track-screen {
font-weight: 200;
@@ -197,10 +203,11 @@ button {
&.track-screen-wrapper {
- right: 50% - 30;
+ // right: 50% - 30;
.track-screen {
font-weight: 200;
+ color: aqua;
}
}
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 640e4f5f2..1e9ce22f1 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -71,13 +71,21 @@ export function RecordingView(props: IRecordingViewProps) {
inputPaths.push(name)
});
- console.log(videoFiles)
+ console.log(videoFiles)
+
+ const data = await Networking.UploadSegmentsAndConcatenate(videoFiles)
+ console.log('data', data)
+ const result = data[0].result
+ if (!(result instanceof Error)) { // convert this screenshotBox into normal videoBox
+ props.setResult(result, trackScreen)
+ } else {
+ alert("video conversion failed");
+ }
// const inputListName = 'order.txt';
// fs.writeFileSync(inputListName, inputPaths.join('\n'));
-
// var merge = ffmpeg();
// merge.input(inputListName)
// .inputOptions(['-f concat', '-safe 0'])
@@ -345,16 +353,17 @@ export function RecordingView(props: IRecordingViewProps) {
<span className="checkmark"></span>
Track Screen
</label>
- </div>)}
-
- </div>
+ </div>)}
- <ProgressBar
+ </div>
+
+ </div>
+
+ <ProgressBar
videos={videos}
setVideos={setVideos}
// playSegment={playSegment}
/>
- </div>
</div>
</div>)
} \ No newline at end of file
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 634548154..faf36c6e5 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -40,7 +40,31 @@ export function clientPathToFile(directory: Directory, filename: string) {
export default class UploadManager extends ApiManager {
- protected initialize(register: Registration): void {
+ protected initialize(register: Registration): void {
+
+ register({
+ method: Method.POST,
+ subscription: "/uploadVideosAndConcatenate",
+ 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 result: Upload.FileResponse[] = [];
+ for (const key in files) {
+ const f = files[key];
+ if (Array.isArray(f)) {
+ const result = await DashUploadUtils.concatenateVideos(f);
+ console.log('concatenated', result);
+ result && !(result.result instanceof Error) && _success(res, result);
+ }
+ }
+ resolve();
+ });
+ });
+ }
+ });
register({
method: Method.POST,
@@ -50,7 +74,7 @@ export default class UploadManager extends ApiManager {
form.keepExtensions = true;
form.uploadDir = pathToDirectory(Directory.parsed_files);
return new Promise<void>(resolve => {
- form.parse(req, async (_err, _fields, files) => {
+ form.parse(req, async (_err, _fields, files) => {
const results: Upload.FileResponse[] = [];
for (const key in files) {
const f = files[key];
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 0c4f87905..6a7c8543d 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -1,9 +1,9 @@
import { green, red } from 'colors';
import { ExifImage } from 'exif';
+import * as exifr from 'exifr';
import { File } from 'formidable';
import { createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
import * as path from 'path';
-import * as exifr from 'exifr';
import { basename } from "path";
import * as sharp from 'sharp';
import { Stream } from 'stream';
@@ -17,7 +17,6 @@ import { resolvedServerUrl } from "./server_Initialization";
import { AcceptableMedia, Upload } from './SharedMediaTypes';
import request = require('request-promise');
import formidable = require('formidable');
-import { output } from '../../webpack.config';
const { exec } = require("child_process");
const parse = require('pdf-parse');
const ffmpeg = require("fluent-ffmpeg");
@@ -63,19 +62,31 @@ export namespace DashUploadUtils {
const { imageFormats, videoFormats, applicationFormats, audioFormats } = AcceptableMedia; //TODO:glr
- export async function combineSegments(filePtr: File[], inputPaths: string[]): Promise<File> {
- const inputListName = 'order.txt';
-
- return new Promise<File>((resolve, reject) => {
- fs.writeFileSync(inputListName, inputPaths.join('\n'));
- ffmpeg(inputListName).inputOptions(['-f concat', '-safe 0']).outputOptions('-c copy').save('output.mp4')
+ export async function concatenateVideos(videoFiles: File[]): Promise<Upload.FileResponse> {
+ // make a list of paths to create the ordered text file for ffmpeg
+ const filePaths = videoFiles.map(file => file.path);
+ // write the text file to the file system
+ const inputListName = 'concat.txt';
+ const textFilePath = path.join(filesDirectory, "concat.txt");
+ writeFile(textFilePath, filePaths.join("\n"), (err) => console.log(err));
+
+
+ // make output file name based on timestamp
+ const outputFileName = `output-${Utils.GenerateGuid()}.mp4`;
+ await new Promise((resolve, reject) => {
+ ffmpeg(inputListName).inputOptions(['-f concat', '-safe 0']).outputOptions('-c copy').save(outputFileName)
.on("error", reject)
- .on("end", () => {
- fs.unlinkSync(inputListName);
- filePtr[0].path = 'output.mp4';
- resolve(filePtr[0]);
- });
- });
+ .on("end", resolve);
+ })
+
+ // delete concat.txt from the file system
+ unlinkSync(textFilePath);
+
+ // read the output file from the file system
+ const outputFile = fs.readFileSync(outputFileName);
+ console.log('outputFile', outputFile);
+ // move only the output file to the videos directory
+ return MoveParsedFile(outputFile, Directory.videos)
}
export function uploadYoutube(videoId: string): Promise<Upload.FileResponse> {
@@ -237,6 +248,7 @@ export namespace DashUploadUtils {
}
let resolvedUrl: string;
/**
+ *
* At this point, we want to take whatever url we have and make sure it's requestable.
* Anything that's hosted by some other website already is, but if the url is a local file url
* (locates the file on this server machine), we have to resolve the client side url by cutting out the