]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
Move engines outside package.json
[github/Chocobozzz/PeerTube.git] / client / src / app / +videos / +video-edit / video-add-components / video-upload.component.ts
index e18e3c9a775342cef28498b28a8daad72971992e..effb37077465c3d7b9c3b913b3c034c7255e4e41 100644 (file)
@@ -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<string>()
   @Output() firstStepError = new EventEmitter<void>()
   @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement>
@@ -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