diff options
Diffstat (limited to 'client/src/app/videos/+video-edit/video-add-components')
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 @@ | |||
1 | import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' |
2 | import { Router } from '@angular/router' | 2 | import { Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' | 3 | import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' |
5 | import { AuthService, ServerService } from '../../../core' | 4 | import { AuthService, Notifier, ServerService } from '../../../core' |
6 | import { VideoService } from '../../../shared/video/video.service' | 5 | import { VideoService } from '../../../shared/video/video.service' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 6 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { LoadingBarService } from '@ngx-loading-bar/core' | 7 | import { LoadingBarService } from '@ngx-loading-bar/core' |
@@ -12,20 +11,22 @@ import { VideoEdit } from '@app/shared/video/video-edit.model' | |||
12 | import { FormValidatorService } from '@app/shared' | 11 | import { FormValidatorService } from '@app/shared' |
13 | import { VideoCaptionService } from '@app/shared/video-caption' | 12 | import { VideoCaptionService } from '@app/shared/video-caption' |
14 | import { VideoImportService } from '@app/shared/video-import' | 13 | import { VideoImportService } from '@app/shared/video-import' |
14 | import { 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 | }) |
24 | export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { | 25 | export 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 @@ | |||
1 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' | 1 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' |
2 | import { Router } from '@angular/router' | 2 | import { Router } from '@angular/router' |
3 | import { NotificationsService } from 'angular2-notifications' | ||
4 | import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' | 3 | import { VideoPrivacy, VideoUpdate } from '../../../../../../shared/models/videos' |
5 | import { AuthService, ServerService } from '../../../core' | 4 | import { AuthService, Notifier, ServerService } from '../../../core' |
6 | import { VideoService } from '../../../shared/video/video.service' | 5 | import { VideoService } from '../../../shared/video/video.service' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 6 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { LoadingBarService } from '@ngx-loading-bar/core' | 7 | import { LoadingBarService } from '@ngx-loading-bar/core' |
@@ -12,33 +11,35 @@ import { VideoEdit } from '@app/shared/video/video-edit.model' | |||
12 | import { FormValidatorService } from '@app/shared' | 11 | import { FormValidatorService } from '@app/shared' |
13 | import { VideoCaptionService } from '@app/shared/video-caption' | 12 | import { VideoCaptionService } from '@app/shared/video-caption' |
14 | import { VideoImportService } from '@app/shared/video-import' | 13 | import { VideoImportService } from '@app/shared/video-import' |
14 | import { 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 | }) |
24 | export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { | 24 | export 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 @@ | |||
1 | import { EventEmitter, OnInit } from '@angular/core' | 1 | import { EventEmitter, OnInit } from '@angular/core' |
2 | import { LoadingBarService } from '@ngx-loading-bar/core' | 2 | import { LoadingBarService } from '@ngx-loading-bar/core' |
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { AuthService, Notifier, ServerService } from '@app/core' |
4 | import { catchError, switchMap, tap } from 'rxjs/operators' | 4 | import { catchError, switchMap, tap } from 'rxjs/operators' |
5 | import { FormReactive } from '@app/shared' | 5 | import { FormReactive } from '@app/shared' |
6 | import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' | ||
7 | import { VideoConstant, VideoPrivacy } from '../../../../../../shared' | 6 | import { VideoConstant, VideoPrivacy } from '../../../../../../shared' |
8 | import { AuthService, ServerService } from '@app/core' | ||
9 | import { VideoService } from '@app/shared/video/video.service' | 7 | import { VideoService } from '@app/shared/video/video.service' |
10 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' | 8 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' |
11 | import { VideoCaptionService } from '@app/shared/video-caption' | 9 | import { VideoCaptionService } from '@app/shared/video-caption' |
12 | import { VideoEdit } from '@app/shared/video/video-edit.model' | 10 | import { VideoEdit } from '@app/shared/video/video-edit.model' |
13 | import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' | 11 | import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' |
12 | import { CanComponentDeactivateResult } from '@app/shared/guards/can-deactivate-guard.service' | ||
14 | 13 | ||
15 | export abstract class VideoSend extends FormReactive implements OnInit, CanComponentDeactivate { | 14 | export 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 @@ | |||
1 | import { HttpEventType, HttpResponse } from '@angular/common/http' | 1 | import { HttpEventType, HttpResponse } from '@angular/common/http' |
2 | import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' | 2 | import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' |
3 | import { Router } from '@angular/router' | 3 | import { Router } from '@angular/router' |
4 | import { LoadingBarService } from '@ngx-loading-bar/core' | 4 | import { LoadingBarService } from '@ngx-loading-bar/core' |
5 | import { NotificationsService } from 'angular2-notifications' | ||
6 | import { BytesPipe } from 'ngx-pipes' | 5 | import { BytesPipe } from 'ngx-pipes' |
7 | import { Subscription } from 'rxjs' | 6 | import { Subscription } from 'rxjs' |
8 | import { VideoPrivacy } from '../../../../../../shared/models/videos' | 7 | import { VideoPrivacy } from '../../../../../../shared/models/videos' |
9 | import { AuthService, ServerService } from '../../../core' | 8 | import { AuthService, Notifier, ServerService } from '../../../core' |
10 | import { VideoEdit } from '../../../shared/video/video-edit.model' | 9 | import { VideoEdit } from '../../../shared/video/video-edit.model' |
11 | import { VideoService } from '../../../shared/video/video.service' | 10 | import { VideoService } from '../../../shared/video/video.service' |
12 | import { I18n } from '@ngx-translate/i18n-polyfill' | 11 | import { I18n } from '@ngx-translate/i18n-polyfill' |
@@ -14,18 +13,21 @@ import { VideoSend } from '@app/videos/+video-edit/video-add-components/video-se | |||
14 | import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' | 13 | import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' |
15 | import { FormValidatorService, UserService } from '@app/shared' | 14 | import { FormValidatorService, UserService } from '@app/shared' |
16 | import { VideoCaptionService } from '@app/shared/video-caption' | 15 | import { VideoCaptionService } from '@app/shared/video-caption' |
16 | import { 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 | }) |
26 | export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { | 27 | export 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 | ) |