aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.prettierrc.yml4
-rw-r--r--client/src/app/+accounts/account-about/account-about.component.ts13
-rw-r--r--client/src/app/+accounts/account-video-channels/account-video-channels.component.ts11
-rw-r--r--client/src/app/+accounts/account-videos/account-videos.component.ts2
-rw-r--r--client/src/app/+admin/config/shared/config.service.ts5
-rw-r--r--client/src/app/+admin/follows/shared/follow.service.ts34
-rw-r--r--client/src/app/+admin/jobs/shared/job.service.ts13
-rw-r--r--client/src/app/+admin/users/shared/user.service.ts31
-rw-r--r--client/src/app/+admin/users/user-edit/user-update.component.ts13
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts2
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts6
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts5
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.ts15
-rw-r--r--client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts2
-rw-r--r--client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts2
-rw-r--r--client/src/app/core/auth/auth.service.ts111
-rw-r--r--client/src/app/core/confirm/confirm.service.ts9
-rw-r--r--client/src/app/core/routing/preload-selected-modules-list.ts11
-rw-r--r--client/src/app/core/server/server.service.ts14
-rw-r--r--client/src/app/header/header.component.ts11
-rw-r--r--client/src/app/shared/account/account.service.ts18
-rw-r--r--client/src/app/shared/actor/actor.model.ts8
-rw-r--r--client/src/app/shared/auth/auth-interceptor.service.ts38
-rw-r--r--client/src/app/shared/forms/markdown-textarea.component.ts13
-rw-r--r--client/src/app/shared/guards/can-deactivate-guard.service.ts4
-rw-r--r--client/src/app/shared/rest/rest-extractor.service.ts7
-rw-r--r--client/src/app/shared/users/user.service.ts40
-rw-r--r--client/src/app/shared/video-abuse/video-abuse.service.ts17
-rw-r--r--client/src/app/shared/video-blacklist/video-blacklist.service.ts23
-rw-r--r--client/src/app/shared/video-channel/video-channel.service.ts44
-rw-r--r--client/src/app/shared/video/abstract-video-list.ts8
-rw-r--r--client/src/app/shared/video/infinite-scroller.directive.ts68
-rw-r--r--client/src/app/shared/video/video.service.ts89
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.ts1
-rw-r--r--client/src/app/videos/+video-edit/shared/video-image.component.ts2
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.ts3
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.ts61
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment-add.component.ts2
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comment.service.ts44
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.ts2
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts3
-rw-r--r--client/src/app/videos/video-list/video-search.component.ts2
-rw-r--r--package.json2
-rwxr-xr-xscripts/watch/client.sh2
44 files changed, 424 insertions, 391 deletions
diff --git a/.prettierrc.yml b/.prettierrc.yml
index aa374328e..d8379671f 100644
--- a/.prettierrc.yml
+++ b/.prettierrc.yml
@@ -1,8 +1,8 @@
1printWidth: 80 1printWidth: 140
2tabWidth: 2 2tabWidth: 2
3useTabs: false 3useTabs: false
4semi: false 4semi: false
5singleQuote: true 5singleQuote: true
6trailingComma: all 6trailingComma: false
7bracketSpacing: true 7bracketSpacing: true
8arrowParens: always 8arrowParens: always
diff --git a/client/src/app/+accounts/account-about/account-about.component.ts b/client/src/app/+accounts/account-about/account-about.component.ts
index 8746875cb..f063df392 100644
--- a/client/src/app/+accounts/account-about/account-about.component.ts
+++ b/client/src/app/+accounts/account-about/account-about.component.ts
@@ -1,14 +1,5 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute } from '@angular/router'
3import { Location } from '@angular/common'
4import { getParameterByName, immutableAssign } from '@app/shared/misc/utils'
5import { NotificationsService } from 'angular2-notifications'
6import 'rxjs/add/observable/from'
7import 'rxjs/add/operator/concatAll'
8import { AuthService } from '../../core/auth'
9import { ConfirmService } from '../../core/confirm'
10import { AbstractVideoList } from '../../shared/video/abstract-video-list'
11import { VideoService } from '../../shared/video/video.service'
12import { Account } from '@app/shared/account/account.model' 3import { Account } from '@app/shared/account/account.model'
13import { AccountService } from '@app/shared/account/account.service' 4import { AccountService } from '@app/shared/account/account.service'
14 5
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
index 4c5782f9d..0852c4bb7 100644
--- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
+++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
@@ -1,11 +1,10 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute } from '@angular/router' 2import { ActivatedRoute } from '@angular/router'
3import 'rxjs/add/observable/from'
4import 'rxjs/add/operator/concatAll'
5import { Account } from '@app/shared/account/account.model' 3import { Account } from '@app/shared/account/account.model'
6import { AccountService } from '@app/shared/account/account.service' 4import { AccountService } from '@app/shared/account/account.service'
7import { VideoChannel } from '../../../../../shared/models/videos' 5import { VideoChannel } from '../../../../../shared/models/videos'
8import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 6import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
7import { flatMap, map, tap } from 'rxjs/operators'
9 8
10@Component({ 9@Component({
11 selector: 'my-account-video-channels', 10 selector: 'my-account-video-channels',
@@ -25,9 +24,11 @@ export class AccountVideoChannelsComponent implements OnInit {
25 ngOnInit () { 24 ngOnInit () {
26 // Parent get the account for us 25 // Parent get the account for us
27 this.accountService.accountLoaded 26 this.accountService.accountLoaded
28 .do(account => this.account = account) 27 .pipe(
29 .flatMap(account => this.videoChannelService.listAccountVideoChannels(account.id)) 28 tap(account => this.account = account),
30 .map(res => res.data) 29 flatMap(account => this.videoChannelService.listAccountVideoChannels(account.id)),
30 map(res => res.data)
31 )
31 .subscribe(videoChannels => this.videoChannels = videoChannels) 32 .subscribe(videoChannels => this.videoChannels = videoChannels)
32 } 33 }
33} 34}
diff --git a/client/src/app/+accounts/account-videos/account-videos.component.ts b/client/src/app/+accounts/account-videos/account-videos.component.ts
index 6c0f0bb52..1b0590f73 100644
--- a/client/src/app/+accounts/account-videos/account-videos.component.ts
+++ b/client/src/app/+accounts/account-videos/account-videos.component.ts
@@ -3,8 +3,6 @@ import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common' 3import { Location } from '@angular/common'
4import { immutableAssign } from '@app/shared/misc/utils' 4import { immutableAssign } from '@app/shared/misc/utils'
5import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
6import 'rxjs/add/observable/from'
7import 'rxjs/add/operator/concatAll'
8import { AuthService } from '../../core/auth' 6import { AuthService } from '../../core/auth'
9import { ConfirmService } from '../../core/confirm' 7import { ConfirmService } from '../../core/confirm'
10import { AbstractVideoList } from '../../shared/video/abstract-video-list' 8import { AbstractVideoList } from '../../shared/video/abstract-video-list'
diff --git a/client/src/app/+admin/config/shared/config.service.ts b/client/src/app/+admin/config/shared/config.service.ts
index 2a39c7155..1565774b3 100644
--- a/client/src/app/+admin/config/shared/config.service.ts
+++ b/client/src/app/+admin/config/shared/config.service.ts
@@ -1,3 +1,4 @@
1import { catchError } from 'rxjs/operators'
1import { HttpClient } from '@angular/common/http' 2import { HttpClient } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model' 4import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model'
@@ -16,11 +17,11 @@ export class ConfigService {
16 17
17 getCustomConfig () { 18 getCustomConfig () {
18 return this.authHttp.get<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom') 19 return this.authHttp.get<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom')
19 .catch(res => this.restExtractor.handleError(res)) 20 .pipe(catchError(res => this.restExtractor.handleError(res)))
20 } 21 }
21 22
22 updateCustomConfig (data: CustomConfig) { 23 updateCustomConfig (data: CustomConfig) {
23 return this.authHttp.put<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom', data) 24 return this.authHttp.put<CustomConfig>(ConfigService.BASE_APPLICATION_URL + '/custom', data)
24 .catch(res => this.restExtractor.handleError(res)) 25 .pipe(catchError(res => this.restExtractor.handleError(res)))
25 } 26 }
26} 27}
diff --git a/client/src/app/+admin/follows/shared/follow.service.ts b/client/src/app/+admin/follows/shared/follow.service.ts
index 089be9d64..5897e64ca 100644
--- a/client/src/app/+admin/follows/shared/follow.service.ts
+++ b/client/src/app/+admin/follows/shared/follow.service.ts
@@ -1,9 +1,8 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { SortMeta } from 'primeng/primeng' 4import { SortMeta } from 'primeng/primeng'
4import 'rxjs/add/operator/catch' 5import { Observable } from 'rxjs'
5import 'rxjs/add/operator/map'
6import { Observable } from 'rxjs/Observable'
7import { AccountFollow, ResultList } from '../../../../../../shared' 6import { AccountFollow, ResultList } from '../../../../../../shared'
8import { environment } from '../../../../environments/environment' 7import { environment } from '../../../../environments/environment'
9import { RestExtractor, RestPagination, RestService } from '../../../shared' 8import { RestExtractor, RestPagination, RestService } from '../../../shared'
@@ -16,24 +15,29 @@ export class FollowService {
16 private authHttp: HttpClient, 15 private authHttp: HttpClient,
17 private restService: RestService, 16 private restService: RestService,
18 private restExtractor: RestExtractor 17 private restExtractor: RestExtractor
19 ) {} 18 ) {
19 }
20 20
21 getFollowing (pagination: RestPagination, sort: SortMeta): Observable<ResultList<AccountFollow>> { 21 getFollowing (pagination: RestPagination, sort: SortMeta): Observable<ResultList<AccountFollow>> {
22 let params = new HttpParams() 22 let params = new HttpParams()
23 params = this.restService.addRestGetParams(params, pagination, sort) 23 params = this.restService.addRestGetParams(params, pagination, sort)
24 24
25 return this.authHttp.get<ResultList<Account>>(FollowService.BASE_APPLICATION_URL + '/following', { params }) 25 return this.authHttp.get<ResultList<Account>>(FollowService.BASE_APPLICATION_URL + '/following', { params })
26 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 26 .pipe(
27 .catch(res => this.restExtractor.handleError(res)) 27 map(res => this.restExtractor.convertResultListDateToHuman(res)),
28 catchError(res => this.restExtractor.handleError(res))
29 )
28 } 30 }
29 31
30 getFollowers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<AccountFollow>> { 32 getFollowers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<AccountFollow>> {
31 let params = new HttpParams() 33 let params = new HttpParams()
32 params = this.restService.addRestGetParams(params, pagination, sort) 34 params = this.restService.addRestGetParams(params, pagination, sort)
33 35
34 return this.authHttp.get<ResultList<Account>>(FollowService.BASE_APPLICATION_URL + '/followers', { params }) 36 return this.authHttp.get<ResultList<AccountFollow>>(FollowService.BASE_APPLICATION_URL + '/followers', { params })
35 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 37 .pipe(
36 .catch(res => this.restExtractor.handleError(res)) 38 map(res => this.restExtractor.convertResultListDateToHuman(res)),
39 catchError(res => this.restExtractor.handleError(res))
40 )
37 } 41 }
38 42
39 follow (notEmptyHosts: string[]) { 43 follow (notEmptyHosts: string[]) {
@@ -42,13 +46,17 @@ export class FollowService {
42 } 46 }
43 47
44 return this.authHttp.post(FollowService.BASE_APPLICATION_URL + '/following', body) 48 return this.authHttp.post(FollowService.BASE_APPLICATION_URL + '/following', body)
45 .map(this.restExtractor.extractDataBool) 49 .pipe(
46 .catch(res => this.restExtractor.handleError(res)) 50 map(this.restExtractor.extractDataBool),
51 catchError(res => this.restExtractor.handleError(res))
52 )
47 } 53 }
48 54
49 unfollow (follow: AccountFollow) { 55 unfollow (follow: AccountFollow) {
50 return this.authHttp.delete(FollowService.BASE_APPLICATION_URL + '/following/' + follow.following.host) 56 return this.authHttp.delete(FollowService.BASE_APPLICATION_URL + '/following/' + follow.following.host)
51 .map(this.restExtractor.extractDataBool) 57 .pipe(
52 .catch(res => this.restExtractor.handleError(res)) 58 map(this.restExtractor.extractDataBool),
59 catchError(res => this.restExtractor.handleError(res))
60 )
53 } 61 }
54} 62}
diff --git a/client/src/app/+admin/jobs/shared/job.service.ts b/client/src/app/+admin/jobs/shared/job.service.ts
index 98f29b742..6441eaac1 100644
--- a/client/src/app/+admin/jobs/shared/job.service.ts
+++ b/client/src/app/+admin/jobs/shared/job.service.ts
@@ -1,9 +1,8 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { SortMeta } from 'primeng/primeng' 4import { SortMeta } from 'primeng/primeng'
4import 'rxjs/add/operator/catch' 5import { Observable } from 'rxjs'
5import 'rxjs/add/operator/map'
6import { Observable } from 'rxjs/Observable'
7import { ResultList } from '../../../../../../shared' 6import { ResultList } from '../../../../../../shared'
8import { JobState } from '../../../../../../shared/models' 7import { JobState } from '../../../../../../shared/models'
9import { Job } from '../../../../../../shared/models/server/job.model' 8import { Job } from '../../../../../../shared/models/server/job.model'
@@ -25,9 +24,11 @@ export class JobService {
25 params = this.restService.addRestGetParams(params, pagination, sort) 24 params = this.restService.addRestGetParams(params, pagination, sort)
26 25
27 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + '/' + state, { params }) 26 return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + '/' + state, { params })
28 .map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'updatedAt' ])) 27 .pipe(
29 .map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData)) 28 map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'updatedAt' ])),
30 .catch(err => this.restExtractor.handleError(err)) 29 map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData)),
30 catchError(err => this.restExtractor.handleError(err))
31 )
31 } 32 }
32 33
33 private prettyPrintData (obj: Job) { 34 private prettyPrintData (obj: Job) {
diff --git a/client/src/app/+admin/users/shared/user.service.ts b/client/src/app/+admin/users/shared/user.service.ts
index 6536546fb..578cd98c3 100644
--- a/client/src/app/+admin/users/shared/user.service.ts
+++ b/client/src/app/+admin/users/shared/user.service.ts
@@ -1,10 +1,9 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { BytesPipe } from 'ngx-pipes' 4import { BytesPipe } from 'ngx-pipes'
4import { SortMeta } from 'primeng/components/common/sortmeta' 5import { SortMeta } from 'primeng/components/common/sortmeta'
5import 'rxjs/add/operator/catch' 6import { Observable } from 'rxjs'
6import 'rxjs/add/operator/map'
7import { Observable } from 'rxjs/Observable'
8import { ResultList, UserCreate, UserUpdate } from '../../../../../../shared' 7import { ResultList, UserCreate, UserUpdate } from '../../../../../../shared'
9import { environment } from '../../../../environments/environment' 8import { environment } from '../../../../environments/environment'
10import { RestExtractor, RestPagination, RestService, User } from '../../../shared' 9import { RestExtractor, RestPagination, RestService, User } from '../../../shared'
@@ -18,23 +17,28 @@ export class UserService {
18 private authHttp: HttpClient, 17 private authHttp: HttpClient,
19 private restService: RestService, 18 private restService: RestService,
20 private restExtractor: RestExtractor 19 private restExtractor: RestExtractor
21 ) {} 20 ) {
21 }
22 22
23 addUser (userCreate: UserCreate) { 23 addUser (userCreate: UserCreate) {
24 return this.authHttp.post(UserService.BASE_USERS_URL, userCreate) 24 return this.authHttp.post(UserService.BASE_USERS_URL, userCreate)
25 .map(this.restExtractor.extractDataBool) 25 .pipe(
26 .catch(err => this.restExtractor.handleError(err)) 26 map(this.restExtractor.extractDataBool),
27 catchError(err => this.restExtractor.handleError(err))
28 )
27 } 29 }
28 30
29 updateUser (userId: number, userUpdate: UserUpdate) { 31 updateUser (userId: number, userUpdate: UserUpdate) {
30 return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate) 32 return this.authHttp.put(UserService.BASE_USERS_URL + userId, userUpdate)
31 .map(this.restExtractor.extractDataBool) 33 .pipe(
32 .catch(err => this.restExtractor.handleError(err)) 34 map(this.restExtractor.extractDataBool),
35 catchError(err => this.restExtractor.handleError(err))
36 )
33 } 37 }
34 38
35 getUser (userId: number) { 39 getUser (userId: number) {
36 return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId) 40 return this.authHttp.get<User>(UserService.BASE_USERS_URL + userId)
37 .catch(err => this.restExtractor.handleError(err)) 41 .pipe(catchError(err => this.restExtractor.handleError(err)))
38 } 42 }
39 43
40 getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> { 44 getUsers (pagination: RestPagination, sort: SortMeta): Observable<ResultList<User>> {
@@ -42,13 +46,16 @@ export class UserService {
42 params = this.restService.addRestGetParams(params, pagination, sort) 46 params = this.restService.addRestGetParams(params, pagination, sort)
43 47
44 return this.authHttp.get<ResultList<User>>(UserService.BASE_USERS_URL, { params }) 48 return this.authHttp.get<ResultList<User>>(UserService.BASE_USERS_URL, { params })
45 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 49 .pipe(
46 .map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))) 50 map(res => this.restExtractor.convertResultListDateToHuman(res)),
47 .catch(err => this.restExtractor.handleError(err)) 51 map(res => this.restExtractor.applyToResultListData(res, this.formatUser.bind(this))),
52 catchError(err => this.restExtractor.handleError(err))
53 )
48 } 54 }
49 55
50 removeUser (user: User) { 56 removeUser (user: User) {
51 return this.authHttp.delete(UserService.BASE_USERS_URL + user.id) 57 return this.authHttp.delete(UserService.BASE_USERS_URL + user.id)
58 .pipe(catchError(err => this.restExtractor.handleError(err)))
52 } 59 }
53 60
54 private formatUser (user: User) { 61 private formatUser (user: User) {
diff --git a/client/src/app/+admin/users/user-edit/user-update.component.ts b/client/src/app/+admin/users/user-edit/user-update.component.ts
index 23e44ac1f..3cde07c65 100644
--- a/client/src/app/+admin/users/user-edit/user-update.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-update.component.ts
@@ -1,20 +1,13 @@
1import { Component, OnDestroy, OnInit } from '@angular/core' 1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 2import { FormBuilder, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { Subscription } from 'rxjs/Subscription' 4import { Subscription } from 'rxjs'
5
6import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
7
8import { UserService } from '../shared' 6import { UserService } from '../shared'
9import { 7import { User, USER_EMAIL, USER_ROLE, USER_VIDEO_QUOTA } from '../../../shared'
10 USER_EMAIL,
11 USER_VIDEO_QUOTA,
12 USER_ROLE,
13 User
14} from '../../../shared'
15import { ServerService } from '../../../core' 8import { ServerService } from '../../../core'
16import { UserEdit } from './user-edit' 9import { UserEdit } from './user-edit'
17import { UserUpdate, UserRole } from '../../../../../../shared' 10import { UserUpdate } from '../../../../../../shared'
18 11
19@Component({ 12@Component({
20 selector: 'my-user-update', 13 selector: 'my-user-update',
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
index fab9cacd8..c82bb39c8 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-create.component.ts
@@ -1,8 +1,6 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import 'rxjs/add/observable/from'
5import 'rxjs/add/operator/concatAll'
6import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' 4import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
7import { FormBuilder, FormGroup } from '@angular/forms' 5import { FormBuilder, FormGroup } from '@angular/forms'
8import { VideoChannelCreate } from '../../../../../shared/models/videos' 6import { VideoChannelCreate } from '../../../../../shared/models/videos'
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
index 9adc38691..b4c8df3cd 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
@@ -1,8 +1,6 @@
1import { Component, OnInit, OnDestroy } from '@angular/core' 1import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 2import { ActivatedRoute, Router } from '@angular/router'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import 'rxjs/add/observable/from'
5import 'rxjs/add/operator/concatAll'
6import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit' 4import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
7import { FormBuilder, FormGroup } from '@angular/forms' 5import { FormBuilder, FormGroup } from '@angular/forms'
8import { VideoChannelUpdate } from '../../../../../shared/models/videos' 6import { VideoChannelUpdate } from '../../../../../shared/models/videos'
@@ -12,7 +10,7 @@ import {
12 VIDEO_CHANNEL_SUPPORT 10 VIDEO_CHANNEL_SUPPORT
13} from '@app/shared/forms/form-validators/video-channel' 11} from '@app/shared/forms/form-validators/video-channel'
14import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 12import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
15import { Subscription } from 'rxjs/Subscription' 13import { Subscription } from 'rxjs'
16import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 14import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
17import { AuthService } from '@app/core' 15import { AuthService } from '@app/core'
18 16
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
index eeaca11df..7abf48826 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
@@ -1,12 +1,11 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { NotificationsService } from 'angular2-notifications' 2import { NotificationsService } from 'angular2-notifications'
3import 'rxjs/add/observable/from'
4import 'rxjs/add/operator/concatAll'
5import { AuthService } from '../../core/auth' 3import { AuthService } from '../../core/auth'
6import { ConfirmService } from '../../core/confirm' 4import { ConfirmService } from '../../core/confirm'
7import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 5import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
8import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 6import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
9import { User } from '@app/shared' 7import { User } from '@app/shared'
8import { flatMap } from 'rxjs/operators'
10 9
11@Component({ 10@Component({
12 selector: 'my-account-video-channels', 11 selector: 'my-account-video-channels',
@@ -53,7 +52,7 @@ export class MyAccountVideoChannelsComponent implements OnInit {
53 52
54 private loadVideoChannels () { 53 private loadVideoChannels () {
55 this.authService.userInformationLoaded 54 this.authService.userInformationLoaded
56 .flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account.id)) 55 .pipe(flatMap(() => this.videoChannelService.listAccountVideoChannels(this.user.account.id)))
57 .subscribe(res => this.videoChannels = res.data) 56 .subscribe(res => this.videoChannels = res.data)
58 } 57 }
59} 58}
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
index c1b53bcd5..d8c919fee 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.ts
@@ -1,12 +1,11 @@
1import { Component, OnInit, OnDestroy } from '@angular/core' 1import { from as observableFrom, Observable } from 'rxjs'
2import { concatAll, tap } from 'rxjs/operators'
3import { Component, OnDestroy, OnInit } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common' 5import { Location } from '@angular/common'
4import { immutableAssign } from '@app/shared/misc/utils' 6import { immutableAssign } from '@app/shared/misc/utils'
5import { ComponentPagination } from '@app/shared/rest/component-pagination.model' 7import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
6import { NotificationsService } from 'angular2-notifications' 8import { NotificationsService } from 'angular2-notifications'
7import 'rxjs/add/observable/from'
8import 'rxjs/add/operator/concatAll'
9import { Observable } from 'rxjs/Observable'
10import { AuthService } from '../../core/auth' 9import { AuthService } from '../../core/auth'
11import { ConfirmService } from '../../core/confirm' 10import { ConfirmService } from '../../core/confirm'
12import { AbstractVideoList } from '../../shared/video/abstract-video-list' 11import { AbstractVideoList } from '../../shared/video/abstract-video-list'
@@ -78,14 +77,14 @@ export class MyAccountVideosComponent extends AbstractVideoList implements OnIni
78 const observables: Observable<any>[] = [] 77 const observables: Observable<any>[] = []
79 for (const videoId of toDeleteVideosIds) { 78 for (const videoId of toDeleteVideosIds) {
80 const o = this.videoService 79 const o = this.videoService
81 .removeVideo(videoId) 80 .removeVideo(videoId)
82 .do(() => this.spliceVideosById(videoId)) 81 .pipe(tap(() => this.spliceVideosById(videoId)))
83 82
84 observables.push(o) 83 observables.push(o)
85 } 84 }
86 85
87 Observable.from(observables) 86 observableFrom(observables).pipe(
88 .concatAll() 87 concatAll())
89 .subscribe( 88 .subscribe(
90 res => { 89 res => {
91 this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`) 90 this.notificationsService.success('Success', `${toDeleteVideosIds.length} videos deleted.`)
diff --git a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
index 5d435708e..6f862718f 100644
--- a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
+++ b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts
@@ -1,7 +1,5 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { ActivatedRoute } from '@angular/router' 2import { ActivatedRoute } from '@angular/router'
3import 'rxjs/add/observable/from'
4import 'rxjs/add/operator/concatAll'
5import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 3import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
6import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 4import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
7 5
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
index 3cda630d3..c3eb359f2 100644
--- a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
+++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
@@ -3,8 +3,6 @@ import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common' 3import { Location } from '@angular/common'
4import { immutableAssign } from '@app/shared/misc/utils' 4import { immutableAssign } from '@app/shared/misc/utils'
5import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
6import 'rxjs/add/observable/from'
7import 'rxjs/add/operator/concatAll'
8import { AuthService } from '../../core/auth' 6import { AuthService } from '../../core/auth'
9import { ConfirmService } from '../../core/confirm' 7import { ConfirmService } from '../../core/confirm'
10import { AbstractVideoList } from '../../shared/video/abstract-video-list' 8import { AbstractVideoList } from '../../shared/video/abstract-video-list'
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 6223cde6d..4b388d7be 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -1,14 +1,9 @@
1import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
2import { catchError, map, mergeMap, tap } from 'rxjs/operators'
1import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http' 3import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 4import { Injectable } from '@angular/core'
3import { Router } from '@angular/router' 5import { Router } from '@angular/router'
4import { NotificationsService } from 'angular2-notifications' 6import { NotificationsService } from 'angular2-notifications'
5import 'rxjs/add/observable/throw'
6import 'rxjs/add/operator/do'
7import 'rxjs/add/operator/map'
8import 'rxjs/add/operator/mergeMap'
9import { Observable } from 'rxjs/Observable'
10import { ReplaySubject } from 'rxjs/ReplaySubject'
11import { Subject } from 'rxjs/Subject'
12import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared' 7import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared'
13import { User } from '../../../../../shared/models/users' 8import { User } from '../../../../../shared/models/users'
14import { UserLogin } from '../../../../../shared/models/users/user-login.model' 9import { UserLogin } from '../../../../../shared/models/users/user-login.model'
@@ -46,7 +41,7 @@ export class AuthService {
46 private notificationsService: NotificationsService, 41 private notificationsService: NotificationsService,
47 private restExtractor: RestExtractor, 42 private restExtractor: RestExtractor,
48 private router: Router 43 private router: Router
49 ) { 44 ) {
50 this.loginChanged = new Subject<AuthStatus>() 45 this.loginChanged = new Subject<AuthStatus>()
51 this.loginChangedSource = this.loginChanged.asObservable() 46 this.loginChangedSource = this.loginChanged.asObservable()
52 47
@@ -58,28 +53,28 @@ export class AuthService {
58 // Fetch the client_id/client_secret 53 // Fetch the client_id/client_secret
59 // FIXME: save in local storage? 54 // FIXME: save in local storage?
60 this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL) 55 this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL)
61 .catch(res => this.restExtractor.handleError(res)) 56 .pipe(catchError(res => this.restExtractor.handleError(res)))
62 .subscribe( 57 .subscribe(
63 res => { 58 res => {
64 this.clientId = res.client_id 59 this.clientId = res.client_id
65 this.clientSecret = res.client_secret 60 this.clientSecret = res.client_secret
66 console.log('Client credentials loaded.') 61 console.log('Client credentials loaded.')
67 }, 62 },
68 63
69 error => { 64 error => {
70 let errorMessage = error.message 65 let errorMessage = error.message
71 66
72 if (error.status === 403) { 67 if (error.status === 403) {
73 errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n` 68 errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
74 errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), ' + 69 errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), ' +
75 'in particular the "webserver" section.' 70 'in particular the "webserver" section.'
76 } 71 }
77 72
78 // We put a bigger timeout 73 // We put a bigger timeout
79 // This is an important message 74 // This is an important message
80 this.notificationsService.error('Error', errorMessage, { timeOut: 7000 }) 75 this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
81 } 76 }
82 ) 77 )
83 } 78 }
84 79
85 getRefreshToken () { 80 getRefreshToken () {
@@ -129,10 +124,12 @@ export class AuthService {
129 124
130 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded') 125 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
131 return this.http.post<UserLogin>(AuthService.BASE_TOKEN_URL, body.toString(), { headers }) 126 return this.http.post<UserLogin>(AuthService.BASE_TOKEN_URL, body.toString(), { headers })
132 .map(res => Object.assign(res, { username })) 127 .pipe(
133 .flatMap(res => this.mergeUserInformation(res)) 128 map(res => Object.assign(res, { username })),
134 .map(res => this.handleLogin(res)) 129 mergeMap(res => this.mergeUserInformation(res)),
135 .catch(res => this.restExtractor.handleError(res)) 130 map(res => this.handleLogin(res)),
131 catchError(res => this.restExtractor.handleError(res))
132 )
136 } 133 }
137 134
138 logout () { 135 logout () {
@@ -161,20 +158,22 @@ export class AuthService {
161 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded') 158 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
162 159
163 this.refreshingTokenObservable = this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers }) 160 this.refreshingTokenObservable = this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
164 .map(res => this.handleRefreshToken(res)) 161 .pipe(
165 .do(() => this.refreshingTokenObservable = null) 162 map(res => this.handleRefreshToken(res)),
166 .catch(err => { 163 tap(() => this.refreshingTokenObservable = null),
167 this.refreshingTokenObservable = null 164 catchError(err => {
168 165 this.refreshingTokenObservable = null
169 console.error(err) 166
170 console.log('Cannot refresh token -> logout...') 167 console.error(err)
171 this.logout() 168 console.log('Cannot refresh token -> logout...')
172 this.router.navigate([ '/login' ]) 169 this.logout()
173 170 this.router.navigate([ '/login' ])
174 return Observable.throw({ 171
175 error: 'You need to reconnect.' 172 return observableThrowError({
176 }) 173 error: 'You need to reconnect.'
177 }) 174 })
175 })
176 )
178 177
179 return this.refreshingTokenObservable 178 return this.refreshingTokenObservable
180 } 179 }
@@ -188,14 +187,14 @@ export class AuthService {
188 } 187 }
189 188
190 this.mergeUserInformation(obj) 189 this.mergeUserInformation(obj)
191 .subscribe( 190 .subscribe(
192 res => { 191 res => {
193 this.user.patch(res) 192 this.user.patch(res)
194 this.user.save() 193 this.user.save()
195 194
196 this.userInformationLoaded.next(true) 195 this.userInformationLoaded.next(true)
197 } 196 }
198 ) 197 )
199 } 198 }
200 199
201 private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> { 200 private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
@@ -203,7 +202,7 @@ export class AuthService {
203 const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`) 202 const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)
204 203
205 return this.http.get<UserServerModel>(AuthService.BASE_USER_INFORMATION_URL, { headers }) 204 return this.http.get<UserServerModel>(AuthService.BASE_USER_INFORMATION_URL, { headers })
206 .map(res => Object.assign(obj, res)) 205 .pipe(map(res => Object.assign(obj, res)))
207 } 206 }
208 207
209 private handleLogin (obj: UserLoginWithUserInformation) { 208 private handleLogin (obj: UserLoginWithUserInformation) {
diff --git a/client/src/app/core/confirm/confirm.service.ts b/client/src/app/core/confirm/confirm.service.ts
index d99226f05..8419f622b 100644
--- a/client/src/app/core/confirm/confirm.service.ts
+++ b/client/src/app/core/confirm/confirm.service.ts
@@ -1,7 +1,6 @@
1import { first } from 'rxjs/operators'
1import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
2import { Subject } from 'rxjs/Subject' 3import { Subject } from 'rxjs'
3import 'rxjs/add/operator/first'
4import 'rxjs/add/operator/toPromise'
5 4
6type ConfirmOptions = { 5type ConfirmOptions = {
7 title: string 6 title: string
@@ -19,12 +18,12 @@ export class ConfirmService {
19 confirm (message: string, title = '', confirmButtonText?: string) { 18 confirm (message: string, title = '', confirmButtonText?: string) {
20 this.showConfirm.next({ title, message, confirmButtonText }) 19 this.showConfirm.next({ title, message, confirmButtonText })
21 20
22 return this.confirmResponse.asObservable().first().toPromise() 21 return this.confirmResponse.asObservable().pipe(first()).toPromise()
23 } 22 }
24 23
25 confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) { 24 confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) {
26 this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText }) 25 this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText })
27 26
28 return this.confirmResponse.asObservable().first().toPromise() 27 return this.confirmResponse.asObservable().pipe(first()).toPromise()
29 } 28 }
30} 29}
diff --git a/client/src/app/core/routing/preload-selected-modules-list.ts b/client/src/app/core/routing/preload-selected-modules-list.ts
index 8a458ec3e..3bca60317 100644
--- a/client/src/app/core/routing/preload-selected-modules-list.ts
+++ b/client/src/app/core/routing/preload-selected-modules-list.ts
@@ -1,14 +1,13 @@
1import { Route, PreloadingStrategy } from '@angular/router' 1import { Observable, timer as observableTimer, of as ofObservable } from 'rxjs'
2import { Observable } from 'rxjs/Observable' 2import { switchMap } from 'rxjs/operators'
3import 'rxjs/add/observable/timer' 3import { PreloadingStrategy, Route } from '@angular/router'
4import 'rxjs/add/operator/switchMap'
5 4
6export class PreloadSelectedModulesList implements PreloadingStrategy { 5export class PreloadSelectedModulesList implements PreloadingStrategy {
7 preload (route: Route, load: Function): Observable<any> { 6 preload (route: Route, load: Function): Observable<any> {
8 if (!route.data || !route.data.preload) return Observable.of(null) 7 if (!route.data || !route.data.preload) return ofObservable(null)
9 8
10 if (typeof route.data.preload === 'number') { 9 if (typeof route.data.preload === 'number') {
11 return Observable.timer(route.data.preload).switchMap(() => load()) 10 return observableTimer(route.data.preload).pipe(switchMap(() => load()))
12 } 11 }
13 12
14 return load() 13 return load()
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index a71c6d0bf..c5353023b 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -1,8 +1,8 @@
1import { tap } from 'rxjs/operators'
1import { HttpClient } from '@angular/common/http' 2import { HttpClient } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' 4import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
4import 'rxjs/add/operator/do' 5import { ReplaySubject } from 'rxjs'
5import { ReplaySubject } from 'rxjs/ReplaySubject'
6import { ServerConfig } from '../../../../../shared' 6import { ServerConfig } from '../../../../../shared'
7import { About } from '../../../../../shared/models/server/about.model' 7import { About } from '../../../../../shared/models/server/about.model'
8import { environment } from '../../../environments/environment' 8import { environment } from '../../../environments/environment'
@@ -69,12 +69,12 @@ export class ServerService {
69 69
70 loadConfig () { 70 loadConfig () {
71 this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL) 71 this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
72 .do(this.saveConfigLocally) 72 .pipe(tap(this.saveConfigLocally))
73 .subscribe(data => { 73 .subscribe(data => {
74 this.config = data 74 this.config = data
75 75
76 this.configLoaded.next(true) 76 this.configLoaded.next(true)
77 }) 77 })
78 } 78 }
79 79
80 loadVideoCategories () { 80 loadVideoCategories () {
diff --git a/client/src/app/header/header.component.ts b/client/src/app/header/header.component.ts
index 42de2dd92..9d2a83773 100644
--- a/client/src/app/header/header.component.ts
+++ b/client/src/app/header/header.component.ts
@@ -1,5 +1,6 @@
1import { filter, map } from 'rxjs/operators'
1import { Component, OnInit } from '@angular/core' 2import { Component, OnInit } from '@angular/core'
2import { Router, NavigationEnd } from '@angular/router' 3import { NavigationEnd, Router } from '@angular/router'
3import { getParameterByName } from '../shared/misc/utils' 4import { getParameterByName } from '../shared/misc/utils'
4 5
5@Component({ 6@Component({
@@ -15,9 +16,11 @@ export class HeaderComponent implements OnInit {
15 16
16 ngOnInit () { 17 ngOnInit () {
17 this.router.events 18 this.router.events
18 .filter(e => e instanceof NavigationEnd) 19 .pipe(
19 .map(() => getParameterByName('search', window.location.href)) 20 filter(e => e instanceof NavigationEnd),
20 .filter(searchQuery => !!searchQuery) 21 map(() => getParameterByName('search', window.location.href)),
22 filter(searchQuery => !!searchQuery)
23 )
21 .subscribe(searchQuery => this.searchValue = searchQuery) 24 .subscribe(searchQuery => this.searchValue = searchQuery)
22 } 25 }
23 26
diff --git a/client/src/app/shared/account/account.service.ts b/client/src/app/shared/account/account.service.ts
index 8c66ae04a..20e52d946 100644
--- a/client/src/app/shared/account/account.service.ts
+++ b/client/src/app/shared/account/account.service.ts
@@ -1,14 +1,11 @@
1import { map, tap, catchError } from 'rxjs/operators'
1import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
2import 'rxjs/add/operator/catch'
3import 'rxjs/add/operator/map'
4import { environment } from '../../../environments/environment' 3import { environment } from '../../../environments/environment'
5import { Observable } from 'rxjs/Observable' 4import { Observable, ReplaySubject } from 'rxjs'
6import { Account } from '@app/shared/account/account.model' 5import { Account } from '@app/shared/account/account.model'
7import { RestExtractor } from '@app/shared/rest/rest-extractor.service' 6import { RestExtractor } from '@app/shared/rest/rest-extractor.service'
8import { RestService } from '@app/shared/rest/rest.service'
9import { HttpClient } from '@angular/common/http' 7import { HttpClient } from '@angular/common/http'
10import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model' 8import { Account as ServerAccount } from '../../../../../shared/models/actors/account.model'
11import { ReplaySubject } from 'rxjs/ReplaySubject'
12 9
13@Injectable() 10@Injectable()
14export class AccountService { 11export class AccountService {
@@ -18,14 +15,15 @@ export class AccountService {
18 15
19 constructor ( 16 constructor (
20 private authHttp: HttpClient, 17 private authHttp: HttpClient,
21 private restExtractor: RestExtractor, 18 private restExtractor: RestExtractor
22 private restService: RestService
23 ) {} 19 ) {}
24 20
25 getAccount (id: number): Observable<Account> { 21 getAccount (id: number): Observable<Account> {
26 return this.authHttp.get<ServerAccount>(AccountService.BASE_ACCOUNT_URL + id) 22 return this.authHttp.get<ServerAccount>(AccountService.BASE_ACCOUNT_URL + id)
27 .map(accountHash => new Account(accountHash)) 23 .pipe(
28 .do(account => this.accountLoaded.next(account)) 24 map(accountHash => new Account(accountHash)),
29 .catch((res) => this.restExtractor.handleError(res)) 25 tap(account => this.accountLoaded.next(account)),
26 catchError(res => this.restExtractor.handleError(res))
27 )
30 } 28 }
31} 29}
diff --git a/client/src/app/shared/actor/actor.model.ts b/client/src/app/shared/actor/actor.model.ts
index 37d84cb6e..f820dc3c4 100644
--- a/client/src/app/shared/actor/actor.model.ts
+++ b/client/src/app/shared/actor/actor.model.ts
@@ -10,8 +10,8 @@ export abstract class Actor implements ActorServer {
10 host: string 10 host: string
11 followingCount: number 11 followingCount: number
12 followersCount: number 12 followersCount: number
13 createdAt: Date 13 createdAt: Date | string
14 updatedAt: Date 14 updatedAt: Date | string
15 avatar: Avatar 15 avatar: Avatar
16 16
17 avatarUrl: string 17 avatarUrl: string
@@ -41,8 +41,8 @@ export abstract class Actor implements ActorServer {
41 this.host = hash.host 41 this.host = hash.host
42 this.followingCount = hash.followingCount 42 this.followingCount = hash.followingCount
43 this.followersCount = hash.followersCount 43 this.followersCount = hash.followersCount
44 this.createdAt = new Date(hash.createdAt) 44 this.createdAt = new Date(hash.createdAt.toString())
45 this.updatedAt = new Date(hash.updatedAt) 45 this.updatedAt = new Date(hash.updatedAt.toString())
46 this.avatar = hash.avatar 46 this.avatar = hash.avatar
47 47
48 this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this) 48 this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this)
diff --git a/client/src/app/shared/auth/auth-interceptor.service.ts b/client/src/app/shared/auth/auth-interceptor.service.ts
index efcfc452b..bb236bf8c 100644
--- a/client/src/app/shared/auth/auth-interceptor.service.ts
+++ b/client/src/app/shared/auth/auth-interceptor.service.ts
@@ -1,14 +1,8 @@
1import { Observable, throwError as observableThrowError } from 'rxjs'
2import { catchError, switchMap } from 'rxjs/operators'
1import { Injectable, Injector } from '@angular/core' 3import { Injectable, Injector } from '@angular/core'
2import { 4import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'
3 HttpInterceptor,
4 HttpRequest,
5 HttpEvent,
6 HttpHandler, HTTP_INTERCEPTORS
7} from '@angular/common/http'
8import { Observable } from 'rxjs/Observable'
9
10import { AuthService } from '../../core' 5import { AuthService } from '../../core'
11import 'rxjs/add/operator/switchMap'
12 6
13@Injectable() 7@Injectable()
14export class AuthInterceptor implements HttpInterceptor { 8export class AuthInterceptor implements HttpInterceptor {
@@ -27,22 +21,26 @@ export class AuthInterceptor implements HttpInterceptor {
27 // Pass on the cloned request instead of the original request 21 // Pass on the cloned request instead of the original request
28 // Catch 401 errors (refresh token expired) 22 // Catch 401 errors (refresh token expired)
29 return next.handle(authReq) 23 return next.handle(authReq)
30 .catch(err => { 24 .pipe(
31 if (err.status === 401 && err.error && err.error.code === 'invalid_token') { 25 catchError(err => {
32 return this.handleTokenExpired(req, next) 26 if (err.status === 401 && err.error && err.error.code === 'invalid_token') {
33 } 27 return this.handleTokenExpired(req, next)
34 28 }
35 return Observable.throw(err) 29
36 }) 30 return observableThrowError(err)
31 })
32 )
37 } 33 }
38 34
39 private handleTokenExpired (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 35 private handleTokenExpired (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
40 return this.authService.refreshAccessToken() 36 return this.authService.refreshAccessToken()
41 .switchMap(() => { 37 .pipe(
42 const authReq = this.cloneRequestWithAuth(req) 38 switchMap(() => {
39 const authReq = this.cloneRequestWithAuth(req)
43 40
44 return next.handle(authReq) 41 return next.handle(authReq)
45 }) 42 })
43 )
46 } 44 }
47 45
48 private cloneRequestWithAuth (req: HttpRequest<any>) { 46 private cloneRequestWithAuth (req: HttpRequest<any>) {
diff --git a/client/src/app/shared/forms/markdown-textarea.component.ts b/client/src/app/shared/forms/markdown-textarea.component.ts
index 928a63b28..dcc85f3cd 100644
--- a/client/src/app/shared/forms/markdown-textarea.component.ts
+++ b/client/src/app/shared/forms/markdown-textarea.component.ts
@@ -1,10 +1,9 @@
1import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
1import { Component, forwardRef, Input, OnInit } from '@angular/core' 2import { Component, forwardRef, Input, OnInit } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 3import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import 'rxjs/add/operator/debounceTime'
4import 'rxjs/add/operator/distinctUntilChanged'
5import { isInSmallView } from '@app/shared/misc/utils' 4import { isInSmallView } from '@app/shared/misc/utils'
6import { MarkdownService } from '@app/videos/shared' 5import { MarkdownService } from '@app/videos/shared'
7import { Subject } from 'rxjs/Subject' 6import { Subject } from 'rxjs'
8import truncate from 'lodash-es/truncate' 7import truncate from 'lodash-es/truncate'
9 8
10@Component({ 9@Component({
@@ -40,9 +39,11 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
40 39
41 ngOnInit () { 40 ngOnInit () {
42 this.contentChanged 41 this.contentChanged
43 .debounceTime(150) 42 .pipe(
44 .distinctUntilChanged() 43 debounceTime(150),
45 .subscribe(() => this.updatePreviews()) 44 distinctUntilChanged()
45 )
46 .subscribe(() => this.updatePreviews())
46 47
47 this.contentChanged.next(this.content) 48 this.contentChanged.next(this.content)
48 49
diff --git a/client/src/app/shared/guards/can-deactivate-guard.service.ts b/client/src/app/shared/guards/can-deactivate-guard.service.ts
index c3b5f37f8..550dd656e 100644
--- a/client/src/app/shared/guards/can-deactivate-guard.service.ts
+++ b/client/src/app/shared/guards/can-deactivate-guard.service.ts
@@ -1,6 +1,6 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router' 2import { ActivatedRouteSnapshot, CanDeactivate, RouterStateSnapshot } from '@angular/router'
3import { Observable } from 'rxjs/Observable' 3import { Observable } from 'rxjs'
4import { ConfirmService } from '../../core/index' 4import { ConfirmService } from '../../core/index'
5 5
6export interface CanComponentDeactivate { 6export interface CanComponentDeactivate {
diff --git a/client/src/app/shared/rest/rest-extractor.service.ts b/client/src/app/shared/rest/rest-extractor.service.ts
index 8ed24c727..4cfe28536 100644
--- a/client/src/app/shared/rest/rest-extractor.service.ts
+++ b/client/src/app/shared/rest/rest-extractor.service.ts
@@ -1,7 +1,6 @@
1import { HttpErrorResponse } from '@angular/common/http' 1import { of, throwError as observableThrowError } from 'rxjs'
2import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
3import { dateToHuman } from '@app/shared/misc/utils' 3import { dateToHuman } from '@app/shared/misc/utils'
4import { Observable } from 'rxjs/Observable'
5import { ResultList } from '../../../../../shared' 4import { ResultList } from '../../../../../shared'
6 5
7@Injectable() 6@Injectable()
@@ -86,6 +85,8 @@ export class RestExtractor {
86 errorObj.body = err.error 85 errorObj.body = err.error
87 } 86 }
88 87
89 return Observable.throw(errorObj) 88 observableThrowError(errorObj)
89
90 return of(undefined)
90 } 91 }
91} 92}
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index adb840cec..4843be618 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -1,7 +1,6 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient } from '@angular/common/http' 2import { HttpClient } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import 'rxjs/add/operator/catch'
4import 'rxjs/add/operator/map'
5import { UserCreate, UserUpdateMe } from '../../../../../shared' 4import { UserCreate, UserUpdateMe } from '../../../../../shared'
6import { environment } from '../../../environments/environment' 5import { environment } from '../../../environments/environment'
7import { RestExtractor } from '../rest' 6import { RestExtractor } from '../rest'
@@ -13,7 +12,8 @@ export class UserService {
13 constructor ( 12 constructor (
14 private authHttp: HttpClient, 13 private authHttp: HttpClient,
15 private restExtractor: RestExtractor 14 private restExtractor: RestExtractor
16 ) {} 15 ) {
16 }
17 17
18 changePassword (newPassword: string) { 18 changePassword (newPassword: string) {
19 const url = UserService.BASE_USERS_URL + 'me' 19 const url = UserService.BASE_USERS_URL + 'me'
@@ -22,44 +22,52 @@ export class UserService {
22 } 22 }
23 23
24 return this.authHttp.put(url, body) 24 return this.authHttp.put(url, body)
25 .map(this.restExtractor.extractDataBool) 25 .pipe(
26 .catch(res => this.restExtractor.handleError(res)) 26 map(this.restExtractor.extractDataBool),
27 catchError(res => this.restExtractor.handleError(res))
28 )
27 } 29 }
28 30
29 updateMyProfile (profile: UserUpdateMe) { 31 updateMyProfile (profile: UserUpdateMe) {
30 const url = UserService.BASE_USERS_URL + 'me' 32 const url = UserService.BASE_USERS_URL + 'me'
31 33
32 return this.authHttp.put(url, profile) 34 return this.authHttp.put(url, profile)
33 .map(this.restExtractor.extractDataBool) 35 .pipe(
34 .catch(res => this.restExtractor.handleError(res)) 36 map(this.restExtractor.extractDataBool),
37 catchError(res => this.restExtractor.handleError(res))
38 )
35 } 39 }
36 40
37 changeAvatar (avatarForm: FormData) { 41 changeAvatar (avatarForm: FormData) {
38 const url = UserService.BASE_USERS_URL + 'me/avatar/pick' 42 const url = UserService.BASE_USERS_URL + 'me/avatar/pick'
39 43
40 return this.authHttp.post(url, avatarForm) 44 return this.authHttp.post(url, avatarForm)
41 .catch(this.restExtractor.handleError) 45 .pipe(catchError(this.restExtractor.handleError))
42 } 46 }
43 47
44 signup (userCreate: UserCreate) { 48 signup (userCreate: UserCreate) {
45 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate) 49 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
46 .map(this.restExtractor.extractDataBool) 50 .pipe(
47 .catch(res => this.restExtractor.handleError(res)) 51 map(this.restExtractor.extractDataBool),
52 catchError(res => this.restExtractor.handleError(res))
53 )
48 } 54 }
49 55
50 getMyVideoQuotaUsed () { 56 getMyVideoQuotaUsed () {
51 const url = UserService.BASE_USERS_URL + '/me/video-quota-used' 57 const url = UserService.BASE_USERS_URL + '/me/video-quota-used'
52 58
53 return this.authHttp.get(url) 59 return this.authHttp.get(url)
54 .catch(res => this.restExtractor.handleError(res)) 60 .pipe(catchError(res => this.restExtractor.handleError(res)))
55 } 61 }
56 62
57 askResetPassword (email: string) { 63 askResetPassword (email: string) {
58 const url = UserService.BASE_USERS_URL + '/ask-reset-password' 64 const url = UserService.BASE_USERS_URL + '/ask-reset-password'
59 65
60 return this.authHttp.post(url, { email }) 66 return this.authHttp.post(url, { email })
61 .map(this.restExtractor.extractDataBool) 67 .pipe(
62 .catch(res => this.restExtractor.handleError(res)) 68 map(this.restExtractor.extractDataBool),
69 catchError(res => this.restExtractor.handleError(res))
70 )
63 } 71 }
64 72
65 resetPassword (userId: number, verificationString: string, password: string) { 73 resetPassword (userId: number, verificationString: string, password: string) {
@@ -70,7 +78,9 @@ export class UserService {
70 } 78 }
71 79
72 return this.authHttp.post(url, body) 80 return this.authHttp.post(url, body)
73 .map(this.restExtractor.extractDataBool) 81 .pipe(
74 .catch(res => this.restExtractor.handleError(res)) 82 map(this.restExtractor.extractDataBool),
83 catchError(res => this.restExtractor.handleError(res))
84 )
75 } 85 }
76} 86}
diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts
index ae00c4c45..6fab3ef43 100644
--- a/client/src/app/shared/video-abuse/video-abuse.service.ts
+++ b/client/src/app/shared/video-abuse/video-abuse.service.ts
@@ -1,9 +1,8 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { SortMeta } from 'primeng/components/common/sortmeta' 4import { SortMeta } from 'primeng/components/common/sortmeta'
4import 'rxjs/add/operator/catch' 5import { Observable } from 'rxjs'
5import 'rxjs/add/operator/map'
6import { Observable } from 'rxjs/Observable'
7import { ResultList, VideoAbuse } from '../../../../../shared' 6import { ResultList, VideoAbuse } from '../../../../../shared'
8import { environment } from '../../../environments/environment' 7import { environment } from '../../../environments/environment'
9import { RestExtractor, RestPagination, RestService } from '../rest' 8import { RestExtractor, RestPagination, RestService } from '../rest'
@@ -25,8 +24,10 @@ export class VideoAbuseService {
25 params = this.restService.addRestGetParams(params, pagination, sort) 24 params = this.restService.addRestGetParams(params, pagination, sort)
26 25
27 return this.authHttp.get<ResultList<VideoAbuse>>(url, { params }) 26 return this.authHttp.get<ResultList<VideoAbuse>>(url, { params })
28 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 27 .pipe(
29 .catch(res => this.restExtractor.handleError(res)) 28 map(res => this.restExtractor.convertResultListDateToHuman(res)),
29 catchError(res => this.restExtractor.handleError(res))
30 )
30 } 31 }
31 32
32 reportVideo (id: number, reason: string) { 33 reportVideo (id: number, reason: string) {
@@ -36,7 +37,9 @@ export class VideoAbuseService {
36 } 37 }
37 38
38 return this.authHttp.post(url, body) 39 return this.authHttp.post(url, body)
39 .map(this.restExtractor.extractDataBool) 40 .pipe(
40 .catch(res => this.restExtractor.handleError(res)) 41 map(this.restExtractor.extractDataBool),
42 catchError(res => this.restExtractor.handleError(res))
43 )
41 } 44 }
42} 45}
diff --git a/client/src/app/shared/video-blacklist/video-blacklist.service.ts b/client/src/app/shared/video-blacklist/video-blacklist.service.ts
index 14c8b5dc0..040d82c9a 100644
--- a/client/src/app/shared/video-blacklist/video-blacklist.service.ts
+++ b/client/src/app/shared/video-blacklist/video-blacklist.service.ts
@@ -1,9 +1,8 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { SortMeta } from 'primeng/components/common/sortmeta' 4import { SortMeta } from 'primeng/components/common/sortmeta'
4import 'rxjs/add/operator/catch' 5import { Observable } from 'rxjs'
5import 'rxjs/add/operator/map'
6import { Observable } from 'rxjs/Observable'
7import { BlacklistedVideo, ResultList } from '../../../../../shared' 6import { BlacklistedVideo, ResultList } from '../../../../../shared'
8import { environment } from '../../../environments/environment' 7import { environment } from '../../../environments/environment'
9import { RestExtractor, RestPagination, RestService } from '../rest' 8import { RestExtractor, RestPagination, RestService } from '../rest'
@@ -23,19 +22,25 @@ export class VideoBlacklistService {
23 params = this.restService.addRestGetParams(params, pagination, sort) 22 params = this.restService.addRestGetParams(params, pagination, sort)
24 23
25 return this.authHttp.get<ResultList<BlacklistedVideo>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params }) 24 return this.authHttp.get<ResultList<BlacklistedVideo>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params })
26 .map(res => this.restExtractor.convertResultListDateToHuman(res)) 25 .pipe(
27 .catch(res => this.restExtractor.handleError(res)) 26 map(res => this.restExtractor.convertResultListDateToHuman(res)),
27 catchError(res => this.restExtractor.handleError(res))
28 )
28 } 29 }
29 30
30 removeVideoFromBlacklist (videoId: number) { 31 removeVideoFromBlacklist (videoId: number) {
31 return this.authHttp.delete(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist') 32 return this.authHttp.delete(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist')
32 .map(this.restExtractor.extractDataBool) 33 .pipe(
33 .catch(res => this.restExtractor.handleError(res)) 34 map(this.restExtractor.extractDataBool),
35 catchError(res => this.restExtractor.handleError(res))
36 )
34 } 37 }
35 38
36 blacklistVideo (videoId: number) { 39 blacklistVideo (videoId: number) {
37 return this.authHttp.post(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist', {}) 40 return this.authHttp.post(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist', {})
38 .map(this.restExtractor.extractDataBool) 41 .pipe(
39 .catch(res => this.restExtractor.handleError(res)) 42 map(this.restExtractor.extractDataBool),
43 catchError(res => this.restExtractor.handleError(res))
44 )
40 } 45 }
41} 46}
diff --git a/client/src/app/shared/video-channel/video-channel.service.ts b/client/src/app/shared/video-channel/video-channel.service.ts
index 3533a0e9c..e1e3bf697 100644
--- a/client/src/app/shared/video-channel/video-channel.service.ts
+++ b/client/src/app/shared/video-channel/video-channel.service.ts
@@ -1,18 +1,13 @@
1import { catchError, map, tap } from 'rxjs/operators'
1import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
2import 'rxjs/add/operator/catch' 3import { Observable, ReplaySubject } from 'rxjs'
3import 'rxjs/add/operator/map'
4import { Observable } from 'rxjs/Observable'
5import { RestExtractor } from '../rest/rest-extractor.service' 4import { RestExtractor } from '../rest/rest-extractor.service'
6import { RestService } from '../rest/rest.service'
7import { HttpClient } from '@angular/common/http' 5import { HttpClient } from '@angular/common/http'
8import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos' 6import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos'
9import { AccountService } from '../account/account.service' 7import { AccountService } from '../account/account.service'
10import { ResultList } from '../../../../../shared' 8import { ResultList } from '../../../../../shared'
11import { VideoChannel } from './video-channel.model' 9import { VideoChannel } from './video-channel.model'
12import { ReplaySubject } from 'rxjs/ReplaySubject'
13import { environment } from '../../../environments/environment' 10import { environment } from '../../../environments/environment'
14import { UserService } from '@app/+admin/users/shared/user.service'
15import { User } from '@app/shared'
16 11
17@Injectable() 12@Injectable()
18export class VideoChannelService { 13export class VideoChannelService {
@@ -22,39 +17,48 @@ export class VideoChannelService {
22 17
23 constructor ( 18 constructor (
24 private authHttp: HttpClient, 19 private authHttp: HttpClient,
25 private restExtractor: RestExtractor, 20 private restExtractor: RestExtractor
26 private restService: RestService
27 ) {} 21 ) {}
28 22
29 getVideoChannel (videoChannelUUID: string) { 23 getVideoChannel (videoChannelUUID: string) {
30 return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID) 24 return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID)
31 .map(videoChannelHash => new VideoChannel(videoChannelHash)) 25 .pipe(
32 .do(videoChannel => this.videoChannelLoaded.next(videoChannel)) 26 map(videoChannelHash => new VideoChannel(videoChannelHash)),
33 .catch((res) => this.restExtractor.handleError(res)) 27 tap(videoChannel => this.videoChannelLoaded.next(videoChannel)),
28 catchError(res => this.restExtractor.handleError(res))
29 )
34 } 30 }
35 31
36 listAccountVideoChannels (accountId: number): Observable<ResultList<VideoChannel>> { 32 listAccountVideoChannels (accountId: number): Observable<ResultList<VideoChannel>> {
37 return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + accountId + '/video-channels') 33 return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + accountId + '/video-channels')
38 .map(res => this.extractVideoChannels(res)) 34 .pipe(
39 .catch((res) => this.restExtractor.handleError(res)) 35 map(res => this.extractVideoChannels(res)),
36 catchError((res) => this.restExtractor.handleError(res))
37 )
40 } 38 }
41 39
42 createVideoChannel (videoChannel: VideoChannelCreate) { 40 createVideoChannel (videoChannel: VideoChannelCreate) {
43 return this.authHttp.post(VideoChannelService.BASE_VIDEO_CHANNEL_URL, videoChannel) 41 return this.authHttp.post(VideoChannelService.BASE_VIDEO_CHANNEL_URL, videoChannel)
44 .map(this.restExtractor.extractDataBool) 42 .pipe(
45 .catch(err => this.restExtractor.handleError(err)) 43 map(this.restExtractor.extractDataBool),
44 catchError(err => this.restExtractor.handleError(err))
45 )
46 } 46 }
47 47
48 updateVideoChannel (videoChannelUUID: string, videoChannel: VideoChannelUpdate) { 48 updateVideoChannel (videoChannelUUID: string, videoChannel: VideoChannelUpdate) {
49 return this.authHttp.put(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID, videoChannel) 49 return this.authHttp.put(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID, videoChannel)
50 .map(this.restExtractor.extractDataBool) 50 .pipe(
51 .catch(err => this.restExtractor.handleError(err)) 51 map(this.restExtractor.extractDataBool),
52 catchError(err => this.restExtractor.handleError(err))
53 )
52 } 54 }
53 55
54 removeVideoChannel (videoChannel: VideoChannel) { 56 removeVideoChannel (videoChannel: VideoChannel) {
55 return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid) 57 return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid)
56 .map(this.restExtractor.extractDataBool) 58 .pipe(
57 .catch(err => this.restExtractor.handleError(err)) 59 map(this.restExtractor.extractDataBool),
60 catchError(err => this.restExtractor.handleError(err))
61 )
58 } 62 }
59 63
60 private extractVideoChannels (result: ResultList<VideoChannelServer>) { 64 private extractVideoChannels (result: ResultList<VideoChannelServer>) {
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index d8a4b03af..d47df4da4 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -1,13 +1,11 @@
1import { debounceTime } from 'rxjs/operators'
1import { ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core' 2import { ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'
2import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
3import { Location } from '@angular/common' 4import { Location } from '@angular/common'
4import { isInMobileView } from '@app/shared/misc/utils' 5import { isInMobileView } from '@app/shared/misc/utils'
5import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' 6import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
6import { NotificationsService } from 'angular2-notifications' 7import { NotificationsService } from 'angular2-notifications'
7import 'rxjs/add/operator/debounceTime' 8import { fromEvent, Observable, Subscription } from 'rxjs'
8import { Observable } from 'rxjs/Observable'
9import { fromEvent } from 'rxjs/observable/fromEvent'
10import { Subscription } from 'rxjs/Subscription'
11import { AuthService } from '../../core/auth' 9import { AuthService } from '../../core/auth'
12import { ComponentPagination } from '../rest/component-pagination.model' 10import { ComponentPagination } from '../rest/component-pagination.model'
13import { VideoSortField } from './sort-field.type' 11import { VideoSortField } from './sort-field.type'
@@ -64,7 +62,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
64 this.loadRouteParams(routeParams) 62 this.loadRouteParams(routeParams)
65 63
66 this.resizeSubscription = fromEvent(window, 'resize') 64 this.resizeSubscription = fromEvent(window, 'resize')
67 .debounceTime(500) 65 .pipe(debounceTime(500))
68 .subscribe(() => this.calcPageSizes()) 66 .subscribe(() => this.calcPageSizes())
69 67
70 this.calcPageSizes() 68 this.calcPageSizes()
diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts
index e2730423f..0448e2c23 100644
--- a/client/src/app/shared/video/infinite-scroller.directive.ts
+++ b/client/src/app/shared/video/infinite-scroller.directive.ts
@@ -1,14 +1,6 @@
1import { distinct, distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators'
1import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' 2import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
2import 'rxjs/add/operator/debounceTime' 3import { fromEvent, Subscription } from 'rxjs'
3import 'rxjs/add/operator/distinct'
4import 'rxjs/add/operator/distinctUntilChanged'
5import 'rxjs/add/operator/filter'
6import 'rxjs/add/operator/map'
7import 'rxjs/add/operator/share'
8import 'rxjs/add/operator/startWith'
9import 'rxjs/add/operator/throttleTime'
10import { fromEvent } from 'rxjs/observable/fromEvent'
11import { Subscription } from 'rxjs/Subscription'
12 4
13@Directive({ 5@Directive({
14 selector: '[myInfiniteScroller]' 6 selector: '[myInfiniteScroller]'
@@ -51,43 +43,51 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
51 const throttleOptions = { leading: true, trailing: true } 43 const throttleOptions = { leading: true, trailing: true }
52 44
53 const scrollObservable = fromEvent(window, 'scroll') 45 const scrollObservable = fromEvent(window, 'scroll')
54 .startWith(true) 46 .pipe(
55 .throttleTime(200, undefined, throttleOptions) 47 startWith(null),
56 .map(() => ({ current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight })) 48 throttleTime(200, undefined, throttleOptions),
57 .distinctUntilChanged((o1, o2) => o1.current === o2.current) 49 map(() => ({ current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight })),
58 .share() 50 distinctUntilChanged((o1, o2) => o1.current === o2.current),
51 share()
52 )
59 53
60 // Scroll Down 54 // Scroll Down
61 this.scrollDownSub = scrollObservable 55 this.scrollDownSub = scrollObservable
62 // Check we scroll down 56 .pipe(
63 .filter(({ current }) => { 57 // Check we scroll down
64 const res = this.lastCurrentBottom < current 58 filter(({ current }) => {
59 const res = this.lastCurrentBottom < current
65 60
66 this.lastCurrentBottom = current 61 this.lastCurrentBottom = current
67 return res 62 return res
68 }) 63 }),
69 .filter(({ current, maximumScroll }) => maximumScroll <= 0 || (current / maximumScroll) > this.decimalLimit) 64 filter(({ current, maximumScroll }) => maximumScroll <= 0 || (current / maximumScroll) > this.decimalLimit)
65 )
70 .subscribe(() => this.nearOfBottom.emit()) 66 .subscribe(() => this.nearOfBottom.emit())
71 67
72 // Scroll up 68 // Scroll up
73 this.scrollUpSub = scrollObservable 69 this.scrollUpSub = scrollObservable
74 // Check we scroll up 70 .pipe(
75 .filter(({ current }) => { 71 // Check we scroll up
76 const res = this.lastCurrentTop > current 72 filter(({ current }) => {
73 const res = this.lastCurrentTop > current
77 74
78 this.lastCurrentTop = current 75 this.lastCurrentTop = current
79 return res 76 return res
80 }) 77 }),
81 .filter(({ current, maximumScroll }) => { 78 filter(({ current, maximumScroll }) => {
82 return current !== 0 && (1 - (current / maximumScroll)) > this.decimalLimit 79 return current !== 0 && (1 - (current / maximumScroll)) > this.decimalLimit
83 }) 80 })
81 )
84 .subscribe(() => this.nearOfTop.emit()) 82 .subscribe(() => this.nearOfTop.emit())
85 83
86 // Page change 84 // Page change
87 this.pageChangeSub = scrollObservable 85 this.pageChangeSub = scrollObservable
88 .distinct() 86 .pipe(
89 .map(({ current }) => this.calculateCurrentPage(current)) 87 distinct(),
90 .distinctUntilChanged() 88 map(({ current }) => this.calculateCurrentPage(current)),
89 distinctUntilChanged()
90 )
91 .subscribe(res => this.pageChanged.emit(res)) 91 .subscribe(res => this.pageChanged.emit(res))
92 } 92 }
93 93
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index cd8539b41..f57cb6d6d 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -1,8 +1,7 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http' 2import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import 'rxjs/add/operator/catch' 4import { Observable } from 'rxjs'
4import 'rxjs/add/operator/map'
5import { Observable } from 'rxjs/Observable'
6import { Video as VideoServerModel, VideoDetails as VideoDetailsServerModel } from '../../../../../shared' 5import { Video as VideoServerModel, VideoDetails as VideoDetailsServerModel } from '../../../../../shared'
7import { ResultList } from '../../../../../shared/models/result-list.model' 6import { ResultList } from '../../../../../shared/models/result-list.model'
8import { UserVideoRateUpdate } from '../../../../../shared/models/videos/user-video-rate-update.model' 7import { UserVideoRateUpdate } from '../../../../../shared/models/videos/user-video-rate-update.model'
@@ -43,14 +42,18 @@ export class VideoService {
43 42
44 getVideo (uuid: string): Observable<VideoDetails> { 43 getVideo (uuid: string): Observable<VideoDetails> {
45 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) 44 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
46 .map(videoHash => new VideoDetails(videoHash)) 45 .pipe(
47 .catch((res) => this.restExtractor.handleError(res)) 46 map(videoHash => new VideoDetails(videoHash)),
47 catchError(res => this.restExtractor.handleError(res))
48 )
48 } 49 }
49 50
50 viewVideo (uuid: string): Observable<VideoDetails> { 51 viewVideo (uuid: string): Observable<VideoDetails> {
51 return this.authHttp.post(this.getVideoViewUrl(uuid), {}) 52 return this.authHttp.post(this.getVideoViewUrl(uuid), {})
52 .map(this.restExtractor.extractDataBool) 53 .pipe(
53 .catch(this.restExtractor.handleError) 54 map(this.restExtractor.extractDataBool),
55 catchError(this.restExtractor.handleError)
56 )
54 } 57 }
55 58
56 updateVideo (video: VideoEdit) { 59 updateVideo (video: VideoEdit) {
@@ -79,16 +82,18 @@ export class VideoService {
79 const data = objectToFormData(body) 82 const data = objectToFormData(body)
80 83
81 return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data) 84 return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data)
82 .map(this.restExtractor.extractDataBool) 85 .pipe(
83 .catch(this.restExtractor.handleError) 86 map(this.restExtractor.extractDataBool),
87 catchError(this.restExtractor.handleError)
88 )
84 } 89 }
85 90
86 uploadVideo (video: FormData) { 91 uploadVideo (video: FormData) {
87 const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true }) 92 const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
88 93
89 return this.authHttp 94 return this.authHttp
90 .request(req) 95 .request(req)
91 .catch(this.restExtractor.handleError) 96 .pipe(catchError(this.restExtractor.handleError))
92 } 97 }
93 98
94 getMyVideos (videoPagination: ComponentPagination, sort: VideoSortField): Observable<{ videos: Video[], totalVideos: number}> { 99 getMyVideos (videoPagination: ComponentPagination, sort: VideoSortField): Observable<{ videos: Video[], totalVideos: number}> {
@@ -98,8 +103,10 @@ export class VideoService {
98 params = this.restService.addRestGetParams(params, pagination, sort) 103 params = this.restService.addRestGetParams(params, pagination, sort)
99 104
100 return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params }) 105 return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params })
101 .map(this.extractVideos) 106 .pipe(
102 .catch((res) => this.restExtractor.handleError(res)) 107 map(this.extractVideos),
108 catchError(res => this.restExtractor.handleError(res))
109 )
103 } 110 }
104 111
105 getAccountVideos ( 112 getAccountVideos (
@@ -114,8 +121,10 @@ export class VideoService {
114 121
115 return this.authHttp 122 return this.authHttp
116 .get(AccountService.BASE_ACCOUNT_URL + account.id + '/videos', { params }) 123 .get(AccountService.BASE_ACCOUNT_URL + account.id + '/videos', { params })
117 .map(this.extractVideos) 124 .pipe(
118 .catch((res) => this.restExtractor.handleError(res)) 125 map(this.extractVideos),
126 catchError(res => this.restExtractor.handleError(res))
127 )
119 } 128 }
120 129
121 getVideoChannelVideos ( 130 getVideoChannelVideos (
@@ -130,8 +139,10 @@ export class VideoService {
130 139
131 return this.authHttp 140 return this.authHttp
132 .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params }) 141 .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params })
133 .map(this.extractVideos) 142 .pipe(
134 .catch((res) => this.restExtractor.handleError(res)) 143 map(this.extractVideos),
144 catchError(res => this.restExtractor.handleError(res))
145 )
135 } 146 }
136 147
137 getVideos ( 148 getVideos (
@@ -149,9 +160,11 @@ export class VideoService {
149 } 160 }
150 161
151 return this.authHttp 162 return this.authHttp
152 .get(VideoService.BASE_VIDEO_URL, { params }) 163 .get(VideoService.BASE_VIDEO_URL, { params })
153 .map(this.extractVideos) 164 .pipe(
154 .catch((res) => this.restExtractor.handleError(res)) 165 map(this.extractVideos),
166 catchError(res => this.restExtractor.handleError(res))
167 )
155 } 168 }
156 169
157 buildBaseFeedUrls (params: HttpParams) { 170 buildBaseFeedUrls (params: HttpParams) {
@@ -215,23 +228,29 @@ export class VideoService {
215 params = params.append('search', search) 228 params = params.append('search', search)
216 229
217 return this.authHttp 230 return this.authHttp
218 .get<ResultList<VideoServerModel>>(url, { params }) 231 .get<ResultList<VideoServerModel>>(url, { params })
219 .map(this.extractVideos) 232 .pipe(
220 .catch((res) => this.restExtractor.handleError(res)) 233 map(this.extractVideos),
234 catchError(res => this.restExtractor.handleError(res))
235 )
221 } 236 }
222 237
223 removeVideo (id: number) { 238 removeVideo (id: number) {
224 return this.authHttp 239 return this.authHttp
225 .delete(VideoService.BASE_VIDEO_URL + id) 240 .delete(VideoService.BASE_VIDEO_URL + id)
226 .map(this.restExtractor.extractDataBool) 241 .pipe(
227 .catch((res) => this.restExtractor.handleError(res)) 242 map(this.restExtractor.extractDataBool),
243 catchError(res => this.restExtractor.handleError(res))
244 )
228 } 245 }
229 246
230 loadCompleteDescription (descriptionPath: string) { 247 loadCompleteDescription (descriptionPath: string) {
231 return this.authHttp 248 return this.authHttp
232 .get(environment.apiUrl + descriptionPath) 249 .get(environment.apiUrl + descriptionPath)
233 .map(res => res['description']) 250 .pipe(
234 .catch((res) => this.restExtractor.handleError(res)) 251 map(res => res[ 'description' ]),
252 catchError(res => this.restExtractor.handleError(res))
253 )
235 } 254 }
236 255
237 setVideoLike (id: number) { 256 setVideoLike (id: number) {
@@ -250,8 +269,8 @@ export class VideoService {
250 const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating' 269 const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating'
251 270
252 return this.authHttp 271 return this.authHttp
253 .get(url) 272 .get(url)
254 .catch(res => this.restExtractor.handleError(res)) 273 .pipe(catchError(res => this.restExtractor.handleError(res)))
255 } 274 }
256 275
257 private setVideoRate (id: number, rateType: VideoRateType) { 276 private setVideoRate (id: number, rateType: VideoRateType) {
@@ -261,9 +280,11 @@ export class VideoService {
261 } 280 }
262 281
263 return this.authHttp 282 return this.authHttp
264 .put(url, body) 283 .put(url, body)
265 .map(this.restExtractor.extractDataBool) 284 .pipe(
266 .catch(res => this.restExtractor.handleError(res)) 285 map(this.restExtractor.extractDataBool),
286 catchError(res => this.restExtractor.handleError(res))
287 )
267 } 288 }
268 289
269 private extractVideos (result: ResultList<VideoServerModel>) { 290 private extractVideos (result: ResultList<VideoServerModel>) {
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 77e984855..eab0a898e 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
@@ -3,7 +3,6 @@ import { FormBuilder, FormControl, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { VIDEO_IMAGE, VIDEO_SUPPORT } from '@app/shared' 4import { VIDEO_IMAGE, VIDEO_SUPPORT } from '@app/shared'
5import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
6import 'rxjs/add/observable/forkJoin'
7import { ServerService } from '../../../core/server' 6import { ServerService } from '../../../core/server'
8import { VIDEO_CHANNEL } from '../../../shared/forms/form-validators' 7import { VIDEO_CHANNEL } from '../../../shared/forms/form-validators'
9import { ValidatorMessage } from '../../../shared/forms/form-validators/validator-message' 8import { ValidatorMessage } from '../../../shared/forms/form-validators/validator-message'
diff --git a/client/src/app/videos/+video-edit/shared/video-image.component.ts b/client/src/app/videos/+video-edit/shared/video-image.component.ts
index 3f5705a92..df6565857 100644
--- a/client/src/app/videos/+video-edit/shared/video-image.component.ts
+++ b/client/src/app/videos/+video-edit/shared/video-image.component.ts
@@ -2,7 +2,6 @@ import { Component, forwardRef, Input } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' 3import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
4import { ServerService } from '@app/core' 4import { ServerService } from '@app/core'
5import 'rxjs/add/observable/forkJoin'
6 5
7@Component({ 6@Component({
8 selector: 'my-video-image', 7 selector: 'my-video-image',
@@ -16,7 +15,6 @@ import 'rxjs/add/observable/forkJoin'
16 } 15 }
17 ] 16 ]
18}) 17})
19
20export class VideoImageComponent implements ControlValueAccessor { 18export class VideoImageComponent implements ControlValueAccessor {
21 @Input() inputLabel: string 19 @Input() inputLabel: string
22 @Input() inputName: string 20 @Input() inputName: string
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 fa967018d..41d14573c 100644
--- a/client/src/app/videos/+video-edit/video-add.component.ts
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -7,7 +7,7 @@ import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.
7import { LoadingBarService } from '@ngx-loading-bar/core' 7import { LoadingBarService } from '@ngx-loading-bar/core'
8import { NotificationsService } from 'angular2-notifications' 8import { NotificationsService } from 'angular2-notifications'
9import { BytesPipe } from 'ngx-pipes' 9import { BytesPipe } from 'ngx-pipes'
10import { Subscription } from 'rxjs/Subscription' 10import { Subscription } from 'rxjs'
11import { VideoPrivacy } from '../../../../../shared/models/videos' 11import { VideoPrivacy } from '../../../../../shared/models/videos'
12import { AuthService, ServerService } from '../../core' 12import { AuthService, ServerService } from '../../core'
13import { FormReactive } from '../../shared' 13import { FormReactive } from '../../shared'
@@ -24,7 +24,6 @@ import { VideoService } from '../../shared/video/video.service'
24 './video-add.component.scss' 24 './video-add.component.scss'
25 ] 25 ]
26}) 26})
27
28export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy, CanComponentDeactivate { 27export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy, CanComponentDeactivate {
29 @ViewChild('videofileInput') videofileInput 28 @ViewChild('videofileInput') videofileInput
30 29
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 73e2764c6..b1d80bcaa 100644
--- a/client/src/app/videos/+video-edit/video-update.component.ts
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -1,9 +1,9 @@
1import { map, switchMap } from 'rxjs/operators'
1import { Component, OnInit } from '@angular/core' 2import { Component, OnInit } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 3import { FormBuilder, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute, Router } from '@angular/router'
4import { LoadingBarService } from '@ngx-loading-bar/core' 5import { LoadingBarService } from '@ngx-loading-bar/core'
5import { NotificationsService } from 'angular2-notifications' 6import { NotificationsService } from 'angular2-notifications'
6import 'rxjs/add/observable/forkJoin'
7import { VideoPrivacy } from '../../../../../shared/models/videos' 7import { VideoPrivacy } from '../../../../../shared/models/videos'
8import { ServerService } from '../../core' 8import { ServerService } from '../../core'
9import { AuthService } from '../../core/auth' 9import { AuthService } from '../../core/auth'
@@ -18,7 +18,6 @@ import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
18 styleUrls: [ './shared/video-edit.component.scss' ], 18 styleUrls: [ './shared/video-edit.component.scss' ],
19 templateUrl: './video-update.component.html' 19 templateUrl: './video-update.component.html'
20}) 20})
21
22export class VideoUpdateComponent extends FormReactive implements OnInit { 21export class VideoUpdateComponent extends FormReactive implements OnInit {
23 video: VideoEdit 22 video: VideoEdit
24 23
@@ -53,38 +52,40 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
53 this.serverService.videoPrivaciesLoaded 52 this.serverService.videoPrivaciesLoaded
54 .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies()) 53 .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies())
55 54
56 const uuid: string = this.route.snapshot.params['uuid'] 55 const uuid: string = this.route.snapshot.params[ 'uuid' ]
57 this.videoService.getVideo(uuid) 56 this.videoService.getVideo(uuid)
58 .switchMap(video => { 57 .pipe(
59 return this.videoService 58 switchMap(video => {
60 .loadCompleteDescription(video.descriptionPath) 59 return this.videoService
61 .map(description => Object.assign(video, { description })) 60 .loadCompleteDescription(video.descriptionPath)
62 }) 61 .pipe(map(description => Object.assign(video, { description })))
63 .subscribe( 62 })
64 video => { 63 )
65 this.video = new VideoEdit(video) 64 .subscribe(
66 65 video => {
67 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels) 66 this.video = new VideoEdit(video)
68 .catch(err => console.error(err)) 67
69 68 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
70 // We cannot set private a video that was not private 69 .catch(err => console.error(err))
71 if (video.privacy.id !== VideoPrivacy.PRIVATE) { 70
72 const newVideoPrivacies = [] 71 // We cannot set private a video that was not private
73 for (const p of this.videoPrivacies) { 72 if (video.privacy.id !== VideoPrivacy.PRIVATE) {
74 if (p.id !== VideoPrivacy.PRIVATE) newVideoPrivacies.push(p) 73 const newVideoPrivacies = []
74 for (const p of this.videoPrivacies) {
75 if (p.id !== VideoPrivacy.PRIVATE) newVideoPrivacies.push(p)
76 }
77
78 this.videoPrivacies = newVideoPrivacies
75 } 79 }
76 80
77 this.videoPrivacies = newVideoPrivacies 81 this.hydrateFormFromVideo()
78 } 82 },
79 83
80 this.hydrateFormFromVideo() 84 err => {
81 }, 85 console.error(err)
82 86 this.notificationsService.error('Error', err.message)
83 err => { 87 }
84 console.error(err) 88 )
85 this.notificationsService.error('Error', err.message)
86 }
87 )
88 } 89 }
89 90
90 checkForm () { 91 checkForm () {
diff --git a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
index d1ca1968b..b1f446475 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment-add.component.ts
@@ -1,7 +1,7 @@
1import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' 1import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 2import { FormBuilder, FormGroup } from '@angular/forms'
3import { NotificationsService } from 'angular2-notifications' 3import { NotificationsService } from 'angular2-notifications'
4import { Observable } from 'rxjs/Observable' 4import { Observable } from 'rxjs'
5import { VideoCommentCreate } from '../../../../../../shared/models/videos/video-comment.model' 5import { VideoCommentCreate } from '../../../../../../shared/models/videos/video-comment.model'
6import { FormReactive } from '../../../shared' 6import { FormReactive } from '../../../shared'
7import { VIDEO_COMMENT_TEXT } from '../../../shared/forms/form-validators/video-comment' 7import { VIDEO_COMMENT_TEXT } from '../../../shared/forms/form-validators/video-comment'
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.service.ts b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
index 0bf7696fe..5b9a991a0 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment.service.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comment.service.ts
@@ -1,10 +1,8 @@
1import { catchError, map } from 'rxjs/operators'
1import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
2import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
3import { lineFeedToHtml } from '@app/shared/misc/utils' 4import { lineFeedToHtml } from '@app/shared/misc/utils'
4import { MarkdownService } from '@app/videos/shared' 5import { Observable } from 'rxjs'
5import 'rxjs/add/operator/catch'
6import 'rxjs/add/operator/map'
7import { Observable } from 'rxjs/Observable'
8import { ResultList } from '../../../../../../shared/models' 6import { ResultList } from '../../../../../../shared/models'
9import { 7import {
10 VideoComment as VideoCommentServerModel, 8 VideoComment as VideoCommentServerModel,
@@ -32,8 +30,10 @@ export class VideoCommentService {
32 const normalizedComment = lineFeedToHtml(comment, 'text') 30 const normalizedComment = lineFeedToHtml(comment, 'text')
33 31
34 return this.authHttp.post(url, normalizedComment) 32 return this.authHttp.post(url, normalizedComment)
35 .map(data => this.extractVideoComment(data['comment'])) 33 .pipe(
36 .catch(this.restExtractor.handleError) 34 map(data => this.extractVideoComment(data['comment'])),
35 catchError(this.restExtractor.handleError)
36 )
37 } 37 }
38 38
39 addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) { 39 addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) {
@@ -41,8 +41,10 @@ export class VideoCommentService {
41 const normalizedComment = lineFeedToHtml(comment, 'text') 41 const normalizedComment = lineFeedToHtml(comment, 'text')
42 42
43 return this.authHttp.post(url, normalizedComment) 43 return this.authHttp.post(url, normalizedComment)
44 .map(data => this.extractVideoComment(data['comment'])) 44 .pipe(
45 .catch(this.restExtractor.handleError) 45 map(data => this.extractVideoComment(data[ 'comment' ])),
46 catchError(this.restExtractor.handleError)
47 )
46 } 48 }
47 49
48 getVideoCommentThreads ( 50 getVideoCommentThreads (
@@ -57,27 +59,33 @@ export class VideoCommentService {
57 59
58 const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads' 60 const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads'
59 return this.authHttp 61 return this.authHttp
60 .get(url, { params }) 62 .get(url, { params })
61 .map(this.extractVideoComments) 63 .pipe(
62 .catch((res) => this.restExtractor.handleError(res)) 64 map(this.extractVideoComments),
65 catchError((res) => this.restExtractor.handleError(res))
66 )
63 } 67 }
64 68
65 getVideoThreadComments (videoId: number | string, threadId: number): Observable<VideoCommentThreadTree> { 69 getVideoThreadComments (videoId: number | string, threadId: number): Observable<VideoCommentThreadTree> {
66 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comment-threads/${threadId}` 70 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comment-threads/${threadId}`
67 71
68 return this.authHttp 72 return this.authHttp
69 .get(url) 73 .get(url)
70 .map(tree => this.extractVideoCommentTree(tree as VideoCommentThreadTree)) 74 .pipe(
71 .catch((res) => this.restExtractor.handleError(res)) 75 map(tree => this.extractVideoCommentTree(tree as VideoCommentThreadTree)),
76 catchError((res) => this.restExtractor.handleError(res))
77 )
72 } 78 }
73 79
74 deleteVideoComment (videoId: number | string, commentId: number) { 80 deleteVideoComment (videoId: number | string, commentId: number) {
75 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comments/${commentId}` 81 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comments/${commentId}`
76 82
77 return this.authHttp 83 return this.authHttp
78 .delete(url) 84 .delete(url)
79 .map(this.restExtractor.extractDataBool) 85 .pipe(
80 .catch((res) => this.restExtractor.handleError(res)) 86 map(this.restExtractor.extractDataBool),
87 catchError((res) => this.restExtractor.handleError(res))
88 )
81 } 89 }
82 90
83 private extractVideoComment (videoComment: VideoCommentServerModel) { 91 private extractVideoComment (videoComment: VideoCommentServerModel) {
@@ -87,7 +95,7 @@ export class VideoCommentService {
87 private extractVideoComments (result: ResultList<VideoCommentServerModel>) { 95 private extractVideoComments (result: ResultList<VideoCommentServerModel>) {
88 const videoCommentsJson = result.data 96 const videoCommentsJson = result.data
89 const totalComments = result.total 97 const totalComments = result.total
90 const comments = [] 98 const comments: VideoComment[] = []
91 99
92 for (const videoCommentJson of videoCommentsJson) { 100 for (const videoCommentJson of videoCommentsJson) {
93 comments.push(new VideoComment(videoCommentJson)) 101 comments.push(new VideoComment(videoCommentJson))
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.ts b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
index a77a6e9f3..34f4a0701 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.ts
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.ts
@@ -2,7 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@
2import { ActivatedRoute } from '@angular/router' 2import { ActivatedRoute } from '@angular/router'
3import { ConfirmService } from '@app/core' 3import { ConfirmService } from '@app/core'
4import { NotificationsService } from 'angular2-notifications' 4import { NotificationsService } from 'angular2-notifications'
5import { Subscription } from 'rxjs/Subscription' 5import { Subscription } from 'rxjs'
6import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' 6import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
7import { AuthService } from '../../../core/auth' 7import { AuthService } from '../../../core/auth'
8import { ComponentPagination } from '../../../shared/rest/component-pagination.model' 8import { ComponentPagination } from '../../../shared/rest/component-pagination.model'
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 615b969e5..127ae919d 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -5,7 +5,7 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
5import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' 5import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
6import { MetaService } from '@ngx-meta/core' 6import { MetaService } from '@ngx-meta/core'
7import { NotificationsService } from 'angular2-notifications' 7import { NotificationsService } from 'angular2-notifications'
8import { Subscription } from 'rxjs/Subscription' 8import { Subscription } from 'rxjs'
9import * as videojs from 'video.js' 9import * as videojs from 'video.js'
10import 'videojs-hotkeys' 10import 'videojs-hotkeys'
11import * as WebTorrent from 'webtorrent' 11import * as WebTorrent from 'webtorrent'
@@ -13,7 +13,6 @@ import { UserVideoRateType, VideoRateType } from '../../../../../shared'
13import '../../../assets/player/peertube-videojs-plugin' 13import '../../../assets/player/peertube-videojs-plugin'
14import { AuthService, ConfirmService } from '../../core' 14import { AuthService, ConfirmService } from '../../core'
15import { VideoBlacklistService } from '../../shared' 15import { VideoBlacklistService } from '../../shared'
16import { Account } from '../../shared/account/account.model'
17import { VideoDetails } from '../../shared/video/video-details.model' 16import { VideoDetails } from '../../shared/video/video-details.model'
18import { Video } from '../../shared/video/video.model' 17import { Video } from '../../shared/video/video.model'
19import { VideoService } from '../../shared/video/video.service' 18import { VideoService } from '../../shared/video/video.service'
diff --git a/client/src/app/videos/video-list/video-search.component.ts b/client/src/app/videos/video-list/video-search.component.ts
index 774d81ed6..aab896d84 100644
--- a/client/src/app/videos/video-list/video-search.component.ts
+++ b/client/src/app/videos/video-list/video-search.component.ts
@@ -4,7 +4,7 @@ import { Location } from '@angular/common'
4import { RedirectService } from '@app/core' 4import { RedirectService } from '@app/core'
5import { immutableAssign } from '@app/shared/misc/utils' 5import { immutableAssign } from '@app/shared/misc/utils'
6import { NotificationsService } from 'angular2-notifications' 6import { NotificationsService } from 'angular2-notifications'
7import { Subscription } from 'rxjs/Subscription' 7import { Subscription } from 'rxjs'
8import { AuthService } from '../../core/auth' 8import { AuthService } from '../../core/auth'
9import { AbstractVideoList } from '../../shared/video/abstract-video-list' 9import { AbstractVideoList } from '../../shared/video/abstract-video-list'
10import { VideoService } from '../../shared/video/video.service' 10import { VideoService } from '../../shared/video/video.service'
diff --git a/package.json b/package.json
index 94cda5ef8..8c4409011 100644
--- a/package.json
+++ b/package.json
@@ -60,7 +60,7 @@
60 } 60 }
61 }, 61 },
62 "lint-staged": { 62 "lint-staged": {
63 "*.{js,ts,css,md}": "precise-commits", 63 "*.{css,md}": "precise-commits",
64 "*.scss": [ 64 "*.scss": [
65 "sass-lint-auto-fix -c .sass-lint.yml --verbose", 65 "sass-lint-auto-fix -c .sass-lint.yml --verbose",
66 "git add" 66 "git add"
diff --git a/scripts/watch/client.sh b/scripts/watch/client.sh
index 710c87037..7dcce5861 100755
--- a/scripts/watch/client.sh
+++ b/scripts/watch/client.sh
@@ -4,4 +4,4 @@ set -eu
4 4
5cd client 5cd client
6 6
7npm run ng -- server --hmr --host 0.0.0.0 --disable-host-check --port 3000 7npm run ng -- serve --hmr --host 0.0.0.0 --disable-host-check --port 3000