Add ability to update thumbnail and preview on client
This commit is contained in:
parent
b6a4fd6b09
commit
6de3676898
20 changed files with 274 additions and 137 deletions
|
@ -10,6 +10,4 @@
|
|||
</tabset>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
|
|
@ -35,6 +35,10 @@ export class ServerService {
|
|||
}
|
||||
},
|
||||
video: {
|
||||
image: {
|
||||
size: { max: 0 },
|
||||
extensions: []
|
||||
},
|
||||
file: {
|
||||
extensions: []
|
||||
}
|
||||
|
|
|
@ -31,6 +31,11 @@ export const VIDEO_LANGUAGE = {
|
|||
MESSAGES: {}
|
||||
}
|
||||
|
||||
export const VIDEO_IMAGE = {
|
||||
VALIDATORS: [ ],
|
||||
MESSAGES: {}
|
||||
}
|
||||
|
||||
export const VIDEO_CHANNEL = {
|
||||
VALIDATORS: [ Validators.required ],
|
||||
MESSAGES: {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
id="description" name="description">
|
||||
</textarea>
|
||||
|
||||
<tabset *ngIf="arePreviewsDisplayed()" #staticTabs class="previews">
|
||||
<tabset *ngIf="arePreviewsDisplayed()" class="previews">
|
||||
<tab *ngIf="truncate !== undefined" heading="Truncated description preview" [innerHTML]="truncatedDescriptionHTML"></tab>
|
||||
<tab heading="Complete description preview" [innerHTML]="descriptionHTML"></tab>
|
||||
</tabset>
|
||||
|
|
|
@ -67,6 +67,27 @@ function isInMobileView () {
|
|||
return window.innerWidth < 500
|
||||
}
|
||||
|
||||
// Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34
|
||||
function objectToFormData (obj: any, form?: FormData, namespace?: string) {
|
||||
let fd = form || new FormData()
|
||||
let formKey
|
||||
|
||||
for (let key of Object.keys(obj)) {
|
||||
if (namespace) formKey = `${namespace}[${key}]`
|
||||
else formKey = key
|
||||
|
||||
if (obj[key] === undefined) continue
|
||||
|
||||
if (typeof obj[ key ] === 'object' && !(obj[ key ] instanceof File)) {
|
||||
objectToFormData(obj[ key ], fd, key)
|
||||
} else {
|
||||
fd.append(formKey, obj[ key ])
|
||||
}
|
||||
}
|
||||
|
||||
return fd
|
||||
}
|
||||
|
||||
export {
|
||||
viewportHeight,
|
||||
getParameterByName,
|
||||
|
@ -75,5 +96,6 @@ export {
|
|||
dateToHuman,
|
||||
isInSmallView,
|
||||
isInMobileView,
|
||||
immutableAssign
|
||||
immutableAssign,
|
||||
objectToFormData
|
||||
}
|
||||
|
|
|
@ -40,10 +40,10 @@ import { VideoService } from './video/video.service'
|
|||
|
||||
BsDropdownModule.forRoot(),
|
||||
ModalModule.forRoot(),
|
||||
TabsModule.forRoot(),
|
||||
|
||||
PrimeSharedModule,
|
||||
NgPipesModule,
|
||||
TabsModule.forRoot()
|
||||
NgPipesModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
|
@ -69,6 +69,7 @@ import { VideoService } from './video/video.service'
|
|||
|
||||
BsDropdownModule,
|
||||
ModalModule,
|
||||
TabsModule,
|
||||
PrimeSharedModule,
|
||||
BytesPipe,
|
||||
KeysPipe,
|
||||
|
|
|
@ -12,6 +12,10 @@ export class VideoEdit {
|
|||
commentsEnabled: boolean
|
||||
channel: number
|
||||
privacy: VideoPrivacy
|
||||
thumbnailfile?: any
|
||||
previewfile?: any
|
||||
thumbnailUrl: string
|
||||
previewUrl: string
|
||||
uuid?: string
|
||||
id?: number
|
||||
|
||||
|
@ -29,6 +33,8 @@ export class VideoEdit {
|
|||
this.commentsEnabled = videoDetails.commentsEnabled
|
||||
this.channel = videoDetails.channel.id
|
||||
this.privacy = videoDetails.privacy
|
||||
this.thumbnailUrl = videoDetails.thumbnailUrl
|
||||
this.previewUrl = videoDetails.previewUrl
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
[routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name"
|
||||
class="video-thumbnail"
|
||||
>
|
||||
<img [attr.src]="getImageUrl()" alt="video thumbnail" [ngClass]="{ 'blur-filter': nsfw }" />
|
||||
<img [attr.src]="getImageUrl()" [ngClass]="{ 'blur-filter': nsfw }" />
|
||||
|
||||
<div class="video-thumbnail-overlay">
|
||||
{{ video.durationLabel }}
|
||||
|
|
|
@ -18,6 +18,7 @@ import { SortField } from './sort-field.type'
|
|||
import { VideoDetails } from './video-details.model'
|
||||
import { VideoEdit } from './video-edit.model'
|
||||
import { Video } from './video.model'
|
||||
import { objectToFormData } from '@app/shared/misc/utils'
|
||||
|
||||
@Injectable()
|
||||
export class VideoService {
|
||||
|
@ -46,10 +47,10 @@ export class VideoService {
|
|||
}
|
||||
|
||||
updateVideo (video: VideoEdit) {
|
||||
const language = video.language || null
|
||||
const licence = video.licence || null
|
||||
const category = video.category || null
|
||||
const description = video.description || null
|
||||
const language = video.language || undefined
|
||||
const licence = video.licence || undefined
|
||||
const category = video.category || undefined
|
||||
const description = video.description || undefined
|
||||
|
||||
const body: VideoUpdate = {
|
||||
name: video.name,
|
||||
|
@ -60,10 +61,14 @@ export class VideoService {
|
|||
privacy: video.privacy,
|
||||
tags: video.tags,
|
||||
nsfw: video.nsfw,
|
||||
commentsEnabled: video.commentsEnabled
|
||||
commentsEnabled: video.commentsEnabled,
|
||||
thumbnailfile: video.thumbnailfile,
|
||||
previewfile: video.previewfile
|
||||
}
|
||||
|
||||
return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, body)
|
||||
const data = objectToFormData(body)
|
||||
|
||||
return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data)
|
||||
.map(this.restExtractor.extractDataBool)
|
||||
.catch(this.restExtractor.handleError)
|
||||
}
|
||||
|
|
|
@ -1,109 +1,133 @@
|
|||
<div class="video-edit row" [formGroup]="form">
|
||||
<tabset class="root-tabset bootstrap">
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<label for="name">Title</label>
|
||||
<input type="text" id="name" formControlName="name" />
|
||||
<div *ngIf="formErrors.name" class="form-error">
|
||||
{{ formErrors.name }}
|
||||
</div>
|
||||
</div>
|
||||
<tab heading="Basic info">
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<label for="name">Title</label>
|
||||
<input type="text" id="name" formControlName="name" />
|
||||
<div *ngIf="formErrors.name" class="form-error">
|
||||
{{ formErrors.name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="label-tags">Tags</label> <span>(press Enter to add)</span>
|
||||
<tag-input
|
||||
[ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
||||
formControlName="tags" maxItems="5" modelAsStrings="true"
|
||||
></tag-input>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="label-tags">Tags</label> <span>(press Enter to add)</span>
|
||||
<tag-input
|
||||
[ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
|
||||
formControlName="tags" maxItems="5" modelAsStrings="true"
|
||||
></tag-input>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<my-markdown-textarea truncate="250" formControlName="description"></my-markdown-textarea>
|
||||
|
||||
<div *ngIf="formErrors.description" class="form-error">
|
||||
{{ formErrors.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label>Channel</label>
|
||||
<div class="peertube-select-disabled-container">
|
||||
<select formControlName="channelId">
|
||||
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="category" formControlName="category">
|
||||
<option></option>
|
||||
<option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
|
||||
</select>
|
||||
<div *ngIf="formErrors.description" class="form-error">
|
||||
{{ formErrors.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.category" class="form-error">
|
||||
{{ formErrors.category }}
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label>Channel</label>
|
||||
<div class="peertube-select-disabled-container">
|
||||
<select formControlName="channelId">
|
||||
<option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="category" formControlName="category">
|
||||
<option></option>
|
||||
<option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.category" class="form-error">
|
||||
{{ formErrors.category }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="licence">Licence</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="licence" formControlName="licence">
|
||||
<option></option>
|
||||
<option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.licence" class="form-error">
|
||||
{{ formErrors.licence }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="language">Language</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="language" formControlName="language">
|
||||
<option></option>
|
||||
<option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.language" class="form-error">
|
||||
{{ formErrors.language }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="privacy">Privacy</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="privacy" formControlName="privacy">
|
||||
<option></option>
|
||||
<option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.privacy" class="form-error">
|
||||
{{ formErrors.privacy }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-checkbox">
|
||||
<input type="checkbox" id="nsfw" formControlName="nsfw" />
|
||||
<label for="nsfw"></label>
|
||||
<label for="nsfw">This video contains mature or explicit content</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-checkbox">
|
||||
<input type="checkbox" id="commentsEnabled" formControlName="commentsEnabled" />
|
||||
<label for="commentsEnabled"></label>
|
||||
<label for="commentsEnabled">Enable video comments</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="licence">Licence</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="licence" formControlName="licence">
|
||||
<option></option>
|
||||
<option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
|
||||
</select>
|
||||
<tab heading="Advanced settings">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<my-video-image
|
||||
inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
|
||||
previewWidth="200px" previewHeight="110px"
|
||||
></my-video-image>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<my-video-image
|
||||
inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile"
|
||||
previewWidth="360px" previewHeight="200px"
|
||||
></my-video-image>
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
|
||||
<div *ngIf="formErrors.licence" class="form-error">
|
||||
{{ formErrors.licence }}
|
||||
</div>
|
||||
</div>
|
||||
</tabset>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="language">Language</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="language" formControlName="language">
|
||||
<option></option>
|
||||
<option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.language" class="form-error">
|
||||
{{ formErrors.language }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="privacy">Privacy</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="privacy" formControlName="privacy">
|
||||
<option></option>
|
||||
<option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div *ngIf="formErrors.privacy" class="form-error">
|
||||
{{ formErrors.privacy }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-checkbox">
|
||||
<input type="checkbox" id="nsfw" formControlName="nsfw" />
|
||||
<label for="nsfw"></label>
|
||||
<label for="nsfw">This video contains mature or explicit content</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-checkbox">
|
||||
<input type="checkbox" id="commentsEnabled" formControlName="commentsEnabled" />
|
||||
<label for="commentsEnabled"></label>
|
||||
<label for="commentsEnabled">Enable video comments</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
.label-tags + span {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.root-tabset /deep/ > .nav {
|
||||
margin-left: 15px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.nav-link {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
height: 30px !important;
|
||||
padding: 0 15px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submit-container {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, Input, OnInit } from '@angular/core'
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { VIDEO_IMAGE } from '@app/shared'
|
||||
import { NotificationsService } from 'angular2-notifications'
|
||||
import 'rxjs/add/observable/forkJoin'
|
||||
import { ServerService } from '../../../core/server'
|
||||
|
@ -57,6 +58,8 @@ export class VideoEditComponent implements OnInit {
|
|||
this.formErrors['licence'] = ''
|
||||
this.formErrors['language'] = ''
|
||||
this.formErrors['description'] = ''
|
||||
this.formErrors['thumbnailfile'] = ''
|
||||
this.formErrors['previewfile'] = ''
|
||||
|
||||
this.validationMessages['name'] = VIDEO_NAME.MESSAGES
|
||||
this.validationMessages['privacy'] = VIDEO_PRIVACY.MESSAGES
|
||||
|
@ -65,6 +68,8 @@ export class VideoEditComponent implements OnInit {
|
|||
this.validationMessages['licence'] = VIDEO_LICENCE.MESSAGES
|
||||
this.validationMessages['language'] = VIDEO_LANGUAGE.MESSAGES
|
||||
this.validationMessages['description'] = VIDEO_DESCRIPTION.MESSAGES
|
||||
this.validationMessages['thumbnailfile'] = VIDEO_IMAGE.MESSAGES
|
||||
this.validationMessages['previewfile'] = VIDEO_IMAGE.MESSAGES
|
||||
|
||||
this.form.addControl('name', new FormControl('', VIDEO_NAME.VALIDATORS))
|
||||
this.form.addControl('privacy', new FormControl('', VIDEO_PRIVACY.VALIDATORS))
|
||||
|
@ -76,6 +81,8 @@ export class VideoEditComponent implements OnInit {
|
|||
this.form.addControl('language', new FormControl('', VIDEO_LANGUAGE.VALIDATORS))
|
||||
this.form.addControl('description', new FormControl('', VIDEO_DESCRIPTION.VALIDATORS))
|
||||
this.form.addControl('tags', new FormControl(''))
|
||||
this.form.addControl('thumbnailfile', new FormControl(''))
|
||||
this.form.addControl('previewfile', new FormControl(''))
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { NgModule } from '@angular/core'
|
||||
import { VideoImageComponent } from '@app/videos/+video-edit/shared/video-image.component'
|
||||
import { TabsModule } from 'ngx-bootstrap/tabs'
|
||||
import { TagInputModule } from 'ngx-chips'
|
||||
import { SharedModule } from '../../../shared'
|
||||
|
@ -12,7 +13,8 @@ import { VideoEditComponent } from './video-edit.component'
|
|||
],
|
||||
|
||||
declarations: [
|
||||
VideoEditComponent
|
||||
VideoEditComponent,
|
||||
VideoImageComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
|
|
@ -48,11 +48,10 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
|||
this.buildForm()
|
||||
|
||||
this.serverService.videoPrivaciesLoaded
|
||||
.subscribe(
|
||||
() => this.videoPrivacies = this.serverService.getVideoPrivacies()
|
||||
)
|
||||
.subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies())
|
||||
|
||||
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
|
||||
.catch(err => console.error('Cannot populate async user video channels.', err))
|
||||
|
||||
const uuid: string = this.route.snapshot.params['uuid']
|
||||
this.videoService.getVideo(uuid)
|
||||
|
@ -116,5 +115,26 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
|
|||
|
||||
private hydrateFormFromVideo () {
|
||||
this.form.patchValue(this.video.toJSON())
|
||||
|
||||
const objects = [
|
||||
{
|
||||
url: 'thumbnailUrl',
|
||||
name: 'thumbnailfile'
|
||||
},
|
||||
{
|
||||
url: 'previewUrl',
|
||||
name: 'previewfile'
|
||||
}
|
||||
]
|
||||
|
||||
for (const obj of objects) {
|
||||
fetch(this.video[obj.url])
|
||||
.then(response => response.blob())
|
||||
.then(data => {
|
||||
this.form.patchValue({
|
||||
[ obj.name ]: data
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="row">
|
||||
<!-- We need the video container for videojs so we just hide it -->
|
||||
<div [hidden]="videoNotFound" id="video-container">
|
||||
<video id="video-element" class="video-js vjs-peertube-skin"></video>
|
||||
<video [poster]="getVideoPoster()" id="video-element" class="video-js vjs-peertube-skin"></video>
|
||||
</div>
|
||||
|
||||
<div *ngIf="videoNotFound" id="video-not-found">Video not found :'(</div>
|
||||
|
|
|
@ -211,6 +211,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
return Account.GET_ACCOUNT_AVATAR_URL(this.video.account)
|
||||
}
|
||||
|
||||
getVideoPoster () {
|
||||
if (!this.video) return ''
|
||||
|
||||
return this.video.previewUrl
|
||||
}
|
||||
|
||||
getVideoTags () {
|
||||
if (!this.video || Array.isArray(this.video.tags) === false) return []
|
||||
|
||||
|
|
|
@ -299,35 +299,46 @@ p-datatable {
|
|||
}
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-size: 16px !important;
|
||||
border: none !important;
|
||||
|
||||
.nav-item .nav-link {
|
||||
margin-right: 30px;
|
||||
padding: 0;
|
||||
border-radius: 3px;
|
||||
tabset:not(.bootstrap) {
|
||||
.nav {
|
||||
font-size: 16px !important;
|
||||
border: none !important;
|
||||
|
||||
.tab-link {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
min-height: 30px !important;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.nav-item .nav-link {
|
||||
margin-right: 30px;
|
||||
padding: 0;
|
||||
border-radius: 3px;
|
||||
border: none !important;
|
||||
|
||||
.tab-link {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
min-height: 30px !important;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
&, & a {
|
||||
color: #000 !important;
|
||||
@include disable-default-a-behaviour;
|
||||
}
|
||||
|
||||
&.active, &:hover {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: $font-semibold !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabset.bootstrap {
|
||||
.nav-item .nav-link {
|
||||
&, & a {
|
||||
color: #000 !important;
|
||||
color: #000;
|
||||
@include disable-default-a-behaviour;
|
||||
}
|
||||
|
||||
&.active, &:hover {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: $font-semibold !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,12 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
|
|||
}
|
||||
},
|
||||
video: {
|
||||
image: {
|
||||
extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
|
||||
size: {
|
||||
max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
|
||||
}
|
||||
},
|
||||
file: {
|
||||
extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
|
||||
}
|
||||
|
|
|
@ -23,6 +23,12 @@ export interface ServerConfig {
|
|||
}
|
||||
|
||||
video: {
|
||||
image: {
|
||||
size: {
|
||||
max: number
|
||||
}
|
||||
extensions: string[]
|
||||
},
|
||||
file: {
|
||||
extensions: string[]
|
||||
}
|
||||
|
|
|
@ -11,4 +11,6 @@ export interface VideoUpdate {
|
|||
tags?: string[]
|
||||
commentsEnabled?: boolean
|
||||
nsfw?: boolean
|
||||
thumbnailfile?: Blob
|
||||
previewfile?: Blob
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue