aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos/+video-edit/video-add-components
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-02-11 11:52:34 +0100
committerChocobozzz <me@florianbigard.com>2019-02-11 11:52:34 +0100
commit88108880bbdba473cfe36ecbebc1c3c4f972e102 (patch)
treeb242efb3b4f0d7e49d88f2d1f2063b5b3b0489c0 /client/src/app/videos/+video-edit/video-add-components
parent53a94c7cfa8368da4cd248d65df8346905938f0c (diff)
parent9b712a2017e4ab3cf12cd6bd58278905520159d0 (diff)
downloadPeerTube-88108880bbdba473cfe36ecbebc1c3c4f972e102.tar.gz
PeerTube-88108880bbdba473cfe36ecbebc1c3c4f972e102.tar.zst
PeerTube-88108880bbdba473cfe36ecbebc1c3c4f972e102.zip
Merge branch 'develop' into pr/1217
Diffstat (limited to 'client/src/app/videos/+video-edit/video-add-components')
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html13
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.scss45
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts27
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html14
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-url.component.scss37
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts20
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-send.scss54
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-send.ts12
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.html22
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss42
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts48
11 files changed, 156 insertions, 178 deletions
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
index a933a64f0..28eb143c9 100644
--- 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
@@ -1,6 +1,6 @@
1<div *ngIf="!hasImportedVideo" class="upload-video-container"> 1<div *ngIf="!hasImportedVideo" class="upload-video-container">
2 <div class="import-video-torrent"> 2 <div class="first-step-block">
3 <div class="icon icon-upload"></div> 3 <my-global-icon class="upload-icon" iconName="upload"></my-global-icon>
4 4
5 <div class="button-file"> 5 <div class="button-file">
6 <span i18n>Select the torrent to import</span> 6 <span i18n>Select the torrent to import</span>
@@ -45,7 +45,12 @@
45 </div> 45 </div>
46</div> 46</div>
47 47
48<div *ngIf="hasImportedVideo" class="alert alert-info" i18n> 48<div *ngIf="error" class="alert alert-danger">
49 <div i18n>Sorry, but something went wrong</div>
50 {{ error }}
51</div>
52
53<div *ngIf="hasImportedVideo && !error" class="alert alert-info" i18n>
49 Congratulations, the video will be imported with BitTorrent! You can already add information about this video. 54 Congratulations, the video will be imported with BitTorrent! You can already add information about this video.
50</div> 55</div>
51 56
@@ -61,7 +66,7 @@
61 (click)="updateSecondStep()" 66 (click)="updateSecondStep()"
62 [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }" 67 [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }"
63 > 68 >
64 <span class="icon icon-validate"></span> 69 <my-global-icon iconName="validate"></my-global-icon>
65 <input type="button" i18n-value value="Update" /> 70 <input type="button" i18n-value value="Update" />
66 </div> 71 </div>
67 </div> 72 </div>
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
index 262b0b68e..6d59ed834 100644
--- 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
@@ -1,37 +1,7 @@
1@import 'variables'; 1@import 'variables';
2@import 'mixins'; 2@import 'mixins';
3 3
4$width-size: 190px; 4.first-step-block {
5
6.peertube-select-container {
7 @include peertube-select-container($width-size);
8}
9
10.import-video-torrent {
11 display: flex;
12 flex-direction: column;
13 align-items: center;
14
15 .icon.icon-upload {
16 @include icon(90px);
17 margin-bottom: 25px;
18 cursor: default;
19
20 background-image: url('../../../../assets/images/video/upload.svg');
21 }
22
23 .button-file {
24 @include peertube-button-file(auto);
25
26 min-width: 190px;
27 }
28
29 .button-file-extension {
30 display: block;
31 font-size: 12px;
32 margin-top: 5px;
33 }
34
35 .torrent-or-magnet { 5 .torrent-or-magnet {
36 margin: 10px 0; 6 margin: 10px 0;
37 } 7 }
@@ -39,19 +9,6 @@ $width-size: 190px;
39 .form-group-magnet-uri { 9 .form-group-magnet-uri {
40 margin-bottom: 40px; 10 margin-bottom: 40px;
41 } 11 }
42
43 input[type=text] {
44 @include peertube-input-text($width-size);
45 display: block;
46 }
47
48 input[type=button] {
49 @include peertube-button;
50 @include orange-button;
51
52 width: $width-size;
53 margin-top: 30px;
54 }
55} 12}
56 13
57 14
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
index 0f6fd17a9..c12a1d653 100644
--- 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
@@ -1,8 +1,7 @@
1import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' 1import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications'
4import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' 3import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos'
5import { AuthService, ServerService } from '../../../core' 4import { AuthService, Notifier, ServerService } from '../../../core'
6import { VideoService } from '../../../shared/video/video.service' 5import { VideoService } from '../../../shared/video/video.service'
7import { I18n } from '@ngx-translate/i18n-polyfill' 6import { I18n } from '@ngx-translate/i18n-polyfill'
8import { LoadingBarService } from '@ngx-loading-bar/core' 7import { LoadingBarService } from '@ngx-loading-bar/core'
@@ -12,20 +11,22 @@ import { VideoEdit } from '@app/shared/video/video-edit.model'
12import { FormValidatorService } from '@app/shared' 11import { FormValidatorService } from '@app/shared'
13import { VideoCaptionService } from '@app/shared/video-caption' 12import { VideoCaptionService } from '@app/shared/video-caption'
14import { VideoImportService } from '@app/shared/video-import' 13import { VideoImportService } from '@app/shared/video-import'
14import { scrollToTop } from '@app/shared/misc/utils'
15 15
16@Component({ 16@Component({
17 selector: 'my-video-import-torrent', 17 selector: 'my-video-import-torrent',
18 templateUrl: './video-import-torrent.component.html', 18 templateUrl: './video-import-torrent.component.html',
19 styleUrls: [ 19 styleUrls: [
20 '../shared/video-edit.component.scss', 20 '../shared/video-edit.component.scss',
21 './video-import-torrent.component.scss' 21 './video-import-torrent.component.scss',
22 './video-send.scss'
22 ] 23 ]
23}) 24})
24export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { 25export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate {
25 @Output() firstStepDone = new EventEmitter<string>() 26 @Output() firstStepDone = new EventEmitter<string>()
26 @ViewChild('torrentfileInput') torrentfileInput 27 @Output() firstStepError = new EventEmitter<void>()
28 @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement>
27 29
28 videoFileName: string
29 magnetUri = '' 30 magnetUri = ''
30 31
31 isImportingVideo = false 32 isImportingVideo = false
@@ -33,13 +34,14 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
33 isUpdatingVideo = false 34 isUpdatingVideo = false
34 35
35 video: VideoEdit 36 video: VideoEdit
37 error: string
36 38
37 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC 39 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
38 40
39 constructor ( 41 constructor (
40 protected formValidatorService: FormValidatorService, 42 protected formValidatorService: FormValidatorService,
41 protected loadingBar: LoadingBarService, 43 protected loadingBar: LoadingBarService,
42 protected notificationsService: NotificationsService, 44 protected notifier: Notifier,
43 protected authService: AuthService, 45 protected authService: AuthService,
44 protected serverService: ServerService, 46 protected serverService: ServerService,
45 protected videoService: VideoService, 47 protected videoService: VideoService,
@@ -64,7 +66,7 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
64 } 66 }
65 67
66 fileChange () { 68 fileChange () {
67 const torrentfile = this.torrentfileInput.nativeElement.files[0] as File 69 const torrentfile = this.torrentfileInput.nativeElement.files[0]
68 if (!torrentfile) return 70 if (!torrentfile) return
69 71
70 this.importVideo(torrentfile) 72 this.importVideo(torrentfile)
@@ -106,7 +108,8 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
106 err => { 108 err => {
107 this.loadingBar.complete() 109 this.loadingBar.complete()
108 this.isImportingVideo = false 110 this.isImportingVideo = false
109 this.notificationsService.error(this.i18n('Error'), err.message) 111 this.firstStepError.emit()
112 this.notifier.error(err.message)
110 } 113 }
111 ) 114 )
112 } 115 }
@@ -125,14 +128,14 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
125 .subscribe( 128 .subscribe(
126 () => { 129 () => {
127 this.isUpdatingVideo = false 130 this.isUpdatingVideo = false
128 this.notificationsService.success(this.i18n('Success'), this.i18n('Video to import updated.')) 131 this.notifier.success(this.i18n('Video to import updated.'))
129 132
130 this.router.navigate([ '/my-account', 'video-imports' ]) 133 this.router.navigate([ '/my-account', 'video-imports' ])
131 }, 134 },
132 135
133 err => { 136 err => {
134 this.isUpdatingVideo = false 137 this.error = err.message
135 this.notificationsService.error(this.i18n('Error'), err.message) 138 scrollToTop()
136 console.error(err) 139 console.error(err)
137 } 140 }
138 ) 141 )
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
index 9f5fc6d22..3550c3585 100644
--- 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
@@ -1,6 +1,6 @@
1<div *ngIf="!hasImportedVideo" class="upload-video-container"> 1<div *ngIf="!hasImportedVideo" class="upload-video-container">
2 <div class="import-video-url"> 2 <div class="first-step-block">
3 <div class="icon icon-upload"></div> 3 <my-global-icon class="upload-icon" iconName="upload"></my-global-icon>
4 4
5 <div class="form-group"> 5 <div class="form-group">
6 <label i18n for="targetUrl">URL</label> 6 <label i18n for="targetUrl">URL</label>
@@ -37,7 +37,13 @@
37 </div> 37 </div>
38</div> 38</div>
39 39
40<div *ngIf="hasImportedVideo" class="alert alert-info" i18n> 40
41<div *ngIf="error" class="alert alert-danger">
42 <div i18n>Sorry, but something went wrong</div>
43 {{ error }}
44</div>
45
46<div *ngIf="!error && hasImportedVideo" class="alert alert-info" i18n>
41 Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video. 47 Congratulations, the video behind {{ targetUrl }} will be imported! You can already add information about this video.
42</div> 48</div>
43 49
@@ -53,7 +59,7 @@
53 (click)="updateSecondStep()" 59 (click)="updateSecondStep()"
54 [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }" 60 [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }"
55 > 61 >
56 <span class="icon icon-validate"></span> 62 <my-global-icon iconName="validate"></my-global-icon>
57 <input type="button" i18n-value value="Update" /> 63 <input type="button" i18n-value value="Update" />
58 </div> 64 </div>
59 </div> 65 </div>
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.scss b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.scss
deleted file mode 100644
index 7c6deda1d..000000000
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.scss
+++ /dev/null
@@ -1,37 +0,0 @@
1@import 'variables';
2@import 'mixins';
3
4$width-size: 190px;
5
6.peertube-select-container {
7 @include peertube-select-container($width-size);
8}
9
10.import-video-url {
11 display: flex;
12 flex-direction: column;
13 align-items: center;
14
15 .icon.icon-upload {
16 @include icon(90px);
17 margin-bottom: 25px;
18 cursor: default;
19
20 background-image: url('../../../../assets/images/video/upload.svg');
21 }
22
23 input[type=text] {
24 @include peertube-input-text($width-size);
25 display: block;
26 }
27
28 input[type=button] {
29 @include peertube-button;
30 @include orange-button;
31
32 width: $width-size;
33 margin-top: 30px;
34 }
35}
36
37
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
index fbc85c74f..d11685916 100644
--- 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
@@ -1,8 +1,7 @@
1import { Component, EventEmitter, OnInit, Output } from '@angular/core' 1import { Component, EventEmitter, OnInit, Output } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications'
4import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' 3import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos'
5import { AuthService, ServerService } from '../../../core' 4import { AuthService, Notifier, ServerService } from '../../../core'
6import { VideoService } from '../../../shared/video/video.service' 5import { VideoService } from '../../../shared/video/video.service'
7import { I18n } from '@ngx-translate/i18n-polyfill' 6import { I18n } from '@ngx-translate/i18n-polyfill'
8import { LoadingBarService } from '@ngx-loading-bar/core' 7import { LoadingBarService } from '@ngx-loading-bar/core'
@@ -12,33 +11,35 @@ import { VideoEdit } from '@app/shared/video/video-edit.model'
12import { FormValidatorService } from '@app/shared' 11import { FormValidatorService } from '@app/shared'
13import { VideoCaptionService } from '@app/shared/video-caption' 12import { VideoCaptionService } from '@app/shared/video-caption'
14import { VideoImportService } from '@app/shared/video-import' 13import { VideoImportService } from '@app/shared/video-import'
14import { scrollToTop } from '@app/shared/misc/utils'
15 15
16@Component({ 16@Component({
17 selector: 'my-video-import-url', 17 selector: 'my-video-import-url',
18 templateUrl: './video-import-url.component.html', 18 templateUrl: './video-import-url.component.html',
19 styleUrls: [ 19 styleUrls: [
20 '../shared/video-edit.component.scss', 20 '../shared/video-edit.component.scss',
21 './video-import-url.component.scss' 21 './video-send.scss'
22 ] 22 ]
23}) 23})
24export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { 24export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate {
25 @Output() firstStepDone = new EventEmitter<string>() 25 @Output() firstStepDone = new EventEmitter<string>()
26 @Output() firstStepError = new EventEmitter<void>()
26 27
27 targetUrl = '' 28 targetUrl = ''
28 videoFileName: string
29 29
30 isImportingVideo = false 30 isImportingVideo = false
31 hasImportedVideo = false 31 hasImportedVideo = false
32 isUpdatingVideo = false 32 isUpdatingVideo = false
33 33
34 video: VideoEdit 34 video: VideoEdit
35 error: string
35 36
36 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC 37 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
37 38
38 constructor ( 39 constructor (
39 protected formValidatorService: FormValidatorService, 40 protected formValidatorService: FormValidatorService,
40 protected loadingBar: LoadingBarService, 41 protected loadingBar: LoadingBarService,
41 protected notificationsService: NotificationsService, 42 protected notifier: Notifier,
42 protected authService: AuthService, 43 protected authService: AuthService,
43 protected serverService: ServerService, 44 protected serverService: ServerService,
44 protected videoService: VideoService, 45 protected videoService: VideoService,
@@ -98,7 +99,8 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
98 err => { 99 err => {
99 this.loadingBar.complete() 100 this.loadingBar.complete()
100 this.isImportingVideo = false 101 this.isImportingVideo = false
101 this.notificationsService.error(this.i18n('Error'), err.message) 102 this.firstStepError.emit()
103 this.notifier.error(err.message)
102 } 104 }
103 ) 105 )
104 } 106 }
@@ -117,14 +119,14 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
117 .subscribe( 119 .subscribe(
118 () => { 120 () => {
119 this.isUpdatingVideo = false 121 this.isUpdatingVideo = false
120 this.notificationsService.success(this.i18n('Success'), this.i18n('Video to import updated.')) 122 this.notifier.success(this.i18n('Video to import updated.'))
121 123
122 this.router.navigate([ '/my-account', 'video-imports' ]) 124 this.router.navigate([ '/my-account', 'video-imports' ])
123 }, 125 },
124 126
125 err => { 127 err => {
126 this.isUpdatingVideo = false 128 this.error = err.message
127 this.notificationsService.error(this.i18n('Error'), err.message) 129 scrollToTop()
128 console.error(err) 130 console.error(err)
129 } 131 }
130 ) 132 )
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
new file mode 100644
index 000000000..8769dd302
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-add-components/video-send.scss
@@ -0,0 +1,54 @@
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(auto);
45
46 min-width: 190px;
47 }
48
49 .button-file-extension {
50 display: block;
51 font-size: 12px;
52 margin-top: 5px;
53 }
54}
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
index 6d1bac3f2..580c123a0 100644
--- 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
@@ -1,18 +1,17 @@
1import { EventEmitter, OnInit } from '@angular/core' 1import { EventEmitter, OnInit } from '@angular/core'
2import { LoadingBarService } from '@ngx-loading-bar/core' 2import { LoadingBarService } from '@ngx-loading-bar/core'
3import { NotificationsService } from 'angular2-notifications' 3import { AuthService, Notifier, ServerService } from '@app/core'
4import { catchError, switchMap, tap } from 'rxjs/operators' 4import { catchError, switchMap, tap } from 'rxjs/operators'
5import { FormReactive } from '@app/shared' 5import { FormReactive } from '@app/shared'
6import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service'
7import { VideoConstant, VideoPrivacy } from '../../../../../../shared' 6import { VideoConstant, VideoPrivacy } from '../../../../../../shared'
8import { AuthService, ServerService } from '@app/core'
9import { VideoService } from '@app/shared/video/video.service' 7import { VideoService } from '@app/shared/video/video.service'
10import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' 8import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
11import { VideoCaptionService } from '@app/shared/video-caption' 9import { VideoCaptionService } from '@app/shared/video-caption'
12import { VideoEdit } from '@app/shared/video/video-edit.model' 10import { VideoEdit } from '@app/shared/video/video-edit.model'
13import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' 11import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
12import { CanComponentDeactivateResult } from '@app/shared/guards/can-deactivate-guard.service'
14 13
15export abstract class VideoSend extends FormReactive implements OnInit, CanComponentDeactivate { 14export abstract class VideoSend extends FormReactive implements OnInit {
16 userVideoChannels: { id: number, label: string, support: string }[] = [] 15 userVideoChannels: { id: number, label: string, support: string }[] = []
17 videoPrivacies: VideoConstant<VideoPrivacy>[] = [] 16 videoPrivacies: VideoConstant<VideoPrivacy>[] = []
18 videoCaptions: VideoCaptionEdit[] = [] 17 videoCaptions: VideoCaptionEdit[] = []
@@ -21,16 +20,17 @@ export abstract class VideoSend extends FormReactive implements OnInit, CanCompo
21 firstStepChannelId = 0 20 firstStepChannelId = 0
22 21
23 abstract firstStepDone: EventEmitter<string> 22 abstract firstStepDone: EventEmitter<string>
23 abstract firstStepError: EventEmitter<void>
24 protected abstract readonly DEFAULT_VIDEO_PRIVACY: VideoPrivacy 24 protected abstract readonly DEFAULT_VIDEO_PRIVACY: VideoPrivacy
25 25
26 protected loadingBar: LoadingBarService 26 protected loadingBar: LoadingBarService
27 protected notificationsService: NotificationsService 27 protected notifier: Notifier
28 protected authService: AuthService 28 protected authService: AuthService
29 protected serverService: ServerService 29 protected serverService: ServerService
30 protected videoService: VideoService 30 protected videoService: VideoService
31 protected videoCaptionService: VideoCaptionService 31 protected videoCaptionService: VideoCaptionService
32 32
33 abstract canDeactivate () 33 abstract canDeactivate (): CanComponentDeactivateResult
34 34
35 ngOnInit () { 35 ngOnInit () {
36 this.buildForm({}) 36 this.buildForm({})
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
index fa57c8cb5..b252cd60a 100644
--- 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
@@ -1,12 +1,12 @@
1<div *ngIf="!isUploadingVideo" class="upload-video-container"> 1<div *ngIf="!isUploadingVideo" class="upload-video-container">
2 <div class="upload-video"> 2 <div class="first-step-block">
3 <div class="icon icon-upload"></div> 3 <my-global-icon class="upload-icon" iconName="upload"></my-global-icon>
4 4
5 <div class="button-file"> 5 <div class="button-file">
6 <span i18n>Select the file to upload</span> 6 <span i18n>Select the file to upload</span>
7 <input #videofileInput type="file" name="videofile" id="videofile" [accept]="videoExtensions" (change)="fileChange()" /> 7 <input #videofileInput type="file" name="videofile" id="videofile" [accept]="videoExtensions" (change)="fileChange()" />
8 </div> 8 </div>
9 <span class="button-file-extension">(.mp4, .webm, .ogv)</span> 9 <span class="button-file-extension">({{ videoExtensions }})</span>
10 10
11 <div class="form-group form-group-channel"> 11 <div class="form-group form-group-channel">
12 <label i18n for="first-step-channel">Channel</label> 12 <label i18n for="first-step-channel">Channel</label>
@@ -29,7 +29,7 @@
29 </div> 29 </div>
30</div> 30</div>
31 31
32<div *ngIf="isUploadingVideo" class="upload-progress-cancel"> 32<div *ngIf="isUploadingVideo && !error" class="upload-progress-cancel">
33 <p-progressBar 33 <p-progressBar
34 [value]="videoUploadPercents" 34 [value]="videoUploadPercents"
35 [ngClass]="{ processing: videoUploadPercents === 100 && videoUploaded === false }" 35 [ngClass]="{ processing: videoUploadPercents === 100 && videoUploaded === false }"
@@ -37,11 +37,21 @@
37 <input *ngIf="videoUploaded === false" type="button" value="Cancel" (click)="cancelUpload()" /> 37 <input *ngIf="videoUploaded === false" type="button" value="Cancel" (click)="cancelUpload()" />
38</div> 38</div>
39 39
40<div *ngIf="error" class="alert alert-danger">
41 <div i18n>Sorry, but something went wrong</div>
42 {{ error }}
43</div>
44
45<div *ngIf="videoUploaded && !error" class="alert alert-info" i18n>
46 Congratulations! Your video is now available in your private library.
47</div>
48
40<!-- Hidden because we want to load the component --> 49<!-- Hidden because we want to load the component -->
41<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form"> 50<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form">
42 <my-video-edit 51 <my-video-edit
43 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" 52 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions"
44 [validationMessages]="validationMessages" [videoPrivacies]="videoPrivacies" [userVideoChannels]="userVideoChannels" 53 [validationMessages]="validationMessages" [videoPrivacies]="videoPrivacies" [userVideoChannels]="userVideoChannels"
54 [waitTranscodingEnabled]="waitTranscodingEnabled"
45 ></my-video-edit> 55 ></my-video-edit>
46 56
47 <div class="submit-container"> 57 <div class="submit-container">
@@ -51,8 +61,8 @@
51 (click)="updateSecondStep()" 61 (click)="updateSecondStep()"
52 [ngClass]="{ disabled: isPublishingButtonDisabled() }" 62 [ngClass]="{ disabled: isPublishingButtonDisabled() }"
53 > 63 >
54 <span class="icon icon-validate"></span> 64 <my-global-icon iconName="validate"></my-global-icon>
55 <input [disabled]="isPublishingButtonDisabled()" type="button" i18n-value value="Publish" /> 65 <input [disabled]="isPublishingButtonDisabled()" type="button" i18n-value value="Publish" />
56 </div> 66 </div>
57 </div> 67 </div>
58</form> \ No newline at end of file 68</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
index dbae5230d..8adf8f169 100644
--- 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
@@ -1,39 +1,9 @@
1@import 'variables'; 1@import 'variables';
2@import 'mixins'; 2@import 'mixins';
3 3
4.peertube-select-container { 4.first-step-block .form-group-channel {
5 @include peertube-select-container(190px); 5 margin-bottom: 20px;
6} 6 margin-top: 35px;
7
8.upload-video {
9 display: flex;
10 flex-direction: column;
11 align-items: center;
12
13 .form-group-channel {
14 margin-bottom: 20px;
15 margin-top: 35px;
16 }
17
18 .icon.icon-upload {
19 @include icon(90px);
20 margin-bottom: 25px;
21 cursor: default;
22
23 background-image: url('../../../../assets/images/video/upload.svg');
24 }
25
26 .button-file {
27 @include peertube-button-file(auto);
28
29 min-width: 190px;
30 }
31
32 .button-file-extension {
33 display: block;
34 font-size: 12px;
35 margin-top: 5px;
36 }
37} 7}
38 8
39.upload-progress-cancel { 9.upload-progress-cancel {
@@ -46,9 +16,7 @@
46 16
47 /deep/ .ui-progressbar { 17 /deep/ .ui-progressbar {
48 font-size: 15px !important; 18 font-size: 15px !important;
49 color: #fff !important;
50 height: 30px !important; 19 height: 30px !important;
51 line-height: 30px !important;
52 border-radius: 3px !important; 20 border-radius: 3px !important;
53 background-color: rgba(11, 204, 41, 0.16) !important; 21 background-color: rgba(11, 204, 41, 0.16) !important;
54 22
@@ -60,6 +28,8 @@
60 text-align: left; 28 text-align: left;
61 padding-left: 18px; 29 padding-left: 18px;
62 margin-top: 0 !important; 30 margin-top: 0 !important;
31 color: #fff !important;
32 line-height: 30px !important;
63 } 33 }
64 } 34 }
65 35
@@ -82,4 +52,4 @@
82 52
83 margin-left: 10px; 53 margin-left: 10px;
84 } 54 }
85} \ No newline at end of file 55}
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 ac6c1786f..9cadf52cb 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,12 +1,11 @@
1import { HttpEventType, HttpResponse } from '@angular/common/http' 1import { HttpEventType, HttpResponse } from '@angular/common/http'
2import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' 2import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
3import { Router } from '@angular/router' 3import { Router } from '@angular/router'
4import { LoadingBarService } from '@ngx-loading-bar/core' 4import { LoadingBarService } from '@ngx-loading-bar/core'
5import { NotificationsService } from 'angular2-notifications'
6import { BytesPipe } from 'ngx-pipes' 5import { BytesPipe } from 'ngx-pipes'
7import { Subscription } from 'rxjs' 6import { Subscription } from 'rxjs'
8import { VideoPrivacy } from '../../../../../../shared/models/videos' 7import { VideoPrivacy } from '../../../../../../shared/models/videos'
9import { AuthService, ServerService } from '../../../core' 8import { AuthService, Notifier, ServerService } from '../../../core'
10import { VideoEdit } from '../../../shared/video/video-edit.model' 9import { VideoEdit } from '../../../shared/video/video-edit.model'
11import { VideoService } from '../../../shared/video/video.service' 10import { VideoService } from '../../../shared/video/video.service'
12import { I18n } from '@ngx-translate/i18n-polyfill' 11import { I18n } from '@ngx-translate/i18n-polyfill'
@@ -14,18 +13,21 @@ import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-se
14import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' 13import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service'
15import { FormValidatorService, UserService } from '@app/shared' 14import { FormValidatorService, UserService } from '@app/shared'
16import { VideoCaptionService } from '@app/shared/video-caption' 15import { VideoCaptionService } from '@app/shared/video-caption'
16import { scrollToTop } from '@app/shared/misc/utils'
17 17
18@Component({ 18@Component({
19 selector: 'my-video-upload', 19 selector: 'my-video-upload',
20 templateUrl: './video-upload.component.html', 20 templateUrl: './video-upload.component.html',
21 styleUrls: [ 21 styleUrls: [
22 '../shared/video-edit.component.scss', 22 '../shared/video-edit.component.scss',
23 './video-upload.component.scss' 23 './video-upload.component.scss',
24 './video-send.scss'
24 ] 25 ]
25}) 26})
26export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { 27export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate {
27 @Output() firstStepDone = new EventEmitter<string>() 28 @Output() firstStepDone = new EventEmitter<string>()
28 @ViewChild('videofileInput') videofileInput 29 @Output() firstStepError = new EventEmitter<void>()
30 @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement>
29 31
30 // So that it can be accessed in the template 32 // So that it can be accessed in the template
31 readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY 33 readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY
@@ -42,13 +44,16 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
42 id: 0, 44 id: 0,
43 uuid: '' 45 uuid: ''
44 } 46 }
47 waitTranscodingEnabled = true
48
49 error: string
45 50
46 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC 51 protected readonly DEFAULT_VIDEO_PRIVACY = VideoPrivacy.PUBLIC
47 52
48 constructor ( 53 constructor (
49 protected formValidatorService: FormValidatorService, 54 protected formValidatorService: FormValidatorService,
50 protected loadingBar: LoadingBarService, 55 protected loadingBar: LoadingBarService,
51 protected notificationsService: NotificationsService, 56 protected notifier: Notifier,
52 protected authService: AuthService, 57 protected authService: AuthService,
53 protected serverService: ServerService, 58 protected serverService: ServerService,
54 protected videoService: VideoService, 59 protected videoService: VideoService,
@@ -105,20 +110,15 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
105 this.isUploadingVideo = false 110 this.isUploadingVideo = false
106 this.videoUploadPercents = 0 111 this.videoUploadPercents = 0
107 this.videoUploadObservable = null 112 this.videoUploadObservable = null
108 this.notificationsService.info(this.i18n('Info'), this.i18n('Upload cancelled')) 113 this.notifier.info(this.i18n('Upload cancelled'))
109 } 114 }
110 } 115 }
111 116
112 uploadFirstStep () { 117 uploadFirstStep () {
113 const videofile = this.videofileInput.nativeElement.files[0] as File 118 const videofile = this.videofileInput.nativeElement.files[0]
114 if (!videofile) return 119 if (!videofile) return
115 120
116 // Cannot upload videos > 8GB for now 121 // Check global user quota
117 if (videofile.size > 8 * 1024 * 1024 * 1024) {
118 this.notificationsService.error(this.i18n('Error'), this.i18n('We are sorry but PeerTube cannot handle videos > 8GB'))
119 return
120 }
121
122 const bytePipes = new BytesPipe() 122 const bytePipes = new BytesPipe()
123 const videoQuota = this.authService.getUser().videoQuota 123 const videoQuota = this.authService.getUser().videoQuota
124 if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) { 124 if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
@@ -130,10 +130,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
130 videoQuota: bytePipes.transform(videoQuota, 0) 130 videoQuota: bytePipes.transform(videoQuota, 0)
131 } 131 }
132 ) 132 )
133 this.notificationsService.error(this.i18n('Error'), msg) 133 this.notifier.error(msg)
134 return 134 return
135 } 135 }
136 136
137 // Check daily user quota
137 const videoQuotaDaily = this.authService.getUser().videoQuotaDaily 138 const videoQuotaDaily = this.authService.getUser().videoQuotaDaily
138 if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) { 139 if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
139 const msg = this.i18n( 140 const msg = this.i18n(
@@ -144,10 +145,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
144 quotaDaily: bytePipes.transform(videoQuotaDaily, 0) 145 quotaDaily: bytePipes.transform(videoQuotaDaily, 0)
145 } 146 }
146 ) 147 )
147 this.notificationsService.error(this.i18n('Error'), msg) 148 this.notifier.error(msg)
148 return 149 return
149 } 150 }
150 151
152 // Build name field
151 const nameWithoutExtension = videofile.name.replace(/\.[^/.]+$/, '') 153 const nameWithoutExtension = videofile.name.replace(/\.[^/.]+$/, '')
152 let name: string 154 let name: string
153 155
@@ -155,6 +157,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
155 if (nameWithoutExtension.length < 3) name = videofile.name 157 if (nameWithoutExtension.length < 3) name = videofile.name
156 else name = nameWithoutExtension 158 else name = nameWithoutExtension
157 159
160 // Force user to wait transcoding for unsupported video types in web browsers
161 if (!videofile.name.endsWith('.mp4') && !videofile.name.endsWith('.webm') && !videofile.name.endsWith('.ogv')) {
162 this.waitTranscodingEnabled = false
163 }
164
158 const privacy = this.firstStepPrivacyId.toString() 165 const privacy = this.firstStepPrivacyId.toString()
159 const nsfw = false 166 const nsfw = false
160 const waitTranscoding = true 167 const waitTranscoding = true
@@ -203,7 +210,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
203 this.isUploadingVideo = false 210 this.isUploadingVideo = false
204 this.videoUploadPercents = 0 211 this.videoUploadPercents = 0
205 this.videoUploadObservable = null 212 this.videoUploadObservable = null
206 this.notificationsService.error(this.i18n('Error'), err.message) 213 this.firstStepError.emit()
214 this.notifier.error(err.message)
207 } 215 }
208 ) 216 )
209 } 217 }
@@ -232,13 +240,13 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
232 this.isUpdatingVideo = false 240 this.isUpdatingVideo = false
233 this.isUploadingVideo = false 241 this.isUploadingVideo = false
234 242
235 this.notificationsService.success(this.i18n('Success'), this.i18n('Video published.')) 243 this.notifier.success(this.i18n('Video published.'))
236 this.router.navigate([ '/videos/watch', video.uuid ]) 244 this.router.navigate([ '/videos/watch', video.uuid ])
237 }, 245 },
238 246
239 err => { 247 err => {
240 this.isUpdatingVideo = false 248 this.error = err.message
241 this.notificationsService.error(this.i18n('Error'), err.message) 249 scrollToTop()
242 console.error(err) 250 console.error(err)
243 } 251 }
244 ) 252 )