diff options
41 files changed, 112 insertions, 82 deletions
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 30e4aa5d5..2c3b7560d 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 | |||
@@ -273,11 +273,11 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
273 | 273 | ||
274 | const defaultValues = { | 274 | const defaultValues = { |
275 | transcoding: { | 275 | transcoding: { |
276 | resolutions: {} | 276 | resolutions: {} as { [id: string]: string } |
277 | }, | 277 | }, |
278 | live: { | 278 | live: { |
279 | transcoding: { | 279 | transcoding: { |
280 | resolutions: {} | 280 | resolutions: {} as { [id: string]: string } |
281 | } | 281 | } |
282 | } | 282 | } |
283 | } | 283 | } |
diff --git a/client/src/app/+admin/overview/users/user-edit/user-edit.ts b/client/src/app/+admin/overview/users/user-edit/user-edit.ts index 5d6c6a91e..9547da2d1 100644 --- a/client/src/app/+admin/overview/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/overview/users/user-edit/user-edit.ts | |||
@@ -53,8 +53,8 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
53 | this.serverService.getServerLocale() | 53 | this.serverService.getServerLocale() |
54 | .subscribe(translations => { | 54 | .subscribe(translations => { |
55 | if (authUser.role.id === UserRole.ADMINISTRATOR) { | 55 | if (authUser.role.id === UserRole.ADMINISTRATOR) { |
56 | this.roles = Object.keys(USER_ROLE_LABELS) | 56 | this.roles = Object.entries(USER_ROLE_LABELS) |
57 | .map(key => ({ value: key.toString(), label: peertubeTranslate(USER_ROLE_LABELS[key], translations) })) | 57 | .map(([ key, value ]) => ({ value: key.toString(), label: peertubeTranslate(value, translations) })) |
58 | return | 58 | return |
59 | } | 59 | } |
60 | 60 | ||
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 2fdc14d85..3fa1c56dc 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 | |||
@@ -104,7 +104,7 @@ export class PluginListInstalledComponent implements OnInit { | |||
104 | } | 104 | } |
105 | 105 | ||
106 | isUninstalling (plugin: PeerTubePlugin) { | 106 | isUninstalling (plugin: PeerTubePlugin) { |
107 | return !!this.uninstall[this.getPluginKey(plugin)] | 107 | return !!this.uninstalling[this.getPluginKey(plugin)] |
108 | } | 108 | } |
109 | 109 | ||
110 | isTheme (plugin: PeerTubePlugin) { | 110 | isTheme (plugin: PeerTubePlugin) { |
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 769ab647a..8faba676e 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 | |||
@@ -141,11 +141,11 @@ export class MyAccountNotificationPreferencesComponent implements OnInit { | |||
141 | } | 141 | } |
142 | 142 | ||
143 | private loadNotificationSettings () { | 143 | private loadNotificationSettings () { |
144 | for (const key of Object.keys(this.user.notificationSettings)) { | 144 | for (const key of Object.keys(this.user.notificationSettings) as (keyof UserNotificationSetting)[]) { |
145 | const value = this.user.notificationSettings[key] | 145 | const value = this.user.notificationSettings[key] |
146 | this.emailNotifications[key] = value & UserNotificationSettingValue.EMAIL | 146 | this.emailNotifications[key] = !!(value & UserNotificationSettingValue.EMAIL) |
147 | 147 | ||
148 | this.webNotifications[key] = value & UserNotificationSettingValue.WEB | 148 | this.webNotifications[key] = !!(value & UserNotificationSettingValue.WEB) |
149 | } | 149 | } |
150 | } | 150 | } |
151 | } | 151 | } |
diff --git a/client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.ts b/client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.ts index 74dbe222d..1f7287f44 100644 --- a/client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.ts +++ b/client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.ts | |||
@@ -124,7 +124,7 @@ export class MyVideoChannelSyncsComponent extends RestTable implements OnInit { | |||
124 | return '/my-library/video-channel-syncs/create' | 124 | return '/my-library/video-channel-syncs/create' |
125 | } | 125 | } |
126 | 126 | ||
127 | getSyncStateClass (stateId: number) { | 127 | getSyncStateClass (stateId: VideoChannelSyncState) { |
128 | return [ 'pt-badge', MyVideoChannelSyncsComponent.STATE_CLASS_BY_ID[stateId] ] | 128 | return [ 'pt-badge', MyVideoChannelSyncsComponent.STATE_CLASS_BY_ID[stateId] ] |
129 | } | 129 | } |
130 | 130 | ||
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 46dd304ba..b618b3f88 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 | |||
@@ -171,15 +171,15 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook { | |||
171 | .subscribe(result => { | 171 | .subscribe(result => { |
172 | this.videosContainedInPlaylists = Object.keys(result).reduce((acc, videoId) => ({ | 172 | this.videosContainedInPlaylists = Object.keys(result).reduce((acc, videoId) => ({ |
173 | ...acc, | 173 | ...acc, |
174 | [videoId]: uniqBy(result[videoId], (p: VideoExistInPlaylist) => p.playlistId) | 174 | [videoId]: uniqBy(result[+videoId], (p: VideoExistInPlaylist) => p.playlistId) |
175 | }), this.videosContainedInPlaylists) | 175 | }), this.videosContainedInPlaylists) |
176 | }) | 176 | }) |
177 | } | 177 | } |
178 | 178 | ||
179 | async deleteSelectedVideos () { | 179 | async deleteSelectedVideos () { |
180 | const toDeleteVideosIds = Object.keys(this.selection) | 180 | const toDeleteVideosIds = Object.entries(this.selection) |
181 | .filter(k => this.selection[k] === true) | 181 | .filter(([ _k, v ]) => v === true) |
182 | .map(k => parseInt(k, 10)) | 182 | .map(([ k, _v ]) => parseInt(k, 10)) |
183 | 183 | ||
184 | const res = await this.confirmService.confirm( | 184 | const res = await this.confirmService.confirm( |
185 | prepareIcu($localize`Do you really want to delete {length, plural, =1 {this video} other {{length} videos}}?`)( | 185 | prepareIcu($localize`Do you really want to delete {length, plural, =1 {this video} other {{length} videos}}?`)( |
diff --git a/client/src/app/+search/search-filters.component.ts b/client/src/app/+search/search-filters.component.ts index f9de04706..a6fc51383 100644 --- a/client/src/app/+search/search-filters.component.ts +++ b/client/src/app/+search/search-filters.component.ts | |||
@@ -118,11 +118,11 @@ export class SearchFiltersComponent implements OnInit { | |||
118 | this.onDurationOrPublishedUpdated() | 118 | this.onDurationOrPublishedUpdated() |
119 | } | 119 | } |
120 | 120 | ||
121 | resetField (fieldName: string, value?: any) { | 121 | resetField (fieldName: keyof AdvancedSearch, value?: any) { |
122 | this.advancedSearch[fieldName] = value | 122 | (this.advancedSearch as any)[fieldName] = value |
123 | } | 123 | } |
124 | 124 | ||
125 | resetLocalField (fieldName: string, value?: any) { | 125 | resetLocalField (fieldName: keyof SearchFiltersComponent, value?: any) { |
126 | this[fieldName] = value | 126 | this[fieldName] = value |
127 | this.onDurationOrPublishedUpdated() | 127 | this.onDurationOrPublishedUpdated() |
128 | } | 128 | } |
diff --git a/client/src/app/+stats/video/video-stats.component.ts b/client/src/app/+stats/video/video-stats.component.ts index 18312ec33..fa5e33ab6 100644 --- a/client/src/app/+stats/video/video-stats.component.ts +++ b/client/src/app/+stats/video/video-stats.component.ts | |||
@@ -47,7 +47,7 @@ export class VideoStatsComponent implements OnInit { | |||
47 | chartHeight = '300px' | 47 | chartHeight = '300px' |
48 | chartWidth: string = null | 48 | chartWidth: string = null |
49 | 49 | ||
50 | availableCharts: { id: string, label: string, zoomEnabled: boolean }[] = [] | 50 | availableCharts: { id: ActiveGraphId, label: string, zoomEnabled: boolean }[] = [] |
51 | activeGraphId: ActiveGraphId = 'viewers' | 51 | activeGraphId: ActiveGraphId = 'viewers' |
52 | 52 | ||
53 | video: VideoDetails | 53 | video: VideoDetails |
diff --git a/client/src/app/+videos/+video-edit/shared/video-edit-utils.ts b/client/src/app/+videos/+video-edit/shared/video-edit-utils.ts index db1ef8d73..214bde680 100644 --- a/client/src/app/+videos/+video-edit/shared/video-edit-utils.ts +++ b/client/src/app/+videos/+video-edit/shared/video-edit-utils.ts | |||
@@ -8,11 +8,11 @@ function hydrateFormFromVideo (formGroup: FormGroup, video: VideoEdit, thumbnail | |||
8 | 8 | ||
9 | const objects = [ | 9 | const objects = [ |
10 | { | 10 | { |
11 | url: 'thumbnailUrl', | 11 | url: 'thumbnailUrl' as 'thumbnailUrl', |
12 | name: 'thumbnailfile' | 12 | name: 'thumbnailfile' |
13 | }, | 13 | }, |
14 | { | 14 | { |
15 | url: 'previewUrl', | 15 | url: 'previewUrl' as 'previewUrl', |
16 | name: 'previewfile' | 16 | name: 'previewfile' |
17 | } | 17 | } |
18 | ] | 18 | ] |
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 28edcfdcb..96bdb28c9 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 | |||
@@ -263,8 +263,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy { | |||
263 | this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video) | 263 | this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video) |
264 | this.loadMoreThreads() | 264 | this.loadMoreThreads() |
265 | 265 | ||
266 | if (this.activatedRoute.params['threadId']) { | 266 | if (this.activatedRoute.snapshot.params['threadId']) { |
267 | this.processHighlightedThread(+this.activatedRoute.params['threadId']) | 267 | this.processHighlightedThread(+this.activatedRoute.snapshot.params['threadId']) |
268 | } | 268 | } |
269 | } | 269 | } |
270 | } | 270 | } |
diff --git a/client/src/app/+videos/video-list/overview/overview.service.ts b/client/src/app/+videos/video-list/overview/overview.service.ts index 12d2aa1cb..4a7d9c7c5 100644 --- a/client/src/app/+videos/video-list/overview/overview.service.ts +++ b/client/src/app/+videos/video-list/overview/overview.service.ts | |||
@@ -5,6 +5,7 @@ import { Injectable } from '@angular/core' | |||
5 | import { RestExtractor, ServerService } from '@app/core' | 5 | import { RestExtractor, ServerService } from '@app/core' |
6 | import { immutableAssign } from '@app/helpers' | 6 | import { immutableAssign } from '@app/helpers' |
7 | import { VideoService } from '@app/shared/shared-main' | 7 | import { VideoService } from '@app/shared/shared-main' |
8 | import { objectKeysTyped } from '@shared/core-utils' | ||
8 | import { peertubeTranslate } from '@shared/core-utils/i18n' | 9 | import { peertubeTranslate } from '@shared/core-utils/i18n' |
9 | import { VideosOverview as VideosOverviewServer } from '@shared/models' | 10 | import { VideosOverview as VideosOverviewServer } from '@shared/models' |
10 | import { environment } from '../../../../environments/environment' | 11 | import { environment } from '../../../../environments/environment' |
@@ -42,7 +43,7 @@ export class OverviewService { | |||
42 | } | 43 | } |
43 | 44 | ||
44 | // Build videos objects | 45 | // Build videos objects |
45 | for (const key of Object.keys(serverVideosOverview)) { | 46 | for (const key of objectKeysTyped(serverVideosOverview)) { |
46 | for (const object of serverVideosOverview[key]) { | 47 | for (const object of serverVideosOverview[key]) { |
47 | observables.push( | 48 | observables.push( |
48 | of(object.videos) | 49 | of(object.videos) |
@@ -50,7 +51,9 @@ export class OverviewService { | |||
50 | switchMap(videos => this.videosService.extractVideos({ total: 0, data: videos })), | 51 | switchMap(videos => this.videosService.extractVideos({ total: 0, data: videos })), |
51 | map(result => result.data), | 52 | map(result => result.data), |
52 | tap(videos => { | 53 | tap(videos => { |
53 | videosOverviewResult[key].push(immutableAssign(object, { videos })) | 54 | // FIXME: typings & lint |
55 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion | ||
56 | videosOverviewResult[key].push(immutableAssign(object, { videos }) as any) | ||
54 | }) | 57 | }) |
55 | ) | 58 | ) |
56 | ) | 59 | ) |
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 9f191f0a6..fc269749b 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -193,7 +193,8 @@ export class ServerService { | |||
193 | } | 193 | } |
194 | 194 | ||
195 | private loadHTMLConfigLocally () { | 195 | private loadHTMLConfigLocally () { |
196 | const configString = window['PeerTubeServerConfig'] | 196 | // FIXME: typings |
197 | const configString = (window as any)['PeerTubeServerConfig'] | ||
197 | if (!configString) { | 198 | if (!configString) { |
198 | throw new Error('Could not find PeerTubeServerConfig in HTML') | 199 | throw new Error('Could not find PeerTubeServerConfig in HTML') |
199 | } | 200 | } |
diff --git a/client/src/app/core/users/user-local-storage.service.ts b/client/src/app/core/users/user-local-storage.service.ts index 1e629249a..a87f3b98a 100644 --- a/client/src/app/core/users/user-local-storage.service.ts +++ b/client/src/app/core/users/user-local-storage.service.ts | |||
@@ -4,7 +4,8 @@ import { Injectable } from '@angular/core' | |||
4 | import { AuthService, AuthStatus } from '@app/core/auth' | 4 | import { AuthService, AuthStatus } from '@app/core/auth' |
5 | import { getBoolOrDefault } from '@root-helpers/local-storage-utils' | 5 | import { getBoolOrDefault } from '@root-helpers/local-storage-utils' |
6 | import { logger } from '@root-helpers/logger' | 6 | import { logger } from '@root-helpers/logger' |
7 | import { UserLocalStorageKeys, OAuthUserTokens } from '@root-helpers/users' | 7 | import { OAuthUserTokens, UserLocalStorageKeys } from '@root-helpers/users' |
8 | import { objectKeysTyped } from '@shared/core-utils' | ||
8 | import { UserRole, UserUpdateMe } from '@shared/models' | 9 | import { UserRole, UserUpdateMe } from '@shared/models' |
9 | import { NSFWPolicyType } from '@shared/models/videos' | 10 | import { NSFWPolicyType } from '@shared/models/videos' |
10 | import { ServerService } from '../server' | 11 | import { ServerService } from '../server' |
@@ -122,7 +123,7 @@ export class UserLocalStorageService { | |||
122 | } | 123 | } |
123 | 124 | ||
124 | setUserInfo (profile: UserUpdateMe) { | 125 | setUserInfo (profile: UserUpdateMe) { |
125 | const localStorageKeys: { [ id in keyof UserUpdateMe ]: string } = { | 126 | const localStorageKeys = { |
126 | nsfwPolicy: UserLocalStorageKeys.NSFW_POLICY, | 127 | nsfwPolicy: UserLocalStorageKeys.NSFW_POLICY, |
127 | p2pEnabled: UserLocalStorageKeys.P2P_ENABLED, | 128 | p2pEnabled: UserLocalStorageKeys.P2P_ENABLED, |
128 | autoPlayVideo: UserLocalStorageKeys.AUTO_PLAY_VIDEO, | 129 | autoPlayVideo: UserLocalStorageKeys.AUTO_PLAY_VIDEO, |
@@ -132,7 +133,7 @@ export class UserLocalStorageService { | |||
132 | videoLanguages: UserLocalStorageKeys.VIDEO_LANGUAGES | 133 | videoLanguages: UserLocalStorageKeys.VIDEO_LANGUAGES |
133 | } | 134 | } |
134 | 135 | ||
135 | const obj = Object.keys(localStorageKeys) | 136 | const obj: [ string, string | boolean | string[] ][] = objectKeysTyped(localStorageKeys) |
136 | .filter(key => key in profile) | 137 | .filter(key => key in profile) |
137 | .map(key => ([ localStorageKeys[key], profile[key] ])) | 138 | .map(key => ([ localStorageKeys[key], profile[key] ])) |
138 | 139 | ||
diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts index 2d783145f..d57608f1c 100644 --- a/client/src/app/core/users/user.model.ts +++ b/client/src/app/core/users/user.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { Account } from '@app/shared/shared-main/account/account.model' | 1 | import { Account } from '@app/shared/shared-main/account/account.model' |
2 | import { objectKeysTyped } from '@shared/core-utils' | ||
2 | import { hasUserRight } from '@shared/core-utils/users' | 3 | import { hasUserRight } from '@shared/core-utils/users' |
3 | import { | 4 | import { |
4 | ActorImage, | 5 | ActorImage, |
@@ -130,8 +131,9 @@ export class User implements UserServerModel { | |||
130 | } | 131 | } |
131 | 132 | ||
132 | patch (obj: UserServerModel) { | 133 | patch (obj: UserServerModel) { |
133 | for (const key of Object.keys(obj)) { | 134 | for (const key of objectKeysTyped(obj)) { |
134 | this[key] = obj[key] | 135 | // FIXME: typings |
136 | (this as any)[key] = obj[key] | ||
135 | } | 137 | } |
136 | 138 | ||
137 | if (obj.account !== undefined) { | 139 | if (obj.account !== undefined) { |
diff --git a/client/src/app/menu/language-chooser.component.ts b/client/src/app/menu/language-chooser.component.ts index b42e41855..f7ae69717 100644 --- a/client/src/app/menu/language-chooser.component.ts +++ b/client/src/app/menu/language-chooser.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' |
2 | import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers' | 2 | import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers' |
3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
4 | import { objectKeysTyped } from '@shared/core-utils' | ||
4 | import { getCompleteLocale, getShortLocale, I18N_LOCALES } from '@shared/core-utils/i18n' | 5 | import { getCompleteLocale, getShortLocale, I18N_LOCALES } from '@shared/core-utils/i18n' |
5 | 6 | ||
6 | @Component({ | 7 | @Component({ |
@@ -17,8 +18,8 @@ export class LanguageChooserComponent { | |||
17 | private modalService: NgbModal, | 18 | private modalService: NgbModal, |
18 | @Inject(LOCALE_ID) private localeId: string | 19 | @Inject(LOCALE_ID) private localeId: string |
19 | ) { | 20 | ) { |
20 | const l = Object.keys(I18N_LOCALES) | 21 | const l = objectKeysTyped(I18N_LOCALES) |
21 | .map(k => ({ id: k, label: I18N_LOCALES[k], iso: getShortLocale(k) })) | 22 | .map(k => ({ id: k, label: I18N_LOCALES[k], iso: getShortLocale(k) })) |
22 | 23 | ||
23 | this.languages = sortBy(l, 'label') | 24 | this.languages = sortBy(l, 'label') |
24 | } | 25 | } |
@@ -35,7 +36,7 @@ export class LanguageChooserComponent { | |||
35 | const english = 'English' | 36 | const english = 'English' |
36 | const locale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) | 37 | const locale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId) |
37 | 38 | ||
38 | if (locale) return I18N_LOCALES[locale] || english | 39 | if (locale) return I18N_LOCALES[locale as keyof typeof I18N_LOCALES] || english |
39 | return english | 40 | return english |
40 | } | 41 | } |
41 | } | 42 | } |
diff --git a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts index f1c1aa03f..ab2e02ad7 100644 --- a/client/src/app/shared/shared-actor-image/actor-avatar.component.ts +++ b/client/src/app/shared/shared-actor-image/actor-avatar.component.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Component, Input, OnChanges, OnInit } from '@angular/core' | 1 | import { Component, Input, OnChanges, OnInit } from '@angular/core' |
2 | import { VideoChannel } from '../shared-main' | 2 | import { VideoChannel } from '../shared-main' |
3 | import { Account } from '../shared-main/account/account.model' | 3 | import { Account } from '../shared-main/account/account.model' |
4 | import { objectKeysTyped } from '@shared/core-utils' | ||
4 | 5 | ||
5 | type ActorInput = { | 6 | type ActorInput = { |
6 | name: string | 7 | name: string |
@@ -154,8 +155,8 @@ export class ActorAvatarComponent implements OnInit, OnChanges { | |||
154 | 'wxyz': 'dark-blue' | 155 | 'wxyz': 'dark-blue' |
155 | } | 156 | } |
156 | 157 | ||
157 | const theme = Object.keys(themes) | 158 | const theme = objectKeysTyped(themes) |
158 | .find(chars => chars.includes(initialLowercase)) | 159 | .find(chars => chars.includes(initialLowercase)) |
159 | 160 | ||
160 | return themes[theme] || 'blue' | 161 | return themes[theme] || 'blue' |
161 | } | 162 | } |
diff --git a/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts b/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts index 208dba721..a12907055 100644 --- a/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts +++ b/client/src/app/shared/shared-custom-markup/dynamic-element.service.ts | |||
@@ -10,6 +10,7 @@ import { | |||
10 | SimpleChanges, | 10 | SimpleChanges, |
11 | Type | 11 | Type |
12 | } from '@angular/core' | 12 | } from '@angular/core' |
13 | import { objectKeysTyped } from '@shared/core-utils' | ||
13 | 14 | ||
14 | @Injectable() | 15 | @Injectable() |
15 | export class DynamicElementService { | 16 | export class DynamicElementService { |
@@ -41,12 +42,12 @@ export class DynamicElementService { | |||
41 | setModel <T> (componentRef: ComponentRef<T>, attributes: Partial<T>) { | 42 | setModel <T> (componentRef: ComponentRef<T>, attributes: Partial<T>) { |
42 | const changes: SimpleChanges = {} | 43 | const changes: SimpleChanges = {} |
43 | 44 | ||
44 | for (const key of Object.keys(attributes)) { | 45 | for (const key of objectKeysTyped(attributes)) { |
45 | const previousValue = componentRef.instance[key] | 46 | const previousValue = componentRef.instance[key] |
46 | const newValue = attributes[key] | 47 | const newValue = attributes[key] |
47 | 48 | ||
48 | componentRef.instance[key] = newValue | 49 | componentRef.instance[key] = newValue |
49 | changes[key] = new SimpleChange(previousValue, newValue, previousValue === undefined) | 50 | changes[key as string] = new SimpleChange(previousValue, newValue, previousValue === undefined) |
50 | } | 51 | } |
51 | 52 | ||
52 | const component = componentRef.instance | 53 | const component = componentRef.instance |
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 21774b7aa..bd93929c9 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 | |||
@@ -2,6 +2,7 @@ import { finalize } from 'rxjs/operators' | |||
2 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' | 2 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' |
3 | import { AuthService, Notifier } from '@app/core' | 3 | import { AuthService, Notifier } from '@app/core' |
4 | import { FindInBulkService } from '@app/shared/shared-search' | 4 | import { FindInBulkService } from '@app/shared/shared-search' |
5 | import { objectKeysTyped } from '@shared/core-utils' | ||
5 | import { Video } from '../../shared-main' | 6 | import { Video } from '../../shared-main' |
6 | import { MiniatureDisplayOptions } from '../../shared-video-miniature' | 7 | import { MiniatureDisplayOptions } from '../../shared-video-miniature' |
7 | import { CustomMarkupComponent } from './shared' | 8 | import { CustomMarkupComponent } from './shared' |
@@ -47,7 +48,7 @@ export class VideoMiniatureMarkupComponent implements CustomMarkupComponent, OnI | |||
47 | 48 | ||
48 | ngOnInit () { | 49 | ngOnInit () { |
49 | if (this.onlyDisplayTitle) { | 50 | if (this.onlyDisplayTitle) { |
50 | for (const key of Object.keys(this.displayOptions)) { | 51 | for (const key of objectKeysTyped(this.displayOptions)) { |
51 | this.displayOptions[key] = false | 52 | this.displayOptions[key] = false |
52 | } | 53 | } |
53 | } | 54 | } |
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 7c2e7db6a..81363be87 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 | |||
@@ -1,6 +1,7 @@ | |||
1 | import { finalize } from 'rxjs/operators' | 1 | import { finalize } from 'rxjs/operators' |
2 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' | 2 | import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core' |
3 | import { AuthService, Notifier } from '@app/core' | 3 | import { AuthService, Notifier } from '@app/core' |
4 | import { objectKeysTyped } from '@shared/core-utils' | ||
4 | import { VideoSortField } from '@shared/models' | 5 | import { VideoSortField } from '@shared/models' |
5 | import { Video, VideoService } from '../../shared-main' | 6 | import { Video, VideoService } from '../../shared-main' |
6 | import { MiniatureDisplayOptions } from '../../shared-video-miniature' | 7 | import { MiniatureDisplayOptions } from '../../shared-video-miniature' |
@@ -66,7 +67,7 @@ export class VideosListMarkupComponent implements CustomMarkupComponent, OnInit | |||
66 | 67 | ||
67 | ngOnInit () { | 68 | ngOnInit () { |
68 | if (this.onlyDisplayTitle) { | 69 | if (this.onlyDisplayTitle) { |
69 | for (const key of Object.keys(this.displayOptions)) { | 70 | for (const key of objectKeysTyped(this.displayOptions)) { |
70 | this.displayOptions[key] = false | 71 | this.displayOptions[key] = false |
71 | } | 72 | } |
72 | } | 73 | } |
diff --git a/client/src/app/shared/shared-forms/form-validator.service.ts b/client/src/app/shared/shared-forms/form-validator.service.ts index 897008242..14ee044b5 100644 --- a/client/src/app/shared/shared-forms/form-validator.service.ts +++ b/client/src/app/shared/shared-forms/form-validator.service.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { Injectable } from '@angular/core' | 1 | import { Injectable } from '@angular/core' |
2 | import { AsyncValidatorFn, FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms' | 2 | import { AsyncValidatorFn, FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms' |
3 | import { objectKeysTyped } from '@shared/core-utils' | ||
3 | import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model' | 4 | import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model' |
4 | import { FormReactiveErrors, FormReactiveValidationMessages } from './form-reactive.service' | 5 | import { FormReactiveErrors, FormReactiveValidationMessages } from './form-reactive.service' |
5 | 6 | ||
@@ -47,13 +48,14 @@ export class FormValidatorService { | |||
47 | obj: BuildFormArgument, | 48 | obj: BuildFormArgument, |
48 | defaultValues: BuildFormDefaultValues = {} | 49 | defaultValues: BuildFormDefaultValues = {} |
49 | ) { | 50 | ) { |
50 | for (const name of Object.keys(obj)) { | 51 | for (const name of objectKeysTyped(obj)) { |
51 | formErrors[name] = '' | 52 | formErrors[name] = '' |
52 | 53 | ||
53 | const field = obj[name] | 54 | const field = obj[name] |
54 | if (this.isRecursiveField(field)) { | 55 | if (this.isRecursiveField(field)) { |
55 | this.updateFormGroup( | 56 | this.updateFormGroup( |
56 | form[name], | 57 | // FIXME: typings |
58 | (form as any)[name], | ||
57 | formErrors[name] as FormReactiveErrors, | 59 | formErrors[name] as FormReactiveErrors, |
58 | validationMessages[name] as FormReactiveValidationMessages, | 60 | validationMessages[name] as FormReactiveValidationMessages, |
59 | obj[name] as BuildFormArgument, | 61 | obj[name] as BuildFormArgument, |
@@ -67,7 +69,7 @@ export class FormValidatorService { | |||
67 | const defaultValue = defaultValues[name] || '' | 69 | const defaultValue = defaultValues[name] || '' |
68 | 70 | ||
69 | form.addControl( | 71 | form.addControl( |
70 | name, | 72 | name + '', |
71 | new FormControl(defaultValue, field?.VALIDATORS as ValidatorFn[], field?.ASYNC_VALIDATORS as AsyncValidatorFn[]) | 73 | new FormControl(defaultValue, field?.VALIDATORS as ValidatorFn[], field?.ASYNC_VALIDATORS as AsyncValidatorFn[]) |
72 | ) | 74 | ) |
73 | } | 75 | } |
@@ -75,7 +77,8 @@ export class FormValidatorService { | |||
75 | 77 | ||
76 | updateTreeValidity (group: FormGroup | FormArray): void { | 78 | updateTreeValidity (group: FormGroup | FormArray): void { |
77 | for (const key of Object.keys(group.controls)) { | 79 | for (const key of Object.keys(group.controls)) { |
78 | const abstractControl = group.controls[key] as FormControl | 80 | // FIXME: typings |
81 | const abstractControl = (group.controls as any)[key] as FormControl | ||
79 | 82 | ||
80 | if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) { | 83 | if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) { |
81 | this.updateTreeValidity(abstractControl) | 84 | this.updateTreeValidity(abstractControl) |
diff --git a/client/src/app/shared/shared-icons/global-icon.component.ts b/client/src/app/shared/shared-icons/global-icon.component.ts index 96179cbe6..eea460831 100644 --- a/client/src/app/shared/shared-icons/global-icon.component.ts +++ b/client/src/app/shared/shared-icons/global-icon.component.ts | |||
@@ -112,7 +112,7 @@ export class GlobalIconComponent implements OnInit { | |||
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | private getSVGContent (options: { name: string }) { | 115 | private getSVGContent (options: { name: GlobalIconName }) { |
116 | return icons[options.name] | 116 | return icons[options.name] |
117 | } | 117 | } |
118 | } | 118 | } |
diff --git a/client/src/app/shared/shared-instance/instance.service.ts b/client/src/app/shared/shared-instance/instance.service.ts index 2defffbbe..3088f0899 100644 --- a/client/src/app/shared/shared-instance/instance.service.ts +++ b/client/src/app/shared/shared-instance/instance.service.ts | |||
@@ -3,6 +3,7 @@ import { catchError, map } from 'rxjs/operators' | |||
3 | import { HttpClient } from '@angular/common/http' | 3 | import { HttpClient } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 4 | import { Injectable } from '@angular/core' |
5 | import { MarkdownService, RestExtractor, ServerService } from '@app/core' | 5 | import { MarkdownService, RestExtractor, ServerService } from '@app/core' |
6 | import { objectKeysTyped } from '@shared/core-utils' | ||
6 | import { peertubeTranslate } from '@shared/core-utils/i18n' | 7 | import { peertubeTranslate } from '@shared/core-utils/i18n' |
7 | import { About } from '@shared/models' | 8 | import { About } from '@shared/models' |
8 | import { environment } from '../../../environments/environment' | 9 | import { environment } from '../../../environments/environment' |
@@ -55,7 +56,7 @@ export class InstanceService { | |||
55 | hardwareInformation: '' | 56 | hardwareInformation: '' |
56 | } | 57 | } |
57 | 58 | ||
58 | for (const key of Object.keys(html)) { | 59 | for (const key of objectKeysTyped(html)) { |
59 | html[key] = await this.markdownService.enhancedMarkdownToHTML({ markdown: about.instance[key] }) | 60 | html[key] = await this.markdownService.enhancedMarkdownToHTML({ markdown: about.instance[key] }) |
60 | } | 61 | } |
61 | 62 | ||
diff --git a/client/src/app/shared/shared-main/misc/help.component.ts b/client/src/app/shared/shared-main/misc/help.component.ts index 37e2abd97..80fe0e160 100644 --- a/client/src/app/shared/shared-main/misc/help.component.ts +++ b/client/src/app/shared/shared-main/misc/help.component.ts | |||
@@ -77,7 +77,7 @@ export class HelpComponent implements OnInit, OnChanges, AfterContentInit { | |||
77 | } | 77 | } |
78 | 78 | ||
79 | private createMarkdownList (rules: string[]) { | 79 | private createMarkdownList (rules: string[]) { |
80 | const rulesToText = { | 80 | const rulesToText: { [id: string]: string } = { |
81 | emphasis: $localize`Emphasis`, | 81 | emphasis: $localize`Emphasis`, |
82 | link: $localize`Links`, | 82 | link: $localize`Links`, |
83 | newline: $localize`New lines`, | 83 | newline: $localize`New lines`, |
diff --git a/client/src/app/shared/shared-main/video/video-edit.model.ts b/client/src/app/shared/shared-main/video/video-edit.model.ts index 91d57cb6b..47eee80d8 100644 --- a/client/src/app/shared/shared-main/video/video-edit.model.ts +++ b/client/src/app/shared/shared-main/video/video-edit.model.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { getAbsoluteAPIUrl } from '@app/helpers' | 1 | import { getAbsoluteAPIUrl } from '@app/helpers' |
2 | import { VideoPrivacy, VideoScheduleUpdate, VideoUpdate } from '@shared/models' | 2 | import { VideoPrivacy, VideoScheduleUpdate, VideoUpdate } from '@shared/models' |
3 | import { VideoDetails } from './video-details.model' | 3 | import { VideoDetails } from './video-details.model' |
4 | import { objectKeysTyped } from '@shared/core-utils' | ||
4 | 5 | ||
5 | export class VideoEdit implements VideoUpdate { | 6 | export class VideoEdit implements VideoUpdate { |
6 | static readonly SPECIAL_SCHEDULED_PRIVACY = -1 | 7 | static readonly SPECIAL_SCHEDULED_PRIVACY = -1 |
@@ -65,8 +66,9 @@ export class VideoEdit implements VideoUpdate { | |||
65 | } | 66 | } |
66 | 67 | ||
67 | patch (values: { [ id: string ]: any }) { | 68 | patch (values: { [ id: string ]: any }) { |
68 | Object.keys(values).forEach((key) => { | 69 | objectKeysTyped(values).forEach(key => { |
69 | this[key] = values[key] | 70 | // FIXME: typings |
71 | (this as any)[key] = values[key] | ||
70 | }) | 72 | }) |
71 | 73 | ||
72 | // If schedule publication, the video is private and will be changed to public privacy | 74 | // If schedule publication, the video is private and will be changed to public privacy |
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts index 1b69aa2d0..32f900f15 100644 --- a/client/src/app/shared/shared-share-modal/video-share.component.ts +++ b/client/src/app/shared/shared-share-modal/video-share.component.ts | |||
@@ -106,7 +106,8 @@ export class VideoShareComponent { | |||
106 | includeVideoInPlaylist: false | 106 | includeVideoInPlaylist: false |
107 | }, { | 107 | }, { |
108 | set: (target, prop, value) => { | 108 | set: (target, prop, value) => { |
109 | target[prop] = value | 109 | // FIXME: typings |
110 | (target as any)[prop] = value | ||
110 | 111 | ||
111 | if (prop === 'embedP2P') { | 112 | if (prop === 'embedP2P') { |
112 | // Auto enabled warning title if P2P is enabled | 113 | // Auto enabled warning title if P2P is enabled |
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 4135542dc..cac82d8d0 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,4 @@ | |||
1 | import { mapValues, pick } from 'lodash-es' | 1 | import { mapValues } from 'lodash-es' |
2 | import { firstValueFrom } from 'rxjs' | 2 | import { firstValueFrom } from 'rxjs' |
3 | import { tap } from 'rxjs/operators' | 3 | import { tap } from 'rxjs/operators' |
4 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' | 4 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' |
@@ -6,11 +6,12 @@ import { HooksService } from '@app/core' | |||
6 | import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' |
7 | import { logger } from '@root-helpers/logger' | 7 | import { logger } from '@root-helpers/logger' |
8 | import { videoRequiresAuth } from '@root-helpers/video' | 8 | import { videoRequiresAuth } from '@root-helpers/video' |
9 | import { objectKeysTyped, pick } from '@shared/core-utils' | ||
9 | import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models' | 10 | import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models' |
10 | import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoFileTokenService, VideoService } from '../shared-main' | 11 | import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoFileTokenService, VideoService } from '../shared-main' |
11 | 12 | ||
12 | type DownloadType = 'video' | 'subtitles' | 13 | type DownloadType = 'video' | 'subtitles' |
13 | type FileMetadata = { [key: string]: { label: string, value: string } } | 14 | type FileMetadata = { [key: string]: { label: string, value: string | number } } |
14 | 15 | ||
15 | @Component({ | 16 | @Component({ |
16 | selector: 'my-video-download', | 17 | selector: 'my-video-download', |
@@ -218,10 +219,10 @@ export class VideoDownloadComponent { | |||
218 | const keyToTranslateFunction = { | 219 | const keyToTranslateFunction = { |
219 | encoder: (value: string) => ({ label: $localize`Encoder`, value }), | 220 | encoder: (value: string) => ({ label: $localize`Encoder`, value }), |
220 | format_long_name: (value: string) => ({ label: $localize`Format name`, value }), | 221 | format_long_name: (value: string) => ({ label: $localize`Format name`, value }), |
221 | size: (value: number) => ({ label: $localize`Size`, value: this.bytesPipe.transform(value, 2) }), | 222 | size: (value: number | string) => ({ label: $localize`Size`, value: this.bytesPipe.transform(+value, 2) }), |
222 | bit_rate: (value: number) => ({ | 223 | bit_rate: (value: number | string) => ({ |
223 | label: $localize`Bitrate`, | 224 | label: $localize`Bitrate`, |
224 | value: `${this.numbersPipe.transform(value)}bps` | 225 | value: `${this.numbersPipe.transform(+value)}bps` |
225 | }) | 226 | }) |
226 | } | 227 | } |
227 | 228 | ||
@@ -230,8 +231,8 @@ export class VideoDownloadComponent { | |||
230 | delete sanitizedFormat.tags | 231 | delete sanitizedFormat.tags |
231 | 232 | ||
232 | return mapValues( | 233 | return mapValues( |
233 | pick(sanitizedFormat, Object.keys(keyToTranslateFunction)), | 234 | pick(sanitizedFormat, objectKeysTyped(keyToTranslateFunction)), |
234 | (val, key) => keyToTranslateFunction[key](val) | 235 | (val: string, key: keyof typeof keyToTranslateFunction) => keyToTranslateFunction[key](val) |
235 | ) | 236 | ) |
236 | } | 237 | } |
237 | 238 | ||
@@ -242,29 +243,29 @@ export class VideoDownloadComponent { | |||
242 | let keyToTranslateFunction = { | 243 | let keyToTranslateFunction = { |
243 | codec_long_name: (value: string) => ({ label: $localize`Codec`, value }), | 244 | codec_long_name: (value: string) => ({ label: $localize`Codec`, value }), |
244 | profile: (value: string) => ({ label: $localize`Profile`, value }), | 245 | profile: (value: string) => ({ label: $localize`Profile`, value }), |
245 | bit_rate: (value: number) => ({ | 246 | bit_rate: (value: number | string) => ({ |
246 | label: $localize`Bitrate`, | 247 | label: $localize`Bitrate`, |
247 | value: `${this.numbersPipe.transform(value)}bps` | 248 | value: `${this.numbersPipe.transform(+value)}bps` |
248 | }) | 249 | }) |
249 | } | 250 | } |
250 | 251 | ||
251 | if (type === 'video') { | 252 | if (type === 'video') { |
252 | keyToTranslateFunction = Object.assign(keyToTranslateFunction, { | 253 | keyToTranslateFunction = Object.assign(keyToTranslateFunction, { |
253 | width: (value: number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }), | 254 | width: (value: string | number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }), |
254 | display_aspect_ratio: (value: string) => ({ label: $localize`Aspect ratio`, value }), | 255 | display_aspect_ratio: (value: string) => ({ label: $localize`Aspect ratio`, value }), |
255 | avg_frame_rate: (value: string) => ({ label: $localize`Average frame rate`, value }), | 256 | avg_frame_rate: (value: string) => ({ label: $localize`Average frame rate`, value }), |
256 | pix_fmt: (value: string) => ({ label: $localize`Pixel format`, value }) | 257 | pix_fmt: (value: string) => ({ label: $localize`Pixel format`, value }) |
257 | }) | 258 | }) |
258 | } else { | 259 | } else { |
259 | keyToTranslateFunction = Object.assign(keyToTranslateFunction, { | 260 | keyToTranslateFunction = Object.assign(keyToTranslateFunction, { |
260 | sample_rate: (value: number) => ({ label: $localize`Sample rate`, value }), | 261 | sample_rate: (value: string | number) => ({ label: $localize`Sample rate`, value }), |
261 | channel_layout: (value: number) => ({ label: $localize`Channel Layout`, value }) | 262 | channel_layout: (value: string | number) => ({ label: $localize`Channel Layout`, value }) |
262 | }) | 263 | }) |
263 | } | 264 | } |
264 | 265 | ||
265 | return mapValues( | 266 | return mapValues( |
266 | pick(stream, Object.keys(keyToTranslateFunction)), | 267 | pick(stream, Object.keys(keyToTranslateFunction)), |
267 | (val, key) => keyToTranslateFunction[key](val) | 268 | (val: string, key: keyof typeof keyToTranslateFunction) => keyToTranslateFunction[key](val) |
268 | ) | 269 | ) |
269 | } | 270 | } |
270 | 271 | ||
diff --git a/client/src/app/shared/shared-video-miniature/video-filters.model.ts b/client/src/app/shared/shared-video-miniature/video-filters.model.ts index 6b4b72c75..4db73b25a 100644 --- a/client/src/app/shared/shared-video-miniature/video-filters.model.ts +++ b/client/src/app/shared/shared-video-miniature/video-filters.model.ts | |||
@@ -84,7 +84,7 @@ export class VideoFilters { | |||
84 | if (specificKey && specificKey !== key) continue | 84 | if (specificKey && specificKey !== key) continue |
85 | 85 | ||
86 | // FIXME: typings | 86 | // FIXME: typings |
87 | this[key as any] = value | 87 | (this as any)[key] = value |
88 | } | 88 | } |
89 | 89 | ||
90 | this.buildActiveFilters() | 90 | this.buildActiveFilters() |
diff --git a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts index 460a0080e..86fe502e2 100644 --- a/client/src/app/shared/shared-video-miniature/videos-selection.component.ts +++ b/client/src/app/shared/shared-video-miniature/videos-selection.component.ts | |||
@@ -2,6 +2,7 @@ import { Observable, Subject } from 'rxjs' | |||
2 | import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core' | 2 | import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core' |
3 | import { ComponentPagination, Notifier, User } from '@app/core' | 3 | import { ComponentPagination, Notifier, User } from '@app/core' |
4 | import { logger } from '@root-helpers/logger' | 4 | import { logger } from '@root-helpers/logger' |
5 | import { objectKeysTyped } from '@shared/core-utils' | ||
5 | import { ResultList, VideosExistInPlaylists, VideoSortField } from '@shared/models' | 6 | import { ResultList, VideosExistInPlaylists, VideoSortField } from '@shared/models' |
6 | import { PeerTubeTemplateDirective, Video } from '../shared-main' | 7 | import { PeerTubeTemplateDirective, Video } from '../shared-main' |
7 | import { MiniatureDisplayOptions } from './video-miniature.component' | 8 | import { MiniatureDisplayOptions } from './video-miniature.component' |
@@ -93,7 +94,7 @@ export class VideosSelectionComponent implements AfterContentInit { | |||
93 | } | 94 | } |
94 | 95 | ||
95 | isInSelectionMode () { | 96 | isInSelectionMode () { |
96 | return Object.keys(this._selection).some(k => this._selection[k] === true) | 97 | return objectKeysTyped(this._selection).some(k => this._selection[k] === true) |
97 | } | 98 | } |
98 | 99 | ||
99 | videoById (index: number, video: Video) { | 100 | videoById (index: number, video: Video) { |
diff --git a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts index 63f27eecf..d05d6193c 100644 --- a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts +++ b/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts | |||
@@ -349,7 +349,7 @@ class Html5Hlsjs { | |||
349 | } | 349 | } |
350 | 350 | ||
351 | private _oneLevelObjClone (obj: { [ id: string ]: any }) { | 351 | private _oneLevelObjClone (obj: { [ id: string ]: any }) { |
352 | const result = {} | 352 | const result: { [id: string]: any } = {} |
353 | const objKeys = Object.keys(obj) | 353 | const objKeys = Object.keys(obj) |
354 | for (let i = 0; i < objKeys.length; i++) { | 354 | for (let i = 0; i < objKeys.length; i++) { |
355 | result[objKeys[i]] = obj[objKeys[i]] | 355 | result[objKeys[i]] = obj[objKeys[i]] |
diff --git a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts index 6e9bcf103..44a31bfb4 100644 --- a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts +++ b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts | |||
@@ -79,7 +79,7 @@ function fetchSha256Segments (options: { | |||
79 | segmentsSha256Url: string | 79 | segmentsSha256Url: string |
80 | authorizationHeader: () => string | 80 | authorizationHeader: () => string |
81 | requiresAuth: boolean | 81 | requiresAuth: boolean |
82 | }) { | 82 | }): Promise<SegmentsJSON> { |
83 | const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options | 83 | const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options |
84 | 84 | ||
85 | const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url) | 85 | const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url) |
diff --git a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts index 46d009410..3dde44a60 100644 --- a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts | |||
@@ -339,7 +339,7 @@ class WebTorrentPlugin extends Plugin { | |||
339 | if (err.message.indexOf('incorrect info hash') !== -1) { | 339 | if (err.message.indexOf('incorrect info hash') !== -1) { |
340 | logger.error('Incorrect info hash detected, falling back to torrent file.') | 340 | logger.error('Incorrect info hash detected, falling back to torrent file.') |
341 | const newOptions = { forcePlay: true, seek: options.seek } | 341 | const newOptions = { forcePlay: true, seek: options.seek } |
342 | return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done) | 342 | return this.addTorrent((this.torrent as any)['xs'], previousVideoFile, newOptions, done) |
343 | } | 343 | } |
344 | 344 | ||
345 | // Remote instance is down | 345 | // Remote instance is down |
@@ -582,7 +582,7 @@ class WebTorrentPlugin extends Plugin { | |||
582 | private stopTorrent (torrent: WebTorrent.Torrent) { | 582 | private stopTorrent (torrent: WebTorrent.Torrent) { |
583 | torrent.pause() | 583 | torrent.pause() |
584 | // Pause does not remove actual peers (in particular the webseed peer) | 584 | // Pause does not remove actual peers (in particular the webseed peer) |
585 | torrent.removePeer(torrent['ws']) | 585 | torrent.removePeer((torrent as any)['ws']) |
586 | } | 586 | } |
587 | 587 | ||
588 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { | 588 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { |
diff --git a/client/src/root-helpers/plugins-manager.ts b/client/src/root-helpers/plugins-manager.ts index f99c7598d..fd7b5233b 100644 --- a/client/src/root-helpers/plugins-manager.ts +++ b/client/src/root-helpers/plugins-manager.ts | |||
@@ -317,7 +317,7 @@ async function dynamicImport (url: string) { | |||
317 | const script = document.createElement('script') | 317 | const script = document.createElement('script') |
318 | 318 | ||
319 | const destructor = () => { | 319 | const destructor = () => { |
320 | delete window[vector] | 320 | delete window[vector as any] |
321 | script.onerror = null | 321 | script.onerror = null |
322 | script.onload = null | 322 | script.onload = null |
323 | script.remove() | 323 | script.remove() |
@@ -333,7 +333,7 @@ async function dynamicImport (url: string) { | |||
333 | destructor() | 333 | destructor() |
334 | } | 334 | } |
335 | script.onload = () => { | 335 | script.onload = () => { |
336 | resolve(window[vector]) | 336 | resolve(window[vector as any]) |
337 | destructor() | 337 | destructor() |
338 | } | 338 | } |
339 | const loader = `import * as m from "${url}"; window.${vector} = m;` // export Module | 339 | const loader = `import * as m from "${url}"; window.${vector} = m;` // export Module |
diff --git a/client/src/root-helpers/video.ts b/client/src/root-helpers/video.ts index 01feddbdc..9022b908b 100644 --- a/client/src/root-helpers/video.ts +++ b/client/src/root-helpers/video.ts | |||
@@ -21,7 +21,7 @@ function buildVideoOrPlaylistEmbed (options: { | |||
21 | const wrapper = document.createElement('div') | 21 | const wrapper = document.createElement('div') |
22 | 22 | ||
23 | wrapper.style.position = 'relative' | 23 | wrapper.style.position = 'relative' |
24 | wrapper.style['padding-top'] = '56.25%' | 24 | wrapper.style.paddingTop = '56.25%' |
25 | 25 | ||
26 | iframe.style.position = 'absolute' | 26 | iframe.style.position = 'absolute' |
27 | iframe.style.inset = '0' | 27 | iframe.style.inset = '0' |
diff --git a/client/src/standalone/player/player.ts b/client/src/standalone/player/player.ts index bbe37a42b..75487258b 100644 --- a/client/src/standalone/player/player.ts +++ b/client/src/standalone/player/player.ts | |||
@@ -233,4 +233,4 @@ export class PeerTubePlayer { | |||
233 | } | 233 | } |
234 | 234 | ||
235 | // put it on the window as well as the export | 235 | // put it on the window as well as the export |
236 | (window['PeerTubePlayer'] as any) = PeerTubePlayer | 236 | (window as any)['PeerTubePlayer'] = PeerTubePlayer |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index d268f4762..cc4274b99 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -52,7 +52,7 @@ export class PeerTubeEmbed { | |||
52 | this.liveManager = new LiveManager(this.playerHTML) | 52 | this.liveManager = new LiveManager(this.playerHTML) |
53 | 53 | ||
54 | try { | 54 | try { |
55 | this.config = JSON.parse(window['PeerTubeServerConfig']) | 55 | this.config = JSON.parse((window as any)['PeerTubeServerConfig']) |
56 | } catch (err) { | 56 | } catch (err) { |
57 | logger.error('Cannot parse HTML config.', err) | 57 | logger.error('Cannot parse HTML config.', err) |
58 | } | 58 | } |
@@ -254,9 +254,9 @@ export class PeerTubeEmbed { | |||
254 | this.player.dispose() | 254 | this.player.dispose() |
255 | this.playerHTML.removePlayerElement() | 255 | this.playerHTML.removePlayerElement() |
256 | this.playerHTML.displayError('This video is not available because the remote instance is not responding.', translations) | 256 | this.playerHTML.displayError('This video is not available because the remote instance is not responding.', translations) |
257 | }) | 257 | }); |
258 | 258 | ||
259 | window['videojsPlayer'] = this.player | 259 | (window as any)['videojsPlayer'] = this.player |
260 | 260 | ||
261 | this.buildCSS() | 261 | this.buildCSS() |
262 | this.buildPlayerDock(video) | 262 | this.buildPlayerDock(video) |
diff --git a/client/src/standalone/videos/test-embed.ts b/client/src/standalone/videos/test-embed.ts index ab5262902..b34df11ee 100644 --- a/client/src/standalone/videos/test-embed.ts +++ b/client/src/standalone/videos/test-embed.ts | |||
@@ -22,9 +22,9 @@ window.addEventListener('load', async () => { | |||
22 | mainElement.appendChild(iframe) | 22 | mainElement.appendChild(iframe) |
23 | 23 | ||
24 | logger.info('Document finished loading.') | 24 | logger.info('Document finished loading.') |
25 | const player = new PeerTubePlayer(document.querySelector('iframe')) | 25 | const player = new PeerTubePlayer(document.querySelector('iframe')); |
26 | 26 | ||
27 | window['player'] = player | 27 | (window as any)['player'] = player |
28 | 28 | ||
29 | logger.info('Awaiting player ready...') | 29 | logger.info('Awaiting player ready...') |
30 | await player.ready | 30 | await player.ready |
diff --git a/client/tsconfig.json b/client/tsconfig.json index 1668cfced..785ed1c6c 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json | |||
@@ -10,7 +10,6 @@ | |||
10 | "experimentalDecorators": true, | 10 | "experimentalDecorators": true, |
11 | "noImplicitAny": true, | 11 | "noImplicitAny": true, |
12 | "noImplicitThis": true, | 12 | "noImplicitThis": true, |
13 | "suppressImplicitAnyIndexErrors": true, | ||
14 | "alwaysStrict": true, | 13 | "alwaysStrict": true, |
15 | "importHelpers": true, | 14 | "importHelpers": true, |
16 | "allowSyntheticDefaultImports": true, | 15 | "allowSyntheticDefaultImports": true, |
diff --git a/shared/core-utils/common/object.ts b/shared/core-utils/common/object.ts index 9780b2594..1276bfcc7 100644 --- a/shared/core-utils/common/object.ts +++ b/shared/core-utils/common/object.ts | |||
@@ -23,10 +23,18 @@ function omit <O extends object, K extends keyof O> (object: O, keys: K[]): Excl | |||
23 | return result | 23 | return result |
24 | } | 24 | } |
25 | 25 | ||
26 | function objectKeysTyped <O extends object, K extends keyof O> (object: O): K[] { | ||
27 | return (Object.keys(object) as K[]) | ||
28 | } | ||
29 | |||
26 | function getKeys <O extends object, K extends keyof O> (object: O, keys: K[]): K[] { | 30 | function getKeys <O extends object, K extends keyof O> (object: O, keys: K[]): K[] { |
27 | return (Object.keys(object) as K[]).filter(k => keys.includes(k)) | 31 | return (Object.keys(object) as K[]).filter(k => keys.includes(k)) |
28 | } | 32 | } |
29 | 33 | ||
34 | function hasKey <T extends object> (obj: T, k: keyof any): k is keyof T { | ||
35 | return k in obj | ||
36 | } | ||
37 | |||
30 | function sortObjectComparator (key: string, order: 'asc' | 'desc') { | 38 | function sortObjectComparator (key: string, order: 'asc' | 'desc') { |
31 | return (a: any, b: any) => { | 39 | return (a: any, b: any) => { |
32 | if (a[key] < b[key]) { | 40 | if (a[key] < b[key]) { |
@@ -69,7 +77,9 @@ function simpleObjectsDeepEqual (a: any, b: any) { | |||
69 | export { | 77 | export { |
70 | pick, | 78 | pick, |
71 | omit, | 79 | omit, |
80 | objectKeysTyped, | ||
72 | getKeys, | 81 | getKeys, |
82 | hasKey, | ||
73 | shallowCopy, | 83 | shallowCopy, |
74 | sortObjectComparator, | 84 | sortObjectComparator, |
75 | simpleObjectsDeepEqual | 85 | simpleObjectsDeepEqual |
diff --git a/shared/core-utils/i18n/i18n.ts b/shared/core-utils/i18n/i18n.ts index 38c1b0cc9..54b54077a 100644 --- a/shared/core-utils/i18n/i18n.ts +++ b/shared/core-utils/i18n/i18n.ts | |||
@@ -103,9 +103,9 @@ export function is18nLocale (locale: string) { | |||
103 | export function getCompleteLocale (locale: string) { | 103 | export function getCompleteLocale (locale: string) { |
104 | if (!locale) return locale | 104 | if (!locale) return locale |
105 | 105 | ||
106 | if (I18N_LOCALE_ALIAS[locale]) return I18N_LOCALE_ALIAS[locale] | 106 | const found = (I18N_LOCALE_ALIAS as any)[locale] as string |
107 | 107 | ||
108 | return locale | 108 | return found || locale |
109 | } | 109 | } |
110 | 110 | ||
111 | export function getShortLocale (locale: string) { | 111 | export function getShortLocale (locale: string) { |
diff --git a/shared/core-utils/renderer/html.ts b/shared/core-utils/renderer/html.ts index 877f2ec55..365bf7612 100644 --- a/shared/core-utils/renderer/html.ts +++ b/shared/core-utils/renderer/html.ts | |||
@@ -56,7 +56,7 @@ export function getCustomMarkupSanitizeOptions (additionalAllowedTags: string[] | |||
56 | export function escapeHTML (stringParam: string) { | 56 | export function escapeHTML (stringParam: string) { |
57 | if (!stringParam) return '' | 57 | if (!stringParam) return '' |
58 | 58 | ||
59 | const entityMap = { | 59 | const entityMap: { [id: string ]: string } = { |
60 | '&': '&', | 60 | '&': '&', |
61 | '<': '<', | 61 | '<': '<', |
62 | '>': '>', | 62 | '>': '>', |
diff --git a/shared/models/videos/playlist/video-exist-in-playlist.model.ts b/shared/models/videos/playlist/video-exist-in-playlist.model.ts index bc803a99c..6d06c0f4d 100644 --- a/shared/models/videos/playlist/video-exist-in-playlist.model.ts +++ b/shared/models/videos/playlist/video-exist-in-playlist.model.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | export type VideosExistInPlaylists = { | 1 | export type VideosExistInPlaylists = { |
2 | [videoId: number ]: VideoExistInPlaylist[] | 2 | [videoId: number]: VideoExistInPlaylist[] |
3 | } | 3 | } |
4 | export type CachedVideosExistInPlaylists = { | 4 | export type CachedVideosExistInPlaylists = { |
5 | [videoId: number ]: CachedVideoExistInPlaylist[] | 5 | [videoId: number]: CachedVideoExistInPlaylist[] |
6 | } | 6 | } |
7 | 7 | ||
8 | export type CachedVideoExistInPlaylist = { | 8 | export type CachedVideoExistInPlaylist = { |