X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=client%2Fsrc%2Fapp%2F%2Bvideos%2F%2Bvideo-edit%2Fvideo-add-components%2Fvideo-upload.component.ts;h=effb37077465c3d7b9c3b913b3c034c7255e4e41;hb=d29ced1a8582d99b776f664475a157adcf555d98;hp=e18e3c9a775342cef28498b28a8daad72971992e;hpb=94676e631c5045144da598fefbefaa3cfcaaeb0d;p=github%2FChocobozzz%2FPeerTube.git diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts index e18e3c9a7..effb37077 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts @@ -1,13 +1,13 @@ import { Subscription } from 'rxjs' -import { HttpEventType, HttpResponse } from '@angular/common/http' -import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' +import { HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http' +import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' import { Router } from '@angular/router' -import { AuthService, CanComponentDeactivate, Notifier, ServerService, UserService } from '@app/core' -import { scrollToTop } from '@app/helpers' +import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService, UserService } from '@app/core' +import { scrollToTop, uploadErrorHandler } from '@app/helpers' import { FormValidatorService } from '@app/shared/shared-forms' import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' import { LoadingBarService } from '@ngx-loading-bar/core' -import { I18n } from '@ngx-translate/i18n-polyfill' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import { VideoPrivacy } from '@shared/models' import { VideoSend } from './video-send' @@ -20,7 +20,7 @@ import { VideoSend } from './video-send' './video-send.scss' ] }) -export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { +export class VideoUploadComponent extends VideoSend implements OnInit, AfterViewInit, OnDestroy, CanComponentDeactivate { @Output() firstStepDone = new EventEmitter() @Output() firstStepError = new EventEmitter() @ViewChild('videofileInput') videofileInput: ElementRef @@ -42,11 +42,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy id: 0, uuid: '' } + formData: FormData - waitTranscodingEnabled = true previewfileUpload: File error: string + enableRetryAfterError: boolean protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC @@ -60,8 +61,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy protected videoCaptionService: VideoCaptionService, private userService: UserService, private router: Router, - private i18n: I18n - ) { + private hooks: HooksService + ) { super() } @@ -79,6 +80,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy }) } + ngAfterViewInit () { + this.hooks.runAction('action:video-upload.init', 'video-edit') + } + ngOnDestroy () { if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe() } @@ -87,11 +92,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy let text = '' if (this.videoUploaded === true) { - // FIXME: cannot concatenate strings inside i18n service :/ - text = this.i18n('Your video was uploaded to your account and is private.') + ' ' + - this.i18n('But associated data (tags, description...) will be lost, are you sure you want to leave this page?') + // FIXME: cannot concatenate strings using $localize + text = $localize`Your video was uploaded to your account and is private.` + ' ' + + $localize`But associated data (tags, description...) will be lost, are you sure you want to leave this page?` } else { - text = this.i18n('Your video is not uploaded yet, are you sure you want to leave this page?') + text = $localize`Your video is not uploaded yet, are you sure you want to leave this page?` } return { @@ -111,27 +116,35 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy getAudioUploadLabel () { const videofile = this.getVideoFile() - if (!videofile) return this.i18n('Upload') + if (!videofile) return $localize`Upload` - return this.i18n('Upload {{videofileName}}', { videofileName: videofile.name }) + return $localize`Upload ${videofile.name}` } fileChange () { this.uploadFirstStep() } + retryUpload () { + this.enableRetryAfterError = false + this.error = '' + this.uploadVideo() + } + cancelUpload () { if (this.videoUploadObservable !== null) { this.videoUploadObservable.unsubscribe() + } - this.isUploadingVideo = false - this.videoUploadPercents = 0 - this.videoUploadObservable = null + this.isUploadingVideo = false + this.videoUploadPercents = 0 + this.videoUploadObservable = null - this.firstStepError.emit() + this.firstStepError.emit() + this.enableRetryAfterError = false + this.error = '' - this.notifier.info(this.i18n('Upload cancelled')) - } + this.notifier.info($localize`Upload cancelled`) } uploadFirstStep (clickedOnButton = false) { @@ -154,32 +167,26 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy if (nameWithoutExtension.length < 3) name = videofile.name else name = nameWithoutExtension - // Force user to wait transcoding for unsupported video types in web browsers - if (!videofile.name.endsWith('.mp4') && !videofile.name.endsWith('.webm') && !videofile.name.endsWith('.ogv')) { - this.waitTranscodingEnabled = false - } - - const privacy = this.firstStepPrivacyId.toString() const nsfw = this.serverConfig.instance.isNSFW const waitTranscoding = true const commentsEnabled = true const downloadEnabled = true const channelId = this.firstStepChannelId.toString() - const formData = new FormData() - formData.append('name', name) + this.formData = new FormData() + this.formData.append('name', name) // Put the video "private" -> we are waiting the user validation of the second step - formData.append('privacy', VideoPrivacy.PRIVATE.toString()) - formData.append('nsfw', '' + nsfw) - formData.append('commentsEnabled', '' + commentsEnabled) - formData.append('downloadEnabled', '' + downloadEnabled) - formData.append('waitTranscoding', '' + waitTranscoding) - formData.append('channelId', '' + channelId) - formData.append('videofile', videofile) + this.formData.append('privacy', VideoPrivacy.PRIVATE.toString()) + this.formData.append('nsfw', '' + nsfw) + this.formData.append('commentsEnabled', '' + commentsEnabled) + this.formData.append('downloadEnabled', '' + downloadEnabled) + this.formData.append('waitTranscoding', '' + waitTranscoding) + this.formData.append('channelId', '' + channelId) + this.formData.append('videofile', videofile) if (this.previewfileUpload) { - formData.append('previewfile', this.previewfileUpload) - formData.append('thumbnailfile', this.previewfileUpload) + this.formData.append('previewfile', this.previewfileUpload) + this.formData.append('thumbnailfile', this.previewfileUpload) } this.isUploadingVideo = true @@ -187,13 +194,17 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy this.form.patchValue({ name, - privacy, + privacy: this.firstStepPrivacyId, nsfw, - channelId, + channelId: this.firstStepChannelId, previewfile: this.previewfileUpload }) - this.videoUploadObservable = this.videoService.uploadVideo(formData).subscribe( + this.uploadVideo() + } + + uploadVideo () { + this.videoUploadObservable = this.videoService.uploadVideo(this.formData).subscribe( event => { if (event.type === HttpEventType.UploadProgress) { this.videoUploadPercents = Math.round(100 * event.loaded / event.total) @@ -206,13 +217,23 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy } }, - err => { - // Reset progress - this.isUploadingVideo = false + (err: HttpErrorResponse) => { + // Reset progress (but keep isUploadingVideo true) this.videoUploadPercents = 0 this.videoUploadObservable = null - this.firstStepError.emit() - this.notifier.error(err.message) + this.enableRetryAfterError = true + + this.error = uploadErrorHandler({ + err, + name: $localize`video`, + notifier: this.notifier, + sticky: false + }) + + if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413 || + err.status === HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) { + this.cancelUpload() + } } ) } @@ -242,7 +263,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy this.isUpdatingVideo = false this.isUploadingVideo = false - this.notifier.success(this.i18n('Video published.')) + this.notifier.success($localize`Video published.`) this.router.navigate([ '/videos/watch', video.uuid ]) }, @@ -260,14 +281,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy // Check global user quota const videoQuota = this.authService.getUser().videoQuota if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) { - const msg = this.i18n( - 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})', - { - videoSize: bytePipes.transform(videofile.size, 0), - videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0), - videoQuota: bytePipes.transform(videoQuota, 0) - } - ) + const videoSizeBytes = bytePipes.transform(videofile.size, 0) + const videoQuotaUsedBytes = bytePipes.transform(this.userVideoQuotaUsed, 0) + const videoQuotaBytes = bytePipes.transform(videoQuota, 0) + + const msg = $localize`Your video quota is exceeded with this video ( +video size: ${videoSizeBytes}, used: ${videoQuotaUsedBytes}, quota: ${videoQuotaBytes})` this.notifier.error(msg) return false @@ -282,14 +301,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy // Check daily user quota const videoQuotaDaily = this.authService.getUser().videoQuotaDaily if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) { - const msg = this.i18n( - 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})', - { - videoSize: bytePipes.transform(videofile.size, 0), - quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0), - quotaDaily: bytePipes.transform(videoQuotaDaily, 0) - } - ) + const videoSizeBytes = bytePipes.transform(videofile.size, 0) + const quotaUsedDailyBytes = bytePipes.transform(this.userVideoQuotaUsedDaily, 0) + const quotaDailyBytes = bytePipes.transform(videoQuotaDaily, 0) + + const msg = $localize`Your daily video quota is exceeded with this video ( +video size: ${videoSizeBytes}, used: ${quotaUsedDailyBytes}, quota: ${quotaDailyBytes})` this.notifier.error(msg) return false