1
0
Fork 0

Rename studio to editor

This commit is contained in:
Chocobozzz 2022-03-22 16:58:49 +01:00
parent 1808a1f8e4
commit 92e66e04f7
No known key found for this signature in database
GPG key ID: 583A612D890159BE
81 changed files with 368 additions and 370 deletions

View file

@ -200,7 +200,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
resolutions: {} resolutions: {}
} }
}, },
videoEditor: { videoStudio: {
enabled: null enabled: null
}, },
autoBlacklist: { autoBlacklist: {

View file

@ -193,9 +193,9 @@
</div> </div>
</div> </div>
<div class="form-row mt-2"> <!-- video editor grid --> <div class="form-row mt-2"> <!-- video studio grid -->
<div class="form-group col-12 col-lg-4 col-xl-3"> <div class="form-group col-12 col-lg-4 col-xl-3">
<div i18n class="inner-form-title">VIDEO EDITOR</div> <div i18n class="inner-form-title">VIDEO STUDIO</div>
<div i18n class="inner-form-description"> <div i18n class="inner-form-description">
Allows your users to edit their video (cut, add intro/outro, add a watermark etc) Allows your users to edit their video (cut, add intro/outro, add a watermark etc)
</div> </div>
@ -203,14 +203,14 @@
<div class="form-group form-group-right col-12 col-lg-8 col-xl-9"> <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="videoEditor"> <ng-container formGroupName="videoStudio">
<div class="form-group" [ngClass]="getTranscodingDisabledClass()"> <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
<my-peertube-checkbox <my-peertube-checkbox
inputName="videoEditorEnabled" formControlName="enabled" inputName="videoStudioEnabled" formControlName="enabled"
i18n-labelText labelText="Enable video editor" i18n-labelText labelText="Enable video studio"
> >
<ng-container ngProjectAs="description" *ngIf="!isTranscodingEnabled()"> <ng-container ngProjectAs="description" *ngIf="!isTranscodingEnabled()">
<span i18n>⚠️ You need to enable transcoding first to enable video editor</span> <span i18n>⚠️ You need to enable transcoding first to enable video studio</span>
</ng-container> </ng-container>
</my-peertube-checkbox> </my-peertube-checkbox>
</div> </div>

View file

@ -72,7 +72,7 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
private checkTranscodingFields () { private checkTranscodingFields () {
const transcodingControl = this.form.get('transcoding.enabled') const transcodingControl = this.form.get('transcoding.enabled')
const videoEditorControl = this.form.get('videoEditor.enabled') const videoStudioControl = this.form.get('videoStudio.enabled')
const hlsControl = this.form.get('transcoding.hls.enabled') const hlsControl = this.form.get('transcoding.hls.enabled')
const webtorrentControl = this.form.get('transcoding.webtorrent.enabled') const webtorrentControl = this.form.get('transcoding.webtorrent.enabled')
@ -101,7 +101,7 @@ export class EditVODTranscodingComponent implements OnInit, OnChanges {
transcodingControl.valueChanges transcodingControl.valueChanges
.subscribe(newValue => { .subscribe(newValue => {
if (newValue === false) { if (newValue === false) {
videoEditorControl.setValue(false) videoStudioControl.setValue(false)
} }
}) })
} }

View file

@ -45,7 +45,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
abuseStateChange: $localize`One of your abuse reports has been accepted or rejected by moderators`, abuseStateChange: $localize`One of your abuse reports has been accepted or rejected by moderators`,
newPeerTubeVersion: $localize`A new PeerTube version is available`, newPeerTubeVersion: $localize`A new PeerTube version is available`,
newPluginVersion: $localize`One of your plugin/theme has a new available version`, newPluginVersion: $localize`One of your plugin/theme has a new available version`,
myVideoEditionFinished: $localize`Video edition finished` myVideoStudioEditionFinished: $localize`Video studio edition has finished`
} }
this.notificationSettingGroups = [ this.notificationSettingGroups = [
{ {
@ -64,7 +64,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
'blacklistOnMyVideo', 'blacklistOnMyVideo',
'myVideoPublished', 'myVideoPublished',
'myVideoImportFinished', 'myVideoImportFinished',
'myVideoEditionFinished' 'myVideoStudioEditionFinished'
] ]
}, },

View file

@ -205,9 +205,9 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
private buildActions () { private buildActions () {
this.videoActions = [ this.videoActions = [
{ {
label: $localize`Editor`, label: $localize`Studio`,
linkBuilder: ({ video }) => [ '/video-editor/edit', video.uuid ], linkBuilder: ({ video }) => [ '/studio/edit', video.uuid ],
isDisplayed: ({ video }) => video.isEditableBy(this.authService.getUser(), this.serverService.getHTMLConfig().videoEditor.enabled), isDisplayed: ({ video }) => video.isEditableBy(this.authService.getUser(), this.serverService.getHTMLConfig().videoStudio.enabled),
iconName: 'film' iconName: 'film'
}, },
{ {

View file

@ -1,2 +0,0 @@
export * from './video-editor-edit.component'
export * from './video-editor-edit.resolver'

View file

@ -1 +0,0 @@
export * from './video-editor.module'

View file

@ -1 +0,0 @@
export * from './video-editor.service'

View file

@ -1,30 +0,0 @@
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { VideoEditorEditResolver } from './edit'
import { VideoEditorEditComponent } from './edit/video-editor-edit.component'
const videoEditorRoutes: Routes = [
{
path: '',
children: [
{
path: 'edit/:videoId',
component: VideoEditorEditComponent,
data: {
meta: {
title: $localize`Edit video`
}
},
resolve: {
video: VideoEditorEditResolver
}
}
]
}
]
@NgModule({
imports: [ RouterModule.forChild(videoEditorRoutes) ],
exports: [ RouterModule ]
})
export class VideoEditorRoutingModule {}

View file

@ -1,27 +0,0 @@
import { NgModule } from '@angular/core'
import { SharedFormModule } from '@app/shared/shared-forms'
import { SharedMainModule } from '@app/shared/shared-main'
import { VideoEditorEditComponent, VideoEditorEditResolver } from './edit'
import { VideoEditorService } from './shared'
import { VideoEditorRoutingModule } from './video-editor-routing.module'
@NgModule({
imports: [
VideoEditorRoutingModule,
SharedMainModule,
SharedFormModule
],
declarations: [
VideoEditorEditComponent
],
exports: [],
providers: [
VideoEditorService,
VideoEditorEditResolver
]
})
export class VideoEditorModule { }

View file

@ -0,0 +1,2 @@
export * from './video-studio-edit.component'
export * from './video-studio-edit.resolver'

View file

@ -1,5 +1,5 @@
<div class="margin-content"> <div class="margin-content">
<h1 class="title-page title-page-single" i18n>Edit {{ video.name }}</h1> <h1 class="title-page title-page-single" i18n>Studio for {{ video.name }}</h1>
<div class="columns"> <div class="columns">
<form role="form" [formGroup]="form"> <form role="form" [formGroup]="form">

View file

@ -2,18 +2,18 @@ import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { ConfirmService, Notifier, ServerService } from '@app/core' import { ConfirmService, Notifier, ServerService } from '@app/core'
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
import { Video, VideoDetails } from '@app/shared/shared-main' import { VideoDetails } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { secondsToTime } from '@shared/core-utils' import { secondsToTime } from '@shared/core-utils'
import { VideoEditorTask, VideoEditorTaskCut } from '@shared/models' import { VideoStudioTask, VideoStudioTaskCut } from '@shared/models'
import { VideoEditorService } from '../shared' import { VideoStudioService } from '../shared'
@Component({ @Component({
selector: 'my-video-editor-edit', selector: 'my-video-studio-edit',
templateUrl: './video-editor-edit.component.html', templateUrl: './video-studio-edit.component.html',
styleUrls: [ './video-editor-edit.component.scss' ] styleUrls: [ './video-studio-edit.component.scss' ]
}) })
export class VideoEditorEditComponent extends FormReactive implements OnInit { export class VideoStudioEditComponent extends FormReactive implements OnInit {
isRunningEdition = false isRunningEdition = false
video: VideoDetails video: VideoDetails
@ -24,7 +24,7 @@ export class VideoEditorEditComponent extends FormReactive implements OnInit {
private notifier: Notifier, private notifier: Notifier,
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private videoEditorService: VideoEditorService, private videoStudioService: VideoStudioService,
private loadingBar: LoadingBarService, private loadingBar: LoadingBarService,
private confirmService: ConfirmService private confirmService: ConfirmService
) { ) {
@ -84,11 +84,13 @@ export class VideoEditorEditComponent extends FormReactive implements OnInit {
this.loadingBar.useRef().start() this.loadingBar.useRef().start()
return this.videoEditorService.editVideo(this.video.uuid, tasks) return this.videoStudioService.editVideo(this.video.uuid, tasks)
.subscribe({ .subscribe({
next: () => { next: () => {
this.notifier.success($localize`Video updated.`) this.notifier.success($localize`Edition tasks created.`)
this.router.navigateByUrl(Video.buildWatchUrl(this.video))
// Don't redirect to old video version watch page that could be confusing for users
this.router.navigateByUrl('/my-library/videos')
}, },
error: err => { error: err => {
@ -153,13 +155,13 @@ export class VideoEditorEditComponent extends FormReactive implements OnInit {
} }
private buildTasks () { private buildTasks () {
const tasks: VideoEditorTask[] = [] const tasks: VideoStudioTask[] = []
const value = this.form.value const value = this.form.value
const cut = value['cut'] const cut = value['cut']
if (cut['start'] !== 0 || cut['end'] !== this.video.duration) { if (cut['start'] !== 0 || cut['end'] !== this.video.duration) {
const options: VideoEditorTaskCut['options'] = {} const options: VideoStudioTaskCut['options'] = {}
if (cut['start'] !== 0) options.start = cut['start'] if (cut['start'] !== 0) options.start = cut['start']
if (cut['end'] !== this.video.duration) options.end = cut['end'] if (cut['end'] !== this.video.duration) options.end = cut['end']

View file

@ -4,7 +4,7 @@ import { ActivatedRouteSnapshot, Resolve } from '@angular/router'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
@Injectable() @Injectable()
export class VideoEditorEditResolver implements Resolve<any> { export class VideoStudioEditResolver implements Resolve<any> {
constructor ( constructor (
private videoService: VideoService private videoService: VideoService
) { ) {

View file

@ -0,0 +1 @@
export * from './video-studio.module'

View file

@ -0,0 +1 @@
export * from './video-studio.service'

View file

@ -4,19 +4,19 @@ import { Injectable } from '@angular/core'
import { RestExtractor } from '@app/core' import { RestExtractor } from '@app/core'
import { objectToFormData } from '@app/helpers' import { objectToFormData } from '@app/helpers'
import { VideoService } from '@app/shared/shared-main' import { VideoService } from '@app/shared/shared-main'
import { VideoEditorCreateEdition, VideoEditorTask } from '@shared/models' import { VideoStudioCreateEdition, VideoStudioTask } from '@shared/models'
@Injectable() @Injectable()
export class VideoEditorService { export class VideoStudioService {
constructor ( constructor (
private authHttp: HttpClient, private authHttp: HttpClient,
private restExtractor: RestExtractor private restExtractor: RestExtractor
) {} ) {}
editVideo (videoId: number | string, tasks: VideoEditorTask[]) { editVideo (videoId: number | string, tasks: VideoStudioTask[]) {
const url = VideoService.BASE_VIDEO_URL + '/' + videoId + '/editor/edit' const url = VideoService.BASE_VIDEO_URL + '/' + videoId + '/studio/edit'
const body: VideoEditorCreateEdition = { const body: VideoStudioCreateEdition = {
tasks tasks
} }

View file

@ -0,0 +1,29 @@
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { VideoStudioEditComponent, VideoStudioEditResolver } from './edit'
const videoStudioRoutes: Routes = [
{
path: '',
children: [
{
path: 'edit/:videoId',
component: VideoStudioEditComponent,
data: {
meta: {
title: $localize`Studio`
}
},
resolve: {
video: VideoStudioEditResolver
}
}
]
}
]
@NgModule({
imports: [ RouterModule.forChild(videoStudioRoutes) ],
exports: [ RouterModule ]
})
export class VideoStudioRoutingModule {}

View file

@ -0,0 +1,27 @@
import { NgModule } from '@angular/core'
import { SharedFormModule } from '@app/shared/shared-forms'
import { SharedMainModule } from '@app/shared/shared-main'
import { VideoStudioEditComponent, VideoStudioEditResolver } from './edit'
import { VideoStudioService } from './shared'
import { VideoStudioRoutingModule } from './video-studio-routing.module'
@NgModule({
imports: [
VideoStudioRoutingModule,
SharedMainModule,
SharedFormModule
],
declarations: [
VideoStudioEditComponent
],
exports: [],
providers: [
VideoStudioService,
VideoStudioEditResolver
]
})
export class VideoStudioModule { }

View file

@ -35,7 +35,7 @@ export class ActionButtonsComponent implements OnInit, OnChanges {
playlist: false, playlist: false,
download: true, download: true,
update: true, update: true,
editor: true, studio: true,
blacklist: true, blacklist: true,
delete: true, delete: true,
report: true, report: true,

View file

@ -144,8 +144,8 @@ const routes: Routes = [
}, },
{ {
path: 'video-editor', path: 'studio',
loadChildren: () => import('./+video-editor/video-editor.module').then(m => m.VideoEditorModule), loadChildren: () => import('./+video-studio/video-studio.module').then(m => m.VideoStudioModule),
canActivateChild: [ MetaGuard ] canActivateChild: [ MetaGuard ]
}, },

View file

@ -228,7 +228,7 @@ export class UserNotification implements UserNotificationServer {
this.pluginQueryParams.pluginType = this.plugin.type + '' this.pluginQueryParams.pluginType = this.plugin.type + ''
break break
case UserNotificationType.MY_VIDEO_EDITION_FINISHED: case UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED:
this.videoUrl = this.buildVideoUrl(this.video) this.videoUrl = this.buildVideoUrl(this.video)
break break
} }

View file

@ -207,7 +207,7 @@
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="19"> <!-- UserNotificationType.MY_VIDEO_EDITION_FINISHED --> <ng-container *ngSwitchCase="19"> <!-- UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED -->
<my-global-icon iconName="film" aria-hidden="true"></my-global-icon> <my-global-icon iconName="film" aria-hidden="true"></my-global-icon>
<div class="message" i18n> <div class="message" i18n>

View file

@ -228,8 +228,8 @@ export class Video implements VideoServerModel {
return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO))
} }
isEditableBy (user: AuthUser, videoEditorEnabled: boolean) { isEditableBy (user: AuthUser, videoStudioEnabled: boolean) {
return videoEditorEnabled && return videoStudioEnabled &&
this.state?.id === VideoState.PUBLISHED && this.state?.id === VideoState.PUBLISHED &&
this.isUpdatableBy(user) this.isUpdatableBy(user)
} }

View file

@ -29,7 +29,7 @@ export type VideoActionsDisplayType = {
liveInfo?: boolean liveInfo?: boolean
removeFiles?: boolean removeFiles?: boolean
transcoding?: boolean transcoding?: boolean
editor?: boolean studio?: boolean
} }
@Component({ @Component({
@ -61,7 +61,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
liveInfo: false, liveInfo: false,
removeFiles: false, removeFiles: false,
transcoding: false, transcoding: false,
editor: true studio: true
} }
@Input() placement = 'left' @Input() placement = 'left'
@ -153,7 +153,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
} }
isVideoEditable () { isVideoEditable () {
return this.video.isEditableBy(this.user, this.serverService.getHTMLConfig().videoEditor.enabled) return this.video.isEditableBy(this.user, this.serverService.getHTMLConfig().videoStudio.enabled)
} }
isVideoRemovable () { isVideoRemovable () {
@ -337,10 +337,10 @@ export class VideoActionsDropdownComponent implements OnChanges {
isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.update && this.isVideoUpdatable() isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.update && this.isVideoUpdatable()
}, },
{ {
label: $localize`Editor`, label: $localize`Studio`,
linkBuilder: ({ video }) => [ '/video-editor/edit', video.uuid ], linkBuilder: ({ video }) => [ '/studio/edit', video.uuid ],
iconName: 'film', iconName: 'film',
isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.editor && this.isVideoEditable() isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.studio && this.isVideoEditable()
}, },
{ {
label: $localize`Block`, label: $localize`Block`,

View file

@ -436,7 +436,7 @@ live:
1440p: false 1440p: false
2160p: false 2160p: false
video_editor: video_studio:
# Enable video edition by users (cut, add intro/outro, add watermark etc) # Enable video edition by users (cut, add intro/outro, add watermark etc)
enabled: false enabled: false

View file

@ -444,7 +444,7 @@ live:
1440p: false 1440p: false
2160p: false 2160p: false
video_editor: video_studio:
# Enable video edition by users (cut, add intro/outro, add watermark etc) # Enable video edition by users (cut, add intro/outro, add watermark etc)
enabled: false enabled: false

View file

@ -37,7 +37,7 @@ signup:
transcoding: transcoding:
enabled: false enabled: false
video_editor: video_studio:
enabled: false enabled: false
live: live:

View file

@ -31,5 +31,5 @@ admin:
transcoding: transcoding:
enabled: false enabled: false
video_editor: video_studio:
enabled: false enabled: false

View file

@ -31,5 +31,5 @@ admin:
transcoding: transcoding:
enabled: false enabled: false
video_editor: video_studio:
enabled: false enabled: false

View file

@ -31,5 +31,5 @@ admin:
transcoding: transcoding:
enabled: false enabled: false
video_editor: video_studio:
enabled: false enabled: false

View file

@ -31,5 +31,5 @@ admin:
transcoding: transcoding:
enabled: false enabled: false
video_editor: video_studio:
enabled: false enabled: false

View file

@ -168,5 +168,5 @@ views:
local_buffer_update_interval: '5 seconds' local_buffer_update_interval: '5 seconds'
ip_view_expiration: '1 second' ip_view_expiration: '1 second'
video_editor: video_studio:
enabled: true enabled: true

View file

@ -259,8 +259,8 @@ function customConfig (): CustomConfig {
} }
} }
}, },
videoEditor: { videoStudio: {
enabled: CONFIG.VIDEO_EDITOR.ENABLED enabled: CONFIG.VIDEO_STUDIO.ENABLED
}, },
import: { import: {
videos: { videos: {

View file

@ -83,7 +83,7 @@ async function updateNotificationSettings (req: express.Request, res: express.Re
abuseStateChange: body.abuseStateChange, abuseStateChange: body.abuseStateChange,
newPeerTubeVersion: body.newPeerTubeVersion, newPeerTubeVersion: body.newPeerTubeVersion,
newPluginVersion: body.newPluginVersion, newPluginVersion: body.newPluginVersion,
myVideoEditionFinished: body.myVideoEditionFinished myVideoStudioEditionFinished: body.myVideoStudioEditionFinished
} }
await UserNotificationSettingModel.update(values, query) await UserNotificationSettingModel.update(values, query)

View file

@ -35,7 +35,7 @@ import { VideoModel } from '../../../models/video/video'
import { blacklistRouter } from './blacklist' import { blacklistRouter } from './blacklist'
import { videoCaptionsRouter } from './captions' import { videoCaptionsRouter } from './captions'
import { videoCommentRouter } from './comment' import { videoCommentRouter } from './comment'
import { editorRouter } from './editor' import { studioRouter } from './studio'
import { filesRouter } from './files' import { filesRouter } from './files'
import { videoImportsRouter } from './import' import { videoImportsRouter } from './import'
import { liveRouter } from './live' import { liveRouter } from './live'
@ -52,7 +52,7 @@ const videosRouter = express.Router()
videosRouter.use('/', blacklistRouter) videosRouter.use('/', blacklistRouter)
videosRouter.use('/', rateVideoRouter) videosRouter.use('/', rateVideoRouter)
videosRouter.use('/', videoCommentRouter) videosRouter.use('/', videoCommentRouter)
videosRouter.use('/', editorRouter) videosRouter.use('/', studioRouter)
videosRouter.use('/', videoCaptionsRouter) videosRouter.use('/', videoCaptionsRouter)
videosRouter.use('/', videoImportsRouter) videosRouter.use('/', videoImportsRouter)
videosRouter.use('/', ownershipVideoRouter) videosRouter.use('/', ownershipVideoRouter)

View file

@ -2,26 +2,26 @@ import express from 'express'
import { createAnyReqFiles } from '@server/helpers/express-utils' import { createAnyReqFiles } from '@server/helpers/express-utils'
import { MIMETYPES } from '@server/initializers/constants' import { MIMETYPES } from '@server/initializers/constants'
import { JobQueue } from '@server/lib/job-queue' import { JobQueue } from '@server/lib/job-queue'
import { buildTaskFileFieldname, getTaskFile } from '@server/lib/video-editor' import { buildTaskFileFieldname, getTaskFile } from '@server/lib/video-studio'
import { import {
HttpStatusCode, HttpStatusCode,
VideoEditionTaskPayload, VideoState,
VideoEditorCreateEdition, VideoStudioCreateEdition,
VideoEditorTask, VideoStudioTask,
VideoEditorTaskCut, VideoStudioTaskCut,
VideoEditorTaskIntro, VideoStudioTaskIntro,
VideoEditorTaskOutro, VideoStudioTaskOutro,
VideoEditorTaskWatermark, VideoStudioTaskPayload,
VideoState VideoStudioTaskWatermark
} from '@shared/models' } from '@shared/models'
import { asyncMiddleware, authenticate, videosEditorAddEditionValidator } from '../../../middlewares' import { asyncMiddleware, authenticate, videoStudioAddEditionValidator } from '../../../middlewares'
const editorRouter = express.Router() const studioRouter = express.Router()
const tasksFiles = createAnyReqFiles( const tasksFiles = createAnyReqFiles(
MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.VIDEO.MIMETYPE_EXT,
(req: express.Request, file: Express.Multer.File, cb: (err: Error, result?: boolean) => void) => { (req: express.Request, file: Express.Multer.File, cb: (err: Error, result?: boolean) => void) => {
const body = req.body as VideoEditorCreateEdition const body = req.body as VideoStudioCreateEdition
// Fetch array element // Fetch array element
const matches = file.fieldname.match(/tasks\[(\d+)\]/) const matches = file.fieldname.match(/tasks\[(\d+)\]/)
@ -43,24 +43,24 @@ const tasksFiles = createAnyReqFiles(
} }
) )
editorRouter.post('/:videoId/editor/edit', studioRouter.post('/:videoId/studio/edit',
authenticate, authenticate,
tasksFiles, tasksFiles,
asyncMiddleware(videosEditorAddEditionValidator), asyncMiddleware(videoStudioAddEditionValidator),
asyncMiddleware(createEditionTasks) asyncMiddleware(createEditionTasks)
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
editorRouter studioRouter
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
async function createEditionTasks (req: express.Request, res: express.Response) { async function createEditionTasks (req: express.Request, res: express.Response) {
const files = req.files as Express.Multer.File[] const files = req.files as Express.Multer.File[]
const body = req.body as VideoEditorCreateEdition const body = req.body as VideoStudioCreateEdition
const video = res.locals.videoAll const video = res.locals.videoAll
video.state = VideoState.TO_EDIT video.state = VideoState.TO_EDIT
@ -71,13 +71,13 @@ async function createEditionTasks (req: express.Request, res: express.Response)
tasks: body.tasks.map((t, i) => buildTaskPayload(t, i, files)) tasks: body.tasks.map((t, i) => buildTaskPayload(t, i, files))
} }
JobQueue.Instance.createJob({ type: 'video-edition', payload }) JobQueue.Instance.createJob({ type: 'video-studio-edition', payload })
return res.sendStatus(HttpStatusCode.NO_CONTENT_204) return res.sendStatus(HttpStatusCode.NO_CONTENT_204)
} }
const taskPayloadBuilders: { const taskPayloadBuilders: {
[id in VideoEditorTask['name']]: (task: VideoEditorTask, indice?: number, files?: Express.Multer.File[]) => VideoEditionTaskPayload [id in VideoStudioTask['name']]: (task: VideoStudioTask, indice?: number, files?: Express.Multer.File[]) => VideoStudioTaskPayload
} = { } = {
'add-intro': buildIntroOutroTask, 'add-intro': buildIntroOutroTask,
'add-outro': buildIntroOutroTask, 'add-outro': buildIntroOutroTask,
@ -85,11 +85,11 @@ const taskPayloadBuilders: {
'add-watermark': buildWatermarkTask 'add-watermark': buildWatermarkTask
} }
function buildTaskPayload (task: VideoEditorTask, indice: number, files: Express.Multer.File[]): VideoEditionTaskPayload { function buildTaskPayload (task: VideoStudioTask, indice: number, files: Express.Multer.File[]): VideoStudioTaskPayload {
return taskPayloadBuilders[task.name](task, indice, files) return taskPayloadBuilders[task.name](task, indice, files)
} }
function buildIntroOutroTask (task: VideoEditorTaskIntro | VideoEditorTaskOutro, indice: number, files: Express.Multer.File[]) { function buildIntroOutroTask (task: VideoStudioTaskIntro | VideoStudioTaskOutro, indice: number, files: Express.Multer.File[]) {
return { return {
name: task.name, name: task.name,
options: { options: {
@ -98,7 +98,7 @@ function buildIntroOutroTask (task: VideoEditorTaskIntro | VideoEditorTaskOutro,
} }
} }
function buildCutTask (task: VideoEditorTaskCut) { function buildCutTask (task: VideoStudioTaskCut) {
return { return {
name: task.name, name: task.name,
options: { options: {
@ -108,7 +108,7 @@ function buildCutTask (task: VideoEditorTaskCut) {
} }
} }
function buildWatermarkTask (task: VideoEditorTaskWatermark, indice: number, files: Express.Multer.File[]) { function buildWatermarkTask (task: VideoStudioTaskWatermark, indice: number, files: Express.Multer.File[]) {
return { return {
name: task.name, name: task.name,
options: { options: {

View file

@ -1,40 +1,40 @@
import validator from 'validator' import validator from 'validator'
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants' import { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
import { buildTaskFileFieldname } from '@server/lib/video-editor' import { buildTaskFileFieldname } from '@server/lib/video-studio'
import { VideoEditorTask } from '@shared/models' import { VideoStudioTask } from '@shared/models'
import { isArray } from './misc' import { isArray } from './misc'
import { isVideoFileMimeTypeValid, isVideoImageValid } from './videos' import { isVideoFileMimeTypeValid, isVideoImageValid } from './videos'
function isValidEditorTasksArray (tasks: any) { function isValidStudioTasksArray (tasks: any) {
if (!isArray(tasks)) return false if (!isArray(tasks)) return false
return tasks.length >= CONSTRAINTS_FIELDS.VIDEO_EDITOR.TASKS.min && return tasks.length >= CONSTRAINTS_FIELDS.VIDEO_STUDIO.TASKS.min &&
tasks.length <= CONSTRAINTS_FIELDS.VIDEO_EDITOR.TASKS.max tasks.length <= CONSTRAINTS_FIELDS.VIDEO_STUDIO.TASKS.max
} }
function isEditorCutTaskValid (task: VideoEditorTask) { function isStudioCutTaskValid (task: VideoStudioTask) {
if (task.name !== 'cut') return false if (task.name !== 'cut') return false
if (!task.options) return false if (!task.options) return false
const { start, end } = task.options const { start, end } = task.options
if (!start && !end) return false if (!start && !end) return false
if (start && !validator.isInt(start + '', CONSTRAINTS_FIELDS.VIDEO_EDITOR.CUT_TIME)) return false if (start && !validator.isInt(start + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME)) return false
if (end && !validator.isInt(end + '', CONSTRAINTS_FIELDS.VIDEO_EDITOR.CUT_TIME)) return false if (end && !validator.isInt(end + '', CONSTRAINTS_FIELDS.VIDEO_STUDIO.CUT_TIME)) return false
if (!start || !end) return true if (!start || !end) return true
return parseInt(start + '') < parseInt(end + '') return parseInt(start + '') < parseInt(end + '')
} }
function isEditorTaskAddIntroOutroValid (task: VideoEditorTask, indice: number, files: Express.Multer.File[]) { function isStudioTaskAddIntroOutroValid (task: VideoStudioTask, indice: number, files: Express.Multer.File[]) {
const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file')) const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file'))
return (task.name === 'add-intro' || task.name === 'add-outro') && return (task.name === 'add-intro' || task.name === 'add-outro') &&
file && isVideoFileMimeTypeValid([ file ], null) file && isVideoFileMimeTypeValid([ file ], null)
} }
function isEditorTaskAddWatermarkValid (task: VideoEditorTask, indice: number, files: Express.Multer.File[]) { function isStudioTaskAddWatermarkValid (task: VideoStudioTask, indice: number, files: Express.Multer.File[]) {
const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file')) const file = files.find(f => f.fieldname === buildTaskFileFieldname(indice, 'file'))
return task.name === 'add-watermark' && return task.name === 'add-watermark' &&
@ -44,9 +44,9 @@ function isEditorTaskAddWatermarkValid (task: VideoEditorTask, indice: number, f
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
isValidEditorTasksArray, isValidStudioTasksArray,
isEditorCutTaskValid, isStudioCutTaskValid,
isEditorTaskAddIntroOutroValid, isStudioTaskAddIntroOutroValid,
isEditorTaskAddWatermarkValid isStudioTaskAddWatermarkValid
} }

View file

@ -49,7 +49,7 @@ function checkConfig () {
checkSearchConfig() checkSearchConfig()
checkLiveConfig() checkLiveConfig()
checkObjectStorageConfig() checkObjectStorageConfig()
checkVideoEditorConfig() checkVideoStudioConfig()
} }
// We get db by param to not import it in this file (import orders) // We get db by param to not import it in this file (import orders)
@ -260,8 +260,8 @@ function checkObjectStorageConfig () {
} }
} }
function checkVideoEditorConfig () { function checkVideoStudioConfig () {
if (CONFIG.VIDEO_EDITOR.ENABLED === true && CONFIG.TRANSCODING.ENABLED === false) { if (CONFIG.VIDEO_STUDIO.ENABLED === true && CONFIG.TRANSCODING.ENABLED === false) {
throw new Error('Video editor cannot be enabled if transcoding is disabled') throw new Error('Video studio cannot be enabled if transcoding is disabled')
} }
} }

View file

@ -30,7 +30,7 @@ function checkMissedConfig () {
'transcoding.profile', 'transcoding.concurrency', 'transcoding.profile', 'transcoding.concurrency',
'transcoding.resolutions.0p', 'transcoding.resolutions.144p', 'transcoding.resolutions.240p', 'transcoding.resolutions.360p', 'transcoding.resolutions.0p', 'transcoding.resolutions.144p', 'transcoding.resolutions.240p', 'transcoding.resolutions.360p',
'transcoding.resolutions.480p', 'transcoding.resolutions.720p', 'transcoding.resolutions.1080p', 'transcoding.resolutions.1440p', 'transcoding.resolutions.480p', 'transcoding.resolutions.720p', 'transcoding.resolutions.1080p', 'transcoding.resolutions.1440p',
'transcoding.resolutions.2160p', 'video_editor.enabled', 'transcoding.resolutions.2160p', 'video_studio.enabled',
'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled', 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled',
'trending.videos.interval_days', 'trending.videos.interval_days',
'client.videos.miniature.display_author_avatar', 'client.videos.miniature.display_author_avatar',

View file

@ -335,8 +335,8 @@ const CONFIG = {
} }
} }
}, },
VIDEO_EDITOR: { VIDEO_STUDIO: {
get ENABLED () { return config.get<boolean>('video_editor.enabled') } get ENABLED () { return config.get<boolean>('video_studio.enabled') }
}, },
IMPORT: { IMPORT: {
VIDEOS: { VIDEOS: {

View file

@ -152,7 +152,7 @@ const JOB_ATTEMPTS: { [id in JobType]: number } = {
'activitypub-refresher': 1, 'activitypub-refresher': 1,
'video-redundancy': 1, 'video-redundancy': 1,
'video-live-ending': 1, 'video-live-ending': 1,
'video-edition': 1, 'video-studio-edition': 1,
'manage-video-torrent': 1, 'manage-video-torrent': 1,
'move-to-object-storage': 3 'move-to-object-storage': 3
} }
@ -170,7 +170,7 @@ const JOB_CONCURRENCY: { [id in Exclude<JobType, 'video-transcoding' | 'video-im
'activitypub-refresher': 1, 'activitypub-refresher': 1,
'video-redundancy': 1, 'video-redundancy': 1,
'video-live-ending': 10, 'video-live-ending': 10,
'video-edition': 1, 'video-studio-edition': 1,
'manage-video-torrent': 1, 'manage-video-torrent': 1,
'move-to-object-storage': 1 'move-to-object-storage': 1
} }
@ -182,7 +182,7 @@ const JOB_TTL: { [id in JobType]: number } = {
'activitypub-cleaner': 1000 * 3600, // 1 hour 'activitypub-cleaner': 1000 * 3600, // 1 hour
'video-file-import': 1000 * 3600, // 1 hour 'video-file-import': 1000 * 3600, // 1 hour
'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long 'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long
'video-edition': 1000 * 3600 * 10, // 10 hours 'video-studio-edition': 1000 * 3600 * 10, // 10 hours
'video-import': 1000 * 3600 * 2, // 2 hours 'video-import': 1000 * 3600 * 2, // 2 hours
'email': 60000 * 10, // 10 minutes 'email': 60000 * 10, // 10 minutes
'actor-keys': 60000 * 20, // 20 minutes 'actor-keys': 60000 * 20, // 20 minutes
@ -358,7 +358,7 @@ const CONSTRAINTS_FIELDS = {
COMMONS: { COMMONS: {
URL: { min: 5, max: 2000 } // Length URL: { min: 5, max: 2000 } // Length
}, },
VIDEO_EDITOR: { VIDEO_STUDIO: {
TASKS: { min: 1, max: 10 }, // Number of tasks TASKS: { min: 1, max: 10 }, // Number of tasks
CUT_TIME: { min: 0 } // Value CUT_TIME: { min: 0 } // Value
} }

View file

@ -14,11 +14,11 @@ async function up (utils: {
defaultValue: null, defaultValue: null,
allowNull: true allowNull: true
} }
await utils.queryInterface.addColumn('userNotificationSetting', 'myVideoEditionFinished', data, { transaction }) await utils.queryInterface.addColumn('userNotificationSetting', 'myVideoStudioEditionFinished', data, { transaction })
} }
{ {
const query = 'UPDATE "userNotificationSetting" SET "myVideoEditionFinished" = 1' const query = 'UPDATE "userNotificationSetting" SET "myVideoStudioEditionFinished" = 1'
await utils.sequelize.query(query, { transaction }) await utils.sequelize.query(query, { transaction })
} }
@ -28,7 +28,7 @@ async function up (utils: {
defaultValue: null, defaultValue: null,
allowNull: false allowNull: false
} }
await utils.queryInterface.changeColumn('userNotificationSetting', 'myVideoEditionFinished', data, { transaction }) await utils.queryInterface.changeColumn('userNotificationSetting', 'myVideoStudioEditionFinished', data, { transaction })
} }
} }

View file

@ -9,8 +9,8 @@ import { generateWebTorrentVideoFilename } from '@server/lib/paths'
import { VideoTranscodingProfilesManager } from '@server/lib/transcoding/default-transcoding-profiles' import { VideoTranscodingProfilesManager } from '@server/lib/transcoding/default-transcoding-profiles'
import { isAbleToUploadVideo } from '@server/lib/user' import { isAbleToUploadVideo } from '@server/lib/user'
import { addOptimizeOrMergeAudioJob } from '@server/lib/video' import { addOptimizeOrMergeAudioJob } from '@server/lib/video'
import { approximateIntroOutroAdditionalSize } from '@server/lib/video-editor'
import { VideoPathManager } from '@server/lib/video-path-manager' import { VideoPathManager } from '@server/lib/video-path-manager'
import { approximateIntroOutroAdditionalSize } from '@server/lib/video-studio'
import { UserModel } from '@server/models/user/user' import { UserModel } from '@server/models/user/user'
import { VideoModel } from '@server/models/video/video' import { VideoModel } from '@server/models/video/video'
import { VideoFileModel } from '@server/models/video/video-file' import { VideoFileModel } from '@server/models/video/video-file'
@ -26,23 +26,23 @@ import {
getVideoStreamFPS getVideoStreamFPS
} from '@shared/extra-utils' } from '@shared/extra-utils'
import { import {
VideoEditionPayload, VideoStudioEditionPayload,
VideoEditionTaskPayload, VideoStudioTaskPayload,
VideoEditorTask, VideoStudioTaskCutPayload,
VideoEditorTaskCutPayload, VideoStudioTaskIntroPayload,
VideoEditorTaskIntroPayload, VideoStudioTaskOutroPayload,
VideoEditorTaskOutroPayload, VideoStudioTaskWatermarkPayload,
VideoEditorTaskWatermarkPayload VideoStudioTask
} from '@shared/models' } from '@shared/models'
import { logger, loggerTagsFactory } from '../../../helpers/logger' import { logger, loggerTagsFactory } from '../../../helpers/logger'
const lTagsBase = loggerTagsFactory('video-edition') const lTagsBase = loggerTagsFactory('video-edition')
async function processVideoEdition (job: Job) { async function processVideoStudioEdition (job: Job) {
const payload = job.data as VideoEditionPayload const payload = job.data as VideoStudioEditionPayload
const lTags = lTagsBase(payload.videoUUID) const lTags = lTagsBase(payload.videoUUID)
logger.info('Process video edition of %s in job %d.', payload.videoUUID, job.id, lTags) logger.info('Process video studio edition of %s in job %d.', payload.videoUUID, job.id, lTags)
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoUUID) const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoUUID)
@ -106,12 +106,12 @@ async function processVideoEdition (job: Job) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
processVideoEdition processVideoStudioEdition
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
type TaskProcessorOptions <T extends VideoEditionTaskPayload = VideoEditionTaskPayload> = { type TaskProcessorOptions <T extends VideoStudioTaskPayload = VideoStudioTaskPayload> = {
inputPath: string inputPath: string
outputPath: string outputPath: string
video: MVideo video: MVideo
@ -119,7 +119,7 @@ type TaskProcessorOptions <T extends VideoEditionTaskPayload = VideoEditionTaskP
lTags: { tags: string[] } lTags: { tags: string[] }
} }
const taskProcessors: { [id in VideoEditorTask['name']]: (options: TaskProcessorOptions) => Promise<any> } = { const taskProcessors: { [id in VideoStudioTask['name']]: (options: TaskProcessorOptions) => Promise<any> } = {
'add-intro': processAddIntroOutro, 'add-intro': processAddIntroOutro,
'add-outro': processAddIntroOutro, 'add-outro': processAddIntroOutro,
'cut': processCut, 'cut': processCut,
@ -137,7 +137,7 @@ async function processTask (options: TaskProcessorOptions) {
return processor(options) return processor(options)
} }
function processAddIntroOutro (options: TaskProcessorOptions<VideoEditorTaskIntroPayload | VideoEditorTaskOutroPayload>) { function processAddIntroOutro (options: TaskProcessorOptions<VideoStudioTaskIntroPayload | VideoStudioTaskOutroPayload>) {
const { task } = options const { task } = options
return addIntroOutro({ return addIntroOutro({
@ -153,7 +153,7 @@ function processAddIntroOutro (options: TaskProcessorOptions<VideoEditorTaskIntr
}) })
} }
function processCut (options: TaskProcessorOptions<VideoEditorTaskCutPayload>) { function processCut (options: TaskProcessorOptions<VideoStudioTaskCutPayload>) {
const { task } = options const { task } = options
return cutVideo({ return cutVideo({
@ -164,7 +164,7 @@ function processCut (options: TaskProcessorOptions<VideoEditorTaskCutPayload>) {
}) })
} }
function processAddWatermark (options: TaskProcessorOptions<VideoEditorTaskWatermarkPayload>) { function processAddWatermark (options: TaskProcessorOptions<VideoStudioTaskWatermarkPayload>) {
const { task } = options const { task } = options
return addWatermark({ return addWatermark({
@ -212,10 +212,10 @@ async function removeAllFiles (video: MVideoWithAllFiles, webTorrentFileExceptio
} }
} }
async function checkUserQuotaOrThrow (video: MVideoFullLight, payload: VideoEditionPayload) { async function checkUserQuotaOrThrow (video: MVideoFullLight, payload: VideoStudioEditionPayload) {
const user = await UserModel.loadByVideoId(video.id) const user = await UserModel.loadByVideoId(video.id)
const filePathFinder = (i: number) => (payload.tasks[i] as VideoEditorTaskIntroPayload | VideoEditorTaskOutroPayload).options.file const filePathFinder = (i: number) => (payload.tasks[i] as VideoStudioTaskIntroPayload | VideoStudioTaskOutroPayload).options.file
const additionalBytes = await approximateIntroOutroAdditionalSize(video, payload.tasks, filePathFinder) const additionalBytes = await approximateIntroOutroAdditionalSize(video, payload.tasks, filePathFinder)
if (await isAbleToUploadVideo(user.id, additionalBytes) === false) { if (await isAbleToUploadVideo(user.id, additionalBytes) === false) {

View file

@ -15,11 +15,11 @@ import {
ManageVideoTorrentPayload, ManageVideoTorrentPayload,
MoveObjectStoragePayload, MoveObjectStoragePayload,
RefreshPayload, RefreshPayload,
VideoEditionPayload,
VideoFileImportPayload, VideoFileImportPayload,
VideoImportPayload, VideoImportPayload,
VideoLiveEndingPayload, VideoLiveEndingPayload,
VideoRedundancyPayload, VideoRedundancyPayload,
VideoStudioEditionPayload,
VideoTranscodingPayload VideoTranscodingPayload
} from '../../../shared/models' } from '../../../shared/models'
import { logger } from '../../helpers/logger' import { logger } from '../../helpers/logger'
@ -34,10 +34,10 @@ import { processActorKeys } from './handlers/actor-keys'
import { processEmail } from './handlers/email' import { processEmail } from './handlers/email'
import { processManageVideoTorrent } from './handlers/manage-video-torrent' import { processManageVideoTorrent } from './handlers/manage-video-torrent'
import { processMoveToObjectStorage } from './handlers/move-to-object-storage' import { processMoveToObjectStorage } from './handlers/move-to-object-storage'
import { processVideoEdition } from './handlers/video-edition'
import { processVideoFileImport } from './handlers/video-file-import' import { processVideoFileImport } from './handlers/video-file-import'
import { processVideoImport } from './handlers/video-import' import { processVideoImport } from './handlers/video-import'
import { processVideoLiveEnding } from './handlers/video-live-ending' import { processVideoLiveEnding } from './handlers/video-live-ending'
import { processVideoStudioEdition } from './handlers/video-studio-edition'
import { processVideoTranscoding } from './handlers/video-transcoding' import { processVideoTranscoding } from './handlers/video-transcoding'
import { processVideosViewsStats } from './handlers/video-views-stats' import { processVideosViewsStats } from './handlers/video-views-stats'
@ -57,7 +57,7 @@ type CreateJobArgument =
{ type: 'actor-keys', payload: ActorKeysPayload } | { type: 'actor-keys', payload: ActorKeysPayload } |
{ type: 'video-redundancy', payload: VideoRedundancyPayload } | { type: 'video-redundancy', payload: VideoRedundancyPayload } |
{ type: 'delete-resumable-upload-meta-file', payload: DeleteResumableUploadMetaFilePayload } | { type: 'delete-resumable-upload-meta-file', payload: DeleteResumableUploadMetaFilePayload } |
{ type: 'video-edition', payload: VideoEditionPayload } | { type: 'video-studio-edition', payload: VideoStudioEditionPayload } |
{ type: 'manage-video-torrent', payload: ManageVideoTorrentPayload } | { type: 'manage-video-torrent', payload: ManageVideoTorrentPayload } |
{ type: 'move-to-object-storage', payload: MoveObjectStoragePayload } { type: 'move-to-object-storage', payload: MoveObjectStoragePayload }
@ -83,7 +83,7 @@ const handlers: { [id in JobType]: (job: Job) => Promise<any> } = {
'video-redundancy': processVideoRedundancy, 'video-redundancy': processVideoRedundancy,
'move-to-object-storage': processMoveToObjectStorage, 'move-to-object-storage': processMoveToObjectStorage,
'manage-video-torrent': processManageVideoTorrent, 'manage-video-torrent': processManageVideoTorrent,
'video-edition': processVideoEdition 'video-studio-edition': processVideoStudioEdition
} }
const jobTypes: JobType[] = [ const jobTypes: JobType[] = [
@ -103,7 +103,7 @@ const jobTypes: JobType[] = [
'video-live-ending', 'video-live-ending',
'move-to-object-storage', 'move-to-object-storage',
'manage-video-torrent', 'manage-video-torrent',
'video-edition' 'video-studio-edition'
] ]
class JobQueue { class JobQueue {

View file

@ -12,7 +12,7 @@ import {
AbuseStateChangeForReporter, AbuseStateChangeForReporter,
AutoFollowForInstance, AutoFollowForInstance,
CommentMention, CommentMention,
EditionFinishedForOwner, StudioEditionFinishedForOwner,
FollowForInstance, FollowForInstance,
FollowForUser, FollowForUser,
ImportFinishedForOwner, ImportFinishedForOwner,
@ -55,7 +55,7 @@ class Notifier {
newAbuseMessage: [ NewAbuseMessageForReporter, NewAbuseMessageForModerators ], newAbuseMessage: [ NewAbuseMessageForReporter, NewAbuseMessageForModerators ],
newPeertubeVersion: [ NewPeerTubeVersionForAdmins ], newPeertubeVersion: [ NewPeerTubeVersionForAdmins ],
newPluginVersion: [ NewPluginVersionForAdmins ], newPluginVersion: [ NewPluginVersionForAdmins ],
videoEditionFinished: [ EditionFinishedForOwner ] videoStudioEditionFinished: [ StudioEditionFinishedForOwner ]
} }
private static instance: Notifier private static instance: Notifier
@ -200,11 +200,11 @@ class Notifier {
.catch(err => logger.error('Cannot notify on new plugin version %s.', plugin.name, { err })) .catch(err => logger.error('Cannot notify on new plugin version %s.', plugin.name, { err }))
} }
notifyOfFinishedVideoEdition (video: MVideoFullLight) { notifyOfFinishedVideoStudioEdition (video: MVideoFullLight) {
const models = this.notificationModels.videoEditionFinished const models = this.notificationModels.videoStudioEditionFinished
this.sendNotifications(models, video) this.sendNotifications(models, video)
.catch(err => logger.error('Cannot notify on finished edition %s.', video.url, { err })) .catch(err => logger.error('Cannot notify on finished studio edition %s.', video.url, { err }))
} }
private async notify <T> (object: AbstractNotification<T>) { private async notify <T> (object: AbstractNotification<T>) {

View file

@ -1,6 +1,6 @@
export * from './new-video-for-subscribers' export * from './new-video-for-subscribers'
export * from './edition-finished-for-owner'
export * from './import-finished-for-owner' export * from './import-finished-for-owner'
export * from './owned-publication-after-auto-unblacklist' export * from './owned-publication-after-auto-unblacklist'
export * from './owned-publication-after-schedule-update' export * from './owned-publication-after-schedule-update'
export * from './owned-publication-after-transcoding' export * from './owned-publication-after-transcoding'
export * from './studio-edition-finished-for-owner'

View file

@ -6,7 +6,7 @@ import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotifi
import { UserNotificationType } from '@shared/models' import { UserNotificationType } from '@shared/models'
import { AbstractNotification } from '../common/abstract-notification' import { AbstractNotification } from '../common/abstract-notification'
export class EditionFinishedForOwner extends AbstractNotification <MVideoFullLight> { export class StudioEditionFinishedForOwner extends AbstractNotification <MVideoFullLight> {
private user: MUserDefault private user: MUserDefault
async prepare () { async prepare () {
@ -14,11 +14,11 @@ export class EditionFinishedForOwner extends AbstractNotification <MVideoFullLig
} }
log () { log () {
logger.info('Notifying user %s its video edition %s is finished.', this.user.username, this.payload.url) logger.info('Notifying user %s its video studio edition %s is finished.', this.user.username, this.payload.url)
} }
getSetting (user: MUserWithNotificationSetting) { getSetting (user: MUserWithNotificationSetting) {
return user.NotificationSetting.myVideoEditionFinished return user.NotificationSetting.myVideoStudioEditionFinished
} }
getTargetUsers () { getTargetUsers () {
@ -29,7 +29,7 @@ export class EditionFinishedForOwner extends AbstractNotification <MVideoFullLig
async createNotification (user: MUserWithNotificationSetting) { async createNotification (user: MUserWithNotificationSetting) {
const notification = await UserNotificationModel.create<UserNotificationModelForApi>({ const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
type: UserNotificationType.MY_VIDEO_EDITION_FINISHED, type: UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED,
userId: user.id, userId: user.id,
videoId: this.payload.id videoId: this.payload.id
}) })

View file

@ -159,8 +159,8 @@ class ServerConfigManager {
port: CONFIG.LIVE.RTMP.PORT port: CONFIG.LIVE.RTMP.PORT
} }
}, },
videoEditor: { videoStudio: {
enabled: CONFIG.VIDEO_EDITOR.ENABLED enabled: CONFIG.VIDEO_STUDIO.ENABLED
}, },
import: { import: {
videos: { videos: {

View file

@ -253,7 +253,7 @@ function createDefaultUserNotificationSettings (user: MUserId, t: Transaction |
autoInstanceFollowing: UserNotificationSettingValue.WEB, autoInstanceFollowing: UserNotificationSettingValue.WEB,
newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
newPluginVersion: UserNotificationSettingValue.WEB, newPluginVersion: UserNotificationSettingValue.WEB,
myVideoEditionFinished: UserNotificationSettingValue.WEB myVideoStudioEditionFinished: UserNotificationSettingValue.WEB
} }
return UserNotificationSettingModel.create(values, { transaction: t }) return UserNotificationSettingModel.create(values, { transaction: t })

View file

@ -135,7 +135,7 @@ async function moveToPublishedState (options: {
await federateVideoIfNeeded(video, isNewVideo, transaction) await federateVideoIfNeeded(video, isNewVideo, transaction)
if (previousState === VideoState.TO_EDIT) { if (previousState === VideoState.TO_EDIT) {
Notifier.Instance.notifyOfFinishedVideoEdition(video) Notifier.Instance.notifyOfFinishedVideoStudioEdition(video)
return return
} }

View file

@ -1,6 +1,6 @@
import { MVideoFullLight } from "@server/types/models" import { MVideoFullLight } from '@server/types/models'
import { getVideoStreamDuration } from "@shared/extra-utils" import { getVideoStreamDuration } from '@shared/extra-utils'
import { VideoEditorTask } from "@shared/models" import { VideoStudioTask } from '@shared/models'
function buildTaskFileFieldname (indice: number, fieldName = 'file') { function buildTaskFileFieldname (indice: number, fieldName = 'file') {
return `tasks[${indice}][options][${fieldName}]` return `tasks[${indice}][options][${fieldName}]`
@ -10,7 +10,7 @@ function getTaskFile (files: Express.Multer.File[], indice: number, fieldName =
return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName)) return files.find(f => f.fieldname === buildTaskFileFieldname(indice, fieldName))
} }
async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, tasks: VideoEditorTask[], fileFinder: (i: number) => string) { async function approximateIntroOutroAdditionalSize (video: MVideoFullLight, tasks: VideoStudioTask[], fileFinder: (i: number) => string) {
let additionalDuration = 0 let additionalDuration = 0
for (let i = 0; i < tasks.length; i++) { for (let i = 0; i < tasks.length; i++) {

View file

@ -57,7 +57,7 @@ const customConfigUpdateValidator = [
body('transcoding.webtorrent.enabled').isBoolean().withMessage('Should have a valid webtorrent transcoding enabled boolean'), body('transcoding.webtorrent.enabled').isBoolean().withMessage('Should have a valid webtorrent transcoding enabled boolean'),
body('transcoding.hls.enabled').isBoolean().withMessage('Should have a valid hls transcoding enabled boolean'), body('transcoding.hls.enabled').isBoolean().withMessage('Should have a valid hls transcoding enabled boolean'),
body('videoEditor.enabled').isBoolean().withMessage('Should have a valid video editor enabled boolean'), body('videoStudio.enabled').isBoolean().withMessage('Should have a valid video studio enabled boolean'),
body('import.videos.concurrency').isInt({ min: 0 }).withMessage('Should have a valid import concurrency number'), body('import.videos.concurrency').isInt({ min: 0 }).withMessage('Should have a valid import concurrency number'),
body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'),
@ -106,7 +106,7 @@ const customConfigUpdateValidator = [
if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return
if (!checkInvalidTranscodingConfig(req.body, res)) return if (!checkInvalidTranscodingConfig(req.body, res)) return
if (!checkInvalidLiveConfig(req.body, res)) return if (!checkInvalidLiveConfig(req.body, res)) return
if (!checkInvalidVideoEditorConfig(req.body, res)) return if (!checkInvalidVideoStudioConfig(req.body, res)) return
return next() return next()
} }
@ -163,11 +163,11 @@ function checkInvalidLiveConfig (customConfig: CustomConfig, res: express.Respon
return true return true
} }
function checkInvalidVideoEditorConfig (customConfig: CustomConfig, res: express.Response) { function checkInvalidVideoStudioConfig (customConfig: CustomConfig, res: express.Response) {
if (customConfig.videoEditor.enabled === false) return true if (customConfig.videoStudio.enabled === false) return true
if (customConfig.videoEditor.enabled === true && customConfig.transcoding.enabled === false) { if (customConfig.videoStudio.enabled === true && customConfig.transcoding.enabled === false) {
res.fail({ message: 'You cannot enable video editor if transcoding is not enabled' }) res.fail({ message: 'You cannot enable video studio if transcoding is not enabled' })
return false return false
} }

View file

@ -2,7 +2,6 @@ export * from './video-blacklist'
export * from './video-captions' export * from './video-captions'
export * from './video-channels' export * from './video-channels'
export * from './video-comments' export * from './video-comments'
export * from './video-editor'
export * from './video-files' export * from './video-files'
export * from './video-imports' export * from './video-imports'
export * from './video-live' export * from './video-live'
@ -10,5 +9,6 @@ export * from './video-ownership-changes'
export * from './video-watch' export * from './video-watch'
export * from './video-rates' export * from './video-rates'
export * from './video-shares' export * from './video-shares'
export * from './video-studio'
export * from './video-transcoding' export * from './video-transcoding'
export * from './videos' export * from './videos'

View file

@ -2,31 +2,31 @@ import express from 'express'
import { body, param } from 'express-validator' import { body, param } from 'express-validator'
import { isIdOrUUIDValid } from '@server/helpers/custom-validators/misc' import { isIdOrUUIDValid } from '@server/helpers/custom-validators/misc'
import { import {
isEditorCutTaskValid, isStudioCutTaskValid,
isEditorTaskAddIntroOutroValid, isStudioTaskAddIntroOutroValid,
isEditorTaskAddWatermarkValid, isStudioTaskAddWatermarkValid,
isValidEditorTasksArray isValidStudioTasksArray
} from '@server/helpers/custom-validators/video-editor' } from '@server/helpers/custom-validators/video-studio'
import { cleanUpReqFiles } from '@server/helpers/express-utils' import { cleanUpReqFiles } from '@server/helpers/express-utils'
import { CONFIG } from '@server/initializers/config' import { CONFIG } from '@server/initializers/config'
import { approximateIntroOutroAdditionalSize, getTaskFile } from '@server/lib/video-editor' import { approximateIntroOutroAdditionalSize, getTaskFile } from '@server/lib/video-studio'
import { isAudioFile } from '@shared/extra-utils' import { isAudioFile } from '@shared/extra-utils'
import { HttpStatusCode, UserRight, VideoEditorCreateEdition, VideoEditorTask, VideoState } from '@shared/models' import { HttpStatusCode, UserRight, VideoState, VideoStudioCreateEdition, VideoStudioTask } from '@shared/models'
import { logger } from '../../../helpers/logger' import { logger } from '../../../helpers/logger'
import { areValidationErrors, checkUserCanManageVideo, checkUserQuota, doesVideoExist } from '../shared' import { areValidationErrors, checkUserCanManageVideo, checkUserQuota, doesVideoExist } from '../shared'
const videosEditorAddEditionValidator = [ const videoStudioAddEditionValidator = [
param('videoId').custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'), param('videoId').custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'),
body('tasks').custom(isValidEditorTasksArray).withMessage('Should have a valid array of tasks'), body('tasks').custom(isValidStudioTasksArray).withMessage('Should have a valid array of tasks'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => { async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videosEditorAddEditionValidator parameters.', { parameters: req.params, body: req.body, files: req.files }) logger.debug('Checking videoStudioAddEditionValidator parameters.', { parameters: req.params, body: req.body, files: req.files })
if (CONFIG.VIDEO_EDITOR.ENABLED !== true) { if (CONFIG.VIDEO_STUDIO.ENABLED !== true) {
res.fail({ res.fail({
status: HttpStatusCode.BAD_REQUEST_400, status: HttpStatusCode.BAD_REQUEST_400,
message: 'Video editor is disabled on this instance' message: 'Video studio is disabled on this instance'
}) })
return cleanUpReqFiles(req) return cleanUpReqFiles(req)
@ -34,7 +34,7 @@ const videosEditorAddEditionValidator = [
if (areValidationErrors(req, res)) return cleanUpReqFiles(req) if (areValidationErrors(req, res)) return cleanUpReqFiles(req)
const body: VideoEditorCreateEdition = req.body const body: VideoStudioCreateEdition = req.body
const files = req.files as Express.Multer.File[] const files = req.files as Express.Multer.File[]
for (let i = 0; i < body.tasks.length; i++) { for (let i = 0; i < body.tasks.length; i++) {
@ -90,21 +90,21 @@ const videosEditorAddEditionValidator = [
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export { export {
videosEditorAddEditionValidator videoStudioAddEditionValidator
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const taskCheckers: { const taskCheckers: {
[id in VideoEditorTask['name']]: (task: VideoEditorTask, indice?: number, files?: Express.Multer.File[]) => boolean [id in VideoStudioTask['name']]: (task: VideoStudioTask, indice?: number, files?: Express.Multer.File[]) => boolean
} = { } = {
'cut': isEditorCutTaskValid, 'cut': isStudioCutTaskValid,
'add-intro': isEditorTaskAddIntroOutroValid, 'add-intro': isStudioTaskAddIntroOutroValid,
'add-outro': isEditorTaskAddIntroOutroValid, 'add-outro': isStudioTaskAddIntroOutroValid,
'add-watermark': isEditorTaskAddWatermarkValid 'add-watermark': isStudioTaskAddWatermarkValid
} }
function checkTask (req: express.Request, task: VideoEditorTask, indice?: number) { function checkTask (req: express.Request, task: VideoStudioTask, indice?: number) {
const checker = taskCheckers[task.name] const checker = taskCheckers[task.name]
if (!checker) return false if (!checker) return false

View file

@ -178,11 +178,11 @@ export class UserNotificationSettingModel extends Model<Partial<AttributesOnly<U
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)
@Is( @Is(
'UserNotificationSettingMyVideoEditionFinished', 'UserNotificationSettingMyVideoStudioEditionFinished',
value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoEditionFinished') value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoStudioEditionFinished')
) )
@Column @Column
myVideoEditionFinished: UserNotificationSettingValue myVideoStudioEditionFinished: UserNotificationSettingValue
@ForeignKey(() => UserModel) @ForeignKey(() => UserModel)
@Column @Column
@ -225,7 +225,7 @@ export class UserNotificationSettingModel extends Model<Partial<AttributesOnly<U
abuseNewMessage: this.abuseNewMessage, abuseNewMessage: this.abuseNewMessage,
abuseStateChange: this.abuseStateChange, abuseStateChange: this.abuseStateChange,
newPeerTubeVersion: this.newPeerTubeVersion, newPeerTubeVersion: this.newPeerTubeVersion,
myVideoEditionFinished: this.myVideoEditionFinished, myVideoStudioEditionFinished: this.myVideoStudioEditionFinished,
newPluginVersion: this.newPluginVersion newPluginVersion: this.newPluginVersion
} }
} }

View file

@ -148,7 +148,7 @@ describe('Test config API validators', function () {
} }
} }
}, },
videoEditor: { videoStudio: {
enabled: true enabled: true
}, },
import: { import: {

View file

@ -25,7 +25,7 @@ import './video-blacklist'
import './video-captions' import './video-captions'
import './video-channels' import './video-channels'
import './video-comments' import './video-comments'
import './video-editor' import './video-studio'
import './video-imports' import './video-imports'
import './video-playlists' import './video-playlists'
import './videos' import './videos'

View file

@ -171,7 +171,7 @@ describe('Test user notifications API validators', function () {
abuseNewMessage: UserNotificationSettingValue.WEB, abuseNewMessage: UserNotificationSettingValue.WEB,
abuseStateChange: UserNotificationSettingValue.WEB, abuseStateChange: UserNotificationSettingValue.WEB,
newPeerTubeVersion: UserNotificationSettingValue.WEB, newPeerTubeVersion: UserNotificationSettingValue.WEB,
myVideoEditionFinished: UserNotificationSettingValue.WEB, myVideoStudioEditionFinished: UserNotificationSettingValue.WEB,
newPluginVersion: UserNotificationSettingValue.WEB newPluginVersion: UserNotificationSettingValue.WEB
} }

View file

@ -1,19 +1,19 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha' import 'mocha'
import { HttpStatusCode, VideoEditorTask } from '@shared/models' import { HttpStatusCode, VideoStudioTask } from '@shared/models'
import { import {
cleanupTests, cleanupTests,
createSingleServer, createSingleServer,
PeerTubeServer, PeerTubeServer,
setAccessTokensToServers, setAccessTokensToServers,
VideoEditorCommand, VideoStudioCommand,
waitJobs waitJobs
} from '@shared/server-commands' } from '@shared/server-commands'
describe('Test video editor API validator', function () { describe('Test video studio API validator', function () {
let server: PeerTubeServer let server: PeerTubeServer
let command: VideoEditorCommand let command: VideoStudioCommand
let userAccessToken: string let userAccessToken: string
let videoUUID: string let videoUUID: string
@ -32,7 +32,7 @@ describe('Test video editor API validator', function () {
const { uuid } = await server.videos.quickUpload({ name: 'video' }) const { uuid } = await server.videos.quickUpload({ name: 'video' })
videoUUID = uuid videoUUID = uuid
command = server.videoEditor command = server.videoStudio
await waitJobs([ server ]) await waitJobs([ server ])
}) })
@ -41,10 +41,10 @@ describe('Test video editor API validator', function () {
describe('Config settings', function () { describe('Config settings', function () {
it('Should fail if editor is disabled', async function () { it('Should fail if studio is disabled', async function () {
await server.config.updateExistingSubConfig({ await server.config.updateExistingSubConfig({
newConfig: { newConfig: {
videoEditor: { videoStudio: {
enabled: false enabled: false
} }
} }
@ -52,15 +52,15 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: videoUUID, videoId: videoUUID,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.BAD_REQUEST_400 expectedStatus: HttpStatusCode.BAD_REQUEST_400
}) })
}) })
it('Should fail to enable editor if transcoding is disabled', async function () { it('Should fail to enable studio if transcoding is disabled', async function () {
await server.config.updateExistingSubConfig({ await server.config.updateExistingSubConfig({
newConfig: { newConfig: {
videoEditor: { videoStudio: {
enabled: true enabled: true
}, },
transcoding: { transcoding: {
@ -71,10 +71,10 @@ describe('Test video editor API validator', function () {
}) })
}) })
it('Should succeed to enable video editor', async function () { it('Should succeed to enable video studio', async function () {
await server.config.updateExistingSubConfig({ await server.config.updateExistingSubConfig({
newConfig: { newConfig: {
videoEditor: { videoStudio: {
enabled: true enabled: true
}, },
transcoding: { transcoding: {
@ -91,7 +91,7 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
token: null, token: null,
videoId: videoUUID, videoId: videoUUID,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })
}) })
@ -100,7 +100,7 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
token: userAccessToken, token: userAccessToken,
videoId: videoUUID, videoId: videoUUID,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.FORBIDDEN_403 expectedStatus: HttpStatusCode.FORBIDDEN_403
}) })
}) })
@ -108,7 +108,7 @@ describe('Test video editor API validator', function () {
it('Should fail with an invalid video', async function () { it('Should fail with an invalid video', async function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: 'tintin', videoId: 'tintin',
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.BAD_REQUEST_400 expectedStatus: HttpStatusCode.BAD_REQUEST_400
}) })
}) })
@ -116,7 +116,7 @@ describe('Test video editor API validator', function () {
it('Should fail with an unknown video', async function () { it('Should fail with an unknown video', async function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: 42, videoId: 42,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.NOT_FOUND_404 expectedStatus: HttpStatusCode.NOT_FOUND_404
}) })
}) })
@ -132,7 +132,7 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: uuid, videoId: uuid,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.CONFLICT_409 expectedStatus: HttpStatusCode.CONFLICT_409
}) })
@ -171,7 +171,7 @@ describe('Test video editor API validator', function () {
}) })
it('Should fail with too many tasks', async function () { it('Should fail with too many tasks', async function () {
const tasks: VideoEditorTask[] = [] const tasks: VideoStudioTask[] = []
for (let i = 0; i < 110; i++) { for (let i = 0; i < 110; i++) {
tasks.push({ tasks.push({
@ -194,7 +194,7 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: videoUUID, videoId: videoUUID,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.NO_CONTENT_204 expectedStatus: HttpStatusCode.NO_CONTENT_204
}) })
}) })
@ -204,7 +204,7 @@ describe('Test video editor API validator', function () {
await command.createEditionTasks({ await command.createEditionTasks({
videoId: videoUUID, videoId: videoUUID,
tasks: VideoEditorCommand.getComplexTask(), tasks: VideoStudioCommand.getComplexTask(),
expectedStatus: HttpStatusCode.CONFLICT_409 expectedStatus: HttpStatusCode.CONFLICT_409
}) })

View file

@ -7,7 +7,7 @@ import {
checkMyVideoImportIsFinished, checkMyVideoImportIsFinished,
checkNewActorFollow, checkNewActorFollow,
checkNewVideoFromSubscription, checkNewVideoFromSubscription,
checkVideoEditionIsFinished, checkVideoStudioEditionIsFinished,
checkVideoIsPublished, checkVideoIsPublished,
FIXTURE_URLS, FIXTURE_URLS,
MockSmtpServer, MockSmtpServer,
@ -16,7 +16,7 @@ import {
} from '@server/tests/shared' } from '@server/tests/shared'
import { wait } from '@shared/core-utils' import { wait } from '@shared/core-utils'
import { buildUUID } from '@shared/extra-utils' import { buildUUID } from '@shared/extra-utils'
import { UserNotification, UserNotificationType, VideoEditorTask, VideoPrivacy } from '@shared/models' import { UserNotification, UserNotificationType, VideoStudioTask, VideoPrivacy } from '@shared/models'
import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands'
const expect = chai.expect const expect = chai.expect
@ -323,7 +323,7 @@ describe('Test user notifications', function () {
}) })
}) })
describe('Video editor', function () { describe('Video studio', function () {
let baseParams: CheckerBaseParams let baseParams: CheckerBaseParams
before(() => { before(() => {
@ -335,7 +335,7 @@ describe('Test user notifications', function () {
} }
}) })
it('Should send a notification after editor edition', async function () { it('Should send a notification after studio edition', async function () {
this.timeout(240000) this.timeout(240000)
const { name, shortUUID, id } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true }) const { name, shortUUID, id } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true })
@ -343,7 +343,7 @@ describe('Test user notifications', function () {
await waitJobs(servers) await waitJobs(servers)
await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) await checkVideoIsPublished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' })
const tasks: VideoEditorTask[] = [ const tasks: VideoStudioTask[] = [
{ {
name: 'cut', name: 'cut',
options: { options: {
@ -352,10 +352,10 @@ describe('Test user notifications', function () {
} }
} }
] ]
await servers[1].videoEditor.createEditionTasks({ videoId: id, tasks }) await servers[1].videoStudio.createEditionTasks({ videoId: id, tasks })
await waitJobs(servers) await waitJobs(servers)
await checkVideoEditionIsFinished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' }) await checkVideoStudioEditionIsFinished({ ...baseParams, videoName: name, shortUUID, checkType: 'presence' })
}) })
}) })

View file

@ -98,7 +98,7 @@ function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) {
expect(data.live.transcoding.resolutions['1440p']).to.be.false expect(data.live.transcoding.resolutions['1440p']).to.be.false
expect(data.live.transcoding.resolutions['2160p']).to.be.false expect(data.live.transcoding.resolutions['2160p']).to.be.false
expect(data.videoEditor.enabled).to.be.false expect(data.videoStudio.enabled).to.be.false
expect(data.import.videos.concurrency).to.equal(2) expect(data.import.videos.concurrency).to.equal(2)
expect(data.import.videos.http.enabled).to.be.true expect(data.import.videos.http.enabled).to.be.true
@ -201,7 +201,7 @@ function checkUpdatedConfig (data: CustomConfig) {
expect(data.live.transcoding.resolutions['1080p']).to.be.true expect(data.live.transcoding.resolutions['1080p']).to.be.true
expect(data.live.transcoding.resolutions['2160p']).to.be.true expect(data.live.transcoding.resolutions['2160p']).to.be.true
expect(data.videoEditor.enabled).to.be.true expect(data.videoStudio.enabled).to.be.true
expect(data.import.videos.concurrency).to.equal(4) expect(data.import.videos.concurrency).to.equal(4)
expect(data.import.videos.http.enabled).to.be.false expect(data.import.videos.http.enabled).to.be.false
@ -350,7 +350,7 @@ const newCustomConfig: CustomConfig = {
} }
} }
}, },
videoEditor: { videoStudio: {
enabled: true enabled: true
}, },
import: { import: {

View file

@ -2,4 +2,4 @@ export * from './audio-only'
export * from './create-transcoding' export * from './create-transcoding'
export * from './hls' export * from './hls'
export * from './transcoder' export * from './transcoder'
export * from './video-editor' export * from './video-studio'

View file

@ -1,7 +1,7 @@
import { expect } from 'chai' import { expect } from 'chai'
import { expectStartWith, getAllFiles } from '@server/tests/shared' import { expectStartWith, getAllFiles } from '@server/tests/shared'
import { areObjectStorageTestsDisabled } from '@shared/core-utils' import { areObjectStorageTestsDisabled } from '@shared/core-utils'
import { VideoEditorTask } from '@shared/models' import { VideoStudioTask } from '@shared/models'
import { import {
cleanupTests, cleanupTests,
createMultipleServers, createMultipleServers,
@ -10,11 +10,11 @@ import {
PeerTubeServer, PeerTubeServer,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
VideoEditorCommand, VideoStudioCommand,
waitJobs waitJobs
} from '@shared/server-commands' } from '@shared/server-commands'
describe('Test video editor', function () { describe('Test video studio', function () {
let servers: PeerTubeServer[] = [] let servers: PeerTubeServer[] = []
let videoUUID: string let videoUUID: string
@ -39,8 +39,8 @@ describe('Test video editor', function () {
await waitJobs(servers) await waitJobs(servers)
} }
async function createTasks (tasks: VideoEditorTask[]) { async function createTasks (tasks: VideoStudioTask[]) {
await servers[0].videoEditor.createEditionTasks({ videoId: videoUUID, tasks }) await servers[0].videoStudio.createEditionTasks({ videoId: videoUUID, tasks })
await waitJobs(servers) await waitJobs(servers)
} }
@ -56,7 +56,7 @@ describe('Test video editor', function () {
await servers[0].config.enableMinimumTranscoding() await servers[0].config.enableMinimumTranscoding()
await servers[0].config.enableEditor() await servers[0].config.enableStudio()
}) })
describe('Cutting', function () { describe('Cutting', function () {
@ -276,7 +276,7 @@ describe('Test video editor', function () {
this.timeout(240_000) this.timeout(240_000)
await renewVideo() await renewVideo()
await createTasks(VideoEditorCommand.getComplexTask()) await createTasks(VideoStudioCommand.getComplexTask())
for (const server of servers) { for (const server of servers) {
await checkDuration(server, 9) await checkDuration(server, 9)
@ -303,7 +303,7 @@ describe('Test video editor', function () {
this.timeout(240_000) this.timeout(240_000)
await renewVideo() await renewVideo()
await createTasks(VideoEditorCommand.getComplexTask()) await createTasks(VideoStudioCommand.getComplexTask())
for (const server of servers) { for (const server of servers) {
const video = await server.videos.get({ id: videoUUID }) const video = await server.videos.get({ id: videoUUID })
@ -333,7 +333,7 @@ describe('Test video editor', function () {
const video = await servers[0].videos.get({ id: videoUUID }) const video = await servers[0].videos.get({ id: videoUUID })
const oldFileUrls = getAllFiles(video).map(f => f.fileUrl) const oldFileUrls = getAllFiles(video).map(f => f.fileUrl)
await createTasks(VideoEditorCommand.getComplexTask()) await createTasks(VideoStudioCommand.getComplexTask())
for (const server of servers) { for (const server of servers) {
const video = await server.videos.get({ id: videoUUID }) const video = await server.videos.get({ id: videoUUID })

View file

@ -47,7 +47,7 @@ function getAllNotificationsSettings (): UserNotificationSetting {
abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
myVideoEditionFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, myVideoStudioEditionFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL
} }
} }
@ -110,13 +110,13 @@ async function checkVideoIsPublished (options: CheckerBaseParams & {
await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
} }
async function checkVideoEditionIsFinished (options: CheckerBaseParams & { async function checkVideoStudioEditionIsFinished (options: CheckerBaseParams & {
videoName: string videoName: string
shortUUID: string shortUUID: string
checkType: CheckerType checkType: CheckerType
}) { }) {
const { videoName, shortUUID } = options const { videoName, shortUUID } = options
const notificationType = UserNotificationType.MY_VIDEO_EDITION_FINISHED const notificationType = UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED
function notificationChecker (notification: UserNotification, checkType: CheckerType) { function notificationChecker (notification: UserNotification, checkType: CheckerType) {
if (checkType === 'presence') { if (checkType === 'presence') {
@ -685,7 +685,7 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an
await setDefaultChannelAvatar(servers) await setDefaultChannelAvatar(servers)
await setDefaultAccountAvatar(servers) await setDefaultAccountAvatar(servers)
await servers[1].config.enableEditor() await servers[1].config.enableStudio()
if (serversCount > 1) { if (serversCount > 1) {
await doubleFollow(servers[0], servers[1]) await doubleFollow(servers[0], servers[1])
@ -756,7 +756,7 @@ export {
checkNewAccountAbuseForModerators, checkNewAccountAbuseForModerators,
checkNewPeerTubeVersion, checkNewPeerTubeVersion,
checkNewPluginVersion, checkNewPluginVersion,
checkVideoEditionIsFinished checkVideoStudioEditionIsFinished
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View file

@ -147,7 +147,7 @@ export interface CustomConfig {
} }
} }
videoEditor: { videoStudio: {
enabled: boolean enabled: boolean
} }

View file

@ -1,6 +1,6 @@
import { ContextType } from '../activitypub/context' import { ContextType } from '../activitypub/context'
import { VideoState } from '../videos' import { VideoState } from '../videos'
import { VideoEditorTaskCut } from '../videos/editor' import { VideoStudioTaskCut } from '../videos/studio'
import { VideoResolution } from '../videos/file/video-resolution.enum' import { VideoResolution } from '../videos/file/video-resolution.enum'
import { SendEmailOptions } from './emailer.model' import { SendEmailOptions } from './emailer.model'
@ -23,7 +23,7 @@ export type JobType =
| 'actor-keys' | 'actor-keys'
| 'manage-video-torrent' | 'manage-video-torrent'
| 'move-to-object-storage' | 'move-to-object-storage'
| 'video-edition' | 'video-studio-edition'
export interface Job { export interface Job {
id: number id: number
@ -117,9 +117,6 @@ export type ManageVideoTorrentPayload =
interface BaseTranscodingPayload { interface BaseTranscodingPayload {
videoUUID: string videoUUID: string
isNewVideo?: boolean isNewVideo?: boolean
// Custom notification when the task is finished
notification?: 'default' | 'video-edition'
} }
export interface HLSTranscodingPayload extends BaseTranscodingPayload { export interface HLSTranscodingPayload extends BaseTranscodingPayload {
@ -178,9 +175,9 @@ export interface MoveObjectStoragePayload {
previousVideoState: VideoState previousVideoState: VideoState
} }
export type VideoEditorTaskCutPayload = VideoEditorTaskCut export type VideoStudioTaskCutPayload = VideoStudioTaskCut
export type VideoEditorTaskIntroPayload = { export type VideoStudioTaskIntroPayload = {
name: 'add-intro' name: 'add-intro'
options: { options: {
@ -188,7 +185,7 @@ export type VideoEditorTaskIntroPayload = {
} }
} }
export type VideoEditorTaskOutroPayload = { export type VideoStudioTaskOutroPayload = {
name: 'add-outro' name: 'add-outro'
options: { options: {
@ -196,7 +193,7 @@ export type VideoEditorTaskOutroPayload = {
} }
} }
export type VideoEditorTaskWatermarkPayload = { export type VideoStudioTaskWatermarkPayload = {
name: 'add-watermark' name: 'add-watermark'
options: { options: {
@ -204,13 +201,13 @@ export type VideoEditorTaskWatermarkPayload = {
} }
} }
export type VideoEditionTaskPayload = export type VideoStudioTaskPayload =
VideoEditorTaskCutPayload | VideoStudioTaskCutPayload |
VideoEditorTaskIntroPayload | VideoStudioTaskIntroPayload |
VideoEditorTaskOutroPayload | VideoStudioTaskOutroPayload |
VideoEditorTaskWatermarkPayload VideoStudioTaskWatermarkPayload
export interface VideoEditionPayload { export interface VideoStudioEditionPayload {
videoUUID: string videoUUID: string
tasks: VideoEditionTaskPayload[] tasks: VideoStudioTaskPayload[]
} }

View file

@ -175,7 +175,7 @@ export interface ServerConfig {
} }
} }
videoEditor: { videoStudio: {
enabled: boolean enabled: boolean
} }

View file

@ -28,5 +28,5 @@ export interface UserNotificationSetting {
newPeerTubeVersion: UserNotificationSettingValue newPeerTubeVersion: UserNotificationSettingValue
newPluginVersion: UserNotificationSettingValue newPluginVersion: UserNotificationSettingValue
myVideoEditionFinished: UserNotificationSettingValue myVideoStudioEditionFinished: UserNotificationSettingValue
} }

View file

@ -32,7 +32,7 @@ export const enum UserNotificationType {
NEW_PLUGIN_VERSION = 17, NEW_PLUGIN_VERSION = 17,
NEW_PEERTUBE_VERSION = 18, NEW_PEERTUBE_VERSION = 18,
MY_VIDEO_EDITION_FINISHED = 19 MY_VIDEO_STUDIO_EDITION_FINISHED = 19
} }
export interface VideoInfo { export interface VideoInfo {

View file

@ -1 +0,0 @@
export * from './video-editor-create-edit.model'

View file

@ -1,42 +0,0 @@
export interface VideoEditorCreateEdition {
tasks: VideoEditorTask[]
}
export type VideoEditorTask =
VideoEditorTaskCut |
VideoEditorTaskIntro |
VideoEditorTaskOutro |
VideoEditorTaskWatermark
export interface VideoEditorTaskCut {
name: 'cut'
options: {
start?: number
end?: number
}
}
export interface VideoEditorTaskIntro {
name: 'add-intro'
options: {
file: Blob | string
}
}
export interface VideoEditorTaskOutro {
name: 'add-outro'
options: {
file: Blob | string
}
}
export interface VideoEditorTaskWatermark {
name: 'add-watermark'
options: {
file: Blob | string
}
}

View file

@ -3,7 +3,7 @@ export * from './caption'
export * from './change-ownership' export * from './change-ownership'
export * from './channel' export * from './channel'
export * from './comment' export * from './comment'
export * from './editor' export * from './studio'
export * from './live' export * from './live'
export * from './file' export * from './file'
export * from './import' export * from './import'

View file

@ -0,0 +1 @@
export * from './video-studio-create-edit.model'

View file

@ -0,0 +1,42 @@
export interface VideoStudioCreateEdition {
tasks: VideoStudioTask[]
}
export type VideoStudioTask =
VideoStudioTaskCut |
VideoStudioTaskIntro |
VideoStudioTaskOutro |
VideoStudioTaskWatermark
export interface VideoStudioTaskCut {
name: 'cut'
options: {
start?: number
end?: number
}
}
export interface VideoStudioTaskIntro {
name: 'add-intro'
options: {
file: Blob | string
}
}
export interface VideoStudioTaskOutro {
name: 'add-outro'
options: {
file: Blob | string
}
}
export interface VideoStudioTaskWatermark {
name: 'add-watermark'
options: {
file: Blob | string
}
}

View file

@ -60,7 +60,7 @@ export class ConfigCommand extends AbstractCommand {
transcoding: { transcoding: {
enabled: false enabled: false
}, },
videoEditor: { videoStudio: {
enabled: false enabled: false
} }
} }
@ -111,10 +111,10 @@ export class ConfigCommand extends AbstractCommand {
}) })
} }
enableEditor () { enableStudio () {
return this.updateExistingSubConfig({ return this.updateExistingSubConfig({
newConfig: { newConfig: {
videoEditor: { videoStudio: {
enabled: true enabled: true
} }
} }
@ -339,7 +339,7 @@ export class ConfigCommand extends AbstractCommand {
} }
} }
}, },
videoEditor: { videoStudio: {
enabled: false enabled: false
}, },
import: { import: {

View file

@ -25,7 +25,7 @@ import {
PlaylistsCommand, PlaylistsCommand,
ServicesCommand, ServicesCommand,
StreamingPlaylistsCommand, StreamingPlaylistsCommand,
VideoEditorCommand, VideoStudioCommand,
VideosCommand VideosCommand
} from '../videos' } from '../videos'
import { CommentsCommand } from '../videos/comments-command' import { CommentsCommand } from '../videos/comments-command'
@ -125,7 +125,7 @@ export class PeerTubeServer {
login?: LoginCommand login?: LoginCommand
users?: UsersCommand users?: UsersCommand
objectStorage?: ObjectStorageCommand objectStorage?: ObjectStorageCommand
videoEditor?: VideoEditorCommand videoStudio?: VideoStudioCommand
videos?: VideosCommand videos?: VideosCommand
constructor (options: { serverNumber: number } | { url: string }) { constructor (options: { serverNumber: number } | { url: string }) {
@ -396,6 +396,6 @@ export class PeerTubeServer {
this.users = new UsersCommand(this) this.users = new UsersCommand(this)
this.videos = new VideosCommand(this) this.videos = new VideosCommand(this)
this.objectStorage = new ObjectStorageCommand(this) this.objectStorage = new ObjectStorageCommand(this)
this.videoEditor = new VideoEditorCommand(this) this.videoStudio = new VideoStudioCommand(this)
} }
} }

View file

@ -12,5 +12,5 @@ export * from './playlists-command'
export * from './services-command' export * from './services-command'
export * from './streaming-playlists-command' export * from './streaming-playlists-command'
export * from './comments-command' export * from './comments-command'
export * from './video-editor-command' export * from './video-studio-command'
export * from './videos-command' export * from './videos-command'

View file

@ -1,9 +1,9 @@
import { HttpStatusCode, VideoEditorTask } from '@shared/models' import { HttpStatusCode, VideoStudioTask } from '@shared/models'
import { AbstractCommand, OverrideCommandOptions } from '../shared' import { AbstractCommand, OverrideCommandOptions } from '../shared'
export class VideoEditorCommand extends AbstractCommand { export class VideoStudioCommand extends AbstractCommand {
static getComplexTask (): VideoEditorTask[] { static getComplexTask (): VideoStudioTask[] {
return [ return [
// Total duration: 2 // Total duration: 2
{ {
@ -41,9 +41,9 @@ export class VideoEditorCommand extends AbstractCommand {
createEditionTasks (options: OverrideCommandOptions & { createEditionTasks (options: OverrideCommandOptions & {
videoId: number | string videoId: number | string
tasks: VideoEditorTask[] tasks: VideoStudioTask[]
}) { }) {
const path = '/api/v1/videos/' + options.videoId + '/editor/edit' const path = '/api/v1/videos/' + options.videoId + '/studio/edit'
const attaches: { [id: string]: any } = {} const attaches: { [id: string]: any } = {}
for (let i = 0; i < options.tasks.length; i++) { for (let i = 0; i < options.tasks.length; i++) {

View file

@ -85,7 +85,7 @@ server {
try_files /dev/null @api; try_files /dev/null @api;
} }
location ~ ^/api/v1/videos/(upload|([^/]+/editor/edit))$ { location ~ ^/api/v1/videos/(upload|([^/]+/studio/edit))$ {
limit_except POST HEAD { deny all; } limit_except POST HEAD { deny all; }
# This is the maximum upload size, which roughly matches the maximum size of a video file. # This is the maximum upload size, which roughly matches the maximum size of a video file.