diff options
author | Chocobozzz <me@florianbigard.com> | 2020-06-23 14:49:20 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-06-23 16:00:49 +0200 |
commit | 1942f11d5ee6926ad93dc1b79fae18325ba5de18 (patch) | |
tree | 3f2a3cd9466a56c419d197ac832a3e9cbc86bec4 /client/src/app/videos/+video-edit/video-add-components | |
parent | 67ed6552b831df66713bac9e672738796128d33f (diff) | |
download | PeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.tar.gz PeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.tar.zst PeerTube-1942f11d5ee6926ad93dc1b79fae18325ba5de18.zip |
Lazy load all routes
Diffstat (limited to 'client/src/app/videos/+video-edit/video-add-components')
11 files changed, 0 insertions, 1083 deletions
diff --git a/client/src/app/videos/+video-edit/video-add-components/drag-drop.directive.ts b/client/src/app/videos/+video-edit/video-add-components/drag-drop.directive.ts deleted file mode 100644 index 7b1a38c62..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/drag-drop.directive.ts +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@angular/core' | ||
2 | |||
3 | @Directive({ | ||
4 | selector: '[dragDrop]' | ||
5 | }) | ||
6 | export class DragDropDirective { | ||
7 | @Output() fileDropped = new EventEmitter<FileList>() | ||
8 | |||
9 | @HostBinding('class.dragover') dragover = false | ||
10 | |||
11 | @HostListener('dragover', ['$event']) onDragOver (e: Event) { | ||
12 | e.preventDefault() | ||
13 | e.stopPropagation() | ||
14 | this.dragover = true | ||
15 | } | ||
16 | |||
17 | @HostListener('dragleave', ['$event']) public onDragLeave (e: Event) { | ||
18 | e.preventDefault() | ||
19 | e.stopPropagation() | ||
20 | this.dragover = false | ||
21 | } | ||
22 | |||
23 | @HostListener('drop', ['$event']) public ondrop (e: DragEvent) { | ||
24 | e.preventDefault() | ||
25 | e.stopPropagation() | ||
26 | this.dragover = false | ||
27 | const files = e.dataTransfer.files | ||
28 | if (files.length > 0) this.fileDropped.emit(files) | ||
29 | } | ||
30 | } | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html deleted file mode 100644 index 7287f799d..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | <div *ngIf="!hasImportedVideo" class="upload-video-container" dragDrop (fileDropped)="setTorrentFile($event)"> | ||
2 | <div class="first-step-block"> | ||
3 | <my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon> | ||
4 | |||
5 | <div class="button-file form-control" [ngbTooltip]="'(extensions: .torrent)'"> | ||
6 | <span i18n>Select the torrent to import</span> | ||
7 | <input #torrentfileInput type="file" name="torrentfile" id="torrentfile" accept=".torrent" (change)="fileChange()" /> | ||
8 | </div> | ||
9 | |||
10 | <div class="torrent-or-magnet" i18n-data-content data-content="OR"></div> | ||
11 | |||
12 | <div class="form-group form-group-magnet-uri"> | ||
13 | <label i18n for="magnetUri">Paste magnet URI</label> | ||
14 | <my-help> | ||
15 | <ng-template ptTemplate="customHtml"> | ||
16 | <ng-container i18n> | ||
17 | You can import any torrent file that points to a mp4 file. | ||
18 | You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance. | ||
19 | </ng-container> | ||
20 | </ng-template> | ||
21 | </my-help> | ||
22 | |||
23 | <input type="text" id="magnetUri" [(ngModel)]="magnetUri" class="form-control" /> | ||
24 | </div> | ||
25 | |||
26 | <div class="form-group"> | ||
27 | <label i18n for="first-step-channel">Channel</label> | ||
28 | <div class="peertube-select-container"> | ||
29 | <select id="first-step-channel" [(ngModel)]="firstStepChannelId" class="form-control"> | ||
30 | <option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option> | ||
31 | </select> | ||
32 | </div> | ||
33 | </div> | ||
34 | |||
35 | <div class="form-group"> | ||
36 | <label i18n for="first-step-privacy">Privacy</label> | ||
37 | <div class="peertube-select-container"> | ||
38 | <select id="first-step-privacy" [(ngModel)]="firstStepPrivacyId" class="form-control"> | ||
39 | <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option> | ||
40 | </select> | ||
41 | </div> | ||
42 | </div> | ||
43 | |||
44 | <input | ||
45 | type="button" i18n-value value="Import" | ||
46 | [disabled]="!isMagnetUrlValid() || isImportingVideo" (click)="importVideo()" | ||
47 | /> | ||
48 | </div> | ||
49 | </div> | ||
50 | |||
51 | <div *ngIf="error" class="alert alert-danger"> | ||
52 | <div i18n>Sorry, but something went wrong</div> | ||
53 | {{ error }} | ||
54 | </div> | ||
55 | |||
56 | <div *ngIf="hasImportedVideo && !error" class="alert alert-info" i18n> | ||
57 | Congratulations, the video will be imported with BitTorrent! You can already add information about this video. | ||
58 | </div> | ||
59 | |||
60 | <!-- Hidden because we want to load the component --> | ||
61 | <form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> | ||
62 | <my-video-edit | ||
63 | [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false" | ||
64 | [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels" | ||
65 | ></my-video-edit> | ||
66 | |||
67 | <div class="submit-container"> | ||
68 | <div class="submit-button" | ||
69 | (click)="updateSecondStep()" | ||
70 | [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }" | ||
71 | > | ||
72 | <my-global-icon iconName="validate" aria-hidden="true"></my-global-icon> | ||
73 | <input type="button" i18n-value value="Update" /> | ||
74 | </div> | ||
75 | </div> | ||
76 | </form> | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.scss b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.scss deleted file mode 100644 index 1fef74994..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.scss +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | .first-step-block { | ||
5 | .torrent-or-magnet { | ||
6 | @include divider($color: pvar(--inputPlaceholderColor), $background: pvar(--submenuColor)); | ||
7 | |||
8 | &[data-content] { | ||
9 | margin: 1.5rem 0; | ||
10 | } | ||
11 | } | ||
12 | |||
13 | .form-group-magnet-uri { | ||
14 | margin-bottom: 40px; | ||
15 | } | ||
16 | } | ||
17 | |||
18 | |||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts deleted file mode 100644 index 5b453a1d9..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ /dev/null | |||
@@ -1,147 +0,0 @@ | |||
1 | import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | ||
2 | import { Router } from '@angular/router' | ||
3 | import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' | ||
4 | import { scrollToTop } from '@app/helpers' | ||
5 | import { FormValidatorService } from '@app/shared/shared-forms' | ||
6 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' | ||
7 | import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-send' | ||
8 | import { LoadingBarService } from '@ngx-loading-bar/core' | ||
9 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
10 | import { VideoPrivacy, VideoUpdate } from '@shared/models' | ||
11 | |||
12 | @Component({ | ||
13 | selector: 'my-video-import-torrent', | ||
14 | templateUrl: './video-import-torrent.component.html', | ||
15 | styleUrls: [ | ||
16 | '../shared/video-edit.component.scss', | ||
17 | './video-import-torrent.component.scss', | ||
18 | './video-send.scss' | ||
19 | ] | ||
20 | }) | ||
21 | export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { | ||
22 | @Output() firstStepDone = new EventEmitter<string>() | ||
23 | @Output() firstStepError = new EventEmitter<void>() | ||
24 | @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement> | ||
25 | |||
26 | magnetUri = '' | ||
27 | |||
28 | isImportingVideo = false | ||
29 | hasImportedVideo = false | ||
30 | isUpdatingVideo = false | ||
31 | |||
32 | video: VideoEdit | ||
33 | error: string | ||
34 | |||
35 | protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC | ||
36 | |||
37 | constructor ( | ||
38 | protected formValidatorService: FormValidatorService, | ||
39 | protected loadingBar: LoadingBarService, | ||
40 | protected notifier: Notifier, | ||
41 | protected authService: AuthService, | ||
42 | protected serverService: ServerService, | ||
43 | protected videoService: VideoService, | ||
44 | protected videoCaptionService: VideoCaptionService, | ||
45 | private router: Router, | ||
46 | private videoImportService: VideoImportService, | ||
47 | private i18n: I18n | ||
48 | ) { | ||
49 | super() | ||
50 | } | ||
51 | |||
52 | ngOnInit () { | ||
53 | super.ngOnInit() | ||
54 | } | ||
55 | |||
56 | canDeactivate () { | ||
57 | return { canDeactivate: true } | ||
58 | } | ||
59 | |||
60 | isMagnetUrlValid () { | ||
61 | return !!this.magnetUri | ||
62 | } | ||
63 | |||
64 | fileChange () { | ||
65 | const torrentfile = this.torrentfileInput.nativeElement.files[0] | ||
66 | if (!torrentfile) return | ||
67 | |||
68 | this.importVideo(torrentfile) | ||
69 | } | ||
70 | |||
71 | setTorrentFile (files: FileList) { | ||
72 | this.torrentfileInput.nativeElement.files = files | ||
73 | this.fileChange() | ||
74 | } | ||
75 | |||
76 | importVideo (torrentfile?: Blob) { | ||
77 | this.isImportingVideo = true | ||
78 | |||
79 | const videoUpdate: VideoUpdate = { | ||
80 | privacy: this.firstStepPrivacyId, | ||
81 | waitTranscoding: false, | ||
82 | commentsEnabled: true, | ||
83 | downloadEnabled: true, | ||
84 | channelId: this.firstStepChannelId | ||
85 | } | ||
86 | |||
87 | this.loadingBar.start() | ||
88 | |||
89 | this.videoImportService.importVideoTorrent(torrentfile || this.magnetUri, videoUpdate).subscribe( | ||
90 | res => { | ||
91 | this.loadingBar.complete() | ||
92 | this.firstStepDone.emit(res.video.name) | ||
93 | this.isImportingVideo = false | ||
94 | this.hasImportedVideo = true | ||
95 | |||
96 | this.video = new VideoEdit(Object.assign(res.video, { | ||
97 | commentsEnabled: videoUpdate.commentsEnabled, | ||
98 | downloadEnabled: videoUpdate.downloadEnabled, | ||
99 | support: null, | ||
100 | thumbnailUrl: null, | ||
101 | previewUrl: null | ||
102 | })) | ||
103 | |||
104 | this.hydrateFormFromVideo() | ||
105 | }, | ||
106 | |||
107 | err => { | ||
108 | this.loadingBar.complete() | ||
109 | this.isImportingVideo = false | ||
110 | this.firstStepError.emit() | ||
111 | this.notifier.error(err.message) | ||
112 | } | ||
113 | ) | ||
114 | } | ||
115 | |||
116 | updateSecondStep () { | ||
117 | if (this.checkForm() === false) { | ||
118 | return | ||
119 | } | ||
120 | |||
121 | this.video.patch(this.form.value) | ||
122 | |||
123 | this.isUpdatingVideo = true | ||
124 | |||
125 | // Update the video | ||
126 | this.updateVideoAndCaptions(this.video) | ||
127 | .subscribe( | ||
128 | () => { | ||
129 | this.isUpdatingVideo = false | ||
130 | this.notifier.success(this.i18n('Video to import updated.')) | ||
131 | |||
132 | this.router.navigate([ '/my-account', 'video-imports' ]) | ||
133 | }, | ||
134 | |||
135 | err => { | ||
136 | this.error = err.message | ||
137 | scrollToTop() | ||
138 | console.error(err) | ||
139 | } | ||
140 | ) | ||
141 | |||
142 | } | ||
143 | |||
144 | private hydrateFormFromVideo () { | ||
145 | this.form.patchValue(this.video.toFormPatch()) | ||
146 | } | ||
147 | } | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html deleted file mode 100644 index 1910da403..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | <div *ngIf="!hasImportedVideo" class="upload-video-container"> | ||
2 | <div class="first-step-block"> | ||
3 | <my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon> | ||
4 | |||
5 | <div class="form-group"> | ||
6 | <label i18n for="targetUrl">URL</label> | ||
7 | |||
8 | <my-help> | ||
9 | <ng-template ptTemplate="customHtml"> | ||
10 | <ng-container i18n> | ||
11 | You can import any URL <a href='https://rg3.github.io/youtube-dl/supportedsites.html' target='_blank' rel='noopener noreferrer'>supported by youtube-dl</a> | ||
12 | or URL that points to a raw MP4 file. | ||
13 | You should make sure you have diffusion rights over the content it points to, otherwise it could cause legal trouble to yourself and your instance. | ||
14 | </ng-container> | ||
15 | </ng-template> | ||
16 | </my-help> | ||
17 | |||
18 | <input type="text" id="targetUrl" [(ngModel)]="targetUrl" class="form-control" /> | ||
19 | </div> | ||
20 | |||
21 | <div class="form-group"> | ||
22 | <label i18n for="first-step-channel">Channel</label> | ||
23 | <div class="peertube-select-container"> | ||
24 | <select id="first-step-channel" [(ngModel)]="firstStepChannelId" class="form-control"> | ||
25 | <option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option> | ||
26 | </select> | ||
27 | </div> | ||
28 | </div> | ||
29 | |||
30 | <div class="form-group"> | ||
31 | <label i18n for="first-step-privacy">Privacy</label> | ||
32 | <div class="peertube-select-container"> | ||
33 | <select id="first-step-privacy" [(ngModel)]="firstStepPrivacyId" class="form-control"> | ||
34 | <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option> | ||
35 | </select> | ||
36 | </div> | ||
37 | </div> | ||
38 | |||
39 | <input | ||
40 | type="button" i18n-value value="Import" | ||
41 | [disabled]="!isTargetUrlValid() || isImportingVideo" (click)="importVideo()" | ||
42 | /> | ||
43 | </div> | ||
44 | </div> | ||
45 | |||
46 | |||
47 | <div *ngIf="error" class="alert alert-danger"> | ||
48 | <div i18n>Sorry, but something went wrong</div> | ||
49 | {{ error }} | ||
50 | </div> | ||
51 | |||
52 | <div *ngIf="!error && hasImportedVideo" class="alert alert-info" i18n> | ||
53 | Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video. | ||
54 | </div> | ||
55 | |||
56 | <!-- Hidden because we want to load the component --> | ||
57 | <form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> | ||
58 | <my-video-edit | ||
59 | [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false" | ||
60 | [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels" | ||
61 | ></my-video-edit> | ||
62 | |||
63 | <div class="submit-container"> | ||
64 | <div class="submit-button" | ||
65 | (click)="updateSecondStep()" | ||
66 | [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }" | ||
67 | > | ||
68 | <my-global-icon iconName="validate" aria-hidden="true"></my-global-icon> | ||
69 | <input type="button" i18n-value value="Update" /> | ||
70 | </div> | ||
71 | </div> | ||
72 | </form> | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts deleted file mode 100644 index d0bd1f54d..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts +++ /dev/null | |||
@@ -1,178 +0,0 @@ | |||
1 | import { map, switchMap } from 'rxjs/operators' | ||
2 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' | ||
3 | import { Router } from '@angular/router' | ||
4 | import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' | ||
5 | import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers' | ||
6 | import { FormValidatorService } from '@app/shared/shared-forms' | ||
7 | import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' | ||
8 | import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-send' | ||
9 | import { LoadingBarService } from '@ngx-loading-bar/core' | ||
10 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
11 | import { VideoPrivacy, VideoUpdate } from '@shared/models' | ||
12 | |||
13 | @Component({ | ||
14 | selector: 'my-video-import-url', | ||
15 | templateUrl: './video-import-url.component.html', | ||
16 | styleUrls: [ | ||
17 | '../shared/video-edit.component.scss', | ||
18 | './video-send.scss' | ||
19 | ] | ||
20 | }) | ||
21 | export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { | ||
22 | @Output() firstStepDone = new EventEmitter<string>() | ||
23 | @Output() firstStepError = new EventEmitter<void>() | ||
24 | |||
25 | targetUrl = '' | ||
26 | |||
27 | isImportingVideo = false | ||
28 | hasImportedVideo = false | ||
29 | isUpdatingVideo = false | ||
30 | |||
31 | video: VideoEdit | ||
32 | error: string | ||
33 | |||
34 | protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC | ||
35 | |||
36 | constructor ( | ||
37 | protected formValidatorService: FormValidatorService, | ||
38 | protected loadingBar: LoadingBarService, | ||
39 | protected notifier: Notifier, | ||
40 | protected authService: AuthService, | ||
41 | protected serverService: ServerService, | ||
42 | protected videoService: VideoService, | ||
43 | protected videoCaptionService: VideoCaptionService, | ||
44 | private router: Router, | ||
45 | private videoImportService: VideoImportService, | ||
46 | private i18n: I18n | ||
47 | ) { | ||
48 | super() | ||
49 | } | ||
50 | |||
51 | ngOnInit () { | ||
52 | super.ngOnInit() | ||
53 | } | ||
54 | |||
55 | canDeactivate () { | ||
56 | return { canDeactivate: true } | ||
57 | } | ||
58 | |||
59 | isTargetUrlValid () { | ||
60 | return this.targetUrl && this.targetUrl.match(/https?:\/\//) | ||
61 | } | ||
62 | |||
63 | importVideo () { | ||
64 | this.isImportingVideo = true | ||
65 | |||
66 | const videoUpdate: VideoUpdate = { | ||
67 | privacy: this.firstStepPrivacyId, | ||
68 | waitTranscoding: false, | ||
69 | commentsEnabled: true, | ||
70 | downloadEnabled: true, | ||
71 | channelId: this.firstStepChannelId | ||
72 | } | ||
73 | |||
74 | this.loadingBar.start() | ||
75 | |||
76 | this.videoImportService | ||
77 | .importVideoUrl(this.targetUrl, videoUpdate) | ||
78 | .pipe( | ||
79 | switchMap(res => { | ||
80 | return this.videoCaptionService | ||
81 | .listCaptions(res.video.id) | ||
82 | .pipe( | ||
83 | map(result => ({ video: res.video, videoCaptions: result.data })) | ||
84 | ) | ||
85 | }) | ||
86 | ) | ||
87 | .subscribe( | ||
88 | ({ video, videoCaptions }) => { | ||
89 | this.loadingBar.complete() | ||
90 | this.firstStepDone.emit(video.name) | ||
91 | this.isImportingVideo = false | ||
92 | this.hasImportedVideo = true | ||
93 | |||
94 | const absoluteAPIUrl = getAbsoluteAPIUrl() | ||
95 | |||
96 | const thumbnailUrl = video.thumbnailPath | ||
97 | ? absoluteAPIUrl + video.thumbnailPath | ||
98 | : null | ||
99 | |||
100 | const previewUrl = video.previewPath | ||
101 | ? absoluteAPIUrl + video.previewPath | ||
102 | : null | ||
103 | |||
104 | this.video = new VideoEdit(Object.assign(video, { | ||
105 | commentsEnabled: videoUpdate.commentsEnabled, | ||
106 | downloadEnabled: videoUpdate.downloadEnabled, | ||
107 | support: null, | ||
108 | thumbnailUrl, | ||
109 | previewUrl | ||
110 | })) | ||
111 | |||
112 | this.videoCaptions = videoCaptions | ||
113 | |||
114 | this.hydrateFormFromVideo() | ||
115 | }, | ||
116 | |||
117 | err => { | ||
118 | this.loadingBar.complete() | ||
119 | this.isImportingVideo = false | ||
120 | this.firstStepError.emit() | ||
121 | this.notifier.error(err.message) | ||
122 | } | ||
123 | ) | ||
124 | } | ||
125 | |||
126 | updateSecondStep () { | ||
127 | if (this.checkForm() === false) { | ||
128 | return | ||
129 | } | ||
130 | |||
131 | this.video.patch(this.form.value) | ||
132 | |||
133 | this.isUpdatingVideo = true | ||
134 | |||
135 | // Update the video | ||
136 | this.updateVideoAndCaptions(this.video) | ||
137 | .subscribe( | ||
138 | () => { | ||
139 | this.isUpdatingVideo = false | ||
140 | this.notifier.success(this.i18n('Video to import updated.')) | ||
141 | |||
142 | this.router.navigate([ '/my-account', 'video-imports' ]) | ||
143 | }, | ||
144 | |||
145 | err => { | ||
146 | this.error = err.message | ||
147 | scrollToTop() | ||
148 | console.error(err) | ||
149 | } | ||
150 | ) | ||
151 | |||
152 | } | ||
153 | |||
154 | private hydrateFormFromVideo () { | ||
155 | this.form.patchValue(this.video.toFormPatch()) | ||
156 | |||
157 | const objects = [ | ||
158 | { | ||
159 | url: 'thumbnailUrl', | ||
160 | name: 'thumbnailfile' | ||
161 | }, | ||
162 | { | ||
163 | url: 'previewUrl', | ||
164 | name: 'previewfile' | ||
165 | } | ||
166 | ] | ||
167 | |||
168 | for (const obj of objects) { | ||
169 | fetch(this.video[obj.url]) | ||
170 | .then(response => response.blob()) | ||
171 | .then(data => { | ||
172 | this.form.patchValue({ | ||
173 | [ obj.name ]: data | ||
174 | }) | ||
175 | }) | ||
176 | } | ||
177 | } | ||
178 | } | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-send.scss b/client/src/app/videos/+video-edit/video-add-components/video-send.scss deleted file mode 100644 index ebe14c59e..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-send.scss +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | $width-size: 190px; | ||
5 | |||
6 | .alert.alert-danger { | ||
7 | text-align: center; | ||
8 | |||
9 | & > div { | ||
10 | font-weight: $font-semibold; | ||
11 | } | ||
12 | } | ||
13 | |||
14 | .first-step-block { | ||
15 | display: flex; | ||
16 | flex-direction: column; | ||
17 | align-items: center; | ||
18 | |||
19 | .upload-icon { | ||
20 | width: 90px; | ||
21 | margin-bottom: 25px; | ||
22 | |||
23 | @include apply-svg-color(#C6C6C6); | ||
24 | } | ||
25 | |||
26 | .peertube-select-container { | ||
27 | @include peertube-select-container($width-size); | ||
28 | } | ||
29 | |||
30 | input[type=text] { | ||
31 | @include peertube-input-text($width-size); | ||
32 | display: block; | ||
33 | } | ||
34 | |||
35 | input[type=button] { | ||
36 | @include peertube-button; | ||
37 | @include orange-button; | ||
38 | |||
39 | width: $width-size; | ||
40 | margin-top: 30px; | ||
41 | } | ||
42 | |||
43 | .button-file { | ||
44 | @include peertube-button-file(max-content); | ||
45 | } | ||
46 | } | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-send.ts b/client/src/app/videos/+video-edit/video-add-components/video-send.ts deleted file mode 100644 index 94479321d..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-send.ts +++ /dev/null | |||
@@ -1,71 +0,0 @@ | |||
1 | import { catchError, switchMap, tap } from 'rxjs/operators' | ||
2 | import { EventEmitter, OnInit } from '@angular/core' | ||
3 | import { AuthService, CanComponentDeactivateResult, Notifier, ServerService } from '@app/core' | ||
4 | import { populateAsyncUserVideoChannels } from '@app/helpers' | ||
5 | import { FormReactive } from '@app/shared/shared-forms' | ||
6 | import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' | ||
7 | import { LoadingBarService } from '@ngx-loading-bar/core' | ||
8 | import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' | ||
9 | |||
10 | export abstract class VideoSend extends FormReactive implements OnInit { | ||
11 | userVideoChannels: { id: number, label: string, support: string }[] = [] | ||
12 | videoPrivacies: VideoConstant<VideoPrivacy>[] = [] | ||
13 | videoCaptions: VideoCaptionEdit[] = [] | ||
14 | |||
15 | firstStepPrivacyId = 0 | ||
16 | firstStepChannelId = 0 | ||
17 | |||
18 | abstract firstStepDone: EventEmitter<string> | ||
19 | abstract firstStepError: EventEmitter<void> | ||
20 | protected abstract readonly DEFAULT_VIDEO_PRIVACY: VideoPrivacy | ||
21 | |||
22 | protected loadingBar: LoadingBarService | ||
23 | protected notifier: Notifier | ||
24 | protected authService: AuthService | ||
25 | protected serverService: ServerService | ||
26 | protected videoService: VideoService | ||
27 | protected videoCaptionService: VideoCaptionService | ||
28 | protected serverConfig: ServerConfig | ||
29 | |||
30 | abstract canDeactivate (): CanComponentDeactivateResult | ||
31 | |||
32 | ngOnInit () { | ||
33 | this.buildForm({}) | ||
34 | |||
35 | populateAsyncUserVideoChannels(this.authService, this.userVideoChannels) | ||
36 | .then(() => this.firstStepChannelId = this.userVideoChannels[ 0 ].id) | ||
37 | |||
38 | this.serverConfig = this.serverService.getTmpConfig() | ||
39 | this.serverService.getConfig() | ||
40 | .subscribe(config => this.serverConfig = config) | ||
41 | |||
42 | this.serverService.getVideoPrivacies() | ||
43 | .subscribe( | ||
44 | privacies => { | ||
45 | this.videoPrivacies = privacies | ||
46 | |||
47 | this.firstStepPrivacyId = this.DEFAULT_VIDEO_PRIVACY | ||
48 | }) | ||
49 | } | ||
50 | |||
51 | checkForm () { | ||
52 | this.forceCheck() | ||
53 | |||
54 | return this.form.valid | ||
55 | } | ||
56 | |||
57 | protected updateVideoAndCaptions (video: VideoEdit) { | ||
58 | this.loadingBar.start() | ||
59 | |||
60 | return this.videoService.updateVideo(video) | ||
61 | .pipe( | ||
62 | // Then update captions | ||
63 | switchMap(() => this.videoCaptionService.updateCaptions(video.id, this.videoCaptions)), | ||
64 | tap(() => this.loadingBar.complete()), | ||
65 | catchError(err => { | ||
66 | this.loadingBar.complete() | ||
67 | throw err | ||
68 | }) | ||
69 | ) | ||
70 | } | ||
71 | } | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html deleted file mode 100644 index dad88a661..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
1 | <div *ngIf="!isUploadingVideo" class="upload-video-container" dragDrop (fileDropped)="setVideoFile($event)"> | ||
2 | <div class="first-step-block"> | ||
3 | <my-global-icon class="upload-icon" iconName="upload" aria-hidden="true"></my-global-icon> | ||
4 | |||
5 | <div class="button-file form-control" [ngbTooltip]="'(extensions: ' + videoExtensions + ')'"> | ||
6 | <span i18n>Select the file to upload</span> | ||
7 | <input #videofileInput type="file" name="videofile" id="videofile" [accept]="videoExtensions" (change)="fileChange()" autofocus /> | ||
8 | </div> | ||
9 | |||
10 | <div class="form-group form-group-channel"> | ||
11 | <label i18n for="first-step-channel">Channel</label> | ||
12 | <div class="peertube-select-container"> | ||
13 | <select id="first-step-channel" [(ngModel)]="firstStepChannelId" class="form-control"> | ||
14 | <option *ngFor="let channel of userVideoChannels" [value]="channel.id">{{ channel.label }}</option> | ||
15 | </select> | ||
16 | </div> | ||
17 | </div> | ||
18 | |||
19 | <div class="form-group"> | ||
20 | <label i18n for="first-step-privacy">Privacy</label> | ||
21 | <div class="peertube-select-container"> | ||
22 | <select id="first-step-privacy" [(ngModel)]="firstStepPrivacyId" class="form-control"> | ||
23 | <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option> | ||
24 | <option i18n [value]="SPECIAL_SCHEDULED_PRIVACY">Scheduled</option> | ||
25 | </select> | ||
26 | </div> | ||
27 | </div> | ||
28 | |||
29 | <ng-container *ngIf="isUploadingAudioFile"> | ||
30 | <div class="form-group audio-preview"> | ||
31 | <label i18n for="previewfileUpload">Video background image</label> | ||
32 | |||
33 | <div i18n class="audio-image-info"> | ||
34 | Image that will be merged with your audio file. | ||
35 | <br /> | ||
36 | The chosen image will be definitive and cannot be modified. | ||
37 | </div> | ||
38 | |||
39 | <my-preview-upload | ||
40 | i18n-inputLabel inputLabel="Edit" inputName="previewfileUpload" [(ngModel)]="previewfileUpload" | ||
41 | previewWidth="360px" previewHeight="200px" | ||
42 | ></my-preview-upload> | ||
43 | </div> | ||
44 | |||
45 | <div class="form-group upload-audio-button"> | ||
46 | <my-button className="orange-button" i18n-label [label]="getAudioUploadLabel()" icon="upload" (click)="uploadFirstStep(true)"></my-button> | ||
47 | </div> | ||
48 | </ng-container> | ||
49 | </div> | ||
50 | </div> | ||
51 | |||
52 | <div *ngIf="isUploadingVideo && !error" class="upload-progress-cancel"> | ||
53 | <div class="progress" i18n-title title="Total video quota"> | ||
54 | <div class="progress-bar" role="progressbar" [style]="{ width: videoUploadPercents + '%' }" [attr.aria-valuenow]="videoUploadPercents" aria-valuemin="0" [attr.aria-valuemax]="100"> | ||
55 | <span *ngIf="videoUploadPercents === 100 && videoUploaded === false" i18n>Processing…</span> | ||
56 | <span *ngIf="videoUploadPercents !== 100 || videoUploaded">{{ videoUploadPercents }}%</span> | ||
57 | </div> | ||
58 | </div> | ||
59 | <input *ngIf="videoUploaded === false" type="button" value="Cancel" (click)="cancelUpload()" /> | ||
60 | </div> | ||
61 | |||
62 | <div *ngIf="error" class="alert alert-danger"> | ||
63 | <div i18n>Sorry, but something went wrong</div> | ||
64 | {{ error }} | ||
65 | </div> | ||
66 | |||
67 | <div *ngIf="videoUploaded && !error" class="alert alert-info" i18n> | ||
68 | Congratulations! Your video is now available in your private library. | ||
69 | </div> | ||
70 | |||
71 | <!-- Hidden because we want to load the component --> | ||
72 | <form [hidden]="!isUploadingVideo" novalidate [formGroup]="form" class="mb-3"> | ||
73 | <my-video-edit | ||
74 | [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" | ||
75 | [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels" | ||
76 | [waitTranscodingEnabled]="waitTranscodingEnabled" | ||
77 | ></my-video-edit> | ||
78 | |||
79 | <div class="submit-container"> | ||
80 | <div i18n *ngIf="videoUploaded === false" class="message-submit">Publish will be available when upload is finished</div> | ||
81 | |||
82 | <div class="submit-button" | ||
83 | (click)="updateSecondStep()" | ||
84 | [ngClass]="{ disabled: isPublishingButtonDisabled() }" | ||
85 | > | ||
86 | <my-global-icon iconName="validate" aria-hidden="true"></my-global-icon> | ||
87 | <input [disabled]="isPublishingButtonDisabled()" type="button" i18n-value value="Publish" /> | ||
88 | </div> | ||
89 | </div> | ||
90 | </form> | ||
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss deleted file mode 100644 index a4f87b0b8..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | @import 'variables'; | ||
2 | @import 'mixins'; | ||
3 | |||
4 | .first-step-block { | ||
5 | .form-group-channel { | ||
6 | margin-bottom: 20px; | ||
7 | margin-top: 35px; | ||
8 | } | ||
9 | |||
10 | .audio-image-info { | ||
11 | margin-bottom: 10px; | ||
12 | } | ||
13 | |||
14 | .audio-preview { | ||
15 | margin: 30px 0; | ||
16 | } | ||
17 | } | ||
18 | |||
19 | .upload-progress-cancel { | ||
20 | display: flex; | ||
21 | margin-top: 25px; | ||
22 | margin-bottom: 40px; | ||
23 | |||
24 | .progress { | ||
25 | @include progressbar; | ||
26 | flex-grow: 1; | ||
27 | height: 30px; | ||
28 | font-size: 15px; | ||
29 | background-color: rgba(11, 204, 41, 0.16); | ||
30 | |||
31 | .progress-bar { | ||
32 | background-color: $green; | ||
33 | line-height: 30px; | ||
34 | text-align: left; | ||
35 | font-weight: $font-bold; | ||
36 | |||
37 | span { | ||
38 | margin-left: 18px; | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | input { | ||
44 | @include peertube-button; | ||
45 | @include grey-button; | ||
46 | |||
47 | margin-left: 10px; | ||
48 | } | ||
49 | } | ||
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 deleted file mode 100644 index eb7ac32ae..000000000 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts +++ /dev/null | |||
@@ -1,306 +0,0 @@ | |||
1 | import { BytesPipe } from 'ngx-pipes' | ||
2 | import { Subscription } from 'rxjs' | ||
3 | import { HttpEventType, HttpResponse } from '@angular/common/http' | ||
4 | import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' | ||
5 | import { Router } from '@angular/router' | ||
6 | import { AuthService, CanComponentDeactivate, Notifier, ServerService, UserService } from '@app/core' | ||
7 | import { scrollToTop } from '@app/helpers' | ||
8 | import { FormValidatorService } from '@app/shared/shared-forms' | ||
9 | import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' | ||
10 | import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-send' | ||
11 | import { LoadingBarService } from '@ngx-loading-bar/core' | ||
12 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
13 | import { VideoPrivacy } from '@shared/models' | ||
14 | |||
15 | @Component({ | ||
16 | selector: 'my-video-upload', | ||
17 | templateUrl: './video-upload.component.html', | ||
18 | styleUrls: [ | ||
19 | '../shared/video-edit.component.scss', | ||
20 | './video-upload.component.scss', | ||
21 | './video-send.scss' | ||
22 | ] | ||
23 | }) | ||
24 | export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { | ||
25 | @Output() firstStepDone = new EventEmitter<string>() | ||
26 | @Output() firstStepError = new EventEmitter<void>() | ||
27 | @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement> | ||
28 | |||
29 | // So that it can be accessed in the template | ||
30 | readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY | ||
31 | |||
32 | userVideoQuotaUsed = 0 | ||
33 | userVideoQuotaUsedDaily = 0 | ||
34 | |||
35 | isUploadingAudioFile = false | ||
36 | isUploadingVideo = false | ||
37 | isUpdatingVideo = false | ||
38 | |||
39 | videoUploaded = false | ||
40 | videoUploadObservable: Subscription = null | ||
41 | videoUploadPercents = 0 | ||
42 | videoUploadedIds = { | ||
43 | id: 0, | ||
44 | uuid: '' | ||
45 | } | ||
46 | |||
47 | waitTranscodingEnabled = true | ||
48 | previewfileUpload: File | ||
49 | |||
50 | error: string | ||
51 | |||
52 | protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC | ||
53 | |||
54 | constructor ( | ||
55 | protected formValidatorService: FormValidatorService, | ||
56 | protected loadingBar: LoadingBarService, | ||
57 | protected notifier: Notifier, | ||
58 | protected authService: AuthService, | ||
59 | protected serverService: ServerService, | ||
60 | protected videoService: VideoService, | ||
61 | protected videoCaptionService: VideoCaptionService, | ||
62 | private userService: UserService, | ||
63 | private router: Router, | ||
64 | private i18n: I18n | ||
65 | ) { | ||
66 | super() | ||
67 | } | ||
68 | |||
69 | get videoExtensions () { | ||
70 | return this.serverConfig.video.file.extensions.join(', ') | ||
71 | } | ||
72 | |||
73 | ngOnInit () { | ||
74 | super.ngOnInit() | ||
75 | |||
76 | this.userService.getMyVideoQuotaUsed() | ||
77 | .subscribe(data => { | ||
78 | this.userVideoQuotaUsed = data.videoQuotaUsed | ||
79 | this.userVideoQuotaUsedDaily = data.videoQuotaUsedDaily | ||
80 | }) | ||
81 | } | ||
82 | |||
83 | ngOnDestroy () { | ||
84 | if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe() | ||
85 | } | ||
86 | |||
87 | canDeactivate () { | ||
88 | let text = '' | ||
89 | |||
90 | if (this.videoUploaded === true) { | ||
91 | // FIXME: cannot concatenate strings inside i18n service :/ | ||
92 | text = this.i18n('Your video was uploaded to your account and is private.') + ' ' + | ||
93 | this.i18n('But associated data (tags, description...) will be lost, are you sure you want to leave this page?') | ||
94 | } else { | ||
95 | text = this.i18n('Your video is not uploaded yet, are you sure you want to leave this page?') | ||
96 | } | ||
97 | |||
98 | return { | ||
99 | canDeactivate: !this.isUploadingVideo, | ||
100 | text | ||
101 | } | ||
102 | } | ||
103 | |||
104 | getVideoFile () { | ||
105 | return this.videofileInput.nativeElement.files[0] | ||
106 | } | ||
107 | |||
108 | setVideoFile (files: FileList) { | ||
109 | this.videofileInput.nativeElement.files = files | ||
110 | this.fileChange() | ||
111 | } | ||
112 | |||
113 | getAudioUploadLabel () { | ||
114 | const videofile = this.getVideoFile() | ||
115 | if (!videofile) return this.i18n('Upload') | ||
116 | |||
117 | return this.i18n('Upload {{videofileName}}', { videofileName: videofile.name }) | ||
118 | } | ||
119 | |||
120 | fileChange () { | ||
121 | this.uploadFirstStep() | ||
122 | } | ||
123 | |||
124 | cancelUpload () { | ||
125 | if (this.videoUploadObservable !== null) { | ||
126 | this.videoUploadObservable.unsubscribe() | ||
127 | |||
128 | this.isUploadingVideo = false | ||
129 | this.videoUploadPercents = 0 | ||
130 | this.videoUploadObservable = null | ||
131 | |||
132 | this.firstStepError.emit() | ||
133 | |||
134 | this.notifier.info(this.i18n('Upload cancelled')) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | uploadFirstStep (clickedOnButton = false) { | ||
139 | const videofile = this.getVideoFile() | ||
140 | if (!videofile) return | ||
141 | |||
142 | if (!this.checkGlobalUserQuota(videofile)) return | ||
143 | if (!this.checkDailyUserQuota(videofile)) return | ||
144 | |||
145 | if (clickedOnButton === false && this.isAudioFile(videofile.name)) { | ||
146 | this.isUploadingAudioFile = true | ||
147 | return | ||
148 | } | ||
149 | |||
150 | // Build name field | ||
151 | const nameWithoutExtension = videofile.name.replace(/\.[^/.]+$/, '') | ||
152 | let name: string | ||
153 | |||
154 | // If the name of the file is very small, keep the extension | ||
155 | if (nameWithoutExtension.length < 3) name = videofile.name | ||
156 | else name = nameWithoutExtension | ||
157 | |||
158 | // Force user to wait transcoding for unsupported video types in web browsers | ||
159 | if (!videofile.name.endsWith('.mp4') && !videofile.name.endsWith('.webm') && !videofile.name.endsWith('.ogv')) { | ||
160 | this.waitTranscodingEnabled = false | ||
161 | } | ||
162 | |||
163 | const privacy = this.firstStepPrivacyId.toString() | ||
164 | const nsfw = this.serverConfig.instance.isNSFW | ||
165 | const waitTranscoding = true | ||
166 | const commentsEnabled = true | ||
167 | const downloadEnabled = true | ||
168 | const channelId = this.firstStepChannelId.toString() | ||
169 | |||
170 | const formData = new FormData() | ||
171 | formData.append('name', name) | ||
172 | // Put the video "private" -> we are waiting the user validation of the second step | ||
173 | formData.append('privacy', VideoPrivacy.PRIVATE.toString()) | ||
174 | formData.append('nsfw', '' + nsfw) | ||
175 | formData.append('commentsEnabled', '' + commentsEnabled) | ||
176 | formData.append('downloadEnabled', '' + downloadEnabled) | ||
177 | formData.append('waitTranscoding', '' + waitTranscoding) | ||
178 | formData.append('channelId', '' + channelId) | ||
179 | formData.append('videofile', videofile) | ||
180 | |||
181 | if (this.previewfileUpload) { | ||
182 | formData.append('previewfile', this.previewfileUpload) | ||
183 | formData.append('thumbnailfile', this.previewfileUpload) | ||
184 | } | ||
185 | |||
186 | this.isUploadingVideo = true | ||
187 | this.firstStepDone.emit(name) | ||
188 | |||
189 | this.form.patchValue({ | ||
190 | name, | ||
191 | privacy, | ||
192 | nsfw, | ||
193 | channelId, | ||
194 | previewfile: this.previewfileUpload | ||
195 | }) | ||
196 | |||
197 | this.videoUploadObservable = this.videoService.uploadVideo(formData).subscribe( | ||
198 | event => { | ||
199 | if (event.type === HttpEventType.UploadProgress) { | ||
200 | this.videoUploadPercents = Math.round(100 * event.loaded / event.total) | ||
201 | } else if (event instanceof HttpResponse) { | ||
202 | this.videoUploaded = true | ||
203 | |||
204 | this.videoUploadedIds = event.body.video | ||
205 | |||
206 | this.videoUploadObservable = null | ||
207 | } | ||
208 | }, | ||
209 | |||
210 | err => { | ||
211 | // Reset progress | ||
212 | this.isUploadingVideo = false | ||
213 | this.videoUploadPercents = 0 | ||
214 | this.videoUploadObservable = null | ||
215 | this.firstStepError.emit() | ||
216 | this.notifier.error(err.message) | ||
217 | } | ||
218 | ) | ||
219 | } | ||
220 | |||
221 | isPublishingButtonDisabled () { | ||
222 | return !this.form.valid || | ||
223 | this.isUpdatingVideo === true || | ||
224 | this.videoUploaded !== true | ||
225 | } | ||
226 | |||
227 | updateSecondStep () { | ||
228 | if (this.checkForm() === false) { | ||
229 | return | ||
230 | } | ||
231 | |||
232 | const video = new VideoEdit() | ||
233 | video.patch(this.form.value) | ||
234 | video.id = this.videoUploadedIds.id | ||
235 | video.uuid = this.videoUploadedIds.uuid | ||
236 | |||
237 | this.isUpdatingVideo = true | ||
238 | |||
239 | this.updateVideoAndCaptions(video) | ||
240 | .subscribe( | ||
241 | () => { | ||
242 | this.isUpdatingVideo = false | ||
243 | this.isUploadingVideo = false | ||
244 | |||
245 | this.notifier.success(this.i18n('Video published.')) | ||
246 | this.router.navigate([ '/videos/watch', video.uuid ]) | ||
247 | }, | ||
248 | |||
249 | err => { | ||
250 | this.error = err.message | ||
251 | scrollToTop() | ||
252 | console.error(err) | ||
253 | } | ||
254 | ) | ||
255 | } | ||
256 | |||
257 | private checkGlobalUserQuota (videofile: File) { | ||
258 | const bytePipes = new BytesPipe() | ||
259 | |||
260 | // Check global user quota | ||
261 | const videoQuota = this.authService.getUser().videoQuota | ||
262 | if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) { | ||
263 | const msg = this.i18n( | ||
264 | 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})', | ||
265 | { | ||
266 | videoSize: bytePipes.transform(videofile.size, 0), | ||
267 | videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0), | ||
268 | videoQuota: bytePipes.transform(videoQuota, 0) | ||
269 | } | ||
270 | ) | ||
271 | this.notifier.error(msg) | ||
272 | |||
273 | return false | ||
274 | } | ||
275 | |||
276 | return true | ||
277 | } | ||
278 | |||
279 | private checkDailyUserQuota (videofile: File) { | ||
280 | const bytePipes = new BytesPipe() | ||
281 | |||
282 | // Check daily user quota | ||
283 | const videoQuotaDaily = this.authService.getUser().videoQuotaDaily | ||
284 | if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) { | ||
285 | const msg = this.i18n( | ||
286 | 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})', | ||
287 | { | ||
288 | videoSize: bytePipes.transform(videofile.size, 0), | ||
289 | quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0), | ||
290 | quotaDaily: bytePipes.transform(videoQuotaDaily, 0) | ||
291 | } | ||
292 | ) | ||
293 | this.notifier.error(msg) | ||
294 | |||
295 | return false | ||
296 | } | ||
297 | |||
298 | return true | ||
299 | } | ||
300 | |||
301 | private isAudioFile (filename: string) { | ||
302 | const extensions = [ '.mp3', '.flac', '.ogg', '.wma', '.wav' ] | ||
303 | |||
304 | return extensions.some(e => filename.endsWith(e)) | ||
305 | } | ||
306 | } | ||