aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos/+video-edit
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/videos/+video-edit')
-rw-r--r--client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html2
-rw-r--r--client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.ts8
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.html5
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.scss33
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.ts11
-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
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.html8
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.ts19
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.html4
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.ts37
20 files changed, 235 insertions, 226 deletions
diff --git a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html
index 30aefdbfc..19043eee6 100644
--- a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html
+++ b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.html
@@ -3,7 +3,7 @@
3 3
4 <div class="modal-header"> 4 <div class="modal-header">
5 <h4 i18n class="modal-title">Add caption</h4> 5 <h4 i18n class="modal-title">Add caption</h4>
6 <span class="close" aria-label="Close" role="button" (click)="hide()"></span> 6 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
7 </div> 7 </div>
8 8
9 <div class="modal-body"> 9 <div class="modal-body">
diff --git a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.ts b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.ts
index 07c33030a..1413e7262 100644
--- a/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.ts
+++ b/client/src/app/videos/+video-edit/shared/video-caption-add-modal.component.ts
@@ -5,6 +5,7 @@ import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validator
5import { ServerService } from '@app/core' 5import { ServerService } from '@app/core'
6import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' 6import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
7import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' 7import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
8import { VideoConstant } from '../../../../../../shared'
8 9
9@Component({ 10@Component({
10 selector: 'my-video-caption-add-modal', 11 selector: 'my-video-caption-add-modal',
@@ -19,7 +20,7 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
19 20
20 @ViewChild('modal') modal: ElementRef 21 @ViewChild('modal') modal: ElementRef
21 22
22 videoCaptionLanguages = [] 23 videoCaptionLanguages: VideoConstant<string>[] = []
23 24
24 private openedModal: NgbModalRef 25 private openedModal: NgbModalRef
25 private closingModal = false 26 private closingModal = false
@@ -59,6 +60,7 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
59 hide () { 60 hide () {
60 this.closingModal = true 61 this.closingModal = true
61 this.openedModal.close() 62 this.openedModal.close()
63 this.form.reset()
62 } 64 }
63 65
64 isReplacingExistingCaption () { 66 isReplacingExistingCaption () {
@@ -70,8 +72,6 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
70 } 72 }
71 73
72 async addCaption () { 74 async addCaption () {
73 this.hide()
74
75 const languageId = this.form.value[ 'language' ] 75 const languageId = this.form.value[ 'language' ]
76 const languageObject = this.videoCaptionLanguages.find(l => l.id === languageId) 76 const languageObject = this.videoCaptionLanguages.find(l => l.id === languageId)
77 77
@@ -80,6 +80,6 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
80 captionfile: this.form.value[ 'captionfile' ] 80 captionfile: this.form.value[ 'captionfile' ]
81 }) 81 })
82 82
83 this.form.reset() 83 this.hide()
84 } 84 }
85} 85}
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html
index 8c74a1ca6..7fd9af208 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.html
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html
@@ -127,10 +127,11 @@
127 127
128 <my-peertube-checkbox 128 <my-peertube-checkbox
129 inputName="downloadEnabled" formControlName="downloadEnabled" 129 inputName="downloadEnabled" formControlName="downloadEnabled"
130 i18n-labelText labelText="Disable downloading" 130 i18n-labelText labelText="Download enabled"
131 ></my-peertube-checkbox> 131 ></my-peertube-checkbox>
132 132
133 <my-peertube-checkbox 133 <my-peertube-checkbox
134 *ngIf="waitTranscodingEnabled"
134 inputName="waitTranscoding" formControlName="waitTranscoding" 135 inputName="waitTranscoding" formControlName="waitTranscoding"
135 i18n-labelText labelText="Wait transcoding before publishing the video" 136 i18n-labelText labelText="Wait transcoding before publishing the video"
136 i18n-helpHtml helpHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends." 137 i18n-helpHtml helpHtml="If you decide not to wait for transcoding before publishing the video, it could be unplayable until transcoding ends."
@@ -147,7 +148,7 @@
147 148
148 <div class="captions-header"> 149 <div class="captions-header">
149 <a (click)="openAddCaptionModal()" class="create-caption"> 150 <a (click)="openAddCaptionModal()" class="create-caption">
150 <span class="icon icon-add"></span> 151 <my-global-icon iconName="add"></my-global-icon>
151 <ng-container i18n>Add another caption</ng-container> 152 <ng-container i18n>Add another caption</ng-container>
152 </a> 153 </a>
153 </div> 154 </div>
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.scss b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
index b039d7ad4..bb775cb0a 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.scss
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
@@ -5,6 +5,11 @@
5 @include peertube-select-container(auto); 5 @include peertube-select-container(auto);
6} 6}
7 7
8my-peertube-checkbox {
9 display: block;
10 margin-bottom: 1rem;
11}
12
8.video-edit { 13.video-edit {
9 height: 100%; 14 height: 100%;
10 min-height: 300px; 15 min-height: 300px;
@@ -18,10 +23,6 @@
18 display: block; 23 display: block;
19 } 24 }
20 25
21 input, select {
22 font-size: 15px
23 }
24
25 .label-tags + span { 26 .label-tags + span {
26 font-size: 15px; 27 font-size: 15px;
27 } 28 }
@@ -37,7 +38,7 @@
37 text-align: right; 38 text-align: right;
38 39
39 .create-caption { 40 .create-caption {
40 @include create-button('../../../../assets/images/global/add.svg'); 41 @include create-button;
41 } 42 }
42 } 43 }
43 44
@@ -95,13 +96,14 @@
95 display: inline-block; 96 display: inline-block;
96 margin-right: 25px; 97 margin-right: 25px;
97 98
98 color: #585858; 99 color: $grey-foreground-color;
99 font-size: 15px; 100 font-size: 15px;
100 } 101 }
101 102
102 .submit-button { 103 .submit-button {
103 @include peertube-button; 104 @include peertube-button;
104 @include orange-button; 105 @include orange-button;
106 @include button-with-icon(20px, 1px);
105 107
106 display: inline-block; 108 display: inline-block;
107 109
@@ -114,16 +116,6 @@
114 color: inherit; 116 color: inherit;
115 font-weight: $font-semibold; 117 font-weight: $font-semibold;
116 } 118 }
117
118 .icon.icon-validate {
119 @include icon(20px);
120
121 cursor: inherit;
122 position: relative;
123 top: -1px;
124 margin-right: 4px;
125 background-image: url('../../../../assets/images/global/validate.svg');
126 }
127 } 119 }
128} 120}
129 121
@@ -171,10 +163,10 @@ p-calendar {
171 } 163 }
172 164
173 tag { 165 tag {
174 background-color: var(--inputColor) !important; 166 background-color: $grey-background-color !important;
167 color: #000 !important;
175 border-radius: 3px !important; 168 border-radius: 3px !important;
176 font-size: 15px !important; 169 font-size: 15px !important;
177 color: var(--mainForegroundColor) !important;
178 height: 30px !important; 170 height: 30px !important;
179 line-height: 30px !important; 171 line-height: 30px !important;
180 margin: 0 5px 0 0 !important; 172 margin: 0 5px 0 0 !important;
@@ -197,7 +189,10 @@ p-calendar {
197 top: -1px; 189 top: -1px;
198 height: auto !important; 190 height: auto !important;
199 vertical-align: middle !important; 191 vertical-align: middle !important;
200 fill: #585858 !important; 192
193 path {
194 fill: $grey-foreground-color !important;
195 }
201 } 196 }
202 197
203 &:hover { 198 &:hover {
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.ts b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
index 1dae931e2..3ed7a4a10 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.ts
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
@@ -2,7 +2,7 @@ import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'
2import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms' 2import { FormArray, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { FormReactiveValidationMessages, VideoValidatorsService } from '@app/shared' 4import { FormReactiveValidationMessages, VideoValidatorsService } from '@app/shared'
5import { NotificationsService } from 'angular2-notifications' 5import { Notifier } from '@app/core'
6import { ServerService } from '../../../core/server' 6import { ServerService } from '../../../core/server'
7import { VideoEdit } from '../../../shared/video/video-edit.model' 7import { VideoEdit } from '../../../shared/video/video-edit.model'
8import { map } from 'rxjs/operators' 8import { map } from 'rxjs/operators'
@@ -27,6 +27,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
27 @Input() userVideoChannels: { id: number, label: string, support: string }[] = [] 27 @Input() userVideoChannels: { id: number, label: string, support: string }[] = []
28 @Input() schedulePublicationPossible = true 28 @Input() schedulePublicationPossible = true
29 @Input() videoCaptions: VideoCaptionEdit[] = [] 29 @Input() videoCaptions: VideoCaptionEdit[] = []
30 @Input() waitTranscodingEnabled = true
30 31
31 @ViewChild('videoCaptionAddModal') videoCaptionAddModal: VideoCaptionAddModalComponent 32 @ViewChild('videoCaptionAddModal') videoCaptionAddModal: VideoCaptionAddModalComponent
32 33
@@ -48,7 +49,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
48 calendarTimezone: string 49 calendarTimezone: string
49 calendarDateFormat: string 50 calendarDateFormat: string
50 51
51 private schedulerInterval 52 private schedulerInterval: any
52 private firstPatchDone = false 53 private firstPatchDone = false
53 private initialVideoCaptions: string[] = [] 54 private initialVideoCaptions: string[] = []
54 55
@@ -58,7 +59,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
58 private videoCaptionService: VideoCaptionService, 59 private videoCaptionService: VideoCaptionService,
59 private route: ActivatedRoute, 60 private route: ActivatedRoute,
60 private router: Router, 61 private router: Router,
61 private notificationsService: NotificationsService, 62 private notifier: Notifier,
62 private serverService: ServerService, 63 private serverService: ServerService,
63 private i18nPrimengCalendarService: I18nPrimengCalendarService 64 private i18nPrimengCalendarService: I18nPrimengCalendarService
64 ) { 65 ) {
@@ -77,14 +78,14 @@ export class VideoEditComponent implements OnInit, OnDestroy {
77 } 78 }
78 79
79 updateForm () { 80 updateForm () {
80 const defaultValues = { 81 const defaultValues: any = {
81 nsfw: 'false', 82 nsfw: 'false',
82 commentsEnabled: 'true', 83 commentsEnabled: 'true',
83 downloadEnabled: 'true', 84 downloadEnabled: 'true',
84 waitTranscoding: 'true', 85 waitTranscoding: 'true',
85 tags: [] 86 tags: []
86 } 87 }
87 const obj = { 88 const obj: any = {
88 name: this.videoValidatorsService.VIDEO_NAME, 89 name: this.videoValidatorsService.VIDEO_NAME,
89 privacy: this.videoValidatorsService.VIDEO_PRIVACY, 90 privacy: this.videoValidatorsService.VIDEO_PRIVACY,
90 channelId: this.videoValidatorsService.VIDEO_CHANNEL, 91 channelId: this.videoValidatorsService.VIDEO_CHANNEL,
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 )
diff --git a/client/src/app/videos/+video-edit/video-add.component.html b/client/src/app/videos/+video-edit/video-add.component.html
index e14e23aed..72a233b72 100644
--- a/client/src/app/videos/+video-edit/video-add.component.html
+++ b/client/src/app/videos/+video-edit/video-add.component.html
@@ -6,24 +6,24 @@
6 6
7 <ngb-tabset class="video-add-tabset root-tabset bootstrap" [ngClass]="{ 'hide-nav': secondStepType !== undefined }"> 7 <ngb-tabset class="video-add-tabset root-tabset bootstrap" [ngClass]="{ 'hide-nav': secondStepType !== undefined }">
8 8
9 <ngb-tab i18n-title title=""> 9 <ngb-tab>
10 <ng-template ngbTabTitle><span i18n>Upload a file</span></ng-template> 10 <ng-template ngbTabTitle><span i18n>Upload a file</span></ng-template>
11 <ng-template ngbTabContent> 11 <ng-template ngbTabContent>
12 <my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)"></my-video-upload> 12 <my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)" (firstStepError)="onError()"></my-video-upload>
13 </ng-template> 13 </ng-template>
14 </ngb-tab> 14 </ngb-tab>
15 15
16 <ngb-tab *ngIf="isVideoImportHttpEnabled()"> 16 <ngb-tab *ngIf="isVideoImportHttpEnabled()">
17 <ng-template ngbTabTitle><span i18n>Import with URL</span></ng-template> 17 <ng-template ngbTabTitle><span i18n>Import with URL</span></ng-template>
18 <ng-template ngbTabContent> 18 <ng-template ngbTabContent>
19 <my-video-import-url #videoImportUrl (firstStepDone)="onFirstStepDone('import-url', $event)"></my-video-import-url> 19 <my-video-import-url #videoImportUrl (firstStepDone)="onFirstStepDone('import-url', $event)" (firstStepError)="onError()"></my-video-import-url>
20 </ng-template> 20 </ng-template>
21 </ngb-tab> 21 </ngb-tab>
22 22
23 <ngb-tab *ngIf="isVideoImportTorrentEnabled()"> 23 <ngb-tab *ngIf="isVideoImportTorrentEnabled()">
24 <ng-template ngbTabTitle><span i18n>Import with torrent</span></ng-template> 24 <ng-template ngbTabTitle><span i18n>Import with torrent</span></ng-template>
25 <ng-template ngbTabContent> 25 <ng-template ngbTabContent>
26 <my-video-import-torrent #videoImportTorrent (firstStepDone)="onFirstStepDone('import-torrent', $event)"></my-video-import-torrent> 26 <my-video-import-torrent #videoImportTorrent (firstStepDone)="onFirstStepDone('import-torrent', $event)" (firstStepError)="onError()"></my-video-import-torrent>
27 </ng-template> 27 </ng-template>
28 </ngb-tab> 28 </ngb-tab>
29 </ngb-tabset> 29 </ngb-tabset>
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts
index 1a9247dbe..01fdfcb66 100644
--- a/client/src/app/videos/+video-edit/video-add.component.ts
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -1,4 +1,4 @@
1import { Component, ViewChild } from '@angular/core' 1import { Component, HostListener, ViewChild } from '@angular/core'
2import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' 2import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service'
3import { VideoImportUrlComponent } from '@app/videos/+video-edit/video-add-components/video-import-url.component' 3import { VideoImportUrlComponent } from '@app/videos/+video-edit/video-add-components/video-import-url.component'
4import { VideoUploadComponent } from '@app/videos/+video-edit/video-add-components/video-upload.component' 4import { VideoUploadComponent } from '@app/videos/+video-edit/video-add-components/video-upload.component'
@@ -27,7 +27,22 @@ export class VideoAddComponent implements CanComponentDeactivate {
27 this.videoName = videoName 27 this.videoName = videoName
28 } 28 }
29 29
30 canDeactivate () { 30 onError () {
31 this.videoName = undefined
32 this.secondStepType = undefined
33 }
34
35 @HostListener('window:beforeunload', [ '$event' ])
36 onUnload (event: any) {
37 const { text, canDeactivate } = this.canDeactivate()
38
39 if (canDeactivate) return
40
41 event.returnValue = text
42 return text
43 }
44
45 canDeactivate (): { canDeactivate: boolean, text?: string} {
31 if (this.secondStepType === 'upload') return this.videoUpload.canDeactivate() 46 if (this.secondStepType === 'upload') return this.videoUpload.canDeactivate()
32 if (this.secondStepType === 'import-url') return this.videoImportUrl.canDeactivate() 47 if (this.secondStepType === 'import-url') return this.videoImportUrl.canDeactivate()
33 if (this.secondStepType === 'import-torrent') return this.videoImportTorrent.canDeactivate() 48 if (this.secondStepType === 'import-torrent') return this.videoImportTorrent.canDeactivate()
diff --git a/client/src/app/videos/+video-edit/video-update.component.html b/client/src/app/videos/+video-edit/video-update.component.html
index 9242c30a0..4992bb369 100644
--- a/client/src/app/videos/+video-edit/video-update.component.html
+++ b/client/src/app/videos/+video-edit/video-update.component.html
@@ -8,12 +8,12 @@
8 <my-video-edit 8 <my-video-edit
9 [form]="form" [formErrors]="formErrors" [schedulePublicationPossible]="schedulePublicationPossible" 9 [form]="form" [formErrors]="formErrors" [schedulePublicationPossible]="schedulePublicationPossible"
10 [validationMessages]="validationMessages" [videoPrivacies]="videoPrivacies" [userVideoChannels]="userVideoChannels" 10 [validationMessages]="validationMessages" [videoPrivacies]="videoPrivacies" [userVideoChannels]="userVideoChannels"
11 [videoCaptions]="videoCaptions" 11 [videoCaptions]="videoCaptions" [waitTranscodingEnabled]="waitTranscodingEnabled"
12 ></my-video-edit> 12 ></my-video-edit>
13 13
14 <div class="submit-container"> 14 <div class="submit-container">
15 <div class="submit-button" (click)="update()" [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }"> 15 <div class="submit-button" (click)="update()" [ngClass]="{ disabled: !form.valid || isUpdatingVideo === true }">
16 <span class="icon icon-validate"></span> 16 <my-global-icon iconName="validate"></my-global-icon>
17 <input type="button" i18n-value value="Update" /> 17 <input type="button" i18n-value value="Update" />
18 </div> 18 </div>
19 </div> 19 </div>
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts
index 3a0f3a39a..9e849014e 100644
--- a/client/src/app/videos/+video-edit/video-update.component.ts
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -1,8 +1,8 @@
1import { map, switchMap } from 'rxjs/operators' 1import { map, switchMap } from 'rxjs/operators'
2import { Component, OnInit } from '@angular/core' 2import { Component, HostListener, OnInit } from '@angular/core'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { LoadingBarService } from '@ngx-loading-bar/core' 4import { LoadingBarService } from '@ngx-loading-bar/core'
5import { NotificationsService } from 'angular2-notifications' 5import { Notifier } from '@app/core'
6import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos' 6import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
7import { ServerService } from '../../core' 7import { ServerService } from '../../core'
8import { FormReactive } from '../../shared' 8import { FormReactive } from '../../shared'
@@ -12,6 +12,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
12import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' 12import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
13import { VideoCaptionService } from '@app/shared/video-caption' 13import { VideoCaptionService } from '@app/shared/video-caption'
14import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' 14import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
15import { VideoDetails } from '@app/shared/video/video-details.model'
15 16
16@Component({ 17@Component({
17 selector: 'my-videos-update', 18 selector: 'my-videos-update',
@@ -26,6 +27,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
26 userVideoChannels: { id: number, label: string, support: string }[] = [] 27 userVideoChannels: { id: number, label: string, support: string }[] = []
27 schedulePublicationPossible = false 28 schedulePublicationPossible = false
28 videoCaptions: VideoCaptionEdit[] = [] 29 videoCaptions: VideoCaptionEdit[] = []
30 waitTranscodingEnabled = true
29 31
30 private updateDone = false 32 private updateDone = false
31 33
@@ -33,7 +35,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
33 protected formValidatorService: FormValidatorService, 35 protected formValidatorService: FormValidatorService,
34 private route: ActivatedRoute, 36 private route: ActivatedRoute,
35 private router: Router, 37 private router: Router,
36 private notificationsService: NotificationsService, 38 private notifier: Notifier,
37 private serverService: ServerService, 39 private serverService: ServerService,
38 private videoService: VideoService, 40 private videoService: VideoService,
39 private loadingBar: LoadingBarService, 41 private loadingBar: LoadingBarService,
@@ -65,25 +67,42 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
65 67
66 this.videoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies) 68 this.videoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
67 69
70 const videoFiles = (video as VideoDetails).files
71 if (videoFiles.length > 1) { // Already transcoded
72 this.waitTranscodingEnabled = false
73 }
74
68 // FIXME: Angular does not detect the change inside this subscription, so use the patched setTimeout 75 // FIXME: Angular does not detect the change inside this subscription, so use the patched setTimeout
69 setTimeout(() => this.hydrateFormFromVideo()) 76 setTimeout(() => this.hydrateFormFromVideo())
70 }, 77 },
71 78
72 err => { 79 err => {
73 console.error(err) 80 console.error(err)
74 this.notificationsService.error(this.i18n('Error'), err.message) 81 this.notifier.error(err.message)
75 } 82 }
76 ) 83 )
77 } 84 }
78 85
79 canDeactivate () { 86 @HostListener('window:beforeunload', [ '$event' ])
87 onUnload (event: any) {
88 const { text, canDeactivate } = this.canDeactivate()
89
90 if (canDeactivate) return
91
92 event.returnValue = text
93 return text
94 }
95
96 canDeactivate (): { canDeactivate: boolean, text?: string } {
80 if (this.updateDone === true) return { canDeactivate: true } 97 if (this.updateDone === true) return { canDeactivate: true }
81 98
99 const text = this.i18n('You have unsaved changes! If you leave, your changes will be lost.')
100
82 for (const caption of this.videoCaptions) { 101 for (const caption of this.videoCaptions) {
83 if (caption.action) return { canDeactivate: false } 102 if (caption.action) return { canDeactivate: false, text }
84 } 103 }
85 104
86 return { canDeactivate: this.formChanged === false } 105 return { canDeactivate: this.formChanged === false, text }
87 } 106 }
88 107
89 checkForm () { 108 checkForm () {
@@ -114,14 +133,14 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
114 this.updateDone = true 133 this.updateDone = true
115 this.isUpdatingVideo = false 134 this.isUpdatingVideo = false
116 this.loadingBar.complete() 135 this.loadingBar.complete()
117 this.notificationsService.success(this.i18n('Success'), this.i18n('Video updated.')) 136 this.notifier.success(this.i18n('Video updated.'))
118 this.router.navigate([ '/videos/watch', this.video.uuid ]) 137 this.router.navigate([ '/videos/watch', this.video.uuid ])
119 }, 138 },
120 139
121 err => { 140 err => {
122 this.loadingBar.complete() 141 this.loadingBar.complete()
123 this.isUpdatingVideo = false 142 this.isUpdatingVideo = false
124 this.notificationsService.error(this.i18n('Error'), err.message) 143 this.notifier.error(err.message)
125 console.error(err) 144 console.error(err)
126 } 145 }
127 ) 146 )