aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/src/app/+about/about-follows/about-follows.component.ts16
-rw-r--r--client/src/app/+about/about-instance/contact-admin-modal.component.ts8
-rw-r--r--client/src/app/+accounts/accounts.component.ts17
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts24
-rw-r--r--client/src/app/+admin/follows/followers-list/followers-list.component.ts32
-rw-r--r--client/src/app/+admin/follows/following-list/follow-modal.component.ts15
-rw-r--r--client/src/app/+admin/follows/following-list/following-list.component.ts23
-rw-r--r--client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts8
-rw-r--r--client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts16
-rw-r--r--client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts41
-rw-r--r--client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html8
-rw-r--r--client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts59
-rw-r--r--client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts24
-rw-r--r--client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts16
-rw-r--r--client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts16
-rw-r--r--client/src/app/+admin/system/debug/debug.component.ts8
-rw-r--r--client/src/app/+admin/system/jobs/jobs.component.ts8
-rw-r--r--client/src/app/+admin/system/logs/logs.component.ts10
-rw-r--r--client/src/app/+admin/users/user-edit/user-create.component.ts15
-rw-r--r--client/src/app/+admin/users/user-edit/user-password.component.ts11
-rw-r--r--client/src/app/+admin/users/user-edit/user-update.component.ts39
-rw-r--r--client/src/app/+admin/users/user-list/user-list.component.ts46
-rw-r--r--client/src/app/+login/login.component.ts32
-rw-r--r--client/src/app/+my-account/my-account-applications/my-account-applications.component.ts30
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts8
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts29
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts17
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts8
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts9
-rw-r--r--client/src/app/+my-account/my-account-settings/my-account-settings.component.ts16
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts8
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts78
-rw-r--r--client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts8
-rw-r--r--client/src/app/+my-library/my-history/my-history.component.ts16
-rw-r--r--client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts8
-rw-r--r--client/src/app/+my-library/my-ownership/my-ownership.component.ts16
-rw-r--r--client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts8
-rw-r--r--client/src/app/+my-library/my-video-imports/my-video-imports.component.ts8
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-create.component.ts15
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.ts16
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlist-update.component.ts23
-rw-r--r--client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts8
-rw-r--r--client/src/app/+my-library/my-videos/modals/video-change-ownership.component.ts16
-rw-r--r--client/src/app/+my-library/my-videos/my-videos.component.ts16
-rw-r--r--client/src/app/+reset-password/reset-password.component.ts8
-rw-r--r--client/src/app/+search/search.component.ts97
-rw-r--r--client/src/app/+signup/+register/register.component.ts20
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts10
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts8
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts59
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts75
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts18
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts8
-rw-r--r--client/src/app/+videos/+video-edit/video-update.component.ts63
-rw-r--r--client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts16
-rw-r--r--client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.ts8
-rw-r--r--client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts8
-rw-r--r--client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts42
-rw-r--r--client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts10
-rw-r--r--client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts15
-rw-r--r--client/src/app/+videos/+video-watch/shared/recommendations/recommended-videos.component.ts14
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts16
-rw-r--r--client/src/app/+videos/video-list/overview/video-overview.component.ts8
-rw-r--r--client/src/app/+videos/video-list/video-user-subscriptions.component.ts8
-rw-r--r--client/src/app/core/auth/auth.service.ts40
-rw-r--r--client/src/app/core/confirm/confirm.service.ts11
-rw-r--r--client/src/app/core/plugins/plugin.service.ts17
-rw-r--r--client/src/app/core/rest/rest-extractor.service.ts4
-rw-r--r--client/src/app/menu/notification.component.ts8
-rw-r--r--client/src/app/modal/instance-config-warning-modal.component.ts8
-rw-r--r--client/src/app/modal/quick-settings-modal.component.ts12
-rw-r--r--client/src/app/modal/welcome-modal.component.ts8
-rw-r--r--client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts141
-rw-r--r--client/src/app/shared/shared-abuse-list/abuse-message-modal.component.ts24
-rw-r--r--client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts8
-rw-r--r--client/src/app/shared/shared-custom-markup/custom-markup.service.ts4
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts8
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/playlist-miniature-markup.component.ts8
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts8
-rw-r--r--client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts8
-rw-r--r--client/src/app/shared/shared-instance/instance-about-accordion.component.ts8
-rw-r--r--client/src/app/shared/shared-main/auth/auth-interceptor.service.ts2
-rw-r--r--client/src/app/shared/shared-main/users/user-notifications.component.ts24
-rw-r--r--client/src/app/shared/shared-moderation/account-blocklist.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/account-report.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/video-report.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/server-blocklist.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/user-ban-modal.component.ts8
-rw-r--r--client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts112
-rw-r--r--client/src/app/shared/shared-moderation/video-block.component.ts8
-rw-r--r--client/src/app/shared/shared-search/find-in-bulk.service.ts2
-rw-r--r--client/src/app/shared/shared-user-settings/user-interface-settings.component.ts27
-rw-r--r--client/src/app/shared/shared-user-settings/user-video-settings.component.ts15
-rw-r--r--client/src/app/shared/shared-user-subscription/subscribe-button.component.ts16
-rw-r--r--client/src/app/shared/shared-video-miniature/abstract-video-list.ts33
-rw-r--r--client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts32
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.ts3
-rw-r--r--client/src/app/shared/shared-video-miniature/video-miniature.component.ts11
-rw-r--r--client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts51
-rw-r--r--client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts16
-rw-r--r--client/src/root-helpers/plugins-manager.ts7
102 files changed, 1059 insertions, 1037 deletions
diff --git a/client/src/app/+about/about-follows/about-follows.component.ts b/client/src/app/+about/about-follows/about-follows.component.ts
index d335cbf45..1dcb6396c 100644
--- a/client/src/app/+about/about-follows/about-follows.component.ts
+++ b/client/src/app/+about/about-follows/about-follows.component.ts
@@ -91,8 +91,8 @@ export class AboutFollowsComponent implements OnInit {
91 const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination) 91 const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
92 92
93 this.followService.getFollowers({ pagination: pagination, sort: this.sort, state: 'accepted' }) 93 this.followService.getFollowers({ pagination: pagination, sort: this.sort, state: 'accepted' })
94 .subscribe( 94 .subscribe({
95 resultList => { 95 next: resultList => {
96 if (reset) this.followers = [] 96 if (reset) this.followers = []
97 97
98 const newFollowers = resultList.data.map(r => r.follower.host) 98 const newFollowers = resultList.data.map(r => r.follower.host)
@@ -101,16 +101,16 @@ export class AboutFollowsComponent implements OnInit {
101 this.followersPagination.totalItems = resultList.total 101 this.followersPagination.totalItems = resultList.total
102 }, 102 },
103 103
104 err => this.notifier.error(err.message) 104 error: err => this.notifier.error(err.message)
105 ) 105 })
106 } 106 }
107 107
108 private loadMoreFollowings (reset = false) { 108 private loadMoreFollowings (reset = false) {
109 const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination) 109 const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination)
110 110
111 this.followService.getFollowing({ pagination, sort: this.sort, state: 'accepted' }) 111 this.followService.getFollowing({ pagination, sort: this.sort, state: 'accepted' })
112 .subscribe( 112 .subscribe({
113 resultList => { 113 next: resultList => {
114 if (reset) this.followings = [] 114 if (reset) this.followings = []
115 115
116 const newFollowings = resultList.data.map(r => r.following.host) 116 const newFollowings = resultList.data.map(r => r.following.host)
@@ -119,8 +119,8 @@ export class AboutFollowsComponent implements OnInit {
119 this.followingsPagination.totalItems = resultList.total 119 this.followingsPagination.totalItems = resultList.total
120 }, 120 },
121 121
122 err => this.notifier.error(err.message) 122 error: err => this.notifier.error(err.message)
123 ) 123 })
124 } 124 }
125 125
126} 126}
diff --git a/client/src/app/+about/about-instance/contact-admin-modal.component.ts b/client/src/app/+about/about-instance/contact-admin-modal.component.ts
index 37e9feacb..cbc759881 100644
--- a/client/src/app/+about/about-instance/contact-admin-modal.component.ts
+++ b/client/src/app/+about/about-instance/contact-admin-modal.component.ts
@@ -83,18 +83,18 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
83 const body = this.form.value[ 'body' ] 83 const body = this.form.value[ 'body' ]
84 84
85 this.instanceService.contactAdministrator(fromEmail, fromName, subject, body) 85 this.instanceService.contactAdministrator(fromEmail, fromName, subject, body)
86 .subscribe( 86 .subscribe({
87 () => { 87 next: () => {
88 this.notifier.success($localize`Your message has been sent.`) 88 this.notifier.success($localize`Your message has been sent.`)
89 this.hide() 89 this.hide()
90 }, 90 },
91 91
92 err => { 92 error: err => {
93 this.error = err.status === HttpStatusCode.FORBIDDEN_403 93 this.error = err.status === HttpStatusCode.FORBIDDEN_403
94 ? $localize`You already sent this form recently` 94 ? $localize`You already sent this form recently`
95 : err.message 95 : err.message
96 } 96 }
97 ) 97 })
98 } 98 }
99 99
100 private prefillForm (prefill: Prefill) { 100 private prefillForm (prefill: Prefill) {
diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts
index 5b59f3cd0..25eb13588 100644
--- a/client/src/app/+accounts/accounts.component.ts
+++ b/client/src/app/+accounts/accounts.component.ts
@@ -71,11 +71,11 @@ export class AccountsComponent implements OnInit, OnDestroy {
71 HttpStatusCode.NOT_FOUND_404 71 HttpStatusCode.NOT_FOUND_404
72 ])) 72 ]))
73 ) 73 )
74 .subscribe( 74 .subscribe({
75 videoChannels => this.videoChannels = videoChannels.data, 75 next: videoChannels => this.videoChannels = videoChannels.data,
76 76
77 err => this.notifier.error(err.message) 77 error: err => this.notifier.error(err.message)
78 ) 78 })
79 79
80 this.links = [ 80 this.links = [
81 { label: $localize`CHANNELS`, routerLink: 'video-channels' }, 81 { label: $localize`CHANNELS`, routerLink: 'video-channels' },
@@ -174,11 +174,12 @@ export class AccountsComponent implements OnInit, OnDestroy {
174 174
175 const user = this.authService.getUser() 175 const user = this.authService.getUser()
176 if (user.hasRight(UserRight.MANAGE_USERS)) { 176 if (user.hasRight(UserRight.MANAGE_USERS)) {
177 this.userService.getUser(account.userId).subscribe( 177 this.userService.getUser(account.userId)
178 accountUser => this.accountUser = accountUser, 178 .subscribe({
179 next: accountUser => this.accountUser = accountUser,
179 180
180 err => this.notifier.error(err.message) 181 error: err => this.notifier.error(err.message)
181 ) 182 })
182 } 183 }
183 } 184 }
184 185
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index 1e8cfb021..538fa6f14 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -267,8 +267,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
267 this.configService.updateCustomConfig(omit(value, 'instanceCustomHomepage')), 267 this.configService.updateCustomConfig(omit(value, 'instanceCustomHomepage')),
268 this.customPage.updateInstanceHomepage(value.instanceCustomHomepage.content) 268 this.customPage.updateInstanceHomepage(value.instanceCustomHomepage.content)
269 ]) 269 ])
270 .subscribe( 270 .subscribe({
271 ([ resConfig ]) => { 271 next: ([ resConfig ]) => {
272 const instanceCustomHomepage = { 272 const instanceCustomHomepage = {
273 content: value.instanceCustomHomepage.content 273 content: value.instanceCustomHomepage.content
274 } 274 }
@@ -284,8 +284,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
284 this.notifier.success($localize`Configuration updated.`) 284 this.notifier.success($localize`Configuration updated.`)
285 }, 285 },
286 286
287 err => this.notifier.error(err.message) 287 error: err => this.notifier.error(err.message)
288 ) 288 })
289 } 289 }
290 290
291 hasConsistentOptions () { 291 hasConsistentOptions () {
@@ -339,8 +339,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
339 forkJoin([ 339 forkJoin([
340 this.configService.getCustomConfig(), 340 this.configService.getCustomConfig(),
341 this.customPage.getInstanceHomepage() 341 this.customPage.getInstanceHomepage()
342 ]) 342 ]).subscribe({
343 .subscribe(([ config, homepage ]) => { 343 next: ([ config, homepage ]) => {
344 this.customConfig = { ...config, instanceCustomHomepage: homepage } 344 this.customConfig = { ...config, instanceCustomHomepage: homepage }
345 345
346 this.updateForm() 346 this.updateForm()
@@ -348,21 +348,21 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
348 this.forceCheck() 348 this.forceCheck()
349 }, 349 },
350 350
351 err => this.notifier.error(err.message) 351 error: err => this.notifier.error(err.message)
352 ) 352 })
353 } 353 }
354 354
355 private loadCategoriesAndLanguages () { 355 private loadCategoriesAndLanguages () {
356 forkJoin([ 356 forkJoin([
357 this.serverService.getVideoLanguages(), 357 this.serverService.getVideoLanguages(),
358 this.serverService.getVideoCategories() 358 this.serverService.getVideoCategories()
359 ]).subscribe( 359 ]).subscribe({
360 ([ languages, categories ]) => { 360 next: ([ languages, categories ]) => {
361 this.languageItems = languages.map(l => ({ label: l.label, id: l.id })) 361 this.languageItems = languages.map(l => ({ label: l.label, id: l.id }))
362 this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' })) 362 this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' }))
363 }, 363 },
364 364
365 err => this.notifier.error(err.message) 365 error: err => this.notifier.error(err.message)
366 ) 366 })
367 } 367 }
368} 368}
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts
index 4a312f6aa..b867b4ba5 100644
--- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts
+++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts
@@ -35,17 +35,17 @@ export class FollowersListComponent extends RestTable implements OnInit {
35 follow.state = 'accepted' 35 follow.state = 'accepted'
36 36
37 this.followService.acceptFollower(follow) 37 this.followService.acceptFollower(follow)
38 .subscribe( 38 .subscribe({
39 () => { 39 next: () => {
40 const handle = follow.follower.name + '@' + follow.follower.host 40 const handle = follow.follower.name + '@' + follow.follower.host
41 this.notifier.success($localize`${handle} accepted in instance followers`) 41 this.notifier.success($localize`${handle} accepted in instance followers`)
42 }, 42 },
43 43
44 err => { 44 error: err => {
45 follow.state = 'pending' 45 follow.state = 'pending'
46 this.notifier.error(err.message) 46 this.notifier.error(err.message)
47 } 47 }
48 ) 48 })
49 } 49 }
50 50
51 async rejectFollower (follow: ActorFollow) { 51 async rejectFollower (follow: ActorFollow) {
@@ -54,19 +54,19 @@ export class FollowersListComponent extends RestTable implements OnInit {
54 if (res === false) return 54 if (res === false) return
55 55
56 this.followService.rejectFollower(follow) 56 this.followService.rejectFollower(follow)
57 .subscribe( 57 .subscribe({
58 () => { 58 next: () => {
59 const handle = follow.follower.name + '@' + follow.follower.host 59 const handle = follow.follower.name + '@' + follow.follower.host
60 this.notifier.success($localize`${handle} rejected from instance followers`) 60 this.notifier.success($localize`${handle} rejected from instance followers`)
61 61
62 this.reloadData() 62 this.reloadData()
63 }, 63 },
64 64
65 err => { 65 error: err => {
66 follow.state = 'pending' 66 follow.state = 'pending'
67 this.notifier.error(err.message) 67 this.notifier.error(err.message)
68 } 68 }
69 ) 69 })
70 } 70 }
71 71
72 async deleteFollower (follow: ActorFollow) { 72 async deleteFollower (follow: ActorFollow) {
@@ -75,27 +75,27 @@ export class FollowersListComponent extends RestTable implements OnInit {
75 if (res === false) return 75 if (res === false) return
76 76
77 this.followService.removeFollower(follow) 77 this.followService.removeFollower(follow)
78 .subscribe( 78 .subscribe({
79 () => { 79 next: () => {
80 const handle = follow.follower.name + '@' + follow.follower.host 80 const handle = follow.follower.name + '@' + follow.follower.host
81 this.notifier.success($localize`${handle} removed from instance followers`) 81 this.notifier.success($localize`${handle} removed from instance followers`)
82 82
83 this.reloadData() 83 this.reloadData()
84 }, 84 },
85 85
86 err => this.notifier.error(err.message) 86 error: err => this.notifier.error(err.message)
87 ) 87 })
88 } 88 }
89 89
90 protected reloadData () { 90 protected reloadData () {
91 this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search }) 91 this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search })
92 .subscribe( 92 .subscribe({
93 resultList => { 93 next: resultList => {
94 this.followers = resultList.data 94 this.followers = resultList.data
95 this.totalRecords = resultList.total 95 this.totalRecords = resultList.total
96 }, 96 },
97 97
98 err => this.notifier.error(err.message) 98 error: err => this.notifier.error(err.message)
99 ) 99 })
100 } 100 }
101} 101}
diff --git a/client/src/app/+admin/follows/following-list/follow-modal.component.ts b/client/src/app/+admin/follows/following-list/follow-modal.component.ts
index dc6909200..c55fc8d81 100644
--- a/client/src/app/+admin/follows/following-list/follow-modal.component.ts
+++ b/client/src/app/+admin/follows/following-list/follow-modal.component.ts
@@ -57,13 +57,14 @@ export class FollowModalComponent extends FormReactive implements OnInit {
57 private async addFollowing () { 57 private async addFollowing () {
58 const hostsOrHandles = splitAndGetNotEmpty(this.form.value['hostsOrHandles']) 58 const hostsOrHandles = splitAndGetNotEmpty(this.form.value['hostsOrHandles'])
59 59
60 this.followService.follow(hostsOrHandles).subscribe( 60 this.followService.follow(hostsOrHandles)
61 () => { 61 .subscribe({
62 this.notifier.success($localize`Follow request(s) sent!`) 62 next: () => {
63 this.newFollow.emit() 63 this.notifier.success($localize`Follow request(s) sent!`)
64 }, 64 this.newFollow.emit()
65 },
65 66
66 err => this.notifier.error(err.message) 67 error: err => this.notifier.error(err.message)
67 ) 68 })
68 } 69 }
69} 70}
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts
index ba62dfa23..cf0225098 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.ts
+++ b/client/src/app/+admin/follows/following-list/following-list.component.ts
@@ -49,25 +49,26 @@ export class FollowingListComponent extends RestTable implements OnInit {
49 ) 49 )
50 if (res === false) return 50 if (res === false) return
51 51
52 this.followService.unfollow(follow).subscribe( 52 this.followService.unfollow(follow)
53 () => { 53 .subscribe({
54 this.notifier.success($localize`You are not following ${follow.following.host} anymore.`) 54 next: () => {
55 this.reloadData() 55 this.notifier.success($localize`You are not following ${follow.following.host} anymore.`)
56 }, 56 this.reloadData()
57 },
57 58
58 err => this.notifier.error(err.message) 59 error: err => this.notifier.error(err.message)
59 ) 60 })
60 } 61 }
61 62
62 protected reloadData () { 63 protected reloadData () {
63 this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search }) 64 this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search })
64 .subscribe( 65 .subscribe({
65 resultList => { 66 next: resultList => {
66 this.following = resultList.data 67 this.following = resultList.data
67 this.totalRecords = resultList.total 68 this.totalRecords = resultList.total
68 }, 69 },
69 70
70 err => this.notifier.error(err.message) 71 error: err => this.notifier.error(err.message)
71 ) 72 })
72 } 73 }
73} 74}
diff --git a/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts b/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts
index 729b7f599..47c402510 100644
--- a/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts
+++ b/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts
@@ -18,14 +18,14 @@ export class RedundancyCheckboxComponent {
18 18
19 updateRedundancyState () { 19 updateRedundancyState () {
20 this.redundancyService.updateRedundancy(this.host, this.redundancyAllowed) 20 this.redundancyService.updateRedundancy(this.host, this.redundancyAllowed)
21 .subscribe( 21 .subscribe({
22 () => { 22 next: () => {
23 const stateLabel = this.redundancyAllowed ? $localize`enabled` : $localize`disabled` 23 const stateLabel = this.redundancyAllowed ? $localize`enabled` : $localize`disabled`
24 24
25 this.notifier.success($localize`Redundancy for ${this.host} is ${stateLabel}`) 25 this.notifier.success($localize`Redundancy for ${this.host} is ${stateLabel}`)
26 }, 26 },
27 27
28 err => this.notifier.error(err.message) 28 error: err => this.notifier.error(err.message)
29 ) 29 })
30 } 30 }
31} 31}
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts
index 3cd65dd6e..4c691269a 100644
--- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts
+++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts
@@ -142,14 +142,14 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
142 if (res === false) return 142 if (res === false) return
143 143
144 this.redundancyService.removeVideoRedundancies(redundancy) 144 this.redundancyService.removeVideoRedundancies(redundancy)
145 .subscribe( 145 .subscribe({
146 () => { 146 next: () => {
147 this.notifier.success($localize`Video redundancies removed!`) 147 this.notifier.success($localize`Video redundancies removed!`)
148 this.reloadData() 148 this.reloadData()
149 }, 149 },
150 150
151 err => this.notifier.error(err.message) 151 error: err => this.notifier.error(err.message)
152 ) 152 })
153 153
154 } 154 }
155 155
@@ -161,14 +161,14 @@ export class VideoRedundanciesListComponent extends RestTable implements OnInit
161 } 161 }
162 162
163 this.redundancyService.listVideoRedundancies(options) 163 this.redundancyService.listVideoRedundancies(options)
164 .subscribe( 164 .subscribe({
165 resultList => { 165 next: resultList => {
166 this.videoRedundancies = resultList.data 166 this.videoRedundancies = resultList.data
167 this.totalRecords = resultList.total 167 this.totalRecords = resultList.total
168 }, 168 },
169 169
170 err => this.notifier.error(err.message) 170 error: err => this.notifier.error(err.message)
171 ) 171 })
172 } 172 }
173 173
174 private loadSelectLocalStorage () { 174 private loadSelectLocalStorage () {
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
index 4fe5ec441..adef16975 100644
--- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
+++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts
@@ -62,14 +62,14 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
62 handler: videoBlock => { 62 handler: videoBlock => {
63 this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe( 63 this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe(
64 switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true)) 64 switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true))
65 ).subscribe( 65 ).subscribe({
66 () => { 66 next: () => {
67 this.notifier.success($localize`Video ${videoBlock.video.name} switched to manual block.`) 67 this.notifier.success($localize`Video ${videoBlock.video.name} switched to manual block.`)
68 this.reloadData() 68 this.reloadData()
69 }, 69 },
70 70
71 err => this.notifier.error(err.message) 71 error: err => this.notifier.error(err.message)
72 ) 72 })
73 }, 73 },
74 isDisplayed: videoBlock => videoBlock.type === VideoBlacklistType.AUTO_BEFORE_PUBLISHED 74 isDisplayed: videoBlock => videoBlock.type === VideoBlacklistType.AUTO_BEFORE_PUBLISHED
75 } 75 }
@@ -94,13 +94,11 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
94 if (res === false) return 94 if (res === false) return
95 95
96 this.videoService.removeVideo(videoBlock.video.id) 96 this.videoService.removeVideo(videoBlock.video.id)
97 .subscribe( 97 .subscribe({
98 () => { 98 next: () => this.notifier.success($localize`Video deleted.`),
99 this.notifier.success($localize`Video deleted.`)
100 },
101 99
102 err => this.notifier.error(err.message) 100 error: err => this.notifier.error(err.message)
103 ) 101 })
104 } 102 }
105 } 103 }
106 ] 104 ]
@@ -136,14 +134,15 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
136 const res = await this.confirmService.confirm(confirmMessage, $localize`Unblock`) 134 const res = await this.confirmService.confirm(confirmMessage, $localize`Unblock`)
137 if (res === false) return 135 if (res === false) return
138 136
139 this.videoBlocklistService.unblockVideo(entry.video.id).subscribe( 137 this.videoBlocklistService.unblockVideo(entry.video.id)
140 () => { 138 .subscribe({
141 this.notifier.success($localize`Video ${entry.video.name} unblocked.`) 139 next: () => {
142 this.reloadData() 140 this.notifier.success($localize`Video ${entry.video.name} unblocked.`)
143 }, 141 this.reloadData()
142 },
144 143
145 err => this.notifier.error(err.message) 144 error: err => this.notifier.error(err.message)
146 ) 145 })
147 } 146 }
148 147
149 getVideoEmbed (entry: VideoBlacklist) { 148 getVideoEmbed (entry: VideoBlacklist) {
@@ -164,8 +163,8 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
164 sort: this.sort, 163 sort: this.sort,
165 search: this.search 164 search: this.search
166 }) 165 })
167 .subscribe( 166 .subscribe({
168 async resultList => { 167 next: async resultList => {
169 this.totalRecords = resultList.total 168 this.totalRecords = resultList.total
170 169
171 this.blocklist = resultList.data 170 this.blocklist = resultList.data
@@ -178,7 +177,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
178 } 177 }
179 }, 178 },
180 179
181 err => this.notifier.error(err.message) 180 error: err => this.notifier.error(err.message)
182 ) 181 })
183 } 182 }
184} 183}
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html
index 9d9283536..0fd0588ba 100644
--- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html
+++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.html
@@ -34,13 +34,13 @@
34 34
35 <ng-template pTemplate="header"> 35 <ng-template pTemplate="header">
36 <tr> 36 <tr>
37 <th style="width: 40px"> 37 <th style="width: 40px;">
38 <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox> 38 <p-tableHeaderCheckbox ariaLabel="Select all rows" i18n-ariaLabel></p-tableHeaderCheckbox>
39 </th> 39 </th>
40 <th style="width: 40px"></th> 40 <th style="width: 40px;"></th>
41 <th style="width: 150px;"></th> 41 <th style="width: 150px;"></th>
42 <th style="width: 300px" i18n>Account</th> 42 <th style="width: 300px;" i18n>Account</th>
43 <th style="width: 300px" i18n>Video</th> 43 <th style="width: 300px;" i18n>Video</th>
44 <th i18n>Comment</th> 44 <th i18n>Comment</th>
45 <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> 45 <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
46 </tr> 46 </tr>
diff --git a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
index e2ae993b0..4904bcc25 100644
--- a/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
+++ b/client/src/app/+admin/moderation/video-comment-list/video-comment-list.component.ts
@@ -1,5 +1,5 @@
1import { SortMeta } from 'primeng/api' 1import { SortMeta } from 'primeng/api'
2import { AfterViewInit, Component, OnInit } from '@angular/core' 2import { Component, OnInit } from '@angular/core'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' 4import { AuthService, ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core'
5import { AdvancedInputFilter } from '@app/shared/shared-forms' 5import { AdvancedInputFilter } from '@app/shared/shared-forms'
@@ -117,45 +117,46 @@ export class VideoCommentListComponent extends RestTable implements OnInit {
117 pagination: this.pagination, 117 pagination: this.pagination,
118 sort: this.sort, 118 sort: this.sort,
119 search: this.search 119 search: this.search
120 }).subscribe( 120 }).subscribe({
121 async resultList => { 121 next: async resultList => {
122 this.totalRecords = resultList.total 122 this.totalRecords = resultList.total
123 123
124 this.comments = [] 124 this.comments = []
125 125
126 for (const c of resultList.data) { 126 for (const c of resultList.data) {
127 this.comments.push( 127 this.comments.push(
128 new VideoCommentAdmin(c, await this.toHtml(c.text)) 128 new VideoCommentAdmin(c, await this.toHtml(c.text))
129 ) 129 )
130 } 130 }
131 }, 131 },
132 132
133 err => this.notifier.error(err.message) 133 error: err => this.notifier.error(err.message)
134 ) 134 })
135 } 135 }
136 136
137 private async removeComments (comments: VideoCommentAdmin[]) { 137 private async removeComments (comments: VideoCommentAdmin[]) {
138 const commentArgs = comments.map(c => ({ videoId: c.video.id, commentId: c.id })) 138 const commentArgs = comments.map(c => ({ videoId: c.video.id, commentId: c.id }))
139 139
140 this.videoCommentService.deleteVideoComments(commentArgs).subscribe( 140 this.videoCommentService.deleteVideoComments(commentArgs)
141 () => { 141 .subscribe({
142 this.notifier.success($localize`${commentArgs.length} comments deleted.`) 142 next: () => {
143 this.reloadData() 143 this.notifier.success($localize`${commentArgs.length} comments deleted.`)
144 }, 144 this.reloadData()
145 },
145 146
146 err => this.notifier.error(err.message), 147 error: err => this.notifier.error(err.message),
147 148
148 () => this.selectedComments = [] 149 complete: () => this.selectedComments = []
149 ) 150 })
150 } 151 }
151 152
152 private deleteComment (comment: VideoCommentAdmin) { 153 private deleteComment (comment: VideoCommentAdmin) {
153 this.videoCommentService.deleteVideoComment(comment.video.id, comment.id) 154 this.videoCommentService.deleteVideoComment(comment.video.id, comment.id)
154 .subscribe( 155 .subscribe({
155 () => this.reloadData(), 156 next: () => this.reloadData(),
156 157
157 err => this.notifier.error(err.message) 158 error: err => this.notifier.error(err.message)
158 ) 159 })
159 } 160 }
160 161
161 private async deleteUserComments (comment: VideoCommentAdmin) { 162 private async deleteUserComments (comment: VideoCommentAdmin) {
@@ -169,12 +170,12 @@ export class VideoCommentListComponent extends RestTable implements OnInit {
169 } 170 }
170 171
171 this.bulkService.removeCommentsOf(options) 172 this.bulkService.removeCommentsOf(options)
172 .subscribe( 173 .subscribe({
173 () => { 174 next: () => {
174 this.notifier.success($localize`Comments of ${options.accountName} will be deleted in a few minutes`) 175 this.notifier.success($localize`Comments of ${options.accountName} will be deleted in a few minutes`)
175 }, 176 },
176 177
177 err => this.notifier.error(err.message) 178 error: err => this.notifier.error(err.message)
178 ) 179 })
179 } 180 }
180} 181}
diff --git a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts
index 968abcbe5..85f9879bf 100644
--- a/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts
+++ b/client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts
@@ -61,16 +61,16 @@ export class PluginListInstalledComponent implements OnInit {
61 61
62 loadMorePlugins () { 62 loadMorePlugins () {
63 this.pluginApiService.getPlugins(this.pluginType, this.pagination, this.sort) 63 this.pluginApiService.getPlugins(this.pluginType, this.pagination, this.sort)
64 .subscribe( 64 .subscribe({
65 res => { 65 next: res => {
66 this.plugins = this.plugins.concat(res.data) 66 this.plugins = this.plugins.concat(res.data)
67 this.pagination.totalItems = res.total 67 this.pagination.totalItems = res.total
68 68
69 this.onDataSubject.next(res.data) 69 this.onDataSubject.next(res.data)
70 }, 70 },
71 71
72 err => this.notifier.error(err.message) 72 error: err => this.notifier.error(err.message)
73 ) 73 })
74 } 74 }
75 75
76 onNearOfBottom () { 76 onNearOfBottom () {
@@ -113,16 +113,16 @@ export class PluginListInstalledComponent implements OnInit {
113 if (res === false) return 113 if (res === false) return
114 114
115 this.pluginApiService.uninstall(plugin.name, plugin.type) 115 this.pluginApiService.uninstall(plugin.name, plugin.type)
116 .subscribe( 116 .subscribe({
117 () => { 117 next: () => {
118 this.notifier.success($localize`${plugin.name} uninstalled.`) 118 this.notifier.success($localize`${plugin.name} uninstalled.`)
119 119
120 this.plugins = this.plugins.filter(p => p.name !== plugin.name) 120 this.plugins = this.plugins.filter(p => p.name !== plugin.name)
121 this.pagination.totalItems-- 121 this.pagination.totalItems--
122 }, 122 },
123 123
124 err => this.notifier.error(err.message) 124 error: err => this.notifier.error(err.message)
125 ) 125 })
126 } 126 }
127 127
128 async update (plugin: PeerTubePlugin) { 128 async update (plugin: PeerTubePlugin) {
@@ -143,8 +143,8 @@ export class PluginListInstalledComponent implements OnInit {
143 143
144 this.pluginApiService.update(plugin.name, plugin.type) 144 this.pluginApiService.update(plugin.name, plugin.type)
145 .pipe() 145 .pipe()
146 .subscribe( 146 .subscribe({
147 res => { 147 next: res => {
148 this.updating[updatingKey] = false 148 this.updating[updatingKey] = false
149 149
150 this.notifier.success($localize`${plugin.name} updated.`) 150 this.notifier.success($localize`${plugin.name} updated.`)
@@ -152,8 +152,8 @@ export class PluginListInstalledComponent implements OnInit {
152 Object.assign(plugin, res) 152 Object.assign(plugin, res)
153 }, 153 },
154 154
155 err => this.notifier.error(err.message) 155 error: err => this.notifier.error(err.message)
156 ) 156 })
157 } 157 }
158 158
159 getShowRouterLink (plugin: PeerTubePlugin) { 159 getShowRouterLink (plugin: PeerTubePlugin) {
diff --git a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
index 0a6e57904..803777eb3 100644
--- a/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
+++ b/client/src/app/+admin/plugins/plugin-search/plugin-search.component.ts
@@ -84,8 +84,8 @@ export class PluginSearchComponent implements OnInit {
84 this.isSearching = true 84 this.isSearching = true
85 85
86 this.pluginApiService.searchAvailablePlugins(this.pluginType, this.pagination, this.sort, this.search) 86 this.pluginApiService.searchAvailablePlugins(this.pluginType, this.pagination, this.sort, this.search)
87 .subscribe( 87 .subscribe({
88 res => { 88 next: res => {
89 this.isSearching = false 89 this.isSearching = false
90 90
91 this.plugins = this.plugins.concat(res.data) 91 this.plugins = this.plugins.concat(res.data)
@@ -94,13 +94,13 @@ export class PluginSearchComponent implements OnInit {
94 this.onDataSubject.next(res.data) 94 this.onDataSubject.next(res.data)
95 }, 95 },
96 96
97 err => { 97 error: err => {
98 console.error(err) 98 console.error(err)
99 99
100 const message = $localize`The plugin index is not available. Please retry later.` 100 const message = $localize`The plugin index is not available. Please retry later.`
101 this.notifier.error(message) 101 this.notifier.error(message)
102 } 102 }
103 ) 103 })
104 } 104 }
105 105
106 onNearOfBottom () { 106 onNearOfBottom () {
@@ -139,8 +139,8 @@ export class PluginSearchComponent implements OnInit {
139 this.installing[plugin.npmName] = true 139 this.installing[plugin.npmName] = true
140 140
141 this.pluginApiService.install(plugin.npmName) 141 this.pluginApiService.install(plugin.npmName)
142 .subscribe( 142 .subscribe({
143 () => { 143 next: () => {
144 this.installing[plugin.npmName] = false 144 this.installing[plugin.npmName] = false
145 this.pluginInstalled = true 145 this.pluginInstalled = true
146 146
@@ -149,7 +149,7 @@ export class PluginSearchComponent implements OnInit {
149 plugin.installed = true 149 plugin.installed = true
150 }, 150 },
151 151
152 err => this.notifier.error(err.message) 152 error: err => this.notifier.error(err.message)
153 ) 153 })
154 } 154 }
155} 155}
diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
index c3d14d2b3..10fb52911 100644
--- a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
+++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
@@ -50,13 +50,13 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
50 const settings = this.form.value 50 const settings = this.form.value
51 51
52 this.pluginAPIService.updatePluginSettings(this.plugin.name, this.plugin.type, settings) 52 this.pluginAPIService.updatePluginSettings(this.plugin.name, this.plugin.type, settings)
53 .subscribe( 53 .subscribe({
54 () => { 54 next: () => {
55 this.notifier.success($localize`Settings updated.`) 55 this.notifier.success($localize`Settings updated.`)
56 }, 56 },
57 57
58 err => this.notifier.error(err.message) 58 error: err => this.notifier.error(err.message)
59 ) 59 })
60 } 60 }
61 61
62 hasRegisteredSettings () { 62 hasRegisteredSettings () {
@@ -83,8 +83,8 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
83 return this.pluginAPIService.getPluginRegisteredSettings(plugin.name, plugin.type) 83 return this.pluginAPIService.getPluginRegisteredSettings(plugin.name, plugin.type)
84 .pipe(map(data => ({ plugin, registeredSettings: data.registeredSettings }))) 84 .pipe(map(data => ({ plugin, registeredSettings: data.registeredSettings })))
85 })) 85 }))
86 .subscribe( 86 .subscribe({
87 async ({ plugin, registeredSettings }) => { 87 next: async ({ plugin, registeredSettings }) => {
88 this.plugin = plugin 88 this.plugin = plugin
89 89
90 this.registeredSettings = await this.translateSettings(registeredSettings) 90 this.registeredSettings = await this.translateSettings(registeredSettings)
@@ -94,8 +94,8 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
94 this.buildSettingsForm() 94 this.buildSettingsForm()
95 }, 95 },
96 96
97 err => this.notifier.error(err.message) 97 error: err => this.notifier.error(err.message)
98 ) 98 })
99 } 99 }
100 100
101 private buildSettingsForm () { 101 private buildSettingsForm () {
diff --git a/client/src/app/+admin/system/debug/debug.component.ts b/client/src/app/+admin/system/debug/debug.component.ts
index a88d837f3..1f4e71e8a 100644
--- a/client/src/app/+admin/system/debug/debug.component.ts
+++ b/client/src/app/+admin/system/debug/debug.component.ts
@@ -22,10 +22,10 @@ export class DebugComponent implements OnInit {
22 22
23 load () { 23 load () {
24 this.debugService.getDebug() 24 this.debugService.getDebug()
25 .subscribe( 25 .subscribe({
26 debug => this.debug = debug, 26 next: debug => this.debug = debug,
27 27
28 err => this.notifier.error(err.message) 28 error: err => this.notifier.error(err.message)
29 ) 29 })
30 } 30 }
31} 31}
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts
index 4b02e1bc1..b12d7f80a 100644
--- a/client/src/app/+admin/system/jobs/jobs.component.ts
+++ b/client/src/app/+admin/system/jobs/jobs.component.ts
@@ -119,14 +119,14 @@ export class JobsComponent extends RestTable implements OnInit {
119 pagination: this.pagination, 119 pagination: this.pagination,
120 sort: this.sort 120 sort: this.sort
121 }) 121 })
122 .subscribe( 122 .subscribe({
123 resultList => { 123 next: resultList => {
124 this.jobs = resultList.data 124 this.jobs = resultList.data
125 this.totalRecords = resultList.total 125 this.totalRecords = resultList.total
126 }, 126 },
127 127
128 err => this.notifier.error(err.message) 128 error: err => this.notifier.error(err.message)
129 ) 129 })
130 } 130 }
131 131
132 private loadJobStateAndType () { 132 private loadJobStateAndType () {
diff --git a/client/src/app/+admin/system/logs/logs.component.ts b/client/src/app/+admin/system/logs/logs.component.ts
index 48318f07b..865ab80a2 100644
--- a/client/src/app/+admin/system/logs/logs.component.ts
+++ b/client/src/app/+admin/system/logs/logs.component.ts
@@ -52,8 +52,8 @@ export class LogsComponent implements OnInit {
52 this.loading = true 52 this.loading = true
53 53
54 this.logsService.getLogs({ isAuditLog: this.isAuditLog(), level: this.level, startDate: this.startDate }) 54 this.logsService.getLogs({ isAuditLog: this.isAuditLog(), level: this.level, startDate: this.startDate })
55 .subscribe( 55 .subscribe({
56 logs => { 56 next: logs => {
57 this.logs = logs 57 this.logs = logs
58 58
59 setTimeout(() => { 59 setTimeout(() => {
@@ -61,10 +61,10 @@ export class LogsComponent implements OnInit {
61 }) 61 })
62 }, 62 },
63 63
64 err => this.notifier.error(err.message), 64 error: err => this.notifier.error(err.message),
65 65
66 () => this.loading = false 66 complete: () => this.loading = false
67 ) 67 })
68 } 68 }
69 69
70 isAuditLog () { 70 isAuditLog () {
diff --git a/client/src/app/+admin/users/user-edit/user-create.component.ts b/client/src/app/+admin/users/user-edit/user-create.component.ts
index c26ad1208..8403db91a 100644
--- a/client/src/app/+admin/users/user-edit/user-create.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-create.component.ts
@@ -71,14 +71,15 @@ export class UserCreateComponent extends UserEdit implements OnInit {
71 userCreate.videoQuota = parseInt(this.form.value['videoQuota'], 10) 71 userCreate.videoQuota = parseInt(this.form.value['videoQuota'], 10)
72 userCreate.videoQuotaDaily = parseInt(this.form.value['videoQuotaDaily'], 10) 72 userCreate.videoQuotaDaily = parseInt(this.form.value['videoQuotaDaily'], 10)
73 73
74 this.userService.addUser(userCreate).subscribe( 74 this.userService.addUser(userCreate)
75 () => { 75 .subscribe({
76 this.notifier.success($localize`User ${userCreate.username} created.`) 76 next: () => {
77 this.router.navigate([ '/admin/users/list' ]) 77 this.notifier.success($localize`User ${userCreate.username} created.`)
78 }, 78 this.router.navigate([ '/admin/users/list' ])
79 },
79 80
80 err => this.error = err.message 81 error: err => this.error = err.message
81 ) 82 })
82 } 83 }
83 84
84 isCreation () { 85 isCreation () {
diff --git a/client/src/app/+admin/users/user-edit/user-password.component.ts b/client/src/app/+admin/users/user-edit/user-password.component.ts
index 05d52b17f..7c42b9241 100644
--- a/client/src/app/+admin/users/user-edit/user-password.component.ts
+++ b/client/src/app/+admin/users/user-edit/user-password.component.ts
@@ -35,13 +35,12 @@ export class UserPasswordComponent extends FormReactive implements OnInit {
35 35
36 const userUpdate: UserUpdate = this.form.value 36 const userUpdate: UserUpdate = this.form.value
37 37
38 this.userService.updateUser(this.userId, userUpdate).subscribe( 38 this.userService.updateUser(this.userId, userUpdate)
39 () => { 39 .subscribe({
40 this.notifier.success($localize`Password changed for user ${this.username}.`) 40 next: () => this.notifier.success($localize`Password changed for user ${this.username}.`),
41 },
42 41
43 err => this.error = err.message 42 error: err => this.error = err.message
44 ) 43 })
45 } 44 }
46 45
47 togglePasswordVisibility () { 46 togglePasswordVisibility () {
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 1527508f7..2128ba4fd 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
@@ -59,11 +59,12 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
59 59
60 this.paramsSub = this.route.params.subscribe(routeParams => { 60 this.paramsSub = this.route.params.subscribe(routeParams => {
61 const userId = routeParams['id'] 61 const userId = routeParams['id']
62 this.userService.getUser(userId, true).subscribe( 62 this.userService.getUser(userId, true)
63 user => this.onUserFetched(user), 63 .subscribe({
64 next: user => this.onUserFetched(user),
64 65
65 err => this.error = err.message 66 error: err => this.error = err.message
66 ) 67 })
67 }) 68 })
68 } 69 }
69 70
@@ -83,14 +84,15 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
83 84
84 if (userUpdate.pluginAuth === 'null') userUpdate.pluginAuth = null 85 if (userUpdate.pluginAuth === 'null') userUpdate.pluginAuth = null
85 86
86 this.userService.updateUser(this.user.id, userUpdate).subscribe( 87 this.userService.updateUser(this.user.id, userUpdate)
87 () => { 88 .subscribe({
88 this.notifier.success($localize`User ${this.user.username} updated.`) 89 next: () => {
89 this.router.navigate([ '/admin/users/list' ]) 90 this.notifier.success($localize`User ${this.user.username} updated.`)
90 }, 91 this.router.navigate([ '/admin/users/list' ])
92 },
91 93
92 err => this.error = err.message 94 error: err => this.error = err.message
93 ) 95 })
94 } 96 }
95 97
96 isCreation () { 98 isCreation () {
@@ -106,13 +108,14 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
106 } 108 }
107 109
108 resetPassword () { 110 resetPassword () {
109 this.userService.askResetPassword(this.user.email).subscribe( 111 this.userService.askResetPassword(this.user.email)
110 () => { 112 .subscribe({
111 this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`) 113 next: () => {
112 }, 114 this.notifier.success($localize`An email asking for password reset has been sent to ${this.user.username}.`)
113 115 },
114 err => this.error = err.message 116
115 ) 117 error: err => this.error = err.message
118 })
116 } 119 }
117 120
118 private onUserFetched (userJson: UserType) { 121 private onUserFetched (userJson: UserType) {
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts
index e3ae68a93..d4406549a 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.ts
+++ b/client/src/app/+admin/users/user-list/user-list.component.ts
@@ -173,14 +173,14 @@ export class UserListComponent extends RestTable implements OnInit {
173 if (res === false) return 173 if (res === false) return
174 174
175 this.userService.unbanUsers(users) 175 this.userService.unbanUsers(users)
176 .subscribe( 176 .subscribe({
177 () => { 177 next: () => {
178 this.notifier.success($localize`${users.length} users unbanned.`) 178 this.notifier.success($localize`${users.length} users unbanned.`)
179 this.reloadData() 179 this.reloadData()
180 }, 180 },
181 181
182 err => this.notifier.error(err.message) 182 error: err => this.notifier.error(err.message)
183 ) 183 })
184 } 184 }
185 185
186 async removeUsers (users: User[]) { 186 async removeUsers (users: User[]) {
@@ -195,25 +195,27 @@ export class UserListComponent extends RestTable implements OnInit {
195 const res = await this.confirmService.confirm(message, $localize`Delete`) 195 const res = await this.confirmService.confirm(message, $localize`Delete`)
196 if (res === false) return 196 if (res === false) return
197 197
198 this.userService.removeUser(users).subscribe( 198 this.userService.removeUser(users)
199 () => { 199 .subscribe({
200 this.notifier.success($localize`${users.length} users deleted.`) 200 next: () => {
201 this.reloadData() 201 this.notifier.success($localize`${users.length} users deleted.`)
202 }, 202 this.reloadData()
203 },
203 204
204 err => this.notifier.error(err.message) 205 error: err => this.notifier.error(err.message)
205 ) 206 })
206 } 207 }
207 208
208 async setEmailsAsVerified (users: User[]) { 209 async setEmailsAsVerified (users: User[]) {
209 this.userService.updateUsers(users, { emailVerified: true }).subscribe( 210 this.userService.updateUsers(users, { emailVerified: true })
210 () => { 211 .subscribe({
211 this.notifier.success($localize`${users.length} users email set as verified.`) 212 next: () => {
212 this.reloadData() 213 this.notifier.success($localize`${users.length} users email set as verified.`)
213 }, 214 this.reloadData()
215 },
214 216
215 err => this.notifier.error(err.message) 217 error: err => this.notifier.error(err.message)
216 ) 218 })
217 } 219 }
218 220
219 isInSelectionMode () { 221 isInSelectionMode () {
@@ -227,13 +229,13 @@ export class UserListComponent extends RestTable implements OnInit {
227 pagination: this.pagination, 229 pagination: this.pagination,
228 sort: this.sort, 230 sort: this.sort,
229 search: this.search 231 search: this.search
230 }).subscribe( 232 }).subscribe({
231 resultList => { 233 next: resultList => {
232 this.users = resultList.data 234 this.users = resultList.data
233 this.totalRecords = resultList.total 235 this.totalRecords = resultList.total
234 }, 236 },
235 237
236 err => this.notifier.error(err.message) 238 error: err => this.notifier.error(err.message)
237 ) 239 })
238 } 240 }
239} 241}
diff --git a/client/src/app/+login/login.component.ts b/client/src/app/+login/login.component.ts
index 9731383af..16876afd6 100644
--- a/client/src/app/+login/login.component.ts
+++ b/client/src/app/+login/login.component.ts
@@ -107,17 +107,17 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
107 const { username, password } = this.form.value 107 const { username, password } = this.form.value
108 108
109 this.authService.login(username, password) 109 this.authService.login(username, password)
110 .subscribe( 110 .subscribe({
111 () => this.redirectService.redirectToPreviousRoute(), 111 next: () => this.redirectService.redirectToPreviousRoute(),
112 112
113 err => this.handleError(err) 113 error: err => this.handleError(err)
114 ) 114 })
115 } 115 }
116 116
117 askResetPassword () { 117 askResetPassword () {
118 this.userService.askResetPassword(this.forgotPasswordEmail) 118 this.userService.askResetPassword(this.forgotPasswordEmail)
119 .subscribe( 119 .subscribe({
120 () => { 120 next: () => {
121 const message = $localize`An email with the reset password instructions will be sent to ${this.forgotPasswordEmail}. 121 const message = $localize`An email with the reset password instructions will be sent to ${this.forgotPasswordEmail}.
122The link will expire within 1 hour.` 122The link will expire within 1 hour.`
123 123
@@ -125,8 +125,8 @@ The link will expire within 1 hour.`
125 this.hideForgotPasswordModal() 125 this.hideForgotPasswordModal()
126 }, 126 },
127 127
128 err => this.notifier.error(err.message) 128 error: err => this.notifier.error(err.message)
129 ) 129 })
130 } 130 }
131 131
132 openForgotPasswordModal () { 132 openForgotPasswordModal () {
@@ -149,14 +149,14 @@ The link will expire within 1 hour.`
149 this.isAuthenticatedWithExternalAuth = true 149 this.isAuthenticatedWithExternalAuth = true
150 150
151 this.authService.login(username, null, token) 151 this.authService.login(username, null, token)
152 .subscribe( 152 .subscribe({
153 () => this.redirectService.redirectToPreviousRoute(), 153 next: () => this.redirectService.redirectToPreviousRoute(),
154 154
155 err => { 155 error: err => {
156 this.handleError(err) 156 this.handleError(err)
157 this.isAuthenticatedWithExternalAuth = false 157 this.isAuthenticatedWithExternalAuth = false
158 } 158 }
159 ) 159 })
160 } 160 }
161 161
162 private handleError (err: any) { 162 private handleError (err: any) {
diff --git a/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts b/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts
index 5e9525fbb..6873c7d40 100644
--- a/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts
+++ b/client/src/app/+my-account/my-account-applications/my-account-applications.component.ts
@@ -1,5 +1,5 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { AuthService, Notifier, ConfirmService, ScopedTokensService } from '@app/core' 2import { AuthService, ConfirmService, Notifier, ScopedTokensService } from '@app/core'
3import { VideoService } from '@app/shared/shared-main' 3import { VideoService } from '@app/shared/shared-main'
4import { FeedFormat } from '@shared/models' 4import { FeedFormat } from '@shared/models'
5import { ScopedToken } from '@shared/models/users/user-scoped-token' 5import { ScopedToken } from '@shared/models/users/user-scoped-token'
@@ -27,13 +27,11 @@ export class MyAccountApplicationsComponent implements OnInit {
27 ngOnInit () { 27 ngOnInit () {
28 this.feedUrl = this.baseURL 28 this.feedUrl = this.baseURL
29 this.scopedTokensService.getScopedTokens() 29 this.scopedTokensService.getScopedTokens()
30 .subscribe( 30 .subscribe({
31 tokens => this.regenApplications(tokens), 31 next: tokens => this.regenApplications(tokens),
32 32
33 err => { 33 error: err => this.notifier.error(err.message)
34 this.notifier.error(err.message) 34 })
35 }
36 )
37 } 35 }
38 36
39 async renewToken () { 37 async renewToken () {
@@ -43,17 +41,15 @@ export class MyAccountApplicationsComponent implements OnInit {
43 ) 41 )
44 if (res === false) return 42 if (res === false) return
45 43
46 this.scopedTokensService.renewScopedTokens().subscribe( 44 this.scopedTokensService.renewScopedTokens()
47 tokens => { 45 .subscribe({
48 this.regenApplications(tokens) 46 next: tokens => {
49 this.notifier.success($localize`Token renewed. Update your client configuration accordingly.`) 47 this.regenApplications(tokens)
50 }, 48 this.notifier.success($localize`Token renewed. Update your client configuration accordingly.`)
51 49 },
52 err => {
53 this.notifier.error(err.message)
54 }
55 )
56 50
51 error: err => this.notifier.error(err.message)
52 })
57 } 53 }
58 54
59 private regenApplications (tokens: ScopedToken) { 55 private regenApplications (tokens: ScopedToken) {
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
index b2b7849c2..08bc5b425 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
@@ -45,8 +45,8 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
45 this.serverService.getConfig(), 45 this.serverService.getConfig(),
46 this.userService.changeEmail(password, email) 46 this.userService.changeEmail(password, email)
47 ]).pipe(tap(() => this.authService.refreshUserInformation())) 47 ]).pipe(tap(() => this.authService.refreshUserInformation()))
48 .subscribe( 48 .subscribe({
49 ([ config ]) => { 49 next: ([ config ]) => {
50 this.form.reset() 50 this.form.reset()
51 51
52 if (config.signup.requiresEmailVerification) { 52 if (config.signup.requiresEmailVerification) {
@@ -56,7 +56,7 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
56 } 56 }
57 }, 57 },
58 58
59 err => { 59 error: err => {
60 if (err.status === 401) { 60 if (err.status === 401) {
61 this.error = $localize`You current password is invalid.` 61 this.error = $localize`You current password is invalid.`
62 return 62 return
@@ -64,6 +64,6 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
64 64
65 this.error = err.message 65 this.error = err.message
66 } 66 }
67 ) 67 })
68 } 68 }
69} 69}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts
index e034aedef..f91b2f37b 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.ts
@@ -43,22 +43,23 @@ export class MyAccountChangePasswordComponent extends FormReactive implements On
43 const currentPassword = this.form.value[ 'current-password' ] 43 const currentPassword = this.form.value[ 'current-password' ]
44 const newPassword = this.form.value[ 'new-password' ] 44 const newPassword = this.form.value[ 'new-password' ]
45 45
46 this.userService.changePassword(currentPassword, newPassword).subscribe( 46 this.userService.changePassword(currentPassword, newPassword)
47 () => { 47 .subscribe({
48 this.notifier.success($localize`Password updated.`) 48 next: () => {
49 this.notifier.success($localize`Password updated.`)
49 50
50 this.form.reset() 51 this.form.reset()
51 this.error = null 52 this.error = null
52 }, 53 },
53 54
54 err => { 55 error: err => {
55 if (err.status === 401) { 56 if (err.status === 401) {
56 this.error = $localize`You current password is invalid.` 57 this.error = $localize`You current password is invalid.`
57 return 58 return
58 } 59 }
59 60
60 this.error = err.message 61 this.error = err.message
61 } 62 }
62 ) 63 })
63 } 64 }
64} 65}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts
index 387e9e7cd..5005cb630 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts
@@ -27,15 +27,16 @@ export class MyAccountDangerZoneComponent {
27 ) 27 )
28 if (res === false) return 28 if (res === false) return
29 29
30 this.userService.deleteMe().subscribe( 30 this.userService.deleteMe()
31 () => { 31 .subscribe({
32 this.notifier.success($localize`Your account is deleted.`) 32 next: () => {
33 this.notifier.success($localize`Your account is deleted.`)
33 34
34 this.authService.logout() 35 this.authService.logout()
35 this.redirectService.redirectToHomepage() 36 this.redirectService.redirectToHomepage()
36 }, 37 },
37 38
38 err => this.notifier.error(err.message) 39 error: err => this.notifier.error(err.message)
39 ) 40 })
40 } 41 }
41} 42}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts
index b94e6ad82..1eac06234 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts
@@ -89,13 +89,13 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
89 89
90 private savePreferencesImpl () { 90 private savePreferencesImpl () {
91 this.userNotificationService.updateNotificationSettings(this.user.notificationSettings) 91 this.userNotificationService.updateNotificationSettings(this.user.notificationSettings)
92 .subscribe( 92 .subscribe({
93 () => { 93 next: () => {
94 this.notifier.success($localize`Preferences saved`, undefined, 2000) 94 this.notifier.success($localize`Preferences saved`, undefined, 2000)
95 }, 95 },
96 96
97 err => this.notifier.error(err.message) 97 error: err => this.notifier.error(err.message)
98 ) 98 })
99 } 99 }
100 100
101 private loadNotificationSettings () { 101 private loadNotificationSettings () {
diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
index 80e4446c8..f395ad73f 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
@@ -50,15 +50,16 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
50 50
51 this.error = null 51 this.error = null
52 52
53 this.userService.updateMyProfile({ displayName, description }).subscribe( 53 this.userService.updateMyProfile({ displayName, description })
54 () => { 54 .subscribe({
55 next: () => {
55 this.user.account.displayName = displayName 56 this.user.account.displayName = displayName
56 this.user.account.description = description 57 this.user.account.description = description
57 58
58 this.notifier.success($localize`Profile updated.`) 59 this.notifier.success($localize`Profile updated.`)
59 }, 60 },
60 61
61 err => this.error = err.message 62 error: err => this.error = err.message
62 ) 63 })
63 } 64 }
64} 65}
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts
index a0f2f28f8..fc7635f38 100644
--- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts
+++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.ts
@@ -39,31 +39,31 @@ export class MyAccountSettingsComponent implements OnInit, AfterViewChecked {
39 39
40 onAvatarChange (formData: FormData) { 40 onAvatarChange (formData: FormData) {
41 this.userService.changeAvatar(formData) 41 this.userService.changeAvatar(formData)
42 .subscribe( 42 .subscribe({
43 data => { 43 next: data => {
44 this.notifier.success($localize`Avatar changed.`) 44 this.notifier.success($localize`Avatar changed.`)
45 45
46 this.user.updateAccountAvatar(data.avatar) 46 this.user.updateAccountAvatar(data.avatar)
47 }, 47 },
48 48
49 (err: HttpErrorResponse) => genericUploadErrorHandler({ 49 error: (err: HttpErrorResponse) => genericUploadErrorHandler({
50 err, 50 err,
51 name: $localize`avatar`, 51 name: $localize`avatar`,
52 notifier: this.notifier 52 notifier: this.notifier
53 }) 53 })
54 ) 54 })
55 } 55 }
56 56
57 onAvatarDelete () { 57 onAvatarDelete () {
58 this.userService.deleteAvatar() 58 this.userService.deleteAvatar()
59 .subscribe( 59 .subscribe({
60 data => { 60 next: data => {
61 this.notifier.success($localize`Avatar deleted.`) 61 this.notifier.success($localize`Avatar deleted.`)
62 62
63 this.user.updateAccountAvatar() 63 this.user.updateAccountAvatar()
64 }, 64 },
65 65
66 (err: HttpErrorResponse) => this.notifier.error(err.message) 66 error: (err: HttpErrorResponse) => this.notifier.error(err.message)
67 ) 67 })
68 } 68 }
69} 69}
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
index 433475f66..d983aacd9 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-create.component.ts
@@ -59,15 +59,15 @@ export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements
59 .pipe( 59 .pipe(
60 switchMap(() => this.uploadAvatar()), 60 switchMap(() => this.uploadAvatar()),
61 switchMap(() => this.uploadBanner()) 61 switchMap(() => this.uploadBanner())
62 ).subscribe( 62 ).subscribe({
63 () => { 63 next: () => {
64 this.authService.refreshUserInformation() 64 this.authService.refreshUserInformation()
65 65
66 this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`) 66 this.notifier.success($localize`Video channel ${videoChannelCreate.displayName} created.`)
67 this.router.navigate(['/my-library', 'video-channels']) 67 this.router.navigate(['/my-library', 'video-channels'])
68 }, 68 },
69 69
70 err => { 70 error: err => {
71 if (err.status === HttpStatusCode.CONFLICT_409) { 71 if (err.status === HttpStatusCode.CONFLICT_409) {
72 this.error = $localize`This name already exists on this instance.` 72 this.error = $localize`This name already exists on this instance.`
73 return 73 return
@@ -75,7 +75,7 @@ export class MyVideoChannelCreateComponent extends MyVideoChannelEdit implements
75 75
76 this.error = err.message 76 this.error = err.message
77 } 77 }
78 ) 78 })
79 } 79 }
80 80
81 onAvatarChange (formData: FormData) { 81 onAvatarChange (formData: FormData) {
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts
index eb24a60c5..e8bfbf9ce 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channel-update.component.ts
@@ -52,21 +52,22 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
52 this.paramsSub = this.route.params.subscribe(routeParams => { 52 this.paramsSub = this.route.params.subscribe(routeParams => {
53 const videoChannelId = routeParams['videoChannelId'] 53 const videoChannelId = routeParams['videoChannelId']
54 54
55 this.videoChannelService.getVideoChannel(videoChannelId).subscribe( 55 this.videoChannelService.getVideoChannel(videoChannelId)
56 videoChannelToUpdate => { 56 .subscribe({
57 this.videoChannel = videoChannelToUpdate 57 next: videoChannelToUpdate => {
58 58 this.videoChannel = videoChannelToUpdate
59 this.oldSupportField = videoChannelToUpdate.support 59
60 60 this.oldSupportField = videoChannelToUpdate.support
61 this.form.patchValue({ 61
62 'display-name': videoChannelToUpdate.displayName, 62 this.form.patchValue({
63 description: videoChannelToUpdate.description, 63 'display-name': videoChannelToUpdate.displayName,
64 support: videoChannelToUpdate.support 64 description: videoChannelToUpdate.description,
65 }) 65 support: videoChannelToUpdate.support
66 }, 66 })
67 },
67 68
68 err => this.error = err.message 69 error: err => this.error = err.message
69 ) 70 })
70 }) 71 })
71 } 72 }
72 73
@@ -85,77 +86,78 @@ export class MyVideoChannelUpdateComponent extends MyVideoChannelEdit implements
85 bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false 86 bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false
86 } 87 }
87 88
88 this.videoChannelService.updateVideoChannel(this.videoChannel.name, videoChannelUpdate).subscribe( 89 this.videoChannelService.updateVideoChannel(this.videoChannel.name, videoChannelUpdate)
89 () => { 90 .subscribe({
90 this.authService.refreshUserInformation() 91 next: () => {
92 this.authService.refreshUserInformation()
91 93
92 this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`) 94 this.notifier.success($localize`Video channel ${videoChannelUpdate.displayName} updated.`)
93 95
94 this.router.navigate([ '/my-library', 'video-channels' ]) 96 this.router.navigate([ '/my-library', 'video-channels' ])
95 }, 97 },
96 98
97 err => this.error = err.message 99 error: err => this.error = err.message
98 ) 100 })
99 } 101 }
100 102
101 onAvatarChange (formData: FormData) { 103 onAvatarChange (formData: FormData) {
102 this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'avatar') 104 this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'avatar')
103 .subscribe( 105 .subscribe({
104 data => { 106 next: data => {
105 this.notifier.success($localize`Avatar changed.`) 107 this.notifier.success($localize`Avatar changed.`)
106 108
107 this.videoChannel.updateAvatar(data.avatar) 109 this.videoChannel.updateAvatar(data.avatar)
108 }, 110 },
109 111
110 (err: HttpErrorResponse) => genericUploadErrorHandler({ 112 error: (err: HttpErrorResponse) => genericUploadErrorHandler({
111 err, 113 err,
112 name: $localize`avatar`, 114 name: $localize`avatar`,
113 notifier: this.notifier 115 notifier: this.notifier
114 }) 116 })
115 ) 117 })
116 } 118 }
117 119
118 onAvatarDelete () { 120 onAvatarDelete () {
119 this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'avatar') 121 this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'avatar')
120 .subscribe( 122 .subscribe({
121 data => { 123 next: () => {
122 this.notifier.success($localize`Avatar deleted.`) 124 this.notifier.success($localize`Avatar deleted.`)
123 125
124 this.videoChannel.resetAvatar() 126 this.videoChannel.resetAvatar()
125 }, 127 },
126 128
127 err => this.notifier.error(err.message) 129 error: err => this.notifier.error(err.message)
128 ) 130 })
129 } 131 }
130 132
131 onBannerChange (formData: FormData) { 133 onBannerChange (formData: FormData) {
132 this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'banner') 134 this.videoChannelService.changeVideoChannelImage(this.videoChannel.name, formData, 'banner')
133 .subscribe( 135 .subscribe({
134 data => { 136 next: data => {
135 this.notifier.success($localize`Banner changed.`) 137 this.notifier.success($localize`Banner changed.`)
136 138
137 this.videoChannel.updateBanner(data.banner) 139 this.videoChannel.updateBanner(data.banner)
138 }, 140 },
139 141
140 (err: HttpErrorResponse) => genericUploadErrorHandler({ 142 error: (err: HttpErrorResponse) => genericUploadErrorHandler({
141 err, 143 err,
142 name: $localize`banner`, 144 name: $localize`banner`,
143 notifier: this.notifier 145 notifier: this.notifier
144 }) 146 })
145 ) 147 })
146 } 148 }
147 149
148 onBannerDelete () { 150 onBannerDelete () {
149 this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'banner') 151 this.videoChannelService.deleteVideoChannelImage(this.videoChannel.name, 'banner')
150 .subscribe( 152 .subscribe({
151 data => { 153 next: () => {
152 this.notifier.success($localize`Banner deleted.`) 154 this.notifier.success($localize`Banner deleted.`)
153 155
154 this.videoChannel.resetBanner() 156 this.videoChannel.resetBanner()
155 }, 157 },
156 158
157 err => this.notifier.error(err.message) 159 error: err => this.notifier.error(err.message)
158 ) 160 })
159 } 161 }
160 162
161 get maxAvatarSize () { 163 get maxAvatarSize () {
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
index b6a2f592d..8b665fd58 100644
--- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
+++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.ts
@@ -54,14 +54,14 @@ channel with the same name (${videoChannel.name})!`,
54 if (res === false) return 54 if (res === false) return
55 55
56 this.videoChannelService.removeVideoChannel(videoChannel) 56 this.videoChannelService.removeVideoChannel(videoChannel)
57 .subscribe( 57 .subscribe({
58 () => { 58 next: () => {
59 this.loadVideoChannels() 59 this.loadVideoChannels()
60 this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`) 60 this.notifier.success($localize`Video channel ${videoChannel.displayName} deleted.`)
61 }, 61 },
62 62
63 error => this.notifier.error(error.message) 63 error: err => this.notifier.error(err.message)
64 ) 64 })
65 } 65 }
66 66
67 private loadVideoChannels () { 67 private loadVideoChannels () {
diff --git a/client/src/app/+my-library/my-history/my-history.component.ts b/client/src/app/+my-library/my-history/my-history.component.ts
index ad83db7ab..fe6e86346 100644
--- a/client/src/app/+my-library/my-history/my-history.component.ts
+++ b/client/src/app/+my-library/my-history/my-history.component.ts
@@ -107,8 +107,8 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook {
107 107
108 onVideosHistoryChange () { 108 onVideosHistoryChange () {
109 this.userService.updateMyProfile({ videosHistoryEnabled: this.videosHistoryEnabled }) 109 this.userService.updateMyProfile({ videosHistoryEnabled: this.videosHistoryEnabled })
110 .subscribe( 110 .subscribe({
111 () => { 111 next: () => {
112 const message = this.videosHistoryEnabled === true ? 112 const message = this.videosHistoryEnabled === true ?
113 $localize`Videos history is enabled` : 113 $localize`Videos history is enabled` :
114 $localize`Videos history is disabled` 114 $localize`Videos history is disabled`
@@ -118,8 +118,8 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook {
118 this.authService.refreshUserInformation() 118 this.authService.refreshUserInformation()
119 }, 119 },
120 120
121 err => this.notifier.error(err.message) 121 error: err => this.notifier.error(err.message)
122 ) 122 })
123 } 123 }
124 124
125 async deleteHistory () { 125 async deleteHistory () {
@@ -130,14 +130,14 @@ export class MyHistoryComponent implements OnInit, DisableForReuseHook {
130 if (res !== true) return 130 if (res !== true) return
131 131
132 this.userHistoryService.deleteUserVideosHistory() 132 this.userHistoryService.deleteUserVideosHistory()
133 .subscribe( 133 .subscribe({
134 () => { 134 next: () => {
135 this.notifier.success($localize`Videos history deleted`) 135 this.notifier.success($localize`Videos history deleted`)
136 136
137 this.reloadData() 137 this.reloadData()
138 }, 138 },
139 139
140 err => this.notifier.error(err.message) 140 error: err => this.notifier.error(err.message)
141 ) 141 })
142 } 142 }
143} 143}
diff --git a/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts
index 7889d0985..b92377bca 100644
--- a/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts
+++ b/client/src/app/+my-library/my-ownership/my-accept-ownership/my-accept-ownership.component.ts
@@ -64,14 +64,14 @@ export class MyAcceptOwnershipComponent extends FormReactive implements OnInit {
64 const videoChangeOwnership = this.videoChangeOwnership 64 const videoChangeOwnership = this.videoChangeOwnership
65 this.videoOwnershipService 65 this.videoOwnershipService
66 .acceptOwnership(videoChangeOwnership.id, { channelId: channel }) 66 .acceptOwnership(videoChangeOwnership.id, { channelId: channel })
67 .subscribe( 67 .subscribe({
68 () => { 68 next: () => {
69 this.notifier.success($localize`Ownership accepted`) 69 this.notifier.success($localize`Ownership accepted`)
70 if (this.accepted) this.accepted.emit() 70 if (this.accepted) this.accepted.emit()
71 this.videoChangeOwnership = undefined 71 this.videoChangeOwnership = undefined
72 }, 72 },
73 73
74 err => this.notifier.error(err.message) 74 error: err => this.notifier.error(err.message)
75 ) 75 })
76 } 76 }
77} 77}
diff --git a/client/src/app/+my-library/my-ownership/my-ownership.component.ts b/client/src/app/+my-library/my-ownership/my-ownership.component.ts
index aaf028474..7ea940ceb 100644
--- a/client/src/app/+my-library/my-ownership/my-ownership.component.ts
+++ b/client/src/app/+my-library/my-ownership/my-ownership.component.ts
@@ -53,16 +53,16 @@ export class MyOwnershipComponent extends RestTable implements OnInit {
53 53
54 refuse (videoChangeOwnership: VideoChangeOwnership) { 54 refuse (videoChangeOwnership: VideoChangeOwnership) {
55 this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id) 55 this.videoOwnershipService.refuseOwnership(videoChangeOwnership.id)
56 .subscribe( 56 .subscribe({
57 () => this.reloadData(), 57 next: () => this.reloadData(),
58 err => this.notifier.error(err.message) 58 error: err => this.notifier.error(err.message)
59 ) 59 })
60 } 60 }
61 61
62 protected reloadData () { 62 protected reloadData () {
63 return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort) 63 return this.videoOwnershipService.getOwnershipChanges(this.pagination, this.sort)
64 .subscribe( 64 .subscribe({
65 resultList => { 65 next: resultList => {
66 this.videoChangeOwnerships = resultList.data.map(change => ({ 66 this.videoChangeOwnerships = resultList.data.map(change => ({
67 ...change, 67 ...change,
68 initiatorAccount: new Account(change.initiatorAccount), 68 initiatorAccount: new Account(change.initiatorAccount),
@@ -71,7 +71,7 @@ export class MyOwnershipComponent extends RestTable implements OnInit {
71 this.totalRecords = resultList.total 71 this.totalRecords = resultList.total
72 }, 72 },
73 73
74 err => this.notifier.error(err.message) 74 error: err => this.notifier.error(err.message)
75 ) 75 })
76 } 76 }
77} 77}
diff --git a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
index 1f4a931a0..f676aa014 100644
--- a/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
+++ b/client/src/app/+my-library/my-subscriptions/my-subscriptions.component.ts
@@ -41,8 +41,8 @@ export class MySubscriptionsComponent {
41 41
42 private loadSubscriptions (more = true) { 42 private loadSubscriptions (more = true) {
43 this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.search }) 43 this.userSubscriptionService.listSubscriptions({ pagination: this.pagination, search: this.search })
44 .subscribe( 44 .subscribe({
45 res => { 45 next: res => {
46 this.videoChannels = more 46 this.videoChannels = more
47 ? this.videoChannels.concat(res.data) 47 ? this.videoChannels.concat(res.data)
48 : res.data 48 : res.data
@@ -51,7 +51,7 @@ export class MySubscriptionsComponent {
51 this.onDataSubject.next(res.data) 51 this.onDataSubject.next(res.data)
52 }, 52 },
53 53
54 error => this.notifier.error(error.message) 54 error: err => this.notifier.error(err.message)
55 ) 55 })
56 } 56 }
57} 57}
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
index 68254526a..914785bf7 100644
--- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
+++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts
@@ -64,13 +64,13 @@ export class MyVideoImportsComponent extends RestTable implements OnInit {
64 64
65 protected reloadData () { 65 protected reloadData () {
66 this.videoImportService.getMyVideoImports(this.pagination, this.sort) 66 this.videoImportService.getMyVideoImports(this.pagination, this.sort)
67 .subscribe( 67 .subscribe({
68 resultList => { 68 next: resultList => {
69 this.videoImports = resultList.data 69 this.videoImports = resultList.data
70 this.totalRecords = resultList.total 70 this.totalRecords = resultList.total
71 }, 71 },
72 72
73 err => this.notifier.error(err.message) 73 error: err => this.notifier.error(err.message)
74 ) 74 })
75 } 75 }
76} 76}
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-create.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlist-create.component.ts
index 8606a875a..3e3c3c878 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-create.component.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-create.component.ts
@@ -71,14 +71,15 @@ export class MyVideoPlaylistCreateComponent extends MyVideoPlaylistEdit implemen
71 thumbnailfile: body.thumbnailfile || null 71 thumbnailfile: body.thumbnailfile || null
72 } 72 }
73 73
74 this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe( 74 this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate)
75 () => { 75 .subscribe({
76 this.notifier.success($localize`Playlist ${videoPlaylistCreate.displayName} created.`) 76 next: () => {
77 this.router.navigate([ '/my-library', 'video-playlists' ]) 77 this.notifier.success($localize`Playlist ${videoPlaylistCreate.displayName} created.`)
78 }, 78 this.router.navigate([ '/my-library', 'video-playlists' ])
79 },
79 80
80 err => this.error = err.message 81 error: err => this.error = err.message
81 ) 82 })
82 } 83 }
83 84
84 isCreation () { 85 isCreation () {
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.ts
index 86fe70710..6aff5dbd7 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-elements.component.ts
@@ -85,13 +85,13 @@ export class MyVideoPlaylistElementsComponent implements OnInit, OnDestroy {
85 this.playlistElements.splice(newIndex, 0, element) 85 this.playlistElements.splice(newIndex, 0, element)
86 86
87 this.videoPlaylistService.reorderPlaylist(this.playlist.id, oldPosition, insertAfter) 87 this.videoPlaylistService.reorderPlaylist(this.playlist.id, oldPosition, insertAfter)
88 .subscribe( 88 .subscribe({
89 () => { 89 next: () => {
90 this.reorderClientPositions() 90 this.reorderClientPositions()
91 }, 91 },
92 92
93 err => this.notifier.error(err.message) 93 error: err => this.notifier.error(err.message)
94 ) 94 })
95 } 95 }
96 96
97 onElementRemoved (element: VideoPlaylistElement) { 97 onElementRemoved (element: VideoPlaylistElement) {
@@ -129,14 +129,14 @@ export class MyVideoPlaylistElementsComponent implements OnInit, OnDestroy {
129 if (res === false) return 129 if (res === false) return
130 130
131 this.videoPlaylistService.removeVideoPlaylist(videoPlaylist) 131 this.videoPlaylistService.removeVideoPlaylist(videoPlaylist)
132 .subscribe( 132 .subscribe({
133 () => { 133 next: () => {
134 this.router.navigate([ '/my-library', 'video-playlists' ]) 134 this.router.navigate([ '/my-library', 'video-playlists' ])
135 this.notifier.success($localize`Playlist ${videoPlaylist.displayName} deleted.`) 135 this.notifier.success($localize`Playlist ${videoPlaylist.displayName} deleted.`)
136 }, 136 },
137 137
138 error => this.notifier.error(error.message) 138 error: err => this.notifier.error(err.message)
139 ) 139 })
140 } 140 }
141 141
142 /** 142 /**
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlist-update.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlist-update.component.ts
index c554d3772..a3f54279b 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlist-update.component.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlist-update.component.ts
@@ -64,16 +64,16 @@ export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implemen
64 ]) 64 ])
65 }) 65 })
66 ) 66 )
67 .subscribe( 67 .subscribe({
68 ([ videoPlaylistToUpdate, videoPlaylistPrivacies]) => { 68 next: ([ videoPlaylistToUpdate, videoPlaylistPrivacies]) => {
69 this.videoPlaylistToUpdate = videoPlaylistToUpdate 69 this.videoPlaylistToUpdate = videoPlaylistToUpdate
70 this.videoPlaylistPrivacies = videoPlaylistPrivacies 70 this.videoPlaylistPrivacies = videoPlaylistPrivacies
71 71
72 this.hydrateFormFromPlaylist() 72 this.hydrateFormFromPlaylist()
73 }, 73 },
74 74
75 err => this.error = err.message 75 error: err => this.error = err.message
76 ) 76 })
77 } 77 }
78 78
79 ngOnDestroy () { 79 ngOnDestroy () {
@@ -92,14 +92,15 @@ export class MyVideoPlaylistUpdateComponent extends MyVideoPlaylistEdit implemen
92 thumbnailfile: body.thumbnailfile || undefined 92 thumbnailfile: body.thumbnailfile || undefined
93 } 93 }
94 94
95 this.videoPlaylistService.updateVideoPlaylist(this.videoPlaylistToUpdate, videoPlaylistUpdate).subscribe( 95 this.videoPlaylistService.updateVideoPlaylist(this.videoPlaylistToUpdate, videoPlaylistUpdate)
96 () => { 96 .subscribe({
97 this.notifier.success($localize`Playlist ${videoPlaylistUpdate.displayName} updated.`) 97 next: () => {
98 this.router.navigate([ '/my-library', 'video-playlists' ]) 98 this.notifier.success($localize`Playlist ${videoPlaylistUpdate.displayName} updated.`)
99 }, 99 this.router.navigate([ '/my-library', 'video-playlists' ])
100 },
100 101
101 err => this.error = err.message 102 error: err => this.error = err.message
102 ) 103 })
103 } 104 }
104 105
105 isCreation () { 106 isCreation () {
diff --git a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
index d90102693..f0e4c348b 100644
--- a/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
+++ b/client/src/app/+my-library/my-video-playlists/my-video-playlists.component.ts
@@ -37,16 +37,16 @@ export class MyVideoPlaylistsComponent {
37 if (res === false) return 37 if (res === false) return
38 38
39 this.videoPlaylistService.removeVideoPlaylist(videoPlaylist) 39 this.videoPlaylistService.removeVideoPlaylist(videoPlaylist)
40 .subscribe( 40 .subscribe({
41 () => { 41 next: () => {
42 this.videoPlaylists = this.videoPlaylists 42 this.videoPlaylists = this.videoPlaylists
43 .filter(p => p.id !== videoPlaylist.id) 43 .filter(p => p.id !== videoPlaylist.id)
44 44
45 this.notifier.success($localize`Playlist ${videoPlaylist.displayName}} deleted.`) 45 this.notifier.success($localize`Playlist ${videoPlaylist.displayName}} deleted.`)
46 }, 46 },
47 47
48 error => this.notifier.error(error.message) 48 error: err => this.notifier.error(err.message)
49 ) 49 })
50 } 50 }
51 51
52 isRegularPlaylist (playlist: VideoPlaylist) { 52 isRegularPlaylist (playlist: VideoPlaylist) {
diff --git a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.ts b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.ts
index 84237dee1..8c1f94bf3 100644
--- a/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.ts
+++ b/client/src/app/+my-library/my-videos/modals/video-change-ownership.component.ts
@@ -48,11 +48,11 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni
48 search (event: { query: string }) { 48 search (event: { query: string }) {
49 const query = event.query 49 const query = event.query
50 this.userService.autocomplete(query) 50 this.userService.autocomplete(query)
51 .subscribe( 51 .subscribe({
52 usernames => this.usernamePropositions = usernames, 52 next: usernames => this.usernamePropositions = usernames,
53 53
54 err => this.notifier.error(err.message) 54 error: err => this.notifier.error(err.message)
55 ) 55 })
56 } 56 }
57 57
58 changeOwnership () { 58 changeOwnership () {
@@ -60,10 +60,10 @@ export class VideoChangeOwnershipComponent extends FormReactive implements OnIni
60 60
61 this.videoOwnershipService 61 this.videoOwnershipService
62 .changeOwnership(this.video.id, username) 62 .changeOwnership(this.video.id, username)
63 .subscribe( 63 .subscribe({
64 () => this.notifier.success($localize`Ownership change request sent.`), 64 next: () => this.notifier.success($localize`Ownership change request sent.`),
65 65
66 err => this.notifier.error(err.message) 66 error: err => this.notifier.error(err.message)
67 ) 67 })
68 } 68 }
69} 69}
diff --git a/client/src/app/+my-library/my-videos/my-videos.component.ts b/client/src/app/+my-library/my-videos/my-videos.component.ts
index 1e4a4406d..4f9b71cc6 100644
--- a/client/src/app/+my-library/my-videos/my-videos.component.ts
+++ b/client/src/app/+my-library/my-videos/my-videos.component.ts
@@ -126,14 +126,14 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
126 126
127 concat(...observables) 127 concat(...observables)
128 .pipe(toArray()) 128 .pipe(toArray())
129 .subscribe( 129 .subscribe({
130 () => { 130 next: () => {
131 this.notifier.success($localize`${toDeleteVideosIds.length} videos deleted.`) 131 this.notifier.success($localize`${toDeleteVideosIds.length} videos deleted.`)
132 this.selection = {} 132 this.selection = {}
133 }, 133 },
134 134
135 err => this.notifier.error(err.message) 135 error: err => this.notifier.error(err.message)
136 ) 136 })
137 } 137 }
138 138
139 async deleteVideo (video: Video) { 139 async deleteVideo (video: Video) {
@@ -144,14 +144,14 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
144 if (res === false) return 144 if (res === false) return
145 145
146 this.videoService.removeVideo(video.id) 146 this.videoService.removeVideo(video.id)
147 .subscribe( 147 .subscribe({
148 () => { 148 next: () => {
149 this.notifier.success($localize`Video ${video.name} deleted.`) 149 this.notifier.success($localize`Video ${video.name} deleted.`)
150 this.removeVideoFromArray(video.id) 150 this.removeVideoFromArray(video.id)
151 }, 151 },
152 152
153 error => this.notifier.error(error.message) 153 error: err => this.notifier.error(err.message)
154 ) 154 })
155 } 155 }
156 156
157 changeOwnership (video: Video) { 157 changeOwnership (video: Video) {
diff --git a/client/src/app/+reset-password/reset-password.component.ts b/client/src/app/+reset-password/reset-password.component.ts
index ce9144170..a1c04147b 100644
--- a/client/src/app/+reset-password/reset-password.component.ts
+++ b/client/src/app/+reset-password/reset-password.component.ts
@@ -42,14 +42,14 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
42 42
43 resetPassword () { 43 resetPassword () {
44 this.userService.resetPassword(this.userId, this.verificationString, this.form.value.password) 44 this.userService.resetPassword(this.userId, this.verificationString, this.form.value.password)
45 .subscribe( 45 .subscribe({
46 () => { 46 next: () => {
47 this.notifier.success($localize`Your password has been successfully reset!`) 47 this.notifier.success($localize`Your password has been successfully reset!`)
48 this.router.navigate([ '/login' ]) 48 this.router.navigate([ '/login' ])
49 }, 49 },
50 50
51 err => this.notifier.error(err.message) 51 error: err => this.notifier.error(err.message)
52 ) 52 })
53 } 53 }
54 54
55 isConfirmedPasswordValid () { 55 isConfirmedPasswordValid () {
diff --git a/client/src/app/+search/search.component.ts b/client/src/app/+search/search.component.ts
index 7425b7016..81d1006f8 100644
--- a/client/src/app/+search/search.component.ts
+++ b/client/src/app/+search/search.component.ts
@@ -73,36 +73,37 @@ export class SearchComponent implements OnInit, OnDestroy {
73 ngOnInit () { 73 ngOnInit () {
74 this.serverConfig = this.serverService.getHTMLConfig() 74 this.serverConfig = this.serverService.getHTMLConfig()
75 75
76 this.subActivatedRoute = this.route.queryParams.subscribe( 76 this.subActivatedRoute = this.route.queryParams
77 async queryParams => { 77 .subscribe({
78 const querySearch = queryParams['search'] 78 next: async queryParams => {
79 const searchTarget = queryParams['searchTarget'] 79 const querySearch = queryParams['search']
80 80 const searchTarget = queryParams['searchTarget']
81 // Search updated, reset filters
82 if (this.currentSearch !== querySearch || searchTarget !== this.advancedSearch.searchTarget) {
83 this.resetPagination()
84 this.advancedSearch.reset()
85
86 this.currentSearch = querySearch || undefined
87 this.updateTitle()
88 }
89 81
90 this.advancedSearch = new AdvancedSearch(queryParams) 82 // Search updated, reset filters
91 if (!this.advancedSearch.searchTarget) { 83 if (this.currentSearch !== querySearch || searchTarget !== this.advancedSearch.searchTarget) {
92 this.advancedSearch.searchTarget = this.getDefaultSearchTarget() 84 this.resetPagination()
93 } 85 this.advancedSearch.reset()
94 86
95 this.error = this.checkFieldsAndGetError() 87 this.currentSearch = querySearch || undefined
88 this.updateTitle()
89 }
96 90
97 // Don't hide filters if we have some of them AND the user just came on the webpage, or we have an error 91 this.advancedSearch = new AdvancedSearch(queryParams)
98 this.isSearchFilterCollapsed = !this.error && (this.isInitialLoad === false || !this.advancedSearch.containsValues()) 92 if (!this.advancedSearch.searchTarget) {
99 this.isInitialLoad = false 93 this.advancedSearch.searchTarget = this.getDefaultSearchTarget()
94 }
100 95
101 this.search() 96 this.error = this.checkFieldsAndGetError()
102 },
103 97
104 err => this.notifier.error(err.text) 98 // Don't hide filters if we have some of them AND the user just came on the webpage, or we have an error
105 ) 99 this.isSearchFilterCollapsed = !this.error && (this.isInitialLoad === false || !this.advancedSearch.containsValues())
100 this.isInitialLoad = false
101
102 this.search()
103 },
104
105 error: err => this.notifier.error(err.text)
106 })
106 107
107 this.userService.getAnonymousOrLoggedUser() 108 this.userService.getAnonymousOrLoggedUser()
108 .subscribe(user => this.userMiniature = user) 109 .subscribe(user => this.userMiniature = user)
@@ -140,33 +141,35 @@ export class SearchComponent implements OnInit, OnDestroy {
140 this.getVideoChannelObs(), 141 this.getVideoChannelObs(),
141 this.getVideoPlaylistObs(), 142 this.getVideoPlaylistObs(),
142 this.getVideosObs() 143 this.getVideosObs()
143 ]).subscribe(results => { 144 ]).subscribe({
144 for (const result of results) { 145 next: results => {
145 this.results = this.results.concat(result.data) 146 for (const result of results) {
146 } 147 this.results = this.results.concat(result.data)
148 }
147 149
148 this.pagination.totalItems = results.reduce((p, r) => p += r.total, 0) 150 this.pagination.totalItems = results.reduce((p, r) => p += r.total, 0)
149 this.lastSearchTarget = this.advancedSearch.searchTarget 151 this.lastSearchTarget = this.advancedSearch.searchTarget
150 152
151 this.hasMoreResults = this.results.length < this.pagination.totalItems 153 this.hasMoreResults = this.results.length < this.pagination.totalItems
152 }, 154 },
153 155
154 err => { 156 error: err => {
155 if (this.advancedSearch.searchTarget !== 'search-index') { 157 if (this.advancedSearch.searchTarget !== 'search-index') {
156 this.notifier.error(err.message) 158 this.notifier.error(err.message)
157 return 159 return
158 } 160 }
159 161
160 this.notifier.error( 162 this.notifier.error(
161 $localize`Search index is unavailable. Retrying with instance results instead.`, 163 $localize`Search index is unavailable. Retrying with instance results instead.`,
162 $localize`Search error` 164 $localize`Search error`
163 ) 165 )
164 this.advancedSearch.searchTarget = 'local' 166 this.advancedSearch.searchTarget = 'local'
165 this.search() 167 this.search()
166 }, 168 },
167 169
168 () => { 170 complete: () => {
169 this.isSearching = false 171 this.isSearching = false
172 }
170 }) 173 })
171 } 174 }
172 175
diff --git a/client/src/app/+signup/+register/register.component.ts b/client/src/app/+signup/+register/register.component.ts
index 241ca04c6..056442107 100644
--- a/client/src/app/+signup/+register/register.component.ts
+++ b/client/src/app/+signup/+register/register.component.ts
@@ -122,8 +122,8 @@ export class RegisterComponent implements OnInit {
122 'filter:api.signup.registration.create.params' 122 'filter:api.signup.registration.create.params'
123 ) 123 )
124 124
125 this.userService.signup(body).subscribe( 125 this.userService.signup(body).subscribe({
126 () => { 126 next: () => {
127 this.signupDone = true 127 this.signupDone = true
128 128
129 if (this.requiresEmailVerification) { 129 if (this.requiresEmailVerification) {
@@ -133,16 +133,16 @@ export class RegisterComponent implements OnInit {
133 133
134 // Auto login 134 // Auto login
135 this.authService.login(body.username, body.password) 135 this.authService.login(body.username, body.password)
136 .subscribe( 136 .subscribe({
137 () => { 137 next: () => {
138 this.success = $localize`You are now logged in as ${body.username}!` 138 this.success = $localize`You are now logged in as ${body.username}!`
139 }, 139 },
140 140
141 err => this.error = err.message 141 error: err => this.error = err.message
142 ) 142 })
143 }, 143 },
144 144
145 err => this.error = err.message 145 error: err => this.error = err.message
146 ) 146 })
147 } 147 }
148} 148}
diff --git a/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
index afb0e6d6c..83c24a251 100644
--- a/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
@@ -34,15 +34,13 @@ export class VerifyAccountAskSendEmailComponent extends FormReactive implements
34 askSendVerifyEmail () { 34 askSendVerifyEmail () {
35 const email = this.form.value['verify-email-email'] 35 const email = this.form.value['verify-email-email']
36 this.userService.askSendVerifyEmail(email) 36 this.userService.askSendVerifyEmail(email)
37 .subscribe( 37 .subscribe({
38 () => { 38 next: () => {
39 this.notifier.success($localize`An email with verification link will be sent to ${email}.`) 39 this.notifier.success($localize`An email with verification link will be sent to ${email}.`)
40 this.redirectService.redirectToHomepage() 40 this.redirectService.redirectToHomepage()
41 }, 41 },
42 42
43 err => { 43 error: err => this.notifier.error(err.message)
44 this.notifier.error(err.message) 44 })
45 }
46 )
47 } 45 }
48} 46}
diff --git a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
index acc688ab3..457a0abe0 100644
--- a/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
@@ -38,8 +38,8 @@ export class VerifyAccountEmailComponent implements OnInit {
38 38
39 verifyEmail () { 39 verifyEmail () {
40 this.userService.verifyEmail(this.userId, this.verificationString, this.isPendingEmail) 40 this.userService.verifyEmail(this.userId, this.verificationString, this.isPendingEmail)
41 .subscribe( 41 .subscribe({
42 () => { 42 next: () => {
43 if (this.authService.isLoggedIn()) { 43 if (this.authService.isLoggedIn()) {
44 this.authService.refreshUserInformation() 44 this.authService.refreshUserInformation()
45 } 45 }
@@ -47,11 +47,11 @@ export class VerifyAccountEmailComponent implements OnInit {
47 this.success = true 47 this.success = true
48 }, 48 },
49 49
50 err => { 50 error: err => {
51 this.failed = true 51 this.failed = true
52 52
53 this.notifier.error(err.message) 53 this.notifier.error(err.message)
54 } 54 }
55 ) 55 })
56 } 56 }
57} 57}
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
index db25dc6be..30c79594d 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
@@ -8,7 +8,7 @@ import { FormValidatorService } from '@app/shared/shared-forms'
8import { Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' 8import { Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
9import { LiveVideoService } from '@app/shared/shared-video-live' 9import { LiveVideoService } from '@app/shared/shared-video-live'
10import { LoadingBarService } from '@ngx-loading-bar/core' 10import { LoadingBarService } from '@ngx-loading-bar/core'
11import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode, VideoPrivacy } from '@shared/models' 11import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models'
12import { VideoSend } from './video-send' 12import { VideoSend } from './video-send'
13 13
14@Component({ 14@Component({
@@ -74,33 +74,34 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
74 const toPatch = Object.assign({}, video, { privacy: this.firstStepPrivacyId }) 74 const toPatch = Object.assign({}, video, { privacy: this.firstStepPrivacyId })
75 this.form.patchValue(toPatch) 75 this.form.patchValue(toPatch)
76 76
77 this.liveVideoService.goLive(video).subscribe( 77 this.liveVideoService.goLive(video)
78 res => { 78 .subscribe({
79 this.videoId = res.video.id 79 next: res => {
80 this.videoUUID = res.video.uuid 80 this.videoId = res.video.id
81 this.isInUpdateForm = true 81 this.videoUUID = res.video.uuid
82 this.isInUpdateForm = true
82 83
83 this.firstStepDone.emit(name) 84 this.firstStepDone.emit(name)
84 85
85 this.fetchVideoLive() 86 this.fetchVideoLive()
86 }, 87 },
88
89 error: err => {
90 this.firstStepError.emit()
87 91
88 err => { 92 let message = err.message
89 this.firstStepError.emit()
90 93
91 let message = err.message 94 const error = err.body as PeerTubeProblemDocument
92 95
93 const error = err.body as PeerTubeProblemDocument 96 if (error?.code === ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED) {
97 message = $localize`Cannot create live because this instance have too many created lives`
98 } else if (error?.code === ServerErrorCode.MAX_USER_LIVES_LIMIT_REACHED) {
99 message = $localize`Cannot create live because you created too many lives`
100 }
94 101
95 if (error?.code === ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED) { 102 this.notifier.error(message)
96 message = $localize`Cannot create live because this instance have too many created lives`
97 } else if (error?.code === ServerErrorCode.MAX_USER_LIVES_LIMIT_REACHED) {
98 message = $localize`Cannot create live because you created too many lives`
99 } 103 }
100 104 })
101 this.notifier.error(message)
102 }
103 )
104 } 105 }
105 106
106 updateSecondStep () { 107 updateSecondStep () {
@@ -123,19 +124,19 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
123 this.updateVideoAndCaptions(video), 124 this.updateVideoAndCaptions(video),
124 125
125 this.liveVideoService.updateLive(this.videoId, liveVideoUpdate) 126 this.liveVideoService.updateLive(this.videoId, liveVideoUpdate)
126 ]).subscribe( 127 ]).subscribe({
127 () => { 128 next: () => {
128 this.notifier.success($localize`Live published.`) 129 this.notifier.success($localize`Live published.`)
129 130
130 this.router.navigateByUrl(Video.buildWatchUrl(video)) 131 this.router.navigateByUrl(Video.buildWatchUrl(video))
131 }, 132 },
132 133
133 err => { 134 error: err => {
134 this.error = err.message 135 this.error = err.message
135 scrollToTop() 136 scrollToTop()
136 console.error(err) 137 console.error(err)
137 } 138 }
138 ) 139 })
139 } 140 }
140 141
141 getMaxLiveDuration () { 142 getMaxLiveDuration () {
@@ -148,15 +149,15 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
148 149
149 private fetchVideoLive () { 150 private fetchVideoLive () {
150 this.liveVideoService.getVideoLive(this.videoId) 151 this.liveVideoService.getVideoLive(this.videoId)
151 .subscribe( 152 .subscribe({
152 liveVideo => { 153 next: liveVideo => {
153 this.liveVideo = liveVideo 154 this.liveVideo = liveVideo
154 }, 155 },
155 156
156 err => { 157 error: err => {
157 this.firstStepError.emit() 158 this.firstStepError.emit()
158 this.notifier.error(err.message) 159 this.notifier.error(err.message)
159 } 160 }
160 ) 161 })
161 } 162 }
162} 163}
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
index 62aaeb019..fef1f5d65 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
@@ -88,40 +88,41 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af
88 88
89 this.loadingBar.useRef().start() 89 this.loadingBar.useRef().start()
90 90
91 this.videoImportService.importVideoTorrent(torrentfile || this.magnetUri, videoUpdate).subscribe( 91 this.videoImportService.importVideoTorrent(torrentfile || this.magnetUri, videoUpdate)
92 res => { 92 .subscribe({
93 this.loadingBar.useRef().complete() 93 next: res => {
94 this.firstStepDone.emit(res.video.name) 94 this.loadingBar.useRef().complete()
95 this.isImportingVideo = false 95 this.firstStepDone.emit(res.video.name)
96 this.hasImportedVideo = true 96 this.isImportingVideo = false
97 97 this.hasImportedVideo = true
98 this.video = new VideoEdit(Object.assign(res.video, { 98
99 commentsEnabled: videoUpdate.commentsEnabled, 99 this.video = new VideoEdit(Object.assign(res.video, {
100 downloadEnabled: videoUpdate.downloadEnabled, 100 commentsEnabled: videoUpdate.commentsEnabled,
101 privacy: { id: this.firstStepPrivacyId }, 101 downloadEnabled: videoUpdate.downloadEnabled,
102 support: null, 102 privacy: { id: this.firstStepPrivacyId },
103 thumbnailUrl: null, 103 support: null,
104 previewUrl: null 104 thumbnailUrl: null,
105 })) 105 previewUrl: null
106 106 }))
107 hydrateFormFromVideo(this.form, this.video, false) 107
108 }, 108 hydrateFormFromVideo(this.form, this.video, false)
109 109 },
110 err => { 110
111 this.loadingBar.useRef().complete() 111 error: err => {
112 this.isImportingVideo = false 112 this.loadingBar.useRef().complete()
113 this.firstStepError.emit() 113 this.isImportingVideo = false
114 114 this.firstStepError.emit()
115 let message = err.message 115
116 116 let message = err.message
117 const error = err.body as PeerTubeProblemDocument 117
118 if (error?.code === ServerErrorCode.INCORRECT_FILES_IN_TORRENT) { 118 const error = err.body as PeerTubeProblemDocument
119 message = $localize`Torrents with only 1 file are supported.` 119 if (error?.code === ServerErrorCode.INCORRECT_FILES_IN_TORRENT) {
120 } 120 message = $localize`Torrents with only 1 file are supported.`
121 }
121 122
122 this.notifier.error(message) 123 this.notifier.error(message)
123 } 124 }
124 ) 125 })
125 } 126 }
126 127
127 updateSecondStep () { 128 updateSecondStep () {
@@ -135,19 +136,19 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af
135 136
136 // Update the video 137 // Update the video
137 this.updateVideoAndCaptions(this.video) 138 this.updateVideoAndCaptions(this.video)
138 .subscribe( 139 .subscribe({
139 () => { 140 next: () => {
140 this.isUpdatingVideo = false 141 this.isUpdatingVideo = false
141 this.notifier.success($localize`Video to import updated.`) 142 this.notifier.success($localize`Video to import updated.`)
142 143
143 this.router.navigate([ '/my-library', 'video-imports' ]) 144 this.router.navigate([ '/my-library', 'video-imports' ])
144 }, 145 },
145 146
146 err => { 147 error: err => {
147 this.error = err.message 148 this.error = err.message
148 scrollToTop() 149 scrollToTop()
149 console.error(err) 150 console.error(err)
150 } 151 }
151 ) 152 })
152 } 153 }
153} 154}
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
index 3243b4d38..e1893b28f 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
@@ -6,7 +6,7 @@ import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers'
6import { FormValidatorService } from '@app/shared/shared-forms' 6import { FormValidatorService } from '@app/shared/shared-forms'
7import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' 7import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
8import { LoadingBarService } from '@ngx-loading-bar/core' 8import { LoadingBarService } from '@ngx-loading-bar/core'
9import { VideoPrivacy, VideoUpdate } from '@shared/models' 9import { VideoUpdate } from '@shared/models'
10import { hydrateFormFromVideo } from '../shared/video-edit-utils' 10import { hydrateFormFromVideo } from '../shared/video-edit-utils'
11import { VideoSend } from './video-send' 11import { VideoSend } from './video-send'
12 12
@@ -86,8 +86,8 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
86 ) 86 )
87 }) 87 })
88 ) 88 )
89 .subscribe( 89 .subscribe({
90 ({ video, videoCaptions }) => { 90 next: ({ video, videoCaptions }) => {
91 this.loadingBar.useRef().complete() 91 this.loadingBar.useRef().complete()
92 this.firstStepDone.emit(video.name) 92 this.firstStepDone.emit(video.name)
93 this.isImportingVideo = false 93 this.isImportingVideo = false
@@ -117,13 +117,13 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
117 hydrateFormFromVideo(this.form, this.video, true) 117 hydrateFormFromVideo(this.form, this.video, true)
118 }, 118 },
119 119
120 err => { 120 error: err => {
121 this.loadingBar.useRef().complete() 121 this.loadingBar.useRef().complete()
122 this.isImportingVideo = false 122 this.isImportingVideo = false
123 this.firstStepError.emit() 123 this.firstStepError.emit()
124 this.notifier.error(err.message) 124 this.notifier.error(err.message)
125 } 125 }
126 ) 126 })
127 } 127 }
128 128
129 updateSecondStep () { 129 updateSecondStep () {
@@ -137,19 +137,19 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
137 137
138 // Update the video 138 // Update the video
139 this.updateVideoAndCaptions(this.video) 139 this.updateVideoAndCaptions(this.video)
140 .subscribe( 140 .subscribe({
141 () => { 141 next: () => {
142 this.isUpdatingVideo = false 142 this.isUpdatingVideo = false
143 this.notifier.success($localize`Video to import updated.`) 143 this.notifier.success($localize`Video to import updated.`)
144 144
145 this.router.navigate([ '/my-library', 'video-imports' ]) 145 this.router.navigate([ '/my-library', 'video-imports' ])
146 }, 146 },
147 147
148 err => { 148 error: err => {
149 this.error = err.message 149 this.error = err.message
150 scrollToTop() 150 scrollToTop()
151 console.error(err) 151 console.error(err)
152 } 152 }
153 ) 153 })
154 } 154 }
155} 155}
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
index 189bc9669..b8cb4fa1e 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
@@ -240,8 +240,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
240 this.isUpdatingVideo = true 240 this.isUpdatingVideo = true
241 241
242 this.updateVideoAndCaptions(video) 242 this.updateVideoAndCaptions(video)
243 .subscribe( 243 .subscribe({
244 () => { 244 next: () => {
245 this.isUpdatingVideo = false 245 this.isUpdatingVideo = false
246 this.isUploadingVideo = false 246 this.isUploadingVideo = false
247 247
@@ -249,12 +249,12 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
249 this.router.navigateByUrl(Video.buildWatchUrl(video)) 249 this.router.navigateByUrl(Video.buildWatchUrl(video))
250 }, 250 },
251 251
252 err => { 252 error: err => {
253 this.error = err.message 253 this.error = err.message
254 scrollToTop() 254 scrollToTop()
255 console.error(err) 255 console.error(err)
256 } 256 }
257 ) 257 })
258 } 258 }
259 259
260 private getInputVideoFile () { 260 private getInputVideoFile () {
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 1534eee82..95336dc75 100644
--- a/client/src/app/+videos/+video-edit/video-update.component.ts
+++ b/client/src/app/+videos/+video-edit/video-update.component.ts
@@ -47,34 +47,35 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
47 47
48 this.route.data 48 this.route.data
49 .pipe(map(data => data.videoData)) 49 .pipe(map(data => data.videoData))
50 .subscribe(({ video, videoChannels, videoCaptions, liveVideo }) => { 50 .subscribe({
51 this.video = new VideoEdit(video) 51 next: ({ video, videoChannels, videoCaptions, liveVideo }) => {
52 this.videoDetails = video 52 this.video = new VideoEdit(video)
53 53 this.videoDetails = video
54 this.userVideoChannels = videoChannels 54
55 this.videoCaptions = videoCaptions 55 this.userVideoChannels = videoChannels
56 this.liveVideo = liveVideo 56 this.videoCaptions = videoCaptions
57 57 this.liveVideo = liveVideo
58 this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.PRIVATE 58
59 59 this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.PRIVATE
60 // FIXME: Angular does not detect the change inside this subscription, so use the patched setTimeout 60
61 setTimeout(() => { 61 // FIXME: Angular does not detect the change inside this subscription, so use the patched setTimeout
62 hydrateFormFromVideo(this.form, this.video, true) 62 setTimeout(() => {
63 63 hydrateFormFromVideo(this.form, this.video, true)
64 if (this.liveVideo) { 64
65 this.form.patchValue({ 65 if (this.liveVideo) {
66 saveReplay: this.liveVideo.saveReplay, 66 this.form.patchValue({
67 permanentLive: this.liveVideo.permanentLive 67 saveReplay: this.liveVideo.saveReplay,
68 }) 68 permanentLive: this.liveVideo.permanentLive
69 } 69 })
70 }) 70 }
71 }, 71 })
72 },
72 73
73 err => { 74 error: err => {
74 console.error(err) 75 console.error(err)
75 this.notifier.error(err.message) 76 this.notifier.error(err.message)
76 } 77 }
77 ) 78 })
78 } 79 }
79 80
80 @HostListener('window:beforeunload', [ '$event' ]) 81 @HostListener('window:beforeunload', [ '$event' ])
@@ -150,8 +151,8 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
150 return this.liveVideoService.updateLive(this.video.id, liveVideoUpdate) 151 return this.liveVideoService.updateLive(this.video.id, liveVideoUpdate)
151 }) 152 })
152 ) 153 )
153 .subscribe( 154 .subscribe({
154 () => { 155 next: () => {
155 this.updateDone = true 156 this.updateDone = true
156 this.isUpdatingVideo = false 157 this.isUpdatingVideo = false
157 this.loadingBar.useRef().complete() 158 this.loadingBar.useRef().complete()
@@ -159,13 +160,13 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
159 this.router.navigateByUrl(Video.buildWatchUrl(this.video)) 160 this.router.navigateByUrl(Video.buildWatchUrl(this.video))
160 }, 161 },
161 162
162 err => { 163 error: err => {
163 this.loadingBar.useRef().complete() 164 this.loadingBar.useRef().complete()
164 this.isUpdatingVideo = false 165 this.isUpdatingVideo = false
165 this.notifier.error(err.message) 166 this.notifier.error(err.message)
166 console.error(err) 167 console.error(err)
167 } 168 }
168 ) 169 })
169 } 170 }
170 171
171 hydratePluginFieldsFromVideo () { 172 hydratePluginFieldsFromVideo () {
diff --git a/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts
index ecb5a9281..48d48f33f 100644
--- a/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/action-buttons/video-rate.component.ts
@@ -90,16 +90,16 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
90 if (this.isUserLoggedIn === false) return 90 if (this.isUserLoggedIn === false) return
91 91
92 this.videoService.getUserVideoRating(this.video.id) 92 this.videoService.getUserVideoRating(this.video.id)
93 .subscribe( 93 .subscribe({
94 ratingObject => { 94 next: ratingObject => {
95 if (!ratingObject) return 95 if (!ratingObject) return
96 96
97 this.userRating = ratingObject.rating 97 this.userRating = ratingObject.rating
98 this.userRatingLoaded.emit(this.userRating) 98 this.userRatingLoaded.emit(this.userRating)
99 }, 99 },
100 100
101 err => this.notifier.error(err.message) 101 error: err => this.notifier.error(err.message)
102 ) 102 })
103 } 103 }
104 104
105 private setRating (nextRating: UserVideoRateType) { 105 private setRating (nextRating: UserVideoRateType) {
@@ -110,16 +110,16 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
110 } 110 }
111 111
112 ratingMethods[nextRating].call(this.videoService, this.video.id) 112 ratingMethods[nextRating].call(this.videoService, this.video.id)
113 .subscribe( 113 .subscribe({
114 () => { 114 next: () => {
115 // Update the video like attribute 115 // Update the video like attribute
116 this.updateVideoRating(this.userRating, nextRating) 116 this.updateVideoRating(this.userRating, nextRating)
117 this.userRating = nextRating 117 this.userRating = nextRating
118 this.rateUpdated.emit(this.userRating) 118 this.rateUpdated.emit(this.userRating)
119 }, 119 },
120 120
121 (err: { message: string }) => this.notifier.error(err.message) 121 error: err => this.notifier.error(err.message)
122 ) 122 })
123 } 123 }
124 124
125 private updateVideoRating (oldRating: UserVideoRateType, newRating: UserVideoRateType) { 125 private updateVideoRating (oldRating: UserVideoRateType, newRating: UserVideoRateType) {
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.ts b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.ts
index 78efe1684..ac65f7260 100644
--- a/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment-add.component.ts
@@ -137,19 +137,19 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges,
137 obs = this.addCommentThread(commentCreate) 137 obs = this.addCommentThread(commentCreate)
138 } 138 }
139 139
140 obs.subscribe( 140 obs.subscribe({
141 comment => { 141 next: comment => {
142 this.addingComment = false 142 this.addingComment = false
143 this.commentCreated.emit(comment) 143 this.commentCreated.emit(comment)
144 this.form.reset() 144 this.form.reset()
145 }, 145 },
146 146
147 err => { 147 error: err => {
148 this.addingComment = false 148 this.addingComment = false
149 149
150 this.notifier.error(err.text) 150 this.notifier.error(err.text)
151 } 151 }
152 ) 152 })
153 } 153 }
154 154
155 isAddButtonDisplayed () { 155 isAddButtonDisplayed () {
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts
index 0e1c4c207..f858f4750 100644
--- a/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/comment/video-comment.component.ts
@@ -149,11 +149,11 @@ export class VideoCommentComponent implements OnInit, OnChanges {
149 const user = this.authService.getUser() 149 const user = this.authService.getUser()
150 if (user.hasRight(UserRight.MANAGE_USERS)) { 150 if (user.hasRight(UserRight.MANAGE_USERS)) {
151 this.userService.getUserWithCache(account.userId) 151 this.userService.getUserWithCache(account.userId)
152 .subscribe( 152 .subscribe({
153 user => this.commentUser = user, 153 next: user => this.commentUser = user,
154 154
155 err => this.notifier.error(err.message) 155 error: err => this.notifier.error(err.message)
156 ) 156 })
157 } 157 }
158 } 158 }
159 159
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
index 2c39e63fb..72866b874 100644
--- a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
@@ -90,22 +90,22 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
90 'filter:api.video-watch.video-thread-replies.list.result' 90 'filter:api.video-watch.video-thread-replies.list.result'
91 ) 91 )
92 92
93 obs.subscribe( 93 obs.subscribe({
94 res => { 94 next: res => {
95 this.threadComments[commentId] = res 95 this.threadComments[commentId] = res
96 this.threadLoading[commentId] = false 96 this.threadLoading[commentId] = false
97 this.hooks.runAction('action:video-watch.video-thread-replies.loaded', 'video-watch', { data: res }) 97 this.hooks.runAction('action:video-watch.video-thread-replies.loaded', 'video-watch', { data: res })
98 98
99 if (highlightThread) { 99 if (highlightThread) {
100 this.highlightedThread = new VideoComment(res.comment) 100 this.highlightedThread = new VideoComment(res.comment)
101 101
102 // Scroll to the highlighted thread 102 // Scroll to the highlighted thread
103 setTimeout(() => this.commentHighlightBlock.nativeElement.scrollIntoView(), 0) 103 setTimeout(() => this.commentHighlightBlock.nativeElement.scrollIntoView(), 0)
104 } 104 }
105 }, 105 },
106 106
107 err => this.notifier.error(err.message) 107 error: err => this.notifier.error(err.message)
108 ) 108 })
109 } 109 }
110 110
111 loadMoreThreads () { 111 loadMoreThreads () {
@@ -123,8 +123,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
123 'filter:api.video-watch.video-threads.list.result' 123 'filter:api.video-watch.video-threads.list.result'
124 ) 124 )
125 125
126 obs.subscribe( 126 obs.subscribe({
127 res => { 127 next: res => {
128 this.comments = this.comments.concat(res.data) 128 this.comments = this.comments.concat(res.data)
129 this.componentPagination.totalItems = res.total 129 this.componentPagination.totalItems = res.total
130 this.totalNotDeletedComments = res.totalNotDeletedComments 130 this.totalNotDeletedComments = res.totalNotDeletedComments
@@ -133,8 +133,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
133 this.hooks.runAction('action:video-watch.video-threads.loaded', 'video-watch', { data: this.componentPagination }) 133 this.hooks.runAction('action:video-watch.video-threads.loaded', 'video-watch', { data: this.componentPagination })
134 }, 134 },
135 135
136 err => this.notifier.error(err.message) 136 error: err => this.notifier.error(err.message)
137 ) 137 })
138 } 138 }
139 139
140 onCommentThreadCreated (comment: VideoComment) { 140 onCommentThreadCreated (comment: VideoComment) {
@@ -181,8 +181,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
181 if (res === false) return false 181 if (res === false) return false
182 182
183 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id) 183 this.videoCommentService.deleteVideoComment(commentToDelete.videoId, commentToDelete.id)
184 .subscribe( 184 .subscribe({
185 () => { 185 next: () => {
186 if (this.highlightedThread?.id === commentToDelete.id) { 186 if (this.highlightedThread?.id === commentToDelete.id) {
187 commentToDelete = this.comments.find(c => c.id === commentToDelete.id) 187 commentToDelete = this.comments.find(c => c.id === commentToDelete.id)
188 188
@@ -193,8 +193,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
193 this.softDeleteComment(commentToDelete) 193 this.softDeleteComment(commentToDelete)
194 }, 194 },
195 195
196 err => this.notifier.error(err.message) 196 error: err => this.notifier.error(err.message)
197 ) 197 })
198 198
199 return true 199 return true
200 } 200 }
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
index 870c7ae3f..e002b3c22 100644
--- a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts
@@ -50,8 +50,8 @@ export class VideoDescriptionComponent implements OnChanges {
50 this.descriptionLoading = true 50 this.descriptionLoading = true
51 51
52 this.videoService.loadCompleteDescription(this.video.descriptionPath) 52 this.videoService.loadCompleteDescription(this.video.descriptionPath)
53 .subscribe( 53 .subscribe({
54 description => { 54 next: description => {
55 this.completeDescriptionShown = true 55 this.completeDescriptionShown = true
56 this.descriptionLoading = false 56 this.descriptionLoading = false
57 57
@@ -61,11 +61,11 @@ export class VideoDescriptionComponent implements OnChanges {
61 this.updateVideoDescription(this.completeVideoDescription) 61 this.updateVideoDescription(this.completeVideoDescription)
62 }, 62 },
63 63
64 error => { 64 error: err => {
65 this.descriptionLoading = false 65 this.descriptionLoading = false
66 this.notifier.error(error.message) 66 this.notifier.error(err.message)
67 } 67 }
68 ) 68 })
69 } 69 }
70 70
71 onTimestampClicked (timestamp: number) { 71 onTimestampClicked (timestamp: number) {
diff --git a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts
index 8b3ed4964..f0f7966b1 100644
--- a/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/playlist/video-watch-playlist.component.ts
@@ -1,4 +1,3 @@
1
2import { Component, EventEmitter, Input, Output } from '@angular/core' 1import { Component, EventEmitter, Input, Output } from '@angular/core'
3import { Router } from '@angular/router' 2import { Router } from '@angular/router'
4import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core' 3import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core'
@@ -196,12 +195,14 @@ export class VideoWatchPlaylistComponent {
196 autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist 195 autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
197 } 196 }
198 197
199 this.userService.updateMyProfile(details).subscribe( 198 this.userService.updateMyProfile(details)
200 () => { 199 .subscribe({
201 this.auth.refreshUserInformation() 200 next: () => {
202 }, 201 this.auth.refreshUserInformation()
203 err => this.notifier.error(err.message) 202 },
204 ) 203
204 error: err => this.notifier.error(err.message)
205 })
205 } 206 }
206 } 207 }
207 208
diff --git a/client/src/app/+videos/+video-watch/shared/recommendations/recommended-videos.component.ts b/client/src/app/+videos/+video-watch/shared/recommendations/recommended-videos.component.ts
index 89b9c01b6..7f3703c08 100644
--- a/client/src/app/+videos/+video-watch/shared/recommendations/recommended-videos.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/recommendations/recommended-videos.component.ts
@@ -84,12 +84,14 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
84 autoPlayNextVideo: this.autoPlayNextVideo 84 autoPlayNextVideo: this.autoPlayNextVideo
85 } 85 }
86 86
87 this.userService.updateMyProfile(details).subscribe( 87 this.userService.updateMyProfile(details)
88 () => { 88 .subscribe({
89 this.authService.refreshUserInformation() 89 next: () => {
90 }, 90 this.authService.refreshUserInformation()
91 err => this.notifier.error(err.message) 91 },
92 ) 92
93 error: err => this.notifier.error(err.message)
94 })
93 } 95 }
94 } 96 }
95} 97}
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 ccb9c5e71..85100b653 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -238,8 +238,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
238 ) 238 )
239 239
240 forkJoin([ videoObs, this.videoCaptionService.listCaptions(videoId)]) 240 forkJoin([ videoObs, this.videoCaptionService.listCaptions(videoId)])
241 .subscribe( 241 .subscribe({
242 ([ video, captionsResult ]) => { 242 next: ([ video, captionsResult ]) => {
243 const queryParams = this.route.snapshot.queryParams 243 const queryParams = this.route.snapshot.queryParams
244 244
245 const urlOptions = { 245 const urlOptions = {
@@ -260,23 +260,23 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
260 .catch(err => this.handleGlobalError(err)) 260 .catch(err => this.handleGlobalError(err))
261 }, 261 },
262 262
263 err => this.handleRequestError(err) 263 error: err => this.handleRequestError(err)
264 ) 264 })
265 } 265 }
266 266
267 private loadPlaylist (playlistId: string) { 267 private loadPlaylist (playlistId: string) {
268 if (this.isSameElement(this.playlist, playlistId)) return 268 if (this.isSameElement(this.playlist, playlistId)) return
269 269
270 this.playlistService.getVideoPlaylist(playlistId) 270 this.playlistService.getVideoPlaylist(playlistId)
271 .subscribe( 271 .subscribe({
272 playlist => { 272 next: playlist => {
273 this.playlist = playlist 273 this.playlist = playlist
274 274
275 this.videoWatchPlaylist.loadPlaylistElements(playlist, !this.playlistPosition, this.playlistPosition) 275 this.videoWatchPlaylist.loadPlaylistElements(playlist, !this.playlistPosition, this.playlistPosition)
276 }, 276 },
277 277
278 err => this.handleRequestError(err) 278 error: err => this.handleRequestError(err)
279 ) 279 })
280 } 280 }
281 281
282 private isSameElement (element: VideoDetails | VideoPlaylist, newId: string) { 282 private isSameElement (element: VideoDetails | VideoPlaylist, newId: string) {
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.ts b/client/src/app/+videos/video-list/overview/video-overview.component.ts
index 14532ca1e..b32e8f381 100644
--- a/client/src/app/+videos/video-list/overview/video-overview.component.ts
+++ b/client/src/app/+videos/video-list/overview/video-overview.component.ts
@@ -68,8 +68,8 @@ export class VideoOverviewComponent implements OnInit {
68 this.isLoading = true 68 this.isLoading = true
69 69
70 this.overviewService.getVideosOverview(this.currentPage) 70 this.overviewService.getVideosOverview(this.currentPage)
71 .subscribe( 71 .subscribe({
72 overview => { 72 next: overview => {
73 this.isLoading = false 73 this.isLoading = false
74 74
75 if (overview.tags.length === 0 && overview.channels.length === 0 && overview.categories.length === 0) { 75 if (overview.tags.length === 0 && overview.channels.length === 0 && overview.categories.length === 0) {
@@ -85,10 +85,10 @@ export class VideoOverviewComponent implements OnInit {
85 this.overviews.push(overview) 85 this.overviews.push(overview)
86 }, 86 },
87 87
88 err => { 88 error: err => {
89 this.notifier.error(err.message) 89 this.notifier.error(err.message)
90 this.isLoading = false 90 this.isLoading = false
91 } 91 }
92 ) 92 })
93 } 93 }
94} 94}
diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
index 6aabb93a5..a1498e797 100644
--- a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
+++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
@@ -56,8 +56,8 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement
56 56
57 this.authService.userInformationLoaded 57 this.authService.userInformationLoaded
58 .pipe(switchMap(() => this.scopedTokensService.getScopedTokens())) 58 .pipe(switchMap(() => this.scopedTokensService.getScopedTokens()))
59 .subscribe( 59 .subscribe({
60 tokens => { 60 next: tokens => {
61 const feeds = this.videoService.getVideoSubscriptionFeedUrls(user.account.id, tokens.feedToken) 61 const feeds = this.videoService.getVideoSubscriptionFeedUrls(user.account.id, tokens.feedToken)
62 feedUrl = feedUrl + feeds.find(f => f.format === FeedFormat.RSS).url 62 feedUrl = feedUrl + feeds.find(f => f.format === FeedFormat.RSS).url
63 63
@@ -74,10 +74,10 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement
74 }) 74 })
75 }, 75 },
76 76
77 err => { 77 error: err => {
78 this.notifier.error(err.message) 78 this.notifier.error(err.message)
79 } 79 }
80 ) 80 })
81 } 81 }
82 82
83 ngOnDestroy () { 83 ngOnDestroy () {
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index ef5a3808e..5da66c981 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -80,8 +80,8 @@ export class AuthService {
80 // Fetch the client_id/client_secret 80 // Fetch the client_id/client_secret
81 this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL) 81 this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL)
82 .pipe(catchError(res => this.restExtractor.handleError(res))) 82 .pipe(catchError(res => this.restExtractor.handleError(res)))
83 .subscribe( 83 .subscribe({
84 res => { 84 next: res => {
85 this.clientId = res.client_id 85 this.clientId = res.client_id
86 this.clientSecret = res.client_secret 86 this.clientSecret = res.client_secret
87 87
@@ -91,18 +91,18 @@ export class AuthService {
91 console.log('Client credentials loaded.') 91 console.log('Client credentials loaded.')
92 }, 92 },
93 93
94 error => { 94 error: err => {
95 let errorMessage = error.message 95 let errorMessage = err.message
96 96
97 if (error.status === HttpStatusCode.FORBIDDEN_403) { 97 if (err.status === HttpStatusCode.FORBIDDEN_403) {
98 errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${error.text}. 98 errorMessage = $localize`Cannot retrieve OAuth Client credentials: ${err.text}.
99Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.` 99Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.`
100 } 100 }
101 101
102 // We put a bigger timeout: this is an important message 102 // We put a bigger timeout: this is an important message
103 this.notifier.error(errorMessage, $localize`Error`, 7000) 103 this.notifier.error(errorMessage, $localize`Error`, 7000)
104 } 104 }
105 ) 105 })
106 } 106 }
107 107
108 getRefreshToken () { 108 getRefreshToken () {
@@ -168,15 +168,15 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
168 const headers = new HttpHeaders().set('Authorization', authHeaderValue) 168 const headers = new HttpHeaders().set('Authorization', authHeaderValue)
169 169
170 this.http.post<{ redirectUrl?: string }>(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers }) 170 this.http.post<{ redirectUrl?: string }>(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers })
171 .subscribe( 171 .subscribe({
172 res => { 172 next: res => {
173 if (res.redirectUrl) { 173 if (res.redirectUrl) {
174 window.location.href = res.redirectUrl 174 window.location.href = res.redirectUrl
175 } 175 }
176 }, 176 },
177 177
178 err => console.error(err) 178 error: err => console.error(err)
179 ) 179 })
180 180
181 this.user = null 181 this.user = null
182 182
@@ -215,9 +215,9 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
215 this.logout() 215 this.logout()
216 this.router.navigate([ '/login' ]) 216 this.router.navigate([ '/login' ])
217 217
218 return observableThrowError({ 218 return observableThrowError(() => ({
219 error: $localize`You need to reconnect.` 219 error: $localize`You need to reconnect.`
220 }) 220 }))
221 }), 221 }),
222 share() 222 share()
223 ) 223 )
@@ -234,14 +234,14 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
234 } 234 }
235 235
236 this.mergeUserInformation(obj) 236 this.mergeUserInformation(obj)
237 .subscribe( 237 .subscribe({
238 res => { 238 next: res => {
239 this.user.patch(res) 239 this.user.patch(res)
240 this.user.save() 240 this.user.save()
241 241
242 this.userInformationLoaded.next(true) 242 this.userInformationLoaded.next(true)
243 } 243 }
244 ) 244 })
245 } 245 }
246 246
247 private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> { 247 private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
diff --git a/client/src/app/core/confirm/confirm.service.ts b/client/src/app/core/confirm/confirm.service.ts
index 6e042c16b..338b8762c 100644
--- a/client/src/app/core/confirm/confirm.service.ts
+++ b/client/src/app/core/confirm/confirm.service.ts
@@ -1,6 +1,5 @@
1import { first } from 'rxjs/operators' 1import { firstValueFrom, Subject } from 'rxjs'
2import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
3import { Subject } from 'rxjs'
4 3
5type ConfirmOptions = { 4type ConfirmOptions = {
6 title: string 5 title: string
@@ -18,16 +17,12 @@ export class ConfirmService {
18 confirm (message: string, title = '', confirmButtonText?: string) { 17 confirm (message: string, title = '', confirmButtonText?: string) {
19 this.showConfirm.next({ title, message, confirmButtonText }) 18 this.showConfirm.next({ title, message, confirmButtonText })
20 19
21 return this.confirmResponse.asObservable() 20 return firstValueFrom(this.confirmResponse.asObservable())
22 .pipe(first())
23 .toPromise()
24 } 21 }
25 22
26 confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) { 23 confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) {
27 this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText }) 24 this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText })
28 25
29 return this.confirmResponse.asObservable() 26 return firstValueFrom(this.confirmResponse.asObservable())
30 .pipe(first())
31 .toPromise()
32 } 27 }
33} 28}
diff --git a/client/src/app/core/plugins/plugin.service.ts b/client/src/app/core/plugins/plugin.service.ts
index 16108e17a..774c03964 100644
--- a/client/src/app/core/plugins/plugin.service.ts
+++ b/client/src/app/core/plugins/plugin.service.ts
@@ -1,4 +1,4 @@
1import { Observable, of } from 'rxjs' 1import { firstValueFrom, Observable, of } from 'rxjs'
2import { catchError, map, shareReplay } from 'rxjs/operators' 2import { catchError, map, shareReplay } from 'rxjs/operators'
3import { HttpClient } from '@angular/common/http' 3import { HttpClient } from '@angular/common/http'
4import { Inject, Injectable, LOCALE_ID, NgZone } from '@angular/core' 4import { Inject, Injectable, LOCALE_ID, NgZone } from '@angular/core'
@@ -164,18 +164,20 @@ export class PluginService implements ClientHook {
164 getSettings: () => { 164 getSettings: () => {
165 const path = PluginService.BASE_PLUGIN_API_URL + '/' + npmName + '/public-settings' 165 const path = PluginService.BASE_PLUGIN_API_URL + '/' + npmName + '/public-settings'
166 166
167 return this.authHttp.get<PublicServerSetting>(path) 167 const obs = this.authHttp.get<PublicServerSetting>(path)
168 .pipe( 168 .pipe(
169 map(p => p.publicSettings), 169 map(p => p.publicSettings),
170 catchError(res => this.restExtractor.handleError(res)) 170 catchError(res => this.restExtractor.handleError(res))
171 ) 171 )
172 .toPromise() 172
173 return firstValueFrom(obs)
173 }, 174 },
174 175
175 getServerConfig: () => { 176 getServerConfig: () => {
176 return this.server.getConfig() 177 const obs = this.server.getConfig()
177 .pipe(catchError(res => this.restExtractor.handleError(res))) 178 .pipe(catchError(res => this.restExtractor.handleError(res)))
178 .toPromise() 179
180 return firstValueFrom(obs)
179 }, 181 },
180 182
181 isLoggedIn: () => { 183 isLoggedIn: () => {
@@ -216,10 +218,11 @@ export class PluginService implements ClientHook {
216 }, 218 },
217 219
218 translate: (value: string) => { 220 translate: (value: string) => {
219 return this.translationsObservable 221 const obs = this.translationsObservable
220 .pipe(map(allTranslations => allTranslations[npmName])) 222 .pipe(map(allTranslations => allTranslations[npmName]))
221 .pipe(map(translations => peertubeTranslate(value, translations))) 223 .pipe(map(translations => peertubeTranslate(value, translations)))
222 .toPromise() 224
225 return firstValueFrom(obs)
223 } 226 }
224 } 227 }
225 } 228 }
diff --git a/client/src/app/core/rest/rest-extractor.service.ts b/client/src/app/core/rest/rest-extractor.service.ts
index 2a926e68f..29a56ba39 100644
--- a/client/src/app/core/rest/rest-extractor.service.ts
+++ b/client/src/app/core/rest/rest-extractor.service.ts
@@ -89,7 +89,7 @@ export class RestExtractor {
89 errorObj.body = err.error 89 errorObj.body = err.error
90 } 90 }
91 91
92 return observableThrowError(errorObj) 92 return observableThrowError(() => errorObj)
93 } 93 }
94 94
95 redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) { 95 redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) {
@@ -98,6 +98,6 @@ export class RestExtractor {
98 this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true }) 98 this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true })
99 } 99 }
100 100
101 return observableThrowError(obj) 101 return observableThrowError(() => obj)
102 } 102 }
103} 103}
diff --git a/client/src/app/menu/notification.component.ts b/client/src/app/menu/notification.component.ts
index b7d9e9abb..ac9c79991 100644
--- a/client/src/app/menu/notification.component.ts
+++ b/client/src/app/menu/notification.component.ts
@@ -36,14 +36,14 @@ export class NotificationComponent implements OnInit, OnDestroy {
36 36
37 ngOnInit () { 37 ngOnInit () {
38 this.userNotificationService.countUnreadNotifications() 38 this.userNotificationService.countUnreadNotifications()
39 .subscribe( 39 .subscribe({
40 result => { 40 next: result => {
41 this.unreadNotifications = Math.min(result, 99) // Limit number to 99 41 this.unreadNotifications = Math.min(result, 99) // Limit number to 99
42 this.subscribeToNotifications() 42 this.subscribeToNotifications()
43 }, 43 },
44 44
45 err => this.notifier.error(err.message) 45 error: err => this.notifier.error(err.message)
46 ) 46 })
47 47
48 this.routeSub = this.router.events 48 this.routeSub = this.router.events
49 .pipe(filter(event => event instanceof NavigationEnd)) 49 .pipe(filter(event => event instanceof NavigationEnd))
diff --git a/client/src/app/modal/instance-config-warning-modal.component.ts b/client/src/app/modal/instance-config-warning-modal.component.ts
index 8bf7672be..e40958976 100644
--- a/client/src/app/modal/instance-config-warning-modal.component.ts
+++ b/client/src/app/modal/instance-config-warning-modal.component.ts
@@ -50,10 +50,10 @@ export class InstanceConfigWarningModalComponent {
50 peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_INSTANCE_CONFIG_WARNING_MODAL, 'true') 50 peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_INSTANCE_CONFIG_WARNING_MODAL, 'true')
51 51
52 this.userService.updateMyProfile({ noInstanceConfigWarningModal: true }) 52 this.userService.updateMyProfile({ noInstanceConfigWarningModal: true })
53 .subscribe( 53 .subscribe({
54 () => console.log('We will not open the instance config warning modal again.'), 54 next: () => console.log('We will not open the instance config warning modal again.'),
55 55
56 err => this.notifier.error(err.message) 56 error: err => this.notifier.error(err.message)
57 ) 57 })
58 } 58 }
59} 59}
diff --git a/client/src/app/modal/quick-settings-modal.component.ts b/client/src/app/modal/quick-settings-modal.component.ts
index 99859a1a5..7a53179cb 100644
--- a/client/src/app/modal/quick-settings-modal.component.ts
+++ b/client/src/app/modal/quick-settings-modal.component.ts
@@ -31,20 +31,20 @@ export class QuickSettingsModalComponent extends FormReactive implements OnInit
31 ngOnInit () { 31 ngOnInit () {
32 this.user = this.userService.getAnonymousUser() 32 this.user = this.userService.getAnonymousUser()
33 this.localStorageService.watch() 33 this.localStorageService.watch()
34 .subscribe( 34 .subscribe({
35 () => this.user = this.userService.getAnonymousUser() 35 next: () => this.user = this.userService.getAnonymousUser()
36 ) 36 })
37 37
38 this.userInformationLoaded.next(true) 38 this.userInformationLoaded.next(true)
39 39
40 this.authService.loginChangedSource 40 this.authService.loginChangedSource
41 .pipe(filter(status => status !== AuthStatus.LoggedIn)) 41 .pipe(filter(status => status !== AuthStatus.LoggedIn))
42 .subscribe( 42 .subscribe({
43 () => { 43 next: () => {
44 this.user = this.userService.getAnonymousUser() 44 this.user = this.userService.getAnonymousUser()
45 this.userInformationLoaded.next(true) 45 this.userInformationLoaded.next(true)
46 } 46 }
47 ) 47 })
48 } 48 }
49 49
50 isUserLoggedIn () { 50 isUserLoggedIn () {
diff --git a/client/src/app/modal/welcome-modal.component.ts b/client/src/app/modal/welcome-modal.component.ts
index 72ae20b43..06fe4cba5 100644
--- a/client/src/app/modal/welcome-modal.component.ts
+++ b/client/src/app/modal/welcome-modal.component.ts
@@ -37,10 +37,10 @@ export class WelcomeModalComponent {
37 peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL, 'true') 37 peertubeLocalStorage.setItem(this.LOCAL_STORAGE_KEYS.NO_WELCOME_MODAL, 'true')
38 38
39 this.userService.updateMyProfile({ noWelcomeModal: true }) 39 this.userService.updateMyProfile({ noWelcomeModal: true })
40 .subscribe( 40 .subscribe({
41 () => console.log('We will not open the welcome modal again.'), 41 next: () => console.log('We will not open the welcome modal again.'),
42 42
43 err => this.notifier.error(err.message) 43 error: err => this.notifier.error(err.message)
44 ) 44 })
45 } 45 }
46} 46}
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
index a7932ebab..e3bf9e1fb 100644
--- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
+++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts
@@ -145,23 +145,24 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
145 const res = await this.confirmService.confirm($localize`Do you really want to delete this abuse report?`, $localize`Delete`) 145 const res = await this.confirmService.confirm($localize`Do you really want to delete this abuse report?`, $localize`Delete`)
146 if (res === false) return 146 if (res === false) return
147 147
148 this.abuseService.removeAbuse(abuse).subscribe( 148 this.abuseService.removeAbuse(abuse)
149 () => { 149 .subscribe({
150 this.notifier.success($localize`Abuse deleted.`) 150 next: () => {
151 this.reloadData() 151 this.notifier.success($localize`Abuse deleted.`)
152 }, 152 this.reloadData()
153 },
153 154
154 err => this.notifier.error(err.message) 155 error: err => this.notifier.error(err.message)
155 ) 156 })
156 } 157 }
157 158
158 updateAbuseState (abuse: AdminAbuse, state: AbuseState) { 159 updateAbuseState (abuse: AdminAbuse, state: AbuseState) {
159 this.abuseService.updateAbuse(abuse, { state }) 160 this.abuseService.updateAbuse(abuse, { state })
160 .subscribe( 161 .subscribe({
161 () => this.reloadData(), 162 next: () => this.reloadData(),
162 163
163 err => this.notifier.error(err.message) 164 error: err => this.notifier.error(err.message)
164 ) 165 })
165 } 166 }
166 167
167 onCountMessagesUpdated (event: { abuseId: number, countMessages: number }) { 168 onCountMessagesUpdated (event: { abuseId: number, countMessages: number }) {
@@ -198,55 +199,55 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
198 ? this.abuseService.getAdminAbuses(options) 199 ? this.abuseService.getAdminAbuses(options)
199 : this.abuseService.getUserAbuses(options) 200 : this.abuseService.getUserAbuses(options)
200 201
201 return observable.subscribe( 202 return observable.subscribe({
202 async resultList => { 203 next: async resultList => {
203 this.totalRecords = resultList.total 204 this.totalRecords = resultList.total
204 205
205 this.abuses = [] 206 this.abuses = []
206 207
207 for (const a of resultList.data) { 208 for (const a of resultList.data) {
208 const abuse = a as ProcessedAbuse 209 const abuse = a as ProcessedAbuse
209 210
210 abuse.reasonHtml = await this.toHtml(abuse.reason) 211 abuse.reasonHtml = await this.toHtml(abuse.reason)
211 212
212 if (abuse.moderationComment) { 213 if (abuse.moderationComment) {
213 abuse.moderationCommentHtml = await this.toHtml(abuse.moderationComment) 214 abuse.moderationCommentHtml = await this.toHtml(abuse.moderationComment)
214 } 215 }
215 216
216 if (abuse.video) { 217 if (abuse.video) {
217 abuse.embedHtml = this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)) 218 abuse.embedHtml = this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse))
218 219
219 if (abuse.video.channel?.ownerAccount) { 220 if (abuse.video.channel?.ownerAccount) {
220 abuse.video.channel.ownerAccount = new Account(abuse.video.channel.ownerAccount) 221 abuse.video.channel.ownerAccount = new Account(abuse.video.channel.ownerAccount)
221 }
222 } 222 }
223 }
223 224
224 if (abuse.comment) { 225 if (abuse.comment) {
225 if (abuse.comment.deleted) { 226 if (abuse.comment.deleted) {
226 abuse.truncatedCommentHtml = abuse.commentHtml = $localize`Deleted comment` 227 abuse.truncatedCommentHtml = abuse.commentHtml = $localize`Deleted comment`
227 } else { 228 } else {
228 const truncated = truncate(abuse.comment.text, { length: 100 }) 229 const truncated = truncate(abuse.comment.text, { length: 100 })
229 abuse.truncatedCommentHtml = await this.markdownRenderer.textMarkdownToHTML(truncated, true) 230 abuse.truncatedCommentHtml = await this.markdownRenderer.textMarkdownToHTML(truncated, true)
230 abuse.commentHtml = await this.markdownRenderer.textMarkdownToHTML(abuse.comment.text, true) 231 abuse.commentHtml = await this.markdownRenderer.textMarkdownToHTML(abuse.comment.text, true)
231 }
232 } 232 }
233 }
233 234
234 if (abuse.reporterAccount) { 235 if (abuse.reporterAccount) {
235 abuse.reporterAccount = new Account(abuse.reporterAccount) 236 abuse.reporterAccount = new Account(abuse.reporterAccount)
236 } 237 }
237 238
238 if (abuse.flaggedAccount) { 239 if (abuse.flaggedAccount) {
239 abuse.flaggedAccount = new Account(abuse.flaggedAccount) 240 abuse.flaggedAccount = new Account(abuse.flaggedAccount)
240 } 241 }
241 242
242 if (abuse.updatedAt === abuse.createdAt) delete abuse.updatedAt 243 if (abuse.updatedAt === abuse.createdAt) delete abuse.updatedAt
243 244
244 this.abuses.push(abuse) 245 this.abuses.push(abuse)
245 } 246 }
246 }, 247 },
247 248
248 err => this.notifier.error(err.message) 249 error: err => this.notifier.error(err.message)
249 ) 250 })
250 } 251 }
251 252
252 private buildInternalActions (): DropdownAction<ProcessedAbuse>[] { 253 private buildInternalActions (): DropdownAction<ProcessedAbuse>[] {
@@ -351,15 +352,15 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
351 isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted, 352 isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted,
352 handler: abuse => { 353 handler: abuse => {
353 this.videoBlocklistService.blockVideo(abuse.video.id, undefined, abuse.video.channel.isLocal) 354 this.videoBlocklistService.blockVideo(abuse.video.id, undefined, abuse.video.channel.isLocal)
354 .subscribe( 355 .subscribe({
355 () => { 356 next: () => {
356 this.notifier.success($localize`Video blocked.`) 357 this.notifier.success($localize`Video blocked.`)
357 358
358 this.updateAbuseState(abuse, AbuseState.ACCEPTED) 359 this.updateAbuseState(abuse, AbuseState.ACCEPTED)
359 }, 360 },
360 361
361 err => this.notifier.error(err.message) 362 error: err => this.notifier.error(err.message)
362 ) 363 })
363 } 364 }
364 }, 365 },
365 { 366 {
@@ -367,15 +368,15 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
367 isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted, 368 isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted,
368 handler: abuse => { 369 handler: abuse => {
369 this.videoBlocklistService.unblockVideo(abuse.video.id) 370 this.videoBlocklistService.unblockVideo(abuse.video.id)
370 .subscribe( 371 .subscribe({
371 () => { 372 next: () => {
372 this.notifier.success($localize`Video unblocked.`) 373 this.notifier.success($localize`Video unblocked.`)
373 374
374 this.updateAbuseState(abuse, AbuseState.ACCEPTED) 375 this.updateAbuseState(abuse, AbuseState.ACCEPTED)
375 }, 376 },
376 377
377 err => this.notifier.error(err.message) 378 error: err => this.notifier.error(err.message)
378 ) 379 })
379 } 380 }
380 }, 381 },
381 { 382 {
@@ -389,15 +390,15 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
389 if (res === false) return 390 if (res === false) return
390 391
391 this.videoService.removeVideo(abuse.video.id) 392 this.videoService.removeVideo(abuse.video.id)
392 .subscribe( 393 .subscribe({
393 () => { 394 next: () => {
394 this.notifier.success($localize`Video deleted.`) 395 this.notifier.success($localize`Video deleted.`)
395 396
396 this.updateAbuseState(abuse, AbuseState.ACCEPTED) 397 this.updateAbuseState(abuse, AbuseState.ACCEPTED)
397 }, 398 },
398 399
399 err => this.notifier.error(err.message) 400 error: err => this.notifier.error(err.message)
400 ) 401 })
401 } 402 }
402 } 403 }
403 ] 404 ]
@@ -424,15 +425,15 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
424 if (res === false) return 425 if (res === false) return
425 426
426 this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id) 427 this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id)
427 .subscribe( 428 .subscribe({
428 () => { 429 next: () => {
429 this.notifier.success($localize`Comment deleted.`) 430 this.notifier.success($localize`Comment deleted.`)
430 431
431 this.updateAbuseState(abuse, AbuseState.ACCEPTED) 432 this.updateAbuseState(abuse, AbuseState.ACCEPTED)
432 }, 433 },
433 434
434 err => this.notifier.error(err.message) 435 error: err => this.notifier.error(err.message)
435 ) 436 })
436 } 437 }
437 } 438 }
438 ] 439 ]
@@ -440,25 +441,25 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
440 441
441 private muteAccountHelper (account: Account) { 442 private muteAccountHelper (account: Account) {
442 this.blocklistService.blockAccountByInstance(account) 443 this.blocklistService.blockAccountByInstance(account)
443 .subscribe( 444 .subscribe({
444 () => { 445 next: () => {
445 this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`) 446 this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`)
446 account.mutedByInstance = true 447 account.mutedByInstance = true
447 }, 448 },
448 449
449 err => this.notifier.error(err.message) 450 error: err => this.notifier.error(err.message)
450 ) 451 })
451 } 452 }
452 453
453 private muteServerHelper (host: string) { 454 private muteServerHelper (host: string) {
454 this.blocklistService.blockServerByInstance(host) 455 this.blocklistService.blockServerByInstance(host)
455 .subscribe( 456 .subscribe({
456 () => { 457 next: () => {
457 this.notifier.success($localize`Server ${host} muted by the instance.`) 458 this.notifier.success($localize`Server ${host} muted by the instance.`)
458 }, 459 },
459 460
460 err => this.notifier.error(err.message) 461 error: err => this.notifier.error(err.message)
461 ) 462 })
462 } 463 }
463 464
464 private toHtml (text: string) { 465 private toHtml (text: string) {
diff --git a/client/src/app/shared/shared-abuse-list/abuse-message-modal.component.ts b/client/src/app/shared/shared-abuse-list/abuse-message-modal.component.ts
index 9abb4c094..6c8dc6d35 100644
--- a/client/src/app/shared/shared-abuse-list/abuse-message-modal.component.ts
+++ b/client/src/app/shared/shared-abuse-list/abuse-message-modal.component.ts
@@ -61,8 +61,8 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
61 this.sendingMessage = true 61 this.sendingMessage = true
62 62
63 this.abuseService.addAbuseMessage(this.abuse, this.form.value['message']) 63 this.abuseService.addAbuseMessage(this.abuse, this.form.value['message'])
64 .subscribe( 64 .subscribe({
65 () => { 65 next: () => {
66 this.form.reset() 66 this.form.reset()
67 this.sendingMessage = false 67 this.sendingMessage = false
68 this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length + 1 }) 68 this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length + 1 })
@@ -70,25 +70,25 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
70 this.loadMessages() 70 this.loadMessages()
71 }, 71 },
72 72
73 err => { 73 error: err => {
74 this.sendingMessage = false 74 this.sendingMessage = false
75 console.error(err) 75 console.error(err)
76 this.notifier.error('Sorry but you cannot send this message. Please retry later') 76 this.notifier.error('Sorry but you cannot send this message. Please retry later')
77 } 77 }
78 ) 78 })
79 } 79 }
80 80
81 deleteMessage (abuseMessage: AbuseMessage) { 81 deleteMessage (abuseMessage: AbuseMessage) {
82 this.abuseService.deleteAbuseMessage(this.abuse, abuseMessage) 82 this.abuseService.deleteAbuseMessage(this.abuse, abuseMessage)
83 .subscribe( 83 .subscribe({
84 () => { 84 next: () => {
85 this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length - 1 }) 85 this.countMessagesUpdated.emit({ abuseId: this.abuse.id, countMessages: this.abuseMessages.length - 1 })
86 86
87 this.abuseMessages = this.abuseMessages.filter(m => m.id !== abuseMessage.id) 87 this.abuseMessages = this.abuseMessages.filter(m => m.id !== abuseMessage.id)
88 }, 88 },
89 89
90 err => this.notifier.error(err.message) 90 error: err => this.notifier.error(err.message)
91 ) 91 })
92 } 92 }
93 93
94 isMessageByMe (abuseMessage: AbuseMessage) { 94 isMessageByMe (abuseMessage: AbuseMessage) {
@@ -105,8 +105,8 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
105 105
106 private loadMessages () { 106 private loadMessages () {
107 this.abuseService.listAbuseMessages(this.abuse) 107 this.abuseService.listAbuseMessages(this.abuse)
108 .subscribe( 108 .subscribe({
109 async res => { 109 next: async res => {
110 this.abuseMessages = [] 110 this.abuseMessages = []
111 111
112 for (const m of res.data) { 112 for (const m of res.data) {
@@ -124,8 +124,8 @@ export class AbuseMessageModalComponent extends FormReactive implements OnInit {
124 }) 124 })
125 }, 125 },
126 126
127 err => this.notifier.error(err.message) 127 error: err => this.notifier.error(err.message)
128 ) 128 })
129 } 129 }
130 130
131} 131}
diff --git a/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts b/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
index 876aeea8a..06f1555ea 100644
--- a/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
+++ b/client/src/app/shared/shared-abuse-list/moderation-comment-modal.component.ts
@@ -53,16 +53,16 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
53 const moderationComment: string = this.form.value[ 'moderationComment' ] 53 const moderationComment: string = this.form.value[ 'moderationComment' ]
54 54
55 this.abuseService.updateAbuse(this.abuseToComment, { moderationComment }) 55 this.abuseService.updateAbuse(this.abuseToComment, { moderationComment })
56 .subscribe( 56 .subscribe({
57 () => { 57 next: () => {
58 this.notifier.success($localize`Comment updated.`) 58 this.notifier.success($localize`Comment updated.`)
59 59
60 this.commentUpdated.emit(moderationComment) 60 this.commentUpdated.emit(moderationComment)
61 this.hide() 61 this.hide()
62 }, 62 },
63 63
64 err => this.notifier.error(err.message) 64 error: err => this.notifier.error(err.message)
65 ) 65 })
66 } 66 }
67 67
68} 68}
diff --git a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
index c9d33980e..63f2f76f5 100644
--- a/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
+++ b/client/src/app/shared/shared-custom-markup/custom-markup.service.ts
@@ -1,4 +1,4 @@
1import { first } from 'rxjs/operators' 1import { firstValueFrom } from 'rxjs'
2import { ComponentRef, Injectable } from '@angular/core' 2import { ComponentRef, Injectable } from '@angular/core'
3import { MarkdownService } from '@app/core' 3import { MarkdownService } from '@app/core'
4import { 4import {
@@ -85,7 +85,7 @@ export class CustomMarkupService {
85 const component = this.execAngularBuilder(selector, e) 85 const component = this.execAngularBuilder(selector, e)
86 86
87 if (component.instance.loaded) { 87 if (component.instance.loaded) {
88 const p = component.instance.loaded.pipe(first()).toPromise() 88 const p = firstValueFrom(component.instance.loaded)
89 loadedPromises.push(p) 89 loadedPromises.push(p)
90 } 90 }
91 91
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
index 5bb045a82..8c1357d7a 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/channel-miniature-markup.component.ts
@@ -44,14 +44,14 @@ export class ChannelMiniatureMarkupComponent implements CustomMarkupComponent, O
44 tap(html => this.descriptionHTML = html), 44 tap(html => this.descriptionHTML = html),
45 switchMap(() => this.loadVideosObservable()), 45 switchMap(() => this.loadVideosObservable()),
46 finalize(() => this.loaded.emit(true)) 46 finalize(() => this.loaded.emit(true))
47 ).subscribe( 47 ).subscribe({
48 ({ total, data }) => { 48 next: ({ total, data }) => {
49 this.totalVideos = total 49 this.totalVideos = total
50 this.video = data[0] 50 this.video = data[0]
51 }, 51 },
52 52
53 err => this.notifier.error($localize`Error in channel miniature component: ${err.message}`) 53 error: err => this.notifier.error($localize`Error in channel miniature component: ${err.message}`)
54 ) 54 })
55 } 55 }
56 56
57 getVideoChannelLink () { 57 getVideoChannelLink () {
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/playlist-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/playlist-miniature-markup.component.ts
index 5a5c34867..07fa6fd2d 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/playlist-miniature-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/playlist-miniature-markup.component.ts
@@ -41,10 +41,10 @@ export class PlaylistMiniatureMarkupComponent implements CustomMarkupComponent,
41 ngOnInit () { 41 ngOnInit () {
42 this.findInBulkService.getPlaylist(this.uuid) 42 this.findInBulkService.getPlaylist(this.uuid)
43 .pipe(finalize(() => this.loaded.emit(true))) 43 .pipe(finalize(() => this.loaded.emit(true)))
44 .subscribe( 44 .subscribe({
45 playlist => this.playlist = playlist, 45 next: playlist => this.playlist = playlist,
46 46
47 err => this.notifier.error($localize`Error in playlist miniature component: ${err.message}`) 47 error: err => this.notifier.error($localize`Error in playlist miniature component: ${err.message}`)
48 ) 48 })
49 } 49 }
50} 50}
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
index 84c936ee7..56b43d85e 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
@@ -53,10 +53,10 @@ export class VideoMiniatureMarkupComponent implements CustomMarkupComponent, OnI
53 53
54 this.findInBulk.getVideo(this.uuid) 54 this.findInBulk.getVideo(this.uuid)
55 .pipe(finalize(() => this.loaded.emit(true))) 55 .pipe(finalize(() => this.loaded.emit(true)))
56 .subscribe( 56 .subscribe({
57 video => this.video = video, 57 next: video => this.video = video,
58 58
59 err => this.notifier.error($localize`Error in video miniature component: ${err.message}`) 59 error: err => this.notifier.error($localize`Error in video miniature component: ${err.message}`)
60 ) 60 })
61 } 61 }
62} 62}
diff --git a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts
index 6473e9ba0..856e43681 100644
--- a/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts
+++ b/client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts
@@ -71,11 +71,11 @@ export class VideosListMarkupComponent implements CustomMarkupComponent, OnInit
71 71
72 return this.getVideosObservable() 72 return this.getVideosObservable()
73 .pipe(finalize(() => this.loaded.emit(true))) 73 .pipe(finalize(() => this.loaded.emit(true)))
74 .subscribe( 74 .subscribe({
75 ({ data }) => this.videos = data, 75 next: ({ data }) => this.videos = data,
76 76
77 err => this.notifier.error($localize`Error in videos list component: ${err.message}`) 77 error: err => this.notifier.error($localize`Error in videos list component: ${err.message}`)
78 ) 78 })
79 } 79 }
80 80
81 getVideosObservable () { 81 getVideosObservable () {
diff --git a/client/src/app/shared/shared-instance/instance-about-accordion.component.ts b/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
index 8e7bf2021..855c06aa1 100644
--- a/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
+++ b/client/src/app/shared/shared-instance/instance-about-accordion.component.ts
@@ -36,8 +36,8 @@ export class InstanceAboutAccordionComponent implements OnInit {
36 36
37 ngOnInit (): void { 37 ngOnInit (): void {
38 this.instanceService.getAbout() 38 this.instanceService.getAbout()
39 .subscribe( 39 .subscribe({
40 async about => { 40 next: async about => {
41 this.about = about 41 this.about = about
42 42
43 this.aboutHtml = await this.instanceService.buildHtml(about) 43 this.aboutHtml = await this.instanceService.buildHtml(about)
@@ -45,8 +45,8 @@ export class InstanceAboutAccordionComponent implements OnInit {
45 this.init.emit(this) 45 this.init.emit(this)
46 }, 46 },
47 47
48 err => this.notifier.error(err.message) 48 error: err => this.notifier.error(err.message)
49 ) 49 })
50 } 50 }
51 51
52 getAdministratorsPanel () { 52 getAdministratorsPanel () {
diff --git a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts
index a75c8a25c..51248c7b2 100644
--- a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts
+++ b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts
@@ -36,7 +36,7 @@ export class AuthInterceptor implements HttpInterceptor {
36 return this.handleNotAuthenticated(err) 36 return this.handleNotAuthenticated(err)
37 } 37 }
38 38
39 return observableThrowError(err) 39 return observableThrowError(() => err)
40 }) 40 })
41 ) 41 )
42 } 42 }
diff --git a/client/src/app/shared/shared-main/users/user-notifications.component.ts b/client/src/app/shared/shared-main/users/user-notifications.component.ts
index 96b141543..50005b855 100644
--- a/client/src/app/shared/shared-main/users/user-notifications.component.ts
+++ b/client/src/app/shared/shared-main/users/user-notifications.component.ts
@@ -56,8 +56,8 @@ export class UserNotificationsComponent implements OnInit {
56 } 56 }
57 57
58 this.userNotificationService.listMyNotifications(options) 58 this.userNotificationService.listMyNotifications(options)
59 .subscribe( 59 .subscribe({
60 result => { 60 next: result => {
61 this.notifications = reset ? result.data : this.notifications.concat(result.data) 61 this.notifications = reset ? result.data : this.notifications.concat(result.data)
62 this.componentPagination.totalItems = result.total 62 this.componentPagination.totalItems = result.total
63 63
@@ -66,8 +66,8 @@ export class UserNotificationsComponent implements OnInit {
66 this.onDataSubject.next(result.data) 66 this.onDataSubject.next(result.data)
67 }, 67 },
68 68
69 err => this.notifier.error(err.message) 69 error: err => this.notifier.error(err.message)
70 ) 70 })
71 } 71 }
72 72
73 onNearOfBottom () { 73 onNearOfBottom () {
@@ -84,26 +84,26 @@ export class UserNotificationsComponent implements OnInit {
84 if (notification.read) return 84 if (notification.read) return
85 85
86 this.userNotificationService.markAsRead(notification) 86 this.userNotificationService.markAsRead(notification)
87 .subscribe( 87 .subscribe({
88 () => { 88 next: () => {
89 notification.read = true 89 notification.read = true
90 }, 90 },
91 91
92 err => this.notifier.error(err.message) 92 error: err => this.notifier.error(err.message)
93 ) 93 })
94 } 94 }
95 95
96 markAllAsRead () { 96 markAllAsRead () {
97 this.userNotificationService.markAllAsRead() 97 this.userNotificationService.markAllAsRead()
98 .subscribe( 98 .subscribe({
99 () => { 99 next: () => {
100 for (const notification of this.notifications) { 100 for (const notification of this.notifications) {
101 notification.read = true 101 notification.read = true
102 } 102 }
103 }, 103 },
104 104
105 err => this.notifier.error(err.message) 105 error: err => this.notifier.error(err.message)
106 ) 106 })
107 } 107 }
108 108
109 changeSortColumn (column: string) { 109 changeSortColumn (column: string) {
diff --git a/client/src/app/shared/shared-moderation/account-blocklist.component.ts b/client/src/app/shared/shared-moderation/account-blocklist.component.ts
index 1146aeec0..36f2a591b 100644
--- a/client/src/app/shared/shared-moderation/account-blocklist.component.ts
+++ b/client/src/app/shared/shared-moderation/account-blocklist.component.ts
@@ -62,13 +62,13 @@ export class GenericAccountBlocklistComponent extends RestTable implements OnIni
62 search: this.search 62 search: this.search
63 }) 63 })
64 64
65 return operation.subscribe( 65 return operation.subscribe({
66 resultList => { 66 next: resultList => {
67 this.blockedAccounts = resultList.data 67 this.blockedAccounts = resultList.data
68 this.totalRecords = resultList.total 68 this.totalRecords = resultList.total
69 }, 69 },
70 70
71 err => this.notifier.error(err.message) 71 error: err => this.notifier.error(err.message)
72 ) 72 })
73 } 73 }
74} 74}
diff --git a/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts
index cc8875f77..4ec02f11a 100644
--- a/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts
+++ b/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts
@@ -77,14 +77,14 @@ export class AccountReportComponent extends FormReactive implements OnInit {
77 account: { 77 account: {
78 id: this.account.id 78 id: this.account.id
79 } 79 }
80 }).subscribe( 80 }).subscribe({
81 () => { 81 next: () => {
82 this.notifier.success($localize`Account reported.`) 82 this.notifier.success($localize`Account reported.`)
83 this.hide() 83 this.hide()
84 }, 84 },
85 85
86 err => this.notifier.error(err.message) 86 error: err => this.notifier.error(err.message)
87 ) 87 })
88 } 88 }
89 89
90 isRemote () { 90 isRemote () {
diff --git a/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts
index c7395c7b7..7c0907ce4 100644
--- a/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts
+++ b/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts
@@ -77,14 +77,14 @@ export class CommentReportComponent extends FormReactive implements OnInit {
77 comment: { 77 comment: {
78 id: this.comment.id 78 id: this.comment.id
79 } 79 }
80 }).subscribe( 80 }).subscribe({
81 () => { 81 next: () => {
82 this.notifier.success($localize`Comment reported.`) 82 this.notifier.success($localize`Comment reported.`)
83 this.hide() 83 this.hide()
84 }, 84 },
85 85
86 err => this.notifier.error(err.message) 86 error: err => this.notifier.error(err.message)
87 ) 87 })
88 } 88 }
89 89
90 isRemote () { 90 isRemote () {
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
index e509ac88f..278d60ac6 100644
--- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
+++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
@@ -108,14 +108,14 @@ export class VideoReportComponent extends FormReactive implements OnInit {
108 startAt: hasStart && startAt ? startAt : undefined, 108 startAt: hasStart && startAt ? startAt : undefined,
109 endAt: hasEnd && endAt ? endAt : undefined 109 endAt: hasEnd && endAt ? endAt : undefined
110 } 110 }
111 }).subscribe( 111 }).subscribe({
112 () => { 112 next: () => {
113 this.notifier.success($localize`Video reported.`) 113 this.notifier.success($localize`Video reported.`)
114 this.hide() 114 this.hide()
115 }, 115 },
116 116
117 err => this.notifier.error(err.message) 117 error: err => this.notifier.error(err.message)
118 ) 118 })
119 } 119 }
120 120
121 isRemote () { 121 isRemote () {
diff --git a/client/src/app/shared/shared-moderation/server-blocklist.component.ts b/client/src/app/shared/shared-moderation/server-blocklist.component.ts
index 274d8f6e9..da09b1d0e 100644
--- a/client/src/app/shared/shared-moderation/server-blocklist.component.ts
+++ b/client/src/app/shared/shared-moderation/server-blocklist.component.ts
@@ -88,13 +88,13 @@ export class GenericServerBlocklistComponent extends RestTable implements OnInit
88 search: this.search 88 search: this.search
89 }) 89 })
90 90
91 return operation.subscribe( 91 return operation.subscribe({
92 resultList => { 92 next: resultList => {
93 this.blockedServers = resultList.data 93 this.blockedServers = resultList.data
94 this.totalRecords = resultList.total 94 this.totalRecords = resultList.total
95 }, 95 },
96 96
97 err => this.notifier.error(err.message) 97 error: err => this.notifier.error(err.message)
98 ) 98 })
99 } 99 }
100} 100}
diff --git a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
index afc69a1b8..0a2d5e93a 100644
--- a/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
+++ b/client/src/app/shared/shared-moderation/user-ban-modal.component.ts
@@ -47,8 +47,8 @@ export class UserBanModalComponent extends FormReactive implements OnInit {
47 const reason = this.form.value['reason'] || undefined 47 const reason = this.form.value['reason'] || undefined
48 48
49 this.userService.banUsers(this.usersToBan, reason) 49 this.userService.banUsers(this.usersToBan, reason)
50 .subscribe( 50 .subscribe({
51 () => { 51 next: () => {
52 const message = Array.isArray(this.usersToBan) 52 const message = Array.isArray(this.usersToBan)
53 ? $localize`${this.usersToBan.length} users banned.` 53 ? $localize`${this.usersToBan.length} users banned.`
54 : $localize`User ${this.usersToBan.username} banned.` 54 : $localize`User ${this.usersToBan.username} banned.`
@@ -59,8 +59,8 @@ export class UserBanModalComponent extends FormReactive implements OnInit {
59 this.hide() 59 this.hide()
60 }, 60 },
61 61
62 err => this.notifier.error(err.message) 62 error: err => this.notifier.error(err.message)
63 ) 63 })
64 } 64 }
65 65
66} 66}
diff --git a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
index 8c5a48d42..9f1e1bf9b 100644
--- a/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
+++ b/client/src/app/shared/shared-moderation/user-moderation-dropdown.component.ts
@@ -67,14 +67,14 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
67 if (res === false) return 67 if (res === false) return
68 68
69 this.userService.unbanUsers(user) 69 this.userService.unbanUsers(user)
70 .subscribe( 70 .subscribe({
71 () => { 71 next: () => {
72 this.notifier.success($localize`User ${user.username} unbanned.`) 72 this.notifier.success($localize`User ${user.username} unbanned.`)
73 this.userChanged.emit() 73 this.userChanged.emit()
74 }, 74 },
75 75
76 err => this.notifier.error(err.message) 76 error: err => this.notifier.error(err.message)
77 ) 77 })
78 } 78 }
79 79
80 async removeUser (user: User) { 80 async removeUser (user: User) {
@@ -87,137 +87,139 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
87 const res = await this.confirmService.confirm(message, $localize`Delete`) 87 const res = await this.confirmService.confirm(message, $localize`Delete`)
88 if (res === false) return 88 if (res === false) return
89 89
90 this.userService.removeUser(user).subscribe( 90 this.userService.removeUser(user)
91 () => { 91 .subscribe({
92 this.notifier.success($localize`User ${user.username} deleted.`) 92 next: () => {
93 this.userDeleted.emit() 93 this.notifier.success($localize`User ${user.username} deleted.`)
94 }, 94 this.userDeleted.emit()
95 },
95 96
96 err => this.notifier.error(err.message) 97 error: err => this.notifier.error(err.message)
97 ) 98 })
98 } 99 }
99 100
100 setEmailAsVerified (user: User) { 101 setEmailAsVerified (user: User) {
101 this.userService.updateUser(user.id, { emailVerified: true }).subscribe( 102 this.userService.updateUser(user.id, { emailVerified: true })
102 () => { 103 .subscribe({
103 this.notifier.success($localize`User ${user.username} email set as verified`) 104 next: () => {
104 this.userChanged.emit() 105 this.notifier.success($localize`User ${user.username} email set as verified`)
105 }, 106 this.userChanged.emit()
106 107 },
107 err => this.notifier.error(err.message) 108
108 ) 109 error: err => this.notifier.error(err.message)
110 })
109 } 111 }
110 112
111 blockAccountByUser (account: Account) { 113 blockAccountByUser (account: Account) {
112 this.blocklistService.blockAccountByUser(account) 114 this.blocklistService.blockAccountByUser(account)
113 .subscribe( 115 .subscribe({
114 () => { 116 next: () => {
115 this.notifier.success($localize`Account ${account.nameWithHost} muted.`) 117 this.notifier.success($localize`Account ${account.nameWithHost} muted.`)
116 118
117 this.account.mutedByUser = true 119 this.account.mutedByUser = true
118 this.userChanged.emit() 120 this.userChanged.emit()
119 }, 121 },
120 122
121 err => this.notifier.error(err.message) 123 error: err => this.notifier.error(err.message)
122 ) 124 })
123 } 125 }
124 126
125 unblockAccountByUser (account: Account) { 127 unblockAccountByUser (account: Account) {
126 this.blocklistService.unblockAccountByUser(account) 128 this.blocklistService.unblockAccountByUser(account)
127 .subscribe( 129 .subscribe({
128 () => { 130 next: () => {
129 this.notifier.success($localize`Account ${account.nameWithHost} unmuted.`) 131 this.notifier.success($localize`Account ${account.nameWithHost} unmuted.`)
130 132
131 this.account.mutedByUser = false 133 this.account.mutedByUser = false
132 this.userChanged.emit() 134 this.userChanged.emit()
133 }, 135 },
134 136
135 err => this.notifier.error(err.message) 137 error: err => this.notifier.error(err.message)
136 ) 138 })
137 } 139 }
138 140
139 blockServerByUser (host: string) { 141 blockServerByUser (host: string) {
140 this.blocklistService.blockServerByUser(host) 142 this.blocklistService.blockServerByUser(host)
141 .subscribe( 143 .subscribe({
142 () => { 144 next: () => {
143 this.notifier.success($localize`Instance ${host} muted.`) 145 this.notifier.success($localize`Instance ${host} muted.`)
144 146
145 this.account.mutedServerByUser = true 147 this.account.mutedServerByUser = true
146 this.userChanged.emit() 148 this.userChanged.emit()
147 }, 149 },
148 150
149 err => this.notifier.error(err.message) 151 error: err => this.notifier.error(err.message)
150 ) 152 })
151 } 153 }
152 154
153 unblockServerByUser (host: string) { 155 unblockServerByUser (host: string) {
154 this.blocklistService.unblockServerByUser(host) 156 this.blocklistService.unblockServerByUser(host)
155 .subscribe( 157 .subscribe({
156 () => { 158 next: () => {
157 this.notifier.success($localize`Instance ${host} unmuted.`) 159 this.notifier.success($localize`Instance ${host} unmuted.`)
158 160
159 this.account.mutedServerByUser = false 161 this.account.mutedServerByUser = false
160 this.userChanged.emit() 162 this.userChanged.emit()
161 }, 163 },
162 164
163 err => this.notifier.error(err.message) 165 error: err => this.notifier.error(err.message)
164 ) 166 })
165 } 167 }
166 168
167 blockAccountByInstance (account: Account) { 169 blockAccountByInstance (account: Account) {
168 this.blocklistService.blockAccountByInstance(account) 170 this.blocklistService.blockAccountByInstance(account)
169 .subscribe( 171 .subscribe({
170 () => { 172 next: () => {
171 this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`) 173 this.notifier.success($localize`Account ${account.nameWithHost} muted by the instance.`)
172 174
173 this.account.mutedByInstance = true 175 this.account.mutedByInstance = true
174 this.userChanged.emit() 176 this.userChanged.emit()
175 }, 177 },
176 178
177 err => this.notifier.error(err.message) 179 error: err => this.notifier.error(err.message)
178 ) 180 })
179 } 181 }
180 182
181 unblockAccountByInstance (account: Account) { 183 unblockAccountByInstance (account: Account) {
182 this.blocklistService.unblockAccountByInstance(account) 184 this.blocklistService.unblockAccountByInstance(account)
183 .subscribe( 185 .subscribe({
184 () => { 186 next: () => {
185 this.notifier.success($localize`Account ${account.nameWithHost} unmuted by the instance.`) 187 this.notifier.success($localize`Account ${account.nameWithHost} unmuted by the instance.`)
186 188
187 this.account.mutedByInstance = false 189 this.account.mutedByInstance = false
188 this.userChanged.emit() 190 this.userChanged.emit()
189 }, 191 },
190 192
191 err => this.notifier.error(err.message) 193 error: err => this.notifier.error(err.message)
192 ) 194 })
193 } 195 }
194 196
195 blockServerByInstance (host: string) { 197 blockServerByInstance (host: string) {
196 this.blocklistService.blockServerByInstance(host) 198 this.blocklistService.blockServerByInstance(host)
197 .subscribe( 199 .subscribe({
198 () => { 200 next: () => {
199 this.notifier.success($localize`Instance ${host} muted by the instance.`) 201 this.notifier.success($localize`Instance ${host} muted by the instance.`)
200 202
201 this.account.mutedServerByInstance = true 203 this.account.mutedServerByInstance = true
202 this.userChanged.emit() 204 this.userChanged.emit()
203 }, 205 },
204 206
205 err => this.notifier.error(err.message) 207 error: err => this.notifier.error(err.message)
206 ) 208 })
207 } 209 }
208 210
209 unblockServerByInstance (host: string) { 211 unblockServerByInstance (host: string) {
210 this.blocklistService.unblockServerByInstance(host) 212 this.blocklistService.unblockServerByInstance(host)
211 .subscribe( 213 .subscribe({
212 () => { 214 next: () => {
213 this.notifier.success($localize`Instance ${host} unmuted by the instance.`) 215 this.notifier.success($localize`Instance ${host} unmuted by the instance.`)
214 216
215 this.account.mutedServerByInstance = false 217 this.account.mutedServerByInstance = false
216 this.userChanged.emit() 218 this.userChanged.emit()
217 }, 219 },
218 220
219 err => this.notifier.error(err.message) 221 error: err => this.notifier.error(err.message)
220 ) 222 })
221 } 223 }
222 224
223 async bulkRemoveCommentsOf (body: BulkRemoveCommentsOfBody) { 225 async bulkRemoveCommentsOf (body: BulkRemoveCommentsOfBody) {
@@ -226,13 +228,13 @@ export class UserModerationDropdownComponent implements OnInit, OnChanges {
226 if (res === false) return 228 if (res === false) return
227 229
228 this.bulkService.removeCommentsOf(body) 230 this.bulkService.removeCommentsOf(body)
229 .subscribe( 231 .subscribe({
230 () => { 232 next: () => {
231 this.notifier.success($localize`Will remove comments of this account (may take several minutes).`) 233 this.notifier.success($localize`Will remove comments of this account (may take several minutes).`)
232 }, 234 },
233 235
234 err => this.notifier.error(err.message) 236 error: err => this.notifier.error(err.message)
235 ) 237 })
236 } 238 }
237 239
238 getRouterUserEditLink (user: User) { 240 getRouterUserEditLink (user: User) {
diff --git a/client/src/app/shared/shared-moderation/video-block.component.ts b/client/src/app/shared/shared-moderation/video-block.component.ts
index fb47989dc..bc6952620 100644
--- a/client/src/app/shared/shared-moderation/video-block.component.ts
+++ b/client/src/app/shared/shared-moderation/video-block.component.ts
@@ -55,8 +55,8 @@ export class VideoBlockComponent extends FormReactive implements OnInit {
55 const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined 55 const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined
56 56
57 this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate) 57 this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate)
58 .subscribe( 58 .subscribe({
59 () => { 59 next: () => {
60 this.notifier.success($localize`Video blocked.`) 60 this.notifier.success($localize`Video blocked.`)
61 this.hide() 61 this.hide()
62 62
@@ -66,7 +66,7 @@ export class VideoBlockComponent extends FormReactive implements OnInit {
66 this.videoBlocked.emit() 66 this.videoBlocked.emit()
67 }, 67 },
68 68
69 err => this.notifier.error(err.message) 69 error: err => this.notifier.error(err.message)
70 ) 70 })
71 } 71 }
72} 72}
diff --git a/client/src/app/shared/shared-search/find-in-bulk.service.ts b/client/src/app/shared/shared-search/find-in-bulk.service.ts
index 61dd2cbc5..962e374a5 100644
--- a/client/src/app/shared/shared-search/find-in-bulk.service.ts
+++ b/client/src/app/shared/shared-search/find-in-bulk.service.ts
@@ -1,5 +1,5 @@
1import * as debug from 'debug' 1import * as debug from 'debug'
2import { Observable, Subject, throwError } from 'rxjs' 2import { Observable, Subject } from 'rxjs'
3import { first, map } from 'rxjs/operators' 3import { first, map } from 'rxjs/operators'
4import { Injectable, NgZone } from '@angular/core' 4import { Injectable, NgZone } from '@angular/core'
5import { buildBulkObservable } from '@app/helpers' 5import { buildBulkObservable } from '@app/helpers'
diff --git a/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts b/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts
index b721604e5..bd1cb0353 100644
--- a/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts
+++ b/client/src/app/shared/shared-user-settings/user-interface-settings.component.ts
@@ -65,18 +65,21 @@ export class UserInterfaceSettingsComponent extends FormReactive implements OnIn
65 } 65 }
66 66
67 if (this.authService.isLoggedIn()) { 67 if (this.authService.isLoggedIn()) {
68 this.userService.updateMyProfile(details).subscribe( 68 this.userService.updateMyProfile(details)
69 () => { 69 .subscribe({
70 this.authService.refreshUserInformation() 70 next: () => {
71 71 this.authService.refreshUserInformation()
72 if (this.notifyOnUpdate) this.notifier.success($localize`Interface settings updated.`) 72
73 }, 73 if (this.notifyOnUpdate) this.notifier.success($localize`Interface settings updated.`)
74 74 },
75 err => this.notifier.error(err.message) 75
76 ) 76 error: err => this.notifier.error(err.message)
77 } else { 77 })
78 this.userService.updateMyAnonymousProfile(details) 78
79 if (this.notifyOnUpdate) this.notifier.success($localize`Interface settings updated.`) 79 return
80 } 80 }
81
82 this.userService.updateMyAnonymousProfile(details)
83 if (this.notifyOnUpdate) this.notifier.success($localize`Interface settings updated.`)
81 } 84 }
82} 85}
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
index 8b0eaea4f..4aac60c2b 100644
--- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
+++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
@@ -162,15 +162,16 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
162 } 162 }
163 163
164 private updateLoggedProfile (details: UserUpdateMe) { 164 private updateLoggedProfile (details: UserUpdateMe) {
165 this.userService.updateMyProfile(details).subscribe( 165 this.userService.updateMyProfile(details)
166 () => { 166 .subscribe({
167 this.authService.refreshUserInformation() 167 next: () => {
168 this.authService.refreshUserInformation()
168 169
169 if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`) 170 if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`)
170 }, 171 },
171 172
172 err => this.notifier.error(err.message) 173 error: err => this.notifier.error(err.message)
173 ) 174 })
174 } 175 }
175 176
176 private updateAnonymousProfile (details: UserUpdateMe) { 177 private updateAnonymousProfile (details: UserUpdateMe) {
diff --git a/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts b/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
index 2261e07dd..796493bd9 100644
--- a/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
+++ b/client/src/app/shared/shared-user-subscription/subscribe-button.component.ts
@@ -102,8 +102,8 @@ export class SubscribeButtonComponent implements OnInit, OnChanges {
102 .map(handle => this.userSubscriptionService.addSubscription(handle)) 102 .map(handle => this.userSubscriptionService.addSubscription(handle))
103 103
104 forkJoin(observableBatch) 104 forkJoin(observableBatch)
105 .subscribe( 105 .subscribe({
106 () => { 106 next: () => {
107 this.notifier.success( 107 this.notifier.success(
108 this.account 108 this.account
109 ? $localize`Subscribed to all current channels of ${this.account.displayName}. You will be notified of all their new videos.` 109 ? $localize`Subscribed to all current channels of ${this.account.displayName}. You will be notified of all their new videos.`
@@ -113,8 +113,8 @@ export class SubscribeButtonComponent implements OnInit, OnChanges {
113 ) 113 )
114 }, 114 },
115 115
116 err => this.notifier.error(err.message) 116 error: err => this.notifier.error(err.message)
117 ) 117 })
118 } 118 }
119 119
120 unsubscribe () { 120 unsubscribe () {
@@ -182,11 +182,11 @@ export class SubscribeButtonComponent implements OnInit, OnChanges {
182 merge( 182 merge(
183 this.userSubscriptionService.listenToSubscriptionCacheChange(handle), 183 this.userSubscriptionService.listenToSubscriptionCacheChange(handle),
184 this.userSubscriptionService.doesSubscriptionExist(handle) 184 this.userSubscriptionService.doesSubscriptionExist(handle)
185 ).subscribe( 185 ).subscribe({
186 res => this.subscribed.set(handle, res), 186 next: res => this.subscribed.set(handle, res),
187 187
188 err => this.notifier.error(err.message) 188 error: err => this.notifier.error(err.message)
189 ) 189 })
190 } 190 }
191 } 191 }
192} 192}
diff --git a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
index 33061a837..d8b2ee17d 100644
--- a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
+++ b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts
@@ -204,28 +204,29 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte
204 } 204 }
205 205
206 loadMoreVideos (reset = false) { 206 loadMoreVideos (reset = false) {
207 this.getVideosObservable(this.pagination.currentPage).subscribe( 207 this.getVideosObservable(this.pagination.currentPage)
208 ({ data }) => { 208 .subscribe({
209 this.hasDoneFirstQuery = true 209 next: ({ data }) => {
210 this.lastQueryLength = data.length 210 this.hasDoneFirstQuery = true
211 this.lastQueryLength = data.length
211 212
212 if (reset) this.videos = [] 213 if (reset) this.videos = []
213 this.videos = this.videos.concat(data) 214 this.videos = this.videos.concat(data)
214 215
215 if (this.groupByDate) this.buildGroupedDateLabels() 216 if (this.groupByDate) this.buildGroupedDateLabels()
216 217
217 this.onMoreVideos() 218 this.onMoreVideos()
218 219
219 this.onDataSubject.next(data) 220 this.onDataSubject.next(data)
220 }, 221 },
221 222
222 error => { 223 error: err => {
223 const message = $localize`Cannot load more videos. Try again later.` 224 const message = $localize`Cannot load more videos. Try again later.`
224 225
225 console.error(message, { error }) 226 console.error(message, { err })
226 this.notifier.error(message) 227 this.notifier.error(message)
227 } 228 }
228 ) 229 })
229 } 230 }
230 231
231 reloadVideos () { 232 reloadVideos () {
diff --git a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
index 3c2b46d16..2ba091438 100644
--- a/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-actions-dropdown.component.ts
@@ -183,8 +183,8 @@ export class VideoActionsDropdownComponent implements OnChanges {
183 if (res === false) return 183 if (res === false) return
184 184
185 this.videoBlocklistService.unblockVideo(this.video.id) 185 this.videoBlocklistService.unblockVideo(this.video.id)
186 .subscribe( 186 .subscribe({
187 () => { 187 next: () => {
188 this.notifier.success($localize`Video ${this.video.name} unblocked.`) 188 this.notifier.success($localize`Video ${this.video.name} unblocked.`)
189 189
190 this.video.blacklisted = false 190 this.video.blacklisted = false
@@ -193,8 +193,8 @@ export class VideoActionsDropdownComponent implements OnChanges {
193 this.videoUnblocked.emit() 193 this.videoUnblocked.emit()
194 }, 194 },
195 195
196 err => this.notifier.error(err.message) 196 error: err => this.notifier.error(err.message)
197 ) 197 })
198 } 198 }
199 199
200 async removeVideo () { 200 async removeVideo () {
@@ -209,40 +209,40 @@ export class VideoActionsDropdownComponent implements OnChanges {
209 if (res === false) return 209 if (res === false) return
210 210
211 this.videoService.removeVideo(this.video.id) 211 this.videoService.removeVideo(this.video.id)
212 .subscribe( 212 .subscribe({
213 () => { 213 next: () => {
214 this.notifier.success($localize`Video ${this.video.name} deleted.`) 214 this.notifier.success($localize`Video ${this.video.name} deleted.`)
215 this.videoRemoved.emit() 215 this.videoRemoved.emit()
216 }, 216 },
217 217
218 error => this.notifier.error(error.message) 218 error: err => this.notifier.error(err.message)
219 ) 219 })
220 } 220 }
221 221
222 duplicateVideo () { 222 duplicateVideo () {
223 this.redundancyService.addVideoRedundancy(this.video) 223 this.redundancyService.addVideoRedundancy(this.video)
224 .subscribe( 224 .subscribe({
225 () => { 225 next: () => {
226 const message = $localize`This video will be duplicated by your instance.` 226 const message = $localize`This video will be duplicated by your instance.`
227 this.notifier.success(message) 227 this.notifier.success(message)
228 }, 228 },
229 229
230 err => this.notifier.error(err.message) 230 error: err => this.notifier.error(err.message)
231 ) 231 })
232 } 232 }
233 233
234 muteVideoAccount () { 234 muteVideoAccount () {
235 const params = { nameWithHost: Actor.CREATE_BY_STRING(this.video.account.name, this.video.account.host) } 235 const params = { nameWithHost: Actor.CREATE_BY_STRING(this.video.account.name, this.video.account.host) }
236 236
237 this.blocklistService.blockAccountByUser(params) 237 this.blocklistService.blockAccountByUser(params)
238 .subscribe( 238 .subscribe({
239 () => { 239 next: () => {
240 this.notifier.success($localize`Account ${params.nameWithHost} muted.`) 240 this.notifier.success($localize`Account ${params.nameWithHost} muted.`)
241 this.videoAccountMuted.emit() 241 this.videoAccountMuted.emit()
242 }, 242 },
243 243
244 err => this.notifier.error(err.message) 244 error: err => this.notifier.error(err.message)
245 ) 245 })
246 } 246 }
247 247
248 onVideoBlocked () { 248 onVideoBlocked () {
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.ts b/client/src/app/shared/shared-video-miniature/video-download.component.ts
index 355ce8be3..28fefb9dd 100644
--- a/client/src/app/shared/shared-video-miniature/video-download.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-download.component.ts
@@ -1,4 +1,5 @@
1import { mapValues, pick } from 'lodash-es' 1import { mapValues, pick } from 'lodash-es'
2import { firstValueFrom } from 'rxjs'
2import { tap } from 'rxjs/operators' 3import { tap } from 'rxjs/operators'
3import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' 4import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core'
4import { AuthService, HooksService, Notifier } from '@app/core' 5import { AuthService, HooksService, Notifier } from '@app/core'
@@ -265,6 +266,6 @@ export class VideoDownloadComponent {
265 const observable = this.videoService.getVideoFileMetadata(file.metadataUrl) 266 const observable = this.videoService.getVideoFileMetadata(file.metadataUrl)
266 .pipe(tap(res => file.metadata = res)) 267 .pipe(tap(res => file.metadata = res))
267 268
268 return observable.toPromise() 269 return firstValueFrom(observable)
269 } 270 }
270} 271}
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
index 67e0de6a2..cb81ba3bd 100644
--- a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts
@@ -214,11 +214,12 @@ export class VideoMiniatureComponent implements OnInit {
214 addToWatchLater () { 214 addToWatchLater () {
215 const body = { videoId: this.video.id } 215 const body = { videoId: this.video.id }
216 216
217 this.videoPlaylistService.addVideoInPlaylist(this.watchLaterPlaylist.id, body).subscribe( 217 this.videoPlaylistService.addVideoInPlaylist(this.watchLaterPlaylist.id, body)
218 res => { 218 .subscribe(
219 this.watchLaterPlaylist.playlistElementId = res.videoPlaylistElement.id 219 res => {
220 } 220 this.watchLaterPlaylist.playlistElementId = res.videoPlaylistElement.id
221 ) 221 }
222 )
222 } 223 }
223 224
224 removeFromWatchLater () { 225 removeFromWatchLater () {
diff --git a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
index 7069fa8fd..df3aeddb7 100644
--- a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
+++ b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts
@@ -198,15 +198,16 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
198 privacy: VideoPlaylistPrivacy.PRIVATE 198 privacy: VideoPlaylistPrivacy.PRIVATE
199 } 199 }
200 200
201 this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate).subscribe( 201 this.videoPlaylistService.createVideoPlaylist(videoPlaylistCreate)
202 () => { 202 .subscribe({
203 this.isNewPlaylistBlockOpened = false 203 next: () => {
204 this.isNewPlaylistBlockOpened = false
204 205
205 this.cd.markForCheck() 206 this.cd.markForCheck()
206 }, 207 },
207 208
208 err => this.notifier.error(err.message) 209 error: err => this.notifier.error(err.message)
209 ) 210 })
210 } 211 }
211 212
212 onVideoPlaylistSearchChanged () { 213 onVideoPlaylistSearchChanged () {
@@ -268,17 +269,15 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
268 } 269 }
269 270
270 this.videoPlaylistService.updateVideoOfPlaylist(playlist.id, element.playlistElementId, body, this.video.id) 271 this.videoPlaylistService.updateVideoOfPlaylist(playlist.id, element.playlistElementId, body, this.video.id)
271 .subscribe( 272 .subscribe({
272 () => { 273 next: () => {
273 this.notifier.success($localize`Timestamps updated`) 274 this.notifier.success($localize`Timestamps updated`)
274 }, 275 },
275 276
276 err => { 277 error: err => this.notifier.error(err.message),
277 this.notifier.error(err.message)
278 },
279 278
280 () => this.cd.markForCheck() 279 complete: () => this.cd.markForCheck()
281 ) 280 })
282 } 281 }
283 282
284 private isOptionalRowDisplayed (playlist: PlaylistSummary) { 283 private isOptionalRowDisplayed (playlist: PlaylistSummary) {
@@ -302,17 +301,15 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
302 301
303 private removeVideoFromPlaylist (playlist: PlaylistSummary, elementId: number) { 302 private removeVideoFromPlaylist (playlist: PlaylistSummary, elementId: number) {
304 this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, elementId, this.video.id) 303 this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, elementId, this.video.id)
305 .subscribe( 304 .subscribe({
306 () => { 305 next: () => {
307 this.notifier.success($localize`Video removed from ${playlist.displayName}`) 306 this.notifier.success($localize`Video removed from ${playlist.displayName}`)
308 }, 307 },
309 308
310 err => { 309 error: err => this.notifier.error(err.message),
311 this.notifier.error(err.message)
312 },
313 310
314 () => this.cd.markForCheck() 311 complete: () => this.cd.markForCheck()
315 ) 312 })
316 } 313 }
317 314
318 private listenToVideoPlaylistChange () { 315 private listenToVideoPlaylistChange () {
@@ -371,8 +368,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
371 if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp 368 if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp
372 369
373 this.videoPlaylistService.addVideoInPlaylist(playlist.id, body) 370 this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
374 .subscribe( 371 .subscribe({
375 res => { 372 next: res => {
376 const message = body.startTimestamp || body.stopTimestamp 373 const message = body.startTimestamp || body.stopTimestamp
377 ? $localize`Video added in ${playlist.displayName} at timestamps ${this.formatTimestamp(element)}` 374 ? $localize`Video added in ${playlist.displayName} at timestamps ${this.formatTimestamp(element)}`
378 : $localize`Video added in ${playlist.displayName}` 375 : $localize`Video added in ${playlist.displayName}`
@@ -382,12 +379,10 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
382 if (element) element.playlistElementId = res.videoPlaylistElement.id 379 if (element) element.playlistElementId = res.videoPlaylistElement.id
383 }, 380 },
384 381
385 err => { 382 error: err => this.notifier.error(err.message),
386 this.notifier.error(err.message)
387 },
388 383
389 () => this.cd.markForCheck() 384 complete: () => this.cd.markForCheck()
390 ) 385 })
391 } 386 }
392 387
393 private formatTimestamp (element: PlaylistElement) { 388 private formatTimestamp (element: PlaylistElement) {
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
index 2e495ec26..8d1e14f94 100644
--- a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
+++ b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts
@@ -88,14 +88,14 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
88 const videoId = this.playlistElement.video ? this.playlistElement.video.id : undefined 88 const videoId = this.playlistElement.video ? this.playlistElement.video.id : undefined
89 89
90 this.videoPlaylistService.removeVideoFromPlaylist(this.playlist.id, playlistElement.id, videoId) 90 this.videoPlaylistService.removeVideoFromPlaylist(this.playlist.id, playlistElement.id, videoId)
91 .subscribe( 91 .subscribe({
92 () => { 92 next: () => {
93 this.notifier.success($localize`Video removed from ${this.playlist.displayName}`) 93 this.notifier.success($localize`Video removed from ${this.playlist.displayName}`)
94 this.elementRemoved.emit(playlistElement) 94 this.elementRemoved.emit(playlistElement)
95 }, 95 },
96 96
97 err => this.notifier.error(err.message) 97 error: err => this.notifier.error(err.message)
98 ) 98 })
99 99
100 this.moreDropdown.close() 100 this.moreDropdown.close()
101 } 101 }
@@ -107,8 +107,8 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
107 body.stopTimestamp = this.timestampOptions.stopTimestampEnabled ? this.timestampOptions.stopTimestamp : null 107 body.stopTimestamp = this.timestampOptions.stopTimestampEnabled ? this.timestampOptions.stopTimestamp : null
108 108
109 this.videoPlaylistService.updateVideoOfPlaylist(this.playlist.id, playlistElement.id, body, this.playlistElement.video.id) 109 this.videoPlaylistService.updateVideoOfPlaylist(this.playlist.id, playlistElement.id, body, this.playlistElement.video.id)
110 .subscribe( 110 .subscribe({
111 () => { 111 next: () => {
112 this.notifier.success($localize`Timestamps updated`) 112 this.notifier.success($localize`Timestamps updated`)
113 113
114 playlistElement.startTimestamp = body.startTimestamp 114 playlistElement.startTimestamp = body.startTimestamp
@@ -117,8 +117,8 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit {
117 this.cdr.detectChanges() 117 this.cdr.detectChanges()
118 }, 118 },
119 119
120 err => this.notifier.error(err.message) 120 error: err => this.notifier.error(err.message)
121 ) 121 })
122 122
123 this.moreDropdown.close() 123 this.moreDropdown.close()
124 } 124 }
diff --git a/client/src/root-helpers/plugins-manager.ts b/client/src/root-helpers/plugins-manager.ts
index f919db8af..d14ac4acd 100644
--- a/client/src/root-helpers/plugins-manager.ts
+++ b/client/src/root-helpers/plugins-manager.ts
@@ -1,5 +1,5 @@
1import * as debug from 'debug' 1import * as debug from 'debug'
2import { ReplaySubject } from 'rxjs' 2import { firstValueFrom, ReplaySubject } from 'rxjs'
3import { first, shareReplay } from 'rxjs/operators' 3import { first, shareReplay } from 'rxjs/operators'
4import { RegisterClientHelpers } from 'src/types/register-client-option.model' 4import { RegisterClientHelpers } from 'src/types/register-client-option.model'
5import { getHookType, internalRunHook } from '@shared/core-utils/plugins/hooks' 5import { getHookType, internalRunHook } from '@shared/core-utils/plugins/hooks'
@@ -102,9 +102,10 @@ class PluginsManager {
102 ensurePluginsAreLoaded (scope: PluginClientScope) { 102 ensurePluginsAreLoaded (scope: PluginClientScope) {
103 this.loadPluginsByScope(scope) 103 this.loadPluginsByScope(scope)
104 104
105 return this.pluginsLoaded[scope].asObservable() 105 const obs = this.pluginsLoaded[scope].asObservable()
106 .pipe(first(), shareReplay()) 106 .pipe(first(), shareReplay())
107 .toPromise() 107
108 return firstValueFrom(obs)
108 } 109 }
109 110
110 async reloadLoadedScopes () { 111 async reloadLoadedScopes () {