import { truncate } from 'lodash-es'
import { UploadState, UploadxOptions, UploadxService } from 'ngx-uploadx'
-import { isIOS } from 'src/assets/player/utils'
import { HttpErrorResponse, HttpEventType, HttpHeaders } from '@angular/common/http'
import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
-import { Router } from '@angular/router'
-import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService, UserService } from '@app/core'
+import { ActivatedRoute, Router } from '@angular/router'
+import { AuthService, CanComponentDeactivate, HooksService, MetaService, Notifier, ServerService, UserService } from '@app/core'
import { genericUploadErrorHandler, scrollToTop } from '@app/helpers'
import { FormValidatorService } from '@app/shared/shared-forms'
import { BytesPipe, Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core'
+import { logger } from '@root-helpers/logger'
+import { isIOS } from '@root-helpers/web-browser'
import { HttpStatusCode, VideoCreateResult } from '@shared/models'
import { UploaderXFormData } from './uploaderx-form-data'
import { VideoSend } from './video-send'
+import { Subscription } from 'rxjs'
@Component({
selector: 'my-video-upload',
// So that it can be accessed in the template
protected readonly BASE_VIDEO_UPLOAD_URL = VideoService.BASE_VIDEO_URL + '/upload-resumable'
- private uploadxOptions: UploadxOptions
private isUpdatingVideo = false
private fileToUpload: File
+ private alreadyRefreshedToken = false
+
+ private uploadServiceSubscription: Subscription
+
constructor (
protected formValidatorService: FormValidatorService,
protected loadingBar: LoadingBarService,
private userService: UserService,
private router: Router,
private hooks: HooksService,
- private resumableUploadService: UploadxService
+ private resumableUploadService: UploadxService,
+ private metaService: MetaService,
+ private route: ActivatedRoute
) {
super()
-
- // FIXME: https://github.com/Chocobozzz/PeerTube/issues/4382#issuecomment-915854167
- const chunkSize = isIOS()
- ? 0
- : undefined // Auto chunk size
-
- this.uploadxOptions = {
- endpoint: this.BASE_VIDEO_UPLOAD_URL,
- multiple: false,
- token: this.authService.getAccessToken(),
- uploaderClass: UploaderXFormData,
- chunkSize,
- retryConfig: {
- maxAttempts: 30, // maximum attempts for 503 codes, otherwise set to 6, see below
- maxDelay: 120_000, // 2 min
- shouldRetry: (code: number, attempts: number) => {
- return code === HttpStatusCode.SERVICE_UNAVAILABLE_503 || ((code < 400 || code > 500) && attempts < 6)
- }
- }
- }
}
get videoExtensions () {
this.userVideoQuotaUsedDaily = data.videoQuotaUsedDaily
})
- this.resumableUploadService.events
+ this.uploadServiceSubscription = this.resumableUploadService.events
.subscribe(state => this.onUploadVideoOngoing(state))
}
}
ngOnDestroy () {
- this.cancelUpload()
+ this.resumableUploadService.disconnect()
+
+ if (this.uploadServiceSubscription) this.uploadServiceSubscription.unsubscribe()
}
canDeactivate () {
}
}
+ updateTitle () {
+ const videoName = this.form.get('name').value
+
+ if (this.videoUploaded) {
+ this.metaService.setTitle($localize`Publish ${videoName}`)
+ } else if (this.isUploadingAudioFile || this.isUploadingVideo) {
+ this.metaService.setTitle(`${this.videoUploadPercents}% - ${videoName}`)
+ } else {
+ this.metaService.update(this.route.snapshot.data['meta'])
+ }
+ }
+
onUploadVideoOngoing (state: UploadState) {
switch (state.status) {
case 'error': {
- const error = state.response?.error || 'Unknow error'
+ if (!this.alreadyRefreshedToken && state.response.status === HttpStatusCode.UNAUTHORIZED_401) {
+ this.alreadyRefreshedToken = true
+
+ return this.refereshTokenAndRetryUpload()
+ }
+
+ const error = state.response?.error?.message || state.response?.error || 'Unknown error'
this.handleUploadError({
error: new Error(error),
break
case 'uploading':
- this.videoUploadPercents = state.progress
+ // TODO: remove || 0 when // https://github.com/kukhariev/ngx-uploadx/pull/368 is released
+ this.videoUploadPercents = state.progress || 0
break
case 'paused':
this.videoUploadedIds = state?.response.video
break
}
+
+ this.updateTitle()
}
onFileDropped (files: FileList) {
error: err => {
this.error = err.message
scrollToTop()
- console.error(err)
+ logger.error(err)
}
})
}
}
this.resumableUploadService.handleFiles(file, {
- ...this.uploadxOptions,
+ ...this.getUploadxOptions(),
+
metadata
})
})
this.firstStepDone.emit(name)
+ this.updateTitle()
}
private checkGlobalUserQuota (videofile: File) {
return name
}
+
+ private refereshTokenAndRetryUpload () {
+ this.authService.refreshAccessToken()
+ .subscribe(() => this.retryUpload())
+ }
+
+ private getUploadxOptions (): UploadxOptions {
+ // FIXME: https://github.com/Chocobozzz/PeerTube/issues/4382#issuecomment-915854167
+ const chunkSize = isIOS()
+ ? 0
+ : undefined // Auto chunk size
+
+ return {
+ endpoint: this.BASE_VIDEO_UPLOAD_URL,
+ multiple: false,
+
+ maxChunkSize: this.serverConfig.client.videos.resumableUpload.maxChunkSize,
+ chunkSize,
+
+ token: this.authService.getAccessToken(),
+
+ uploaderClass: UploaderXFormData,
+
+ retryConfig: {
+ maxAttempts: 30, // maximum attempts for 503 codes, otherwise set to 6, see below
+ maxDelay: 120_000, // 2 min
+ shouldRetry: (code: number, attempts: number) => {
+ return code === HttpStatusCode.SERVICE_UNAVAILABLE_503 || ((code < 400 || code > 500) && attempts < 6)
+ }
+ }
+ }
+ }
}