From 92e66e04f7f51d37b465cff442ce47f6d6d7cadd Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 22 Mar 2022 16:58:49 +0100 Subject: Rename studio to editor --- client/src/app/+video-studio/edit/index.ts | 2 + .../edit/video-studio-edit.component.html | 88 +++++++++ .../edit/video-studio-edit.component.scss | 76 ++++++++ .../edit/video-studio-edit.component.ts | 204 +++++++++++++++++++++ .../edit/video-studio-edit.resolver.ts | 18 ++ 5 files changed, 388 insertions(+) create mode 100644 client/src/app/+video-studio/edit/index.ts create mode 100644 client/src/app/+video-studio/edit/video-studio-edit.component.html create mode 100644 client/src/app/+video-studio/edit/video-studio-edit.component.scss create mode 100644 client/src/app/+video-studio/edit/video-studio-edit.component.ts create mode 100644 client/src/app/+video-studio/edit/video-studio-edit.resolver.ts (limited to 'client/src/app/+video-studio/edit') diff --git a/client/src/app/+video-studio/edit/index.ts b/client/src/app/+video-studio/edit/index.ts new file mode 100644 index 000000000..ff1d77fc0 --- /dev/null +++ b/client/src/app/+video-studio/edit/index.ts @@ -0,0 +1,2 @@ +export * from './video-studio-edit.component' +export * from './video-studio-edit.resolver' diff --git a/client/src/app/+video-studio/edit/video-studio-edit.component.html b/client/src/app/+video-studio/edit/video-studio-edit.component.html new file mode 100644 index 000000000..a9f34811f --- /dev/null +++ b/client/src/app/+video-studio/edit/video-studio-edit.component.html @@ -0,0 +1,88 @@ +
+

Studio for {{ video.name }}

+ +
+
+ +
+

CUT VIDEO

+ +
Set a new start/end.
+ +
+ + +
+ +
+ + +
+
+ +
+

ADD INTRO

+ +
Concatenate a file at the beginning of the video.
+ +
+ +
+
+ +
+

ADD OUTRO

+ +
Concatenate a file at the end of the video.
+ +
+ +
+
+ +
+

ADD WATERMARK

+ +
Add a watermark image to the video.
+ +
+ +
+
+ + +
+ + +
+
+ + +
+ +
+ + +
    +
  1. {{ task }}
  2. +
+
+
+
+
diff --git a/client/src/app/+video-studio/edit/video-studio-edit.component.scss b/client/src/app/+video-studio/edit/video-studio-edit.component.scss new file mode 100644 index 000000000..43f336f59 --- /dev/null +++ b/client/src/app/+video-studio/edit/video-studio-edit.component.scss @@ -0,0 +1,76 @@ +@use '_variables' as *; +@use '_mixins' as *; + +.columns { + display: flex; + + .information { + width: 100%; + margin-left: 50px; + + > div { + margin-bottom: 30px; + } + + @media screen and (max-width: $small-view) { + display: none; + } + } +} + +h1 { + font-size: 20px; +} + +h2 { + font-weight: $font-bold; + font-size: 16px; + color: pvar(--mainColor); + background-color: pvar(--mainBackgroundColor); + padding: 0 5px; + width: fit-content; + margin: -8px 0 0; +} + +.section { + $min-width: 600px; + + @include padding-left(10px); + + min-width: $min-width; + + margin-bottom: 50px; + border: 1px solid $separator-border-color; + border-radius: 5px; + width: fit-content; + + .form-group, + .description { + @include margin-left(5px); + } + + .description { + color: pvar(--greyForegroundColor); + margin-top: 5px; + margin-bottom: 15px; + } + + @media screen and (max-width: $min-width) { + min-width: none; + } +} + +my-timestamp-input { + display: block; +} + +my-embed { + display: block; + max-width: 500px; + width: 100%; +} + +my-reactive-file { + display: block; + width: fit-content; +} diff --git a/client/src/app/+video-studio/edit/video-studio-edit.component.ts b/client/src/app/+video-studio/edit/video-studio-edit.component.ts new file mode 100644 index 000000000..392b65767 --- /dev/null +++ b/client/src/app/+video-studio/edit/video-studio-edit.component.ts @@ -0,0 +1,204 @@ +import { Component, OnInit } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { ConfirmService, Notifier, ServerService } from '@app/core' +import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' +import { VideoDetails } from '@app/shared/shared-main' +import { LoadingBarService } from '@ngx-loading-bar/core' +import { secondsToTime } from '@shared/core-utils' +import { VideoStudioTask, VideoStudioTaskCut } from '@shared/models' +import { VideoStudioService } from '../shared' + +@Component({ + selector: 'my-video-studio-edit', + templateUrl: './video-studio-edit.component.html', + styleUrls: [ './video-studio-edit.component.scss' ] +}) +export class VideoStudioEditComponent extends FormReactive implements OnInit { + isRunningEdition = false + + video: VideoDetails + + constructor ( + protected formValidatorService: FormValidatorService, + private serverService: ServerService, + private notifier: Notifier, + private router: Router, + private route: ActivatedRoute, + private videoStudioService: VideoStudioService, + private loadingBar: LoadingBarService, + private confirmService: ConfirmService + ) { + super() + } + + ngOnInit () { + this.video = this.route.snapshot.data.video + + const defaultValues = { + cut: { + start: 0, + end: this.video.duration + } + } + + this.buildForm({ + cut: { + start: null, + end: null + }, + 'add-intro': { + file: null + }, + 'add-outro': { + file: null + }, + 'add-watermark': { + file: null + } + }, defaultValues) + } + + get videoExtensions () { + return this.serverService.getHTMLConfig().video.file.extensions + } + + get imageExtensions () { + return this.serverService.getHTMLConfig().video.image.extensions + } + + async runEdition () { + if (this.isRunningEdition) return + + const title = $localize`Are you sure you want to edit "${this.video.name}"?` + const listHTML = this.getTasksSummary().map(t => `
  • ${t}
  • `).join('') + + // eslint-disable-next-line max-len + const confirmHTML = $localize`The current video will be overwritten by this edited video and you won't be able to recover it.

    ` + + $localize`As a reminder, the following tasks will be executed:
      ${listHTML}
    ` + + if (await this.confirmService.confirm(confirmHTML, title) !== true) return + + this.isRunningEdition = true + + const tasks = this.buildTasks() + + this.loadingBar.useRef().start() + + return this.videoStudioService.editVideo(this.video.uuid, tasks) + .subscribe({ + next: () => { + this.notifier.success($localize`Edition tasks created.`) + + // Don't redirect to old video version watch page that could be confusing for users + this.router.navigateByUrl('/my-library/videos') + }, + + error: err => { + this.loadingBar.useRef().complete() + this.isRunningEdition = false + this.notifier.error(err.message) + console.error(err) + } + }) + } + + getIntroOutroTooltip () { + return $localize`(extensions: ${this.videoExtensions.join(', ')})` + } + + getWatermarkTooltip () { + return $localize`(extensions: ${this.imageExtensions.join(', ')})` + } + + noEdition () { + return this.buildTasks().length === 0 + } + + getTasksSummary () { + const tasks = this.buildTasks() + + return tasks.map(t => { + if (t.name === 'add-intro') { + return $localize`"${this.getFilename(t.options.file)}" will be added at the beginning of the video` + } + + if (t.name === 'add-outro') { + return $localize`"${this.getFilename(t.options.file)}" will be added at the end of the video` + } + + if (t.name === 'add-watermark') { + return $localize`"${this.getFilename(t.options.file)}" image watermark will be added to the video` + } + + if (t.name === 'cut') { + const { start, end } = t.options + + if (start !== undefined && end !== undefined) { + return $localize`Video will begin at ${secondsToTime(start)} and stop at ${secondsToTime(end)}` + } + + if (start !== undefined) { + return $localize`Video will begin at ${secondsToTime(start)}` + } + + if (end !== undefined) { + return $localize`Video will stop at ${secondsToTime(end)}` + } + } + + return '' + }) + } + + private getFilename (obj: any) { + return obj.name + } + + private buildTasks () { + const tasks: VideoStudioTask[] = [] + const value = this.form.value + + const cut = value['cut'] + if (cut['start'] !== 0 || cut['end'] !== this.video.duration) { + + const options: VideoStudioTaskCut['options'] = {} + if (cut['start'] !== 0) options.start = cut['start'] + if (cut['end'] !== this.video.duration) options.end = cut['end'] + + tasks.push({ + name: 'cut', + options + }) + } + + if (value['add-intro']?.['file']) { + tasks.push({ + name: 'add-intro', + options: { + file: value['add-intro']['file'] + } + }) + } + + if (value['add-outro']?.['file']) { + tasks.push({ + name: 'add-outro', + options: { + file: value['add-outro']['file'] + } + }) + } + + if (value['add-watermark']?.['file']) { + tasks.push({ + name: 'add-watermark', + options: { + file: value['add-watermark']['file'] + } + }) + } + + return tasks + } + +} diff --git a/client/src/app/+video-studio/edit/video-studio-edit.resolver.ts b/client/src/app/+video-studio/edit/video-studio-edit.resolver.ts new file mode 100644 index 000000000..c658be50b --- /dev/null +++ b/client/src/app/+video-studio/edit/video-studio-edit.resolver.ts @@ -0,0 +1,18 @@ + +import { Injectable } from '@angular/core' +import { ActivatedRouteSnapshot, Resolve } from '@angular/router' +import { VideoService } from '@app/shared/shared-main' + +@Injectable() +export class VideoStudioEditResolver implements Resolve { + constructor ( + private videoService: VideoService + ) { + } + + resolve (route: ActivatedRouteSnapshot) { + const videoId: string = route.params['videoId'] + + return this.videoService.getVideo({ videoId }) + } +} -- cgit v1.2.3