]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Remove suppressImplicitAnyIndexErrors
authorChocobozzz <me@florianbigard.com>
Wed, 24 May 2023 14:48:54 +0000 (16:48 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 24 May 2023 14:56:05 +0000 (16:56 +0200)
It's deprecated by TS

41 files changed:
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
client/src/app/+admin/overview/users/user-edit/user-edit.ts
client/src/app/+admin/plugins/plugin-list-installed/plugin-list-installed.component.ts
client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts
client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.ts
client/src/app/+my-library/my-videos/my-videos.component.ts
client/src/app/+search/search-filters.component.ts
client/src/app/+stats/video/video-stats.component.ts
client/src/app/+videos/+video-edit/shared/video-edit-utils.ts
client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
client/src/app/+videos/video-list/overview/overview.service.ts
client/src/app/core/server/server.service.ts
client/src/app/core/users/user-local-storage.service.ts
client/src/app/core/users/user.model.ts
client/src/app/menu/language-chooser.component.ts
client/src/app/shared/shared-actor-image/actor-avatar.component.ts
client/src/app/shared/shared-custom-markup/dynamic-element.service.ts
client/src/app/shared/shared-custom-markup/peertube-custom-tags/video-miniature-markup.component.ts
client/src/app/shared/shared-custom-markup/peertube-custom-tags/videos-list-markup.component.ts
client/src/app/shared/shared-forms/form-validator.service.ts
client/src/app/shared/shared-icons/global-icon.component.ts
client/src/app/shared/shared-instance/instance.service.ts
client/src/app/shared/shared-main/misc/help.component.ts
client/src/app/shared/shared-main/video/video-edit.model.ts
client/src/app/shared/shared-share-modal/video-share.component.ts
client/src/app/shared/shared-video-miniature/video-download.component.ts
client/src/app/shared/shared-video-miniature/video-filters.model.ts
client/src/app/shared/shared-video-miniature/videos-selection.component.ts
client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
client/src/assets/player/shared/p2p-media-loader/segment-validator.ts
client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts
client/src/root-helpers/plugins-manager.ts
client/src/root-helpers/video.ts
client/src/standalone/player/player.ts
client/src/standalone/videos/embed.ts
client/src/standalone/videos/test-embed.ts
client/tsconfig.json
shared/core-utils/common/object.ts
shared/core-utils/i18n/i18n.ts
shared/core-utils/renderer/html.ts
shared/models/videos/playlist/video-exist-in-playlist.model.ts

index 30e4aa5d54d29aa86e1899dcea02ef44080089d0..2c3b7560d616606c9b72c6252d17409c1a49148b 100644 (file)
@@ -273,11 +273,11 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
 
     const defaultValues = {
       transcoding: {
-        resolutions: {}
+        resolutions: {} as { [id: string]: string }
       },
       live: {
         transcoding: {
-          resolutions: {}
+          resolutions: {} as { [id: string]: string }
         }
       }
     }
index 5d6c6a91edd62d478bf7d1f6034b65e044b01ec9..9547da2d1012703f4214c7697eeba8dcd7887090 100644 (file)
@@ -53,8 +53,8 @@ export abstract class UserEdit extends FormReactive implements OnInit {
     this.serverService.getServerLocale()
       .subscribe(translations => {
         if (authUser.role.id === UserRole.ADMINISTRATOR) {
-          this.roles = Object.keys(USER_ROLE_LABELS)
-                .map(key => ({ value: key.toString(), label: peertubeTranslate(USER_ROLE_LABELS[key], translations) }))
+          this.roles = Object.entries(USER_ROLE_LABELS)
+                .map(([ key, value ]) => ({ value: key.toString(), label: peertubeTranslate(value, translations) }))
           return
         }
 
index 2fdc14d85959fe3376bec223e18c6f05afdabb5e..3fa1c56dc65827beaedb24fc65834e9a7210182a 100644 (file)
@@ -104,7 +104,7 @@ export class PluginListInstalledComponent implements OnInit {
   }
 
   isUninstalling (plugin: PeerTubePlugin) {
-    return !!this.uninstall[this.getPluginKey(plugin)]
+    return !!this.uninstalling[this.getPluginKey(plugin)]
   }
 
   isTheme (plugin: PeerTubePlugin) {
index 769ab647a66a58d5c935c88b57ae4e906a6b4ab2..8faba676e928f9e95dd4b3fcd008808b6433144f 100644 (file)
@@ -141,11 +141,11 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
   }
 
   private loadNotificationSettings () {
-    for (const key of Object.keys(this.user.notificationSettings)) {
+    for (const key of Object.keys(this.user.notificationSettings) as (keyof UserNotificationSetting)[]) {
       const value = this.user.notificationSettings[key]
-      this.emailNotifications[key] = value & UserNotificationSettingValue.EMAIL
+      this.emailNotifications[key] = !!(value & UserNotificationSettingValue.EMAIL)
 
-      this.webNotifications[key] = value & UserNotificationSettingValue.WEB
+      this.webNotifications[key] = !!(value & UserNotificationSettingValue.WEB)
     }
   }
 }
index 74dbe222dfd396faf6db1d02f86095fd899881f6..1f7287f445b99b4346681a117ed02e01578205ad 100644 (file)
@@ -124,7 +124,7 @@ export class MyVideoChannelSyncsComponent extends RestTable implements OnInit {
     return '/my-library/video-channel-syncs/create'
   }
 
-  getSyncStateClass (stateId: number) {
+  getSyncStateClass (stateId: VideoChannelSyncState) {
     return [ 'pt-badge', MyVideoChannelSyncsComponent.STATE_CLASS_BY_ID[stateId] ]
   }
 
index 46dd304bac641cb99503335448114c8f2796c29d..b618b3f8823c3e1d79b82507459a38eec80d639b 100644 (file)
@@ -171,15 +171,15 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
       .subscribe(result => {
         this.videosContainedInPlaylists = Object.keys(result).reduce((acc, videoId) => ({
           ...acc,
-          [videoId]: uniqBy(result[videoId], (p: VideoExistInPlaylist) => p.playlistId)
+          [videoId]: uniqBy(result[+videoId], (p: VideoExistInPlaylist) => p.playlistId)
         }), this.videosContainedInPlaylists)
       })
   }
 
   async deleteSelectedVideos () {
-    const toDeleteVideosIds = Object.keys(this.selection)
-                                    .filter(k => this.selection[k] === true)
-                                    .map(k => parseInt(k, 10))
+    const toDeleteVideosIds = Object.entries(this.selection)
+                                    .filter(([ _k, v ]) => v === true)
+                                    .map(([ k, _v ]) => parseInt(k, 10))
 
     const res = await this.confirmService.confirm(
       prepareIcu($localize`Do you really want to delete {length, plural, =1 {this video} other {{length} videos}}?`)(
index f9de04706218d7106440e81a0d9d78e308fe56e9..a6fc51383437db2f89cbcb833c3a4275f5014591 100644 (file)
@@ -118,11 +118,11 @@ export class SearchFiltersComponent implements OnInit {
     this.onDurationOrPublishedUpdated()
   }
 
-  resetField (fieldName: string, value?: any) {
-    this.advancedSearch[fieldName] = value
+  resetField (fieldName: keyof AdvancedSearch, value?: any) {
+    (this.advancedSearch as any)[fieldName] = value
   }
 
-  resetLocalField (fieldName: string, value?: any) {
+  resetLocalField (fieldName: keyof SearchFiltersComponent, value?: any) {
     this[fieldName] = value
     this.onDurationOrPublishedUpdated()
   }
index 18312ec333ca4a050e2621c3e76e30a643049d5c..fa5e33ab6e3dc1458836bef49e7a86ab195d0b11 100644 (file)
@@ -47,7 +47,7 @@ export class VideoStatsComponent implements OnInit {
   chartHeight = '300px'
   chartWidth: string = null
 
-  availableCharts: { id: string, label: string, zoomEnabled: boolean }[] = []
+  availableCharts: { id: ActiveGraphId, label: string, zoomEnabled: boolean }[] = []
   activeGraphId: ActiveGraphId = 'viewers'
 
   video: VideoDetails
index db1ef8d73c5374698c2c2df7d30105d596a04c47..214bde68056f3370e8dd89d847545ce60ae39095 100644 (file)
@@ -8,11 +8,11 @@ function hydrateFormFromVideo (formGroup: FormGroup, video: VideoEdit, thumbnail
 
   const objects = [
     {
-      url: 'thumbnailUrl',
+      url: 'thumbnailUrl' as 'thumbnailUrl',
       name: 'thumbnailfile'
     },
     {
-      url: 'previewUrl',
+      url: 'previewUrl' as 'previewUrl',
       name: 'previewfile'
     }
   ]
index 28edcfdcb8d24869a7bacdb3422eeaf9e535c9ba..96bdb28c9088128627e533b3cb7f54bd9096bfa6 100644 (file)
@@ -263,8 +263,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
       this.syndicationItems = this.videoCommentService.getVideoCommentsFeeds(this.video)
       this.loadMoreThreads()
 
-      if (this.activatedRoute.params['threadId']) {
-        this.processHighlightedThread(+this.activatedRoute.params['threadId'])
+      if (this.activatedRoute.snapshot.params['threadId']) {
+        this.processHighlightedThread(+this.activatedRoute.snapshot.params['threadId'])
       }
     }
   }
index 12d2aa1cb451d4fc03c9a346fcdd17f905f6d8c7..4a7d9c7c50dfdf796e9a6a0bb2daac9ce2793ff2 100644 (file)
@@ -5,6 +5,7 @@ import { Injectable } from '@angular/core'
 import { RestExtractor, ServerService } from '@app/core'
 import { immutableAssign } from '@app/helpers'
 import { VideoService } from '@app/shared/shared-main'
+import { objectKeysTyped } from '@shared/core-utils'
 import { peertubeTranslate } from '@shared/core-utils/i18n'
 import { VideosOverview as VideosOverviewServer } from '@shared/models'
 import { environment } from '../../../../environments/environment'
@@ -42,7 +43,7 @@ export class OverviewService {
     }
 
     // Build videos objects
-    for (const key of Object.keys(serverVideosOverview)) {
+    for (const key of objectKeysTyped(serverVideosOverview)) {
       for (const object of serverVideosOverview[key]) {
         observables.push(
           of(object.videos)
@@ -50,7 +51,9 @@ export class OverviewService {
               switchMap(videos => this.videosService.extractVideos({ total: 0, data: videos })),
               map(result => result.data),
               tap(videos => {
-                videosOverviewResult[key].push(immutableAssign(object, { videos }))
+                // FIXME: typings & lint
+                // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+                videosOverviewResult[key].push(immutableAssign(object, { videos }) as any)
               })
             )
         )
index 9f191f0a6a0957c4852f0225fd0402e05385e3ec..fc269749bf36d0d7df5df070b83de7403fb4ad80 100644 (file)
@@ -193,7 +193,8 @@ export class ServerService {
   }
 
   private loadHTMLConfigLocally () {
-    const configString = window['PeerTubeServerConfig']
+    // FIXME: typings
+    const configString = (window as any)['PeerTubeServerConfig']
     if (!configString) {
       throw new Error('Could not find PeerTubeServerConfig in HTML')
     }
index 1e629249a692e3b54d589732d274fffd318d15ea..a87f3b98a426f8d618a8868bb8187c0f3e638ee9 100644 (file)
@@ -4,7 +4,8 @@ import { Injectable } from '@angular/core'
 import { AuthService, AuthStatus } from '@app/core/auth'
 import { getBoolOrDefault } from '@root-helpers/local-storage-utils'
 import { logger } from '@root-helpers/logger'
-import { UserLocalStorageKeys, OAuthUserTokens } from '@root-helpers/users'
+import { OAuthUserTokens, UserLocalStorageKeys } from '@root-helpers/users'
+import { objectKeysTyped } from '@shared/core-utils'
 import { UserRole, UserUpdateMe } from '@shared/models'
 import { NSFWPolicyType } from '@shared/models/videos'
 import { ServerService } from '../server'
@@ -122,7 +123,7 @@ export class UserLocalStorageService {
   }
 
   setUserInfo (profile: UserUpdateMe) {
-    const localStorageKeys: { [ id in keyof UserUpdateMe ]: string } = {
+    const localStorageKeys = {
       nsfwPolicy: UserLocalStorageKeys.NSFW_POLICY,
       p2pEnabled: UserLocalStorageKeys.P2P_ENABLED,
       autoPlayVideo: UserLocalStorageKeys.AUTO_PLAY_VIDEO,
@@ -132,7 +133,7 @@ export class UserLocalStorageService {
       videoLanguages: UserLocalStorageKeys.VIDEO_LANGUAGES
     }
 
-    const obj = Object.keys(localStorageKeys)
+    const obj: [ string, string | boolean | string[] ][] = objectKeysTyped(localStorageKeys)
       .filter(key => key in profile)
       .map(key => ([ localStorageKeys[key], profile[key] ]))
 
index 2d783145f8ee7e88ffc843bd7d8cbb6f292de1aa..d57608f1c66310b04debe4cc738b95e3f570ee8a 100644 (file)
@@ -1,4 +1,5 @@
 import { Account } from '@app/shared/shared-main/account/account.model'
+import { objectKeysTyped } from '@shared/core-utils'
 import { hasUserRight } from '@shared/core-utils/users'
 import {
   ActorImage,
@@ -130,8 +131,9 @@ export class User implements UserServerModel {
   }
 
   patch (obj: UserServerModel) {
-    for (const key of Object.keys(obj)) {
-      this[key] = obj[key]
+    for (const key of objectKeysTyped(obj)) {
+      // FIXME: typings
+      (this as any)[key] = obj[key]
     }
 
     if (obj.account !== undefined) {
index b42e41855902228dc91a5f7a2f4a3257bdcea3b4..f7ae697173c67a806846ea79499180d699d7f0b8 100644 (file)
@@ -1,6 +1,7 @@
 import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core'
 import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers'
 import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { objectKeysTyped } from '@shared/core-utils'
 import { getCompleteLocale, getShortLocale, I18N_LOCALES } from '@shared/core-utils/i18n'
 
 @Component({
@@ -17,8 +18,8 @@ export class LanguageChooserComponent {
     private modalService: NgbModal,
     @Inject(LOCALE_ID) private localeId: string
   ) {
-    const l = Object.keys(I18N_LOCALES)
-                    .map(k => ({ id: k, label: I18N_LOCALES[k], iso: getShortLocale(k) }))
+    const l = objectKeysTyped(I18N_LOCALES)
+      .map(k => ({ id: k, label: I18N_LOCALES[k], iso: getShortLocale(k) }))
 
     this.languages = sortBy(l, 'label')
   }
@@ -35,7 +36,7 @@ export class LanguageChooserComponent {
     const english = 'English'
     const locale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
 
-    if (locale) return I18N_LOCALES[locale] || english
+    if (locale) return I18N_LOCALES[locale as keyof typeof I18N_LOCALES] || english
     return english
   }
 }
index f1c1aa03f388215b06a849776abb9ef414b4b1a0..ab2e02ad79157ec17fd7d08e79f46d4809580afe 100644 (file)
@@ -1,6 +1,7 @@
 import { Component, Input, OnChanges, OnInit } from '@angular/core'
 import { VideoChannel } from '../shared-main'
 import { Account } from '../shared-main/account/account.model'
+import { objectKeysTyped } from '@shared/core-utils'
 
 type ActorInput = {
   name: string
@@ -154,8 +155,8 @@ export class ActorAvatarComponent implements OnInit, OnChanges {
       'wxyz': 'dark-blue'
     }
 
-    const theme = Object.keys(themes)
-                        .find(chars => chars.includes(initialLowercase))
+    const theme = objectKeysTyped(themes)
+      .find(chars => chars.includes(initialLowercase))
 
     return themes[theme] || 'blue'
   }
index 208dba721dd8d8fcfc21ee9a0632bf8a4ef07385..a129070553b35dc7e2bd7da023721eff0c6107d3 100644 (file)
@@ -10,6 +10,7 @@ import {
   SimpleChanges,
   Type
 } from '@angular/core'
+import { objectKeysTyped } from '@shared/core-utils'
 
 @Injectable()
 export class DynamicElementService {
@@ -41,12 +42,12 @@ export class DynamicElementService {
   setModel <T> (componentRef: ComponentRef<T>, attributes: Partial<T>) {
     const changes: SimpleChanges = {}
 
-    for (const key of Object.keys(attributes)) {
+    for (const key of objectKeysTyped(attributes)) {
       const previousValue = componentRef.instance[key]
       const newValue = attributes[key]
 
       componentRef.instance[key] = newValue
-      changes[key] = new SimpleChange(previousValue, newValue, previousValue === undefined)
+      changes[key as string] = new SimpleChange(previousValue, newValue, previousValue === undefined)
     }
 
     const component = componentRef.instance
index 21774b7aadc1c05d4bb275cf4e11bee82dff824c..bd93929c9c022547d52cc3fbcd051796f071e33f 100644 (file)
@@ -2,6 +2,7 @@ import { finalize } from 'rxjs/operators'
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
 import { AuthService, Notifier } from '@app/core'
 import { FindInBulkService } from '@app/shared/shared-search'
+import { objectKeysTyped } from '@shared/core-utils'
 import { Video } from '../../shared-main'
 import { MiniatureDisplayOptions } from '../../shared-video-miniature'
 import { CustomMarkupComponent } from './shared'
@@ -47,7 +48,7 @@ export class VideoMiniatureMarkupComponent implements CustomMarkupComponent, OnI
 
   ngOnInit () {
     if (this.onlyDisplayTitle) {
-      for (const key of Object.keys(this.displayOptions)) {
+      for (const key of objectKeysTyped(this.displayOptions)) {
         this.displayOptions[key] = false
       }
     }
index 7c2e7db6a1bbc5fc7668074d9c2a4087a67131ab..81363be8780bf5dfbd9bc81287c29c10cc5e269c 100644 (file)
@@ -1,6 +1,7 @@
 import { finalize } from 'rxjs/operators'
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
 import { AuthService, Notifier } from '@app/core'
+import { objectKeysTyped } from '@shared/core-utils'
 import { VideoSortField } from '@shared/models'
 import { Video, VideoService } from '../../shared-main'
 import { MiniatureDisplayOptions } from '../../shared-video-miniature'
@@ -66,7 +67,7 @@ export class VideosListMarkupComponent implements CustomMarkupComponent, OnInit
 
   ngOnInit () {
     if (this.onlyDisplayTitle) {
-      for (const key of Object.keys(this.displayOptions)) {
+      for (const key of objectKeysTyped(this.displayOptions)) {
         this.displayOptions[key] = false
       }
     }
index 897008242383b0907d7d2512aa335fef7166f2c1..14ee044b5dd34a4bbb0b43b2c88f1d5bd41a4bf8 100644 (file)
@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core'
 import { AsyncValidatorFn, FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms'
+import { objectKeysTyped } from '@shared/core-utils'
 import { BuildFormArgument, BuildFormDefaultValues } from '../form-validators/form-validator.model'
 import { FormReactiveErrors, FormReactiveValidationMessages } from './form-reactive.service'
 
@@ -47,13 +48,14 @@ export class FormValidatorService {
     obj: BuildFormArgument,
     defaultValues: BuildFormDefaultValues = {}
   ) {
-    for (const name of Object.keys(obj)) {
+    for (const name of objectKeysTyped(obj)) {
       formErrors[name] = ''
 
       const field = obj[name]
       if (this.isRecursiveField(field)) {
         this.updateFormGroup(
-          form[name],
+          // FIXME: typings
+          (form as any)[name],
           formErrors[name] as FormReactiveErrors,
           validationMessages[name] as FormReactiveValidationMessages,
           obj[name] as BuildFormArgument,
@@ -67,7 +69,7 @@ export class FormValidatorService {
       const defaultValue = defaultValues[name] || ''
 
       form.addControl(
-        name,
+        name + '',
         new FormControl(defaultValue, field?.VALIDATORS as ValidatorFn[], field?.ASYNC_VALIDATORS as AsyncValidatorFn[])
       )
     }
@@ -75,7 +77,8 @@ export class FormValidatorService {
 
   updateTreeValidity (group: FormGroup | FormArray): void {
     for (const key of Object.keys(group.controls)) {
-      const abstractControl = group.controls[key] as FormControl
+      // FIXME: typings
+      const abstractControl = (group.controls as any)[key] as FormControl
 
       if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
         this.updateTreeValidity(abstractControl)
index 96179cbe643139436626ae19febc2c99eef392f2..eea46083196909568070e120b6aaa6f4667770bb 100644 (file)
@@ -112,7 +112,7 @@ export class GlobalIconComponent implements OnInit {
     }
   }
 
-  private getSVGContent (options: { name: string }) {
+  private getSVGContent (options: { name: GlobalIconName }) {
     return icons[options.name]
   }
 }
index 2defffbbedbfcd9c940c2590034cbafd043ce04b..3088f089967aa0ed8ddae880ffebcd67202bef3b 100644 (file)
@@ -3,6 +3,7 @@ import { catchError, map } from 'rxjs/operators'
 import { HttpClient } from '@angular/common/http'
 import { Injectable } from '@angular/core'
 import { MarkdownService, RestExtractor, ServerService } from '@app/core'
+import { objectKeysTyped } from '@shared/core-utils'
 import { peertubeTranslate } from '@shared/core-utils/i18n'
 import { About } from '@shared/models'
 import { environment } from '../../../environments/environment'
@@ -55,7 +56,7 @@ export class InstanceService {
       hardwareInformation: ''
     }
 
-    for (const key of Object.keys(html)) {
+    for (const key of objectKeysTyped(html)) {
       html[key] = await this.markdownService.enhancedMarkdownToHTML({ markdown: about.instance[key] })
     }
 
index 37e2abd97b8b7026a28fdf41dbbc2e2ddb10e102..80fe0e1600d4f755a28e3835beebb4d6dabaf362 100644 (file)
@@ -77,7 +77,7 @@ export class HelpComponent implements OnInit, OnChanges, AfterContentInit {
   }
 
   private createMarkdownList (rules: string[]) {
-    const rulesToText = {
+    const rulesToText: { [id: string]: string } = {
       emphasis: $localize`Emphasis`,
       link: $localize`Links`,
       newline: $localize`New lines`,
index 91d57cb6bf1292b366f5a5ffcfabdf7d995fad11..47eee80d8930c855db8d95d72e9d5980da70a389 100644 (file)
@@ -1,6 +1,7 @@
 import { getAbsoluteAPIUrl } from '@app/helpers'
 import { VideoPrivacy, VideoScheduleUpdate, VideoUpdate } from '@shared/models'
 import { VideoDetails } from './video-details.model'
+import { objectKeysTyped } from '@shared/core-utils'
 
 export class VideoEdit implements VideoUpdate {
   static readonly SPECIAL_SCHEDULED_PRIVACY = -1
@@ -65,8 +66,9 @@ export class VideoEdit implements VideoUpdate {
   }
 
   patch (values: { [ id: string ]: any }) {
-    Object.keys(values).forEach((key) => {
-      this[key] = values[key]
+    objectKeysTyped(values).forEach(key => {
+      // FIXME: typings
+      (this as any)[key] = values[key]
     })
 
     // If schedule publication, the video is private and will be changed to public privacy
index 1b69aa2d05e5ad6e56b51281506e86d51738697b..32f900f154c96e06ca759d33890cfb7dae51785d 100644 (file)
@@ -106,7 +106,8 @@ export class VideoShareComponent {
       includeVideoInPlaylist: false
     }, {
       set: (target, prop, value) => {
-        target[prop] = value
+        // FIXME: typings
+        (target as any)[prop] = value
 
         if (prop === 'embedP2P') {
           // Auto enabled warning title if P2P is enabled
index 4135542dc59c5e9f01b0f4b72710777c78ac865a..cac82d8d06fc7598c763af5fbf7af9b7689d5933 100644 (file)
@@ -1,4 +1,4 @@
-import { mapValues, pick } from 'lodash-es'
+import { mapValues } from 'lodash-es'
 import { firstValueFrom } from 'rxjs'
 import { tap } from 'rxjs/operators'
 import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core'
@@ -6,11 +6,12 @@ import { HooksService } from '@app/core'
 import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
 import { logger } from '@root-helpers/logger'
 import { videoRequiresAuth } from '@root-helpers/video'
+import { objectKeysTyped, pick } from '@shared/core-utils'
 import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models'
 import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoFileTokenService, VideoService } from '../shared-main'
 
 type DownloadType = 'video' | 'subtitles'
-type FileMetadata = { [key: string]: { label: string, value: string } }
+type FileMetadata = { [key: string]: { label: string, value: string | number } }
 
 @Component({
   selector: 'my-video-download',
@@ -218,10 +219,10 @@ export class VideoDownloadComponent {
     const keyToTranslateFunction = {
       encoder: (value: string) => ({ label: $localize`Encoder`, value }),
       format_long_name: (value: string) => ({ label: $localize`Format name`, value }),
-      size: (value: number) => ({ label: $localize`Size`, value: this.bytesPipe.transform(value, 2) }),
-      bit_rate: (value: number) => ({
+      size: (value: number | string) => ({ label: $localize`Size`, value: this.bytesPipe.transform(+value, 2) }),
+      bit_rate: (value: number | string) => ({
         label: $localize`Bitrate`,
-        value: `${this.numbersPipe.transform(value)}bps`
+        value: `${this.numbersPipe.transform(+value)}bps`
       })
     }
 
@@ -230,8 +231,8 @@ export class VideoDownloadComponent {
     delete sanitizedFormat.tags
 
     return mapValues(
-      pick(sanitizedFormat, Object.keys(keyToTranslateFunction)),
-      (val, key) => keyToTranslateFunction[key](val)
+      pick(sanitizedFormat, objectKeysTyped(keyToTranslateFunction)),
+      (val: string, key: keyof typeof keyToTranslateFunction) => keyToTranslateFunction[key](val)
     )
   }
 
@@ -242,29 +243,29 @@ export class VideoDownloadComponent {
     let keyToTranslateFunction = {
       codec_long_name: (value: string) => ({ label: $localize`Codec`, value }),
       profile: (value: string) => ({ label: $localize`Profile`, value }),
-      bit_rate: (value: number) => ({
+      bit_rate: (value: number | string) => ({
         label: $localize`Bitrate`,
-        value: `${this.numbersPipe.transform(value)}bps`
+        value: `${this.numbersPipe.transform(+value)}bps`
       })
     }
 
     if (type === 'video') {
       keyToTranslateFunction = Object.assign(keyToTranslateFunction, {
-        width: (value: number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }),
+        width: (value: string | number) => ({ label: $localize`Resolution`, value: `${value}x${stream.height}` }),
         display_aspect_ratio: (value: string) => ({ label: $localize`Aspect ratio`, value }),
         avg_frame_rate: (value: string) => ({ label: $localize`Average frame rate`, value }),
         pix_fmt: (value: string) => ({ label: $localize`Pixel format`, value })
       })
     } else {
       keyToTranslateFunction = Object.assign(keyToTranslateFunction, {
-        sample_rate: (value: number) => ({ label: $localize`Sample rate`, value }),
-        channel_layout: (value: number) => ({ label: $localize`Channel Layout`, value })
+        sample_rate: (value: string | number) => ({ label: $localize`Sample rate`, value }),
+        channel_layout: (value: string | number) => ({ label: $localize`Channel Layout`, value })
       })
     }
 
     return mapValues(
       pick(stream, Object.keys(keyToTranslateFunction)),
-      (val, key) => keyToTranslateFunction[key](val)
+      (val: string, key: keyof typeof keyToTranslateFunction) => keyToTranslateFunction[key](val)
     )
   }
 
index 6b4b72c75e30ea3f0d4cc628806ccf20b9ef307b..4db73b25ab7708646bc4143f0502ea8b945870a2 100644 (file)
@@ -84,7 +84,7 @@ export class VideoFilters {
       if (specificKey && specificKey !== key) continue
 
       // FIXME: typings
-      this[key as any] = value
+      (this as any)[key] = value
     }
 
     this.buildActiveFilters()
index 460a0080e905794668465880a65a022cff050ac1..86fe502e248067d8d540f2bac68975052201afb7 100644 (file)
@@ -2,6 +2,7 @@ import { Observable, Subject } from 'rxjs'
 import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core'
 import { ComponentPagination, Notifier, User } from '@app/core'
 import { logger } from '@root-helpers/logger'
+import { objectKeysTyped } from '@shared/core-utils'
 import { ResultList, VideosExistInPlaylists, VideoSortField } from '@shared/models'
 import { PeerTubeTemplateDirective, Video } from '../shared-main'
 import { MiniatureDisplayOptions } from './video-miniature.component'
@@ -93,7 +94,7 @@ export class VideosSelectionComponent implements AfterContentInit {
   }
 
   isInSelectionMode () {
-    return Object.keys(this._selection).some(k => this._selection[k] === true)
+    return objectKeysTyped(this._selection).some(k => this._selection[k] === true)
   }
 
   videoById (index: number, video: Video) {
index 63f27eecf5048e358c494b8e78723462a96db38a..d05d6193c4a0566c6013d526799a9b8cfadcdfc7 100644 (file)
@@ -349,7 +349,7 @@ class Html5Hlsjs {
   }
 
   private _oneLevelObjClone (obj: { [ id: string ]: any }) {
-    const result = {}
+    const result: { [id: string]: any } = {}
     const objKeys = Object.keys(obj)
     for (let i = 0; i < objKeys.length; i++) {
       result[objKeys[i]] = obj[objKeys[i]]
index 6e9bcf1039d174e615705865567116cddfd9e172..44a31bfb4f1c47f669d8ee04dcb10fbda24c4809 100644 (file)
@@ -79,7 +79,7 @@ function fetchSha256Segments (options: {
   segmentsSha256Url: string
   authorizationHeader: () => string
   requiresAuth: boolean
-}) {
+}): Promise<SegmentsJSON> {
   const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options
 
   const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url)
index 46d009410eee5d5e772b9864c95e6f837b06660d..3dde44a609f26160d702a48aa6acaa3d26397338 100644 (file)
@@ -339,7 +339,7 @@ class WebTorrentPlugin extends Plugin {
       if (err.message.indexOf('incorrect info hash') !== -1) {
         logger.error('Incorrect info hash detected, falling back to torrent file.')
         const newOptions = { forcePlay: true, seek: options.seek }
-        return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done)
+        return this.addTorrent((this.torrent as any)['xs'], previousVideoFile, newOptions, done)
       }
 
       // Remote instance is down
@@ -582,7 +582,7 @@ class WebTorrentPlugin extends Plugin {
   private stopTorrent (torrent: WebTorrent.Torrent) {
     torrent.pause()
     // Pause does not remove actual peers (in particular the webseed peer)
-    torrent.removePeer(torrent['ws'])
+    torrent.removePeer((torrent as any)['ws'])
   }
 
   private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) {
index f99c7598d1196e074995fa9eedd1345b5132bf5f..fd7b5233bc0e86dce2298e0d40d31b880ba73706 100644 (file)
@@ -317,7 +317,7 @@ async function dynamicImport (url: string) {
       const script = document.createElement('script')
 
       const destructor = () => {
-        delete window[vector]
+        delete window[vector as any]
         script.onerror = null
         script.onload = null
         script.remove()
@@ -333,7 +333,7 @@ async function dynamicImport (url: string) {
         destructor()
       }
       script.onload = () => {
-        resolve(window[vector])
+        resolve(window[vector as any])
         destructor()
       }
       const loader = `import * as m from "${url}"; window.${vector} = m;` // export Module
index 01feddbdc2a868a51431523637f74306f85543fc..9022b908b77c995e9cd8b6d2a1c943fa715877c4 100644 (file)
@@ -21,7 +21,7 @@ function buildVideoOrPlaylistEmbed (options: {
     const wrapper = document.createElement('div')
 
     wrapper.style.position = 'relative'
-    wrapper.style['padding-top'] = '56.25%'
+    wrapper.style.paddingTop = '56.25%'
 
     iframe.style.position = 'absolute'
     iframe.style.inset = '0'
index bbe37a42b6bcd0ea65d8ca9dd52293817c5657de..75487258bb2e7f8bcd6bae88512654e268ed1428 100644 (file)
@@ -233,4 +233,4 @@ export class PeerTubePlayer {
 }
 
 // put it on the window as well as the export
-(window['PeerTubePlayer'] as any) = PeerTubePlayer
+(window as any)['PeerTubePlayer'] = PeerTubePlayer
index d268f4762ad8d82076e5236dbc820537e5bf2476..cc4274b99810792a1cb950504067ce71d850787a 100644 (file)
@@ -52,7 +52,7 @@ export class PeerTubeEmbed {
     this.liveManager = new LiveManager(this.playerHTML)
 
     try {
-      this.config = JSON.parse(window['PeerTubeServerConfig'])
+      this.config = JSON.parse((window as any)['PeerTubeServerConfig'])
     } catch (err) {
       logger.error('Cannot parse HTML config.', err)
     }
@@ -254,9 +254,9 @@ export class PeerTubeEmbed {
       this.player.dispose()
       this.playerHTML.removePlayerElement()
       this.playerHTML.displayError('This video is not available because the remote instance is not responding.', translations)
-    })
+    });
 
-    window['videojsPlayer'] = this.player
+    (window as any)['videojsPlayer'] = this.player
 
     this.buildCSS()
     this.buildPlayerDock(video)
index ab52629025a3197b4d0845eb6a628b06926e71a5..b34df11eea2bee55531bf501716ebd8b8ee2f5ac 100644 (file)
@@ -22,9 +22,9 @@ window.addEventListener('load', async () => {
   mainElement.appendChild(iframe)
 
   logger.info('Document finished loading.')
-  const player = new PeerTubePlayer(document.querySelector('iframe'))
+  const player = new PeerTubePlayer(document.querySelector('iframe'));
 
-  window['player'] = player
+  (window as any)['player'] = player
 
   logger.info('Awaiting player ready...')
   await player.ready
index 1668cfced03d1c35a4a4944638bde0849cafea5a..785ed1c6c45b80d067db1983a54946e43ea0385b 100644 (file)
@@ -10,7 +10,6 @@
     "experimentalDecorators": true,
     "noImplicitAny": true,
     "noImplicitThis": true,
-    "suppressImplicitAnyIndexErrors": true,
     "alwaysStrict": true,
     "importHelpers": true,
     "allowSyntheticDefaultImports": true,
index 9780b2594327af1b0113dd1e6ae574300e74d7da..1276bfcc7c38b4e0dcaa5849cee41423af626b51 100644 (file)
@@ -23,10 +23,18 @@ function omit <O extends object, K extends keyof O> (object: O, keys: K[]): Excl
   return result
 }
 
+function objectKeysTyped <O extends object, K extends keyof O> (object: O): K[] {
+  return (Object.keys(object) as K[])
+}
+
 function getKeys <O extends object, K extends keyof O> (object: O, keys: K[]): K[] {
   return (Object.keys(object) as K[]).filter(k => keys.includes(k))
 }
 
+function hasKey <T extends object> (obj: T, k: keyof any): k is keyof T {
+  return k in obj
+}
+
 function sortObjectComparator (key: string, order: 'asc' | 'desc') {
   return (a: any, b: any) => {
     if (a[key] < b[key]) {
@@ -69,7 +77,9 @@ function simpleObjectsDeepEqual (a: any, b: any) {
 export {
   pick,
   omit,
+  objectKeysTyped,
   getKeys,
+  hasKey,
   shallowCopy,
   sortObjectComparator,
   simpleObjectsDeepEqual
index 38c1b0cc9e719e927c0245522b98b2bbc9d69346..54b54077ac27e2fc5745b015c0eca961beb7ed0b 100644 (file)
@@ -103,9 +103,9 @@ export function is18nLocale (locale: string) {
 export function getCompleteLocale (locale: string) {
   if (!locale) return locale
 
-  if (I18N_LOCALE_ALIAS[locale]) return I18N_LOCALE_ALIAS[locale]
+  const found = (I18N_LOCALE_ALIAS as any)[locale] as string
 
-  return locale
+  return found || locale
 }
 
 export function getShortLocale (locale: string) {
index 877f2ec5505dff05f4a584396551df158de3dddf..365bf7612c34ccbbad7c825ecedb2c5fb3113c1c 100644 (file)
@@ -56,7 +56,7 @@ export function getCustomMarkupSanitizeOptions (additionalAllowedTags: string[]
 export function escapeHTML (stringParam: string) {
   if (!stringParam) return ''
 
-  const entityMap = {
+  const entityMap: { [id: string ]: string } = {
     '&': '&amp;',
     '<': '&lt;',
     '>': '&gt;',
index bc803a99cfecada0164b61303e4a1c1561ca9419..6d06c0f4debed792a42e3bfc4c201a4a07d3d46a 100644 (file)
@@ -1,8 +1,8 @@
 export type VideosExistInPlaylists = {
-  [videoId: number ]: VideoExistInPlaylist[]
+  [videoId: number]: VideoExistInPlaylist[]
 }
 export type CachedVideosExistInPlaylists = {
-  [videoId: number ]: CachedVideoExistInPlaylist[]
+  [videoId: number]: CachedVideoExistInPlaylist[]
 }
 
 export type CachedVideoExistInPlaylist = {