aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/assets
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/assets')
-rw-r--r--client/src/assets/player/peertube-chunk-store.ts20
-rw-r--r--client/src/assets/player/peertube-link-button.ts6
-rw-r--r--client/src/assets/player/peertube-load-progress-bar.ts5
-rw-r--r--client/src/assets/player/peertube-player-local-storage.ts8
-rw-r--r--client/src/assets/player/peertube-player.ts28
-rw-r--r--client/src/assets/player/peertube-videojs-plugin.ts116
-rw-r--r--client/src/assets/player/peertube-videojs-typings.ts17
-rw-r--r--client/src/assets/player/resolution-menu-button.ts7
-rw-r--r--client/src/assets/player/resolution-menu-item.ts9
-rw-r--r--client/src/assets/player/settings-menu-button.ts19
-rw-r--r--client/src/assets/player/settings-menu-item.ts15
-rw-r--r--client/src/assets/player/theater-button.ts6
-rw-r--r--client/src/assets/player/utils.ts2
-rw-r--r--client/src/assets/player/video-renderer.ts18
-rw-r--r--client/src/assets/player/webtorrent-info-button.ts2
15 files changed, 188 insertions, 90 deletions
diff --git a/client/src/assets/player/peertube-chunk-store.ts b/client/src/assets/player/peertube-chunk-store.ts
index 767e46821..54cc0ea64 100644
--- a/client/src/assets/player/peertube-chunk-store.ts
+++ b/client/src/assets/player/peertube-chunk-store.ts
@@ -40,15 +40,15 @@ export class PeertubeChunkStore extends EventEmitter {
40 // If the store is full 40 // If the store is full
41 private memoryChunks: { [ id: number ]: Buffer | true } = {} 41 private memoryChunks: { [ id: number ]: Buffer | true } = {}
42 private databaseName: string 42 private databaseName: string
43 private putBulkTimeout 43 private putBulkTimeout: any
44 private cleanerInterval 44 private cleanerInterval: any
45 private db: ChunkDatabase 45 private db: ChunkDatabase
46 private expirationDB: ExpirationDatabase 46 private expirationDB: ExpirationDatabase
47 private readonly length: number 47 private readonly length: number
48 private readonly lastChunkLength: number 48 private readonly lastChunkLength: number
49 private readonly lastChunkIndex: number 49 private readonly lastChunkIndex: number
50 50
51 constructor (chunkLength: number, opts) { 51 constructor (chunkLength: number, opts: any) {
52 super() 52 super()
53 53
54 this.databaseName = 'webtorrent-chunks-' 54 this.databaseName = 'webtorrent-chunks-'
@@ -76,7 +76,7 @@ export class PeertubeChunkStore extends EventEmitter {
76 this.runCleaner() 76 this.runCleaner()
77 } 77 }
78 78
79 put (index: number, buf: Buffer, cb: Function) { 79 put (index: number, buf: Buffer, cb: (err?: Error) => void) {
80 const isLastChunk = (index === this.lastChunkIndex) 80 const isLastChunk = (index === this.lastChunkIndex)
81 if (isLastChunk && buf.length !== this.lastChunkLength) { 81 if (isLastChunk && buf.length !== this.lastChunkLength) {
82 return this.nextTick(cb, new Error('Last chunk length must be ' + this.lastChunkLength)) 82 return this.nextTick(cb, new Error('Last chunk length must be ' + this.lastChunkLength))
@@ -113,13 +113,13 @@ export class PeertubeChunkStore extends EventEmitter {
113 }, PeertubeChunkStore.BUFFERING_PUT_MS) 113 }, PeertubeChunkStore.BUFFERING_PUT_MS)
114 } 114 }
115 115
116 get (index: number, opts, cb) { 116 get (index: number, opts: any, cb: (err?: Error, buf?: Buffer) => void): void {
117 if (typeof opts === 'function') return this.get(index, null, opts) 117 if (typeof opts === 'function') return this.get(index, null, opts)
118 118
119 // IndexDB could be slow, use our memory index first 119 // IndexDB could be slow, use our memory index first
120 const memoryChunk = this.memoryChunks[index] 120 const memoryChunk = this.memoryChunks[index]
121 if (memoryChunk === undefined) { 121 if (memoryChunk === undefined) {
122 const err = new Error('Chunk not found') 122 const err = new Error('Chunk not found') as any
123 err['notFound'] = true 123 err['notFound'] = true
124 124
125 return process.nextTick(() => cb(err)) 125 return process.nextTick(() => cb(err))
@@ -146,11 +146,11 @@ export class PeertubeChunkStore extends EventEmitter {
146 }) 146 })
147 } 147 }
148 148
149 close (db) { 149 close (cb: (err?: Error) => void) {
150 return this.destroy(db) 150 return this.destroy(cb)
151 } 151 }
152 152
153 async destroy (cb) { 153 async destroy (cb: (err?: Error) => void) {
154 try { 154 try {
155 if (this.pendingPut) { 155 if (this.pendingPut) {
156 clearTimeout(this.putBulkTimeout) 156 clearTimeout(this.putBulkTimeout)
@@ -225,7 +225,7 @@ export class PeertubeChunkStore extends EventEmitter {
225 } 225 }
226 } 226 }
227 227
228 private nextTick (cb, err, val?) { 228 private nextTick <T> (cb: (err?: Error, val?: T) => void, err: Error, val?: T) {
229 process.nextTick(() => cb(err, val), undefined) 229 process.nextTick(() => cb(err, val), undefined)
230 } 230 }
231} 231}
diff --git a/client/src/assets/player/peertube-link-button.ts b/client/src/assets/player/peertube-link-button.ts
index 715207bc0..de9a49de9 100644
--- a/client/src/assets/player/peertube-link-button.ts
+++ b/client/src/assets/player/peertube-link-button.ts
@@ -1,11 +1,13 @@
1import * as videojs from 'video.js'
2import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 1import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
3import { buildVideoLink } from './utils' 2import { buildVideoLink } from './utils'
3// FIXME: something weird with our path definition in tsconfig and typings
4// @ts-ignore
5import { Player } from 'video.js'
4 6
5const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') 7const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button')
6class PeerTubeLinkButton extends Button { 8class PeerTubeLinkButton extends Button {
7 9
8 constructor (player: videojs.Player, options) { 10 constructor (player: Player, options: any) {
9 super(player, options) 11 super(player, options)
10 } 12 }
11 13
diff --git a/client/src/assets/player/peertube-load-progress-bar.ts b/client/src/assets/player/peertube-load-progress-bar.ts
index aedc641e4..af276d1b2 100644
--- a/client/src/assets/player/peertube-load-progress-bar.ts
+++ b/client/src/assets/player/peertube-load-progress-bar.ts
@@ -1,10 +1,13 @@
1import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 1import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
2// FIXME: something weird with our path definition in tsconfig and typings
3// @ts-ignore
4import { Player } from 'video.js'
2 5
3const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') 6const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component')
4 7
5class PeerTubeLoadProgressBar extends Component { 8class PeerTubeLoadProgressBar extends Component {
6 9
7 constructor (player, options) { 10 constructor (player: Player, options: any) {
8 super(player, options) 11 super(player, options)
9 this.partEls_ = [] 12 this.partEls_ = []
10 this.on(player, 'progress', this.update) 13 this.on(player, 'progress', this.update)
diff --git a/client/src/assets/player/peertube-player-local-storage.ts b/client/src/assets/player/peertube-player-local-storage.ts
index dac54c5a4..3ac5fe58a 100644
--- a/client/src/assets/player/peertube-player-local-storage.ts
+++ b/client/src/assets/player/peertube-player-local-storage.ts
@@ -10,6 +10,13 @@ function getStoredVolume () {
10 return undefined 10 return undefined
11} 11}
12 12
13function getStoredWebTorrentEnabled (): boolean {
14 const value = getLocalStorage('webtorrent_enabled')
15 if (value !== null && value !== undefined) return value === 'true'
16
17 return false
18}
19
13function getStoredMute () { 20function getStoredMute () {
14 const value = getLocalStorage('mute') 21 const value = getLocalStorage('mute')
15 if (value !== null && value !== undefined) return value === 'true' 22 if (value !== null && value !== undefined) return value === 'true'
@@ -56,6 +63,7 @@ function getAverageBandwidthInStore () {
56 63
57export { 64export {
58 getStoredVolume, 65 getStoredVolume,
66 getStoredWebTorrentEnabled,
59 getStoredMute, 67 getStoredMute,
60 getStoredTheater, 68 getStoredTheater,
61 saveVolumeInStore, 69 saveVolumeInStore,
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index 1bf6c9267..db63071cb 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -10,10 +10,14 @@ import './webtorrent-info-button'
10import './peertube-videojs-plugin' 10import './peertube-videojs-plugin'
11import './peertube-load-progress-bar' 11import './peertube-load-progress-bar'
12import './theater-button' 12import './theater-button'
13import { VideoJSCaption, videojsUntyped } from './peertube-videojs-typings' 13import { UserWatching, VideoJSCaption, videojsUntyped } from './peertube-videojs-typings'
14import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' 14import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils'
15import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' 15import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
16 16
17// FIXME: something weird with our path definition in tsconfig and typings
18// @ts-ignore
19import { Player } from 'video.js'
20
17// Change 'Playback Rate' to 'Speed' (smaller for our settings menu) 21// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
18videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' 22videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
19// Change Captions to Subtitles/CC 23// Change Captions to Subtitles/CC
@@ -34,10 +38,13 @@ function getVideojsOptions (options: {
34 startTime: number | string 38 startTime: number | string
35 theaterMode: boolean, 39 theaterMode: boolean,
36 videoCaptions: VideoJSCaption[], 40 videoCaptions: VideoJSCaption[],
41
37 language?: string, 42 language?: string,
38 controls?: boolean, 43 controls?: boolean,
39 muted?: boolean, 44 muted?: boolean,
40 loop?: boolean 45 loop?: boolean
46
47 userWatching?: UserWatching
41}) { 48}) {
42 const videojsOptions = { 49 const videojsOptions = {
43 // We don't use text track settings for now 50 // We don't use text track settings for now
@@ -57,7 +64,8 @@ function getVideojsOptions (options: {
57 playerElement: options.playerElement, 64 playerElement: options.playerElement,
58 videoViewUrl: options.videoViewUrl, 65 videoViewUrl: options.videoViewUrl,
59 videoDuration: options.videoDuration, 66 videoDuration: options.videoDuration,
60 startTime: options.startTime 67 startTime: options.startTime,
68 userWatching: options.userWatching
61 } 69 }
62 }, 70 },
63 controlBar: { 71 controlBar: {
@@ -71,12 +79,12 @@ function getVideojsOptions (options: {
71 enableVolumeScroll: false, 79 enableVolumeScroll: false,
72 enableModifiersForNumbers: false, 80 enableModifiersForNumbers: false,
73 81
74 fullscreenKey: function (event) { 82 fullscreenKey: function (event: KeyboardEvent) {
75 // fullscreen with the f key or Ctrl+Enter 83 // fullscreen with the f key or Ctrl+Enter
76 return event.key === 'f' || (event.ctrlKey && event.key === 'Enter') 84 return event.key === 'f' || (event.ctrlKey && event.key === 'Enter')
77 }, 85 },
78 86
79 seekStep: function (event) { 87 seekStep: function (event: KeyboardEvent) {
80 // mimic VLC seek behavior, and default to 5 (original value is 5). 88 // mimic VLC seek behavior, and default to 5 (original value is 5).
81 if (event.ctrlKey && event.altKey) { 89 if (event.ctrlKey && event.altKey) {
82 return 5 * 60 90 return 5 * 60
@@ -91,26 +99,26 @@ function getVideojsOptions (options: {
91 99
92 customKeys: { 100 customKeys: {
93 increasePlaybackRateKey: { 101 increasePlaybackRateKey: {
94 key: function (event) { 102 key: function (event: KeyboardEvent) {
95 return event.key === '>' 103 return event.key === '>'
96 }, 104 },
97 handler: function (player) { 105 handler: function (player: Player) {
98 player.playbackRate((player.playbackRate() + 0.1).toFixed(2)) 106 player.playbackRate((player.playbackRate() + 0.1).toFixed(2))
99 } 107 }
100 }, 108 },
101 decreasePlaybackRateKey: { 109 decreasePlaybackRateKey: {
102 key: function (event) { 110 key: function (event: KeyboardEvent) {
103 return event.key === '<' 111 return event.key === '<'
104 }, 112 },
105 handler: function (player) { 113 handler: function (player: Player) {
106 player.playbackRate((player.playbackRate() - 0.1).toFixed(2)) 114 player.playbackRate((player.playbackRate() - 0.1).toFixed(2))
107 } 115 }
108 }, 116 },
109 frameByFrame: { 117 frameByFrame: {
110 key: function (event) { 118 key: function (event: KeyboardEvent) {
111 return event.key === '.' 119 return event.key === '.'
112 }, 120 },
113 handler: function (player, options, event) { 121 handler: function (player: Player) {
114 player.pause() 122 player.pause()
115 // Calculate movement distance (assuming 30 fps) 123 // Calculate movement distance (assuming 30 fps)
116 const dist = 1 / 30 124 const dist = 1 / 30
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts
index adc376e94..40da5f1f7 100644
--- a/client/src/assets/player/peertube-videojs-plugin.ts
+++ b/client/src/assets/player/peertube-videojs-plugin.ts
@@ -1,21 +1,32 @@
1// FIXME: something weird with our path definition in tsconfig and typings
2// @ts-ignore
1import * as videojs from 'video.js' 3import * as videojs from 'video.js'
4
2import * as WebTorrent from 'webtorrent' 5import * as WebTorrent from 'webtorrent'
3import { VideoFile } from '../../../../shared/models/videos/video.model' 6import { VideoFile } from '../../../../shared/models/videos/video.model'
4import { renderVideo } from './video-renderer' 7import { renderVideo } from './video-renderer'
5import './settings-menu-button' 8import './settings-menu-button'
6import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 9import { PeertubePluginOptions, UserWatching, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
7import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils' 10import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils'
8import * as CacheChunkStore from 'cache-chunk-store'
9import { PeertubeChunkStore } from './peertube-chunk-store' 11import { PeertubeChunkStore } from './peertube-chunk-store'
10import { 12import {
11 getAverageBandwidthInStore, 13 getAverageBandwidthInStore,
12 getStoredMute, 14 getStoredMute,
13 getStoredVolume, 15 getStoredVolume,
16 getStoredWebTorrentEnabled,
14 saveAverageBandwidth, 17 saveAverageBandwidth,
15 saveMuteInStore, 18 saveMuteInStore,
16 saveVolumeInStore 19 saveVolumeInStore
17} from './peertube-player-local-storage' 20} from './peertube-player-local-storage'
18 21
22const CacheChunkStore = require('cache-chunk-store')
23
24type PlayOptions = {
25 forcePlay?: boolean,
26 seek?: number,
27 delay?: number
28}
29
19const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') 30const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin')
20class PeerTubePlugin extends Plugin { 31class PeerTubePlugin extends Plugin {
21 private readonly playerElement: HTMLVideoElement 32 private readonly playerElement: HTMLVideoElement
@@ -32,7 +43,8 @@ class PeerTubePlugin extends Plugin {
32 AUTO_QUALITY_THRESHOLD_PERCENT: 30, // Bandwidth should be 30% more important than a resolution bitrate to change to it 43 AUTO_QUALITY_THRESHOLD_PERCENT: 30, // Bandwidth should be 30% more important than a resolution bitrate to change to it
33 AUTO_QUALITY_OBSERVATION_TIME: 10000, // Wait 10 seconds after having change the resolution before another check 44 AUTO_QUALITY_OBSERVATION_TIME: 10000, // Wait 10 seconds after having change the resolution before another check
34 AUTO_QUALITY_HIGHER_RESOLUTION_DELAY: 5000, // Buffering higher resolution during 5 seconds 45 AUTO_QUALITY_HIGHER_RESOLUTION_DELAY: 5000, // Buffering higher resolution during 5 seconds
35 BANDWIDTH_AVERAGE_NUMBER_OF_VALUES: 5 // Last 5 seconds to build average bandwidth 46 BANDWIDTH_AVERAGE_NUMBER_OF_VALUES: 5, // Last 5 seconds to build average bandwidth
47 USER_WATCHING_VIDEO_INTERVAL: 5000 // Every 5 seconds, notify the user is watching the video
36 } 48 }
37 49
38 private readonly webtorrent = new WebTorrent({ 50 private readonly webtorrent = new WebTorrent({
@@ -56,20 +68,22 @@ class PeerTubePlugin extends Plugin {
56 private torrent: WebTorrent.Torrent 68 private torrent: WebTorrent.Torrent
57 private videoCaptions: VideoJSCaption[] 69 private videoCaptions: VideoJSCaption[]
58 70
59 private renderer 71 private renderer: any
60 private fakeRenderer 72 private fakeRenderer: any
61 private destoyingFakeRenderer = false 73 private destoyingFakeRenderer = false
62 74
63 private autoResolution = true 75 private autoResolution = true
64 private forbidAutoResolution = false 76 private forbidAutoResolution = false
65 private isAutoResolutionObservation = false 77 private isAutoResolutionObservation = false
78 private playerRefusedP2P = false
66 79
67 private videoViewInterval 80 private videoViewInterval: any
68 private torrentInfoInterval 81 private torrentInfoInterval: any
69 private autoQualityInterval 82 private autoQualityInterval: any
70 private addTorrentDelay 83 private userWatchingVideoInterval: any
71 private qualityObservationTimer 84 private addTorrentDelay: any
72 private runAutoQualitySchedulerTimer 85 private qualityObservationTimer: any
86 private runAutoQualitySchedulerTimer: any
73 87
74 private downloadSpeeds: number[] = [] 88 private downloadSpeeds: number[] = []
75 89
@@ -78,6 +92,7 @@ class PeerTubePlugin extends Plugin {
78 92
79 // Disable auto play on iOS 93 // Disable auto play on iOS
80 this.autoplay = options.autoplay && this.isIOS() === false 94 this.autoplay = options.autoplay && this.isIOS() === false
95 this.playerRefusedP2P = !getStoredWebTorrentEnabled()
81 96
82 this.startTime = timeToInt(options.startTime) 97 this.startTime = timeToInt(options.startTime)
83 this.videoFiles = options.videoFiles 98 this.videoFiles = options.videoFiles
@@ -100,6 +115,8 @@ class PeerTubePlugin extends Plugin {
100 this.runTorrentInfoScheduler() 115 this.runTorrentInfoScheduler()
101 this.runViewAdd() 116 this.runViewAdd()
102 117
118 if (options.userWatching) this.runUserWatchVideo(options.userWatching)
119
103 this.player.one('play', () => { 120 this.player.one('play', () => {
104 // Don't run immediately scheduler, wait some seconds the TCP connections are made 121 // Don't run immediately scheduler, wait some seconds the TCP connections are made
105 this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER) 122 this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER)
@@ -121,6 +138,8 @@ class PeerTubePlugin extends Plugin {
121 clearInterval(this.torrentInfoInterval) 138 clearInterval(this.torrentInfoInterval)
122 clearInterval(this.autoQualityInterval) 139 clearInterval(this.autoQualityInterval)
123 140
141 if (this.userWatchingVideoInterval) clearInterval(this.userWatchingVideoInterval)
142
124 // Don't need to destroy renderer, video player will be destroyed 143 // Don't need to destroy renderer, video player will be destroyed
125 this.flushVideoFile(this.currentVideoFile, false) 144 this.flushVideoFile(this.currentVideoFile, false)
126 145
@@ -172,6 +191,15 @@ class PeerTubePlugin extends Plugin {
172 const previousVideoFile = this.currentVideoFile 191 const previousVideoFile = this.currentVideoFile
173 this.currentVideoFile = videoFile 192 this.currentVideoFile = videoFile
174 193
194 // Don't try on iOS that does not support MediaSource
195 // Or don't use P2P if webtorrent is disabled
196 if (this.isIOS() || this.playerRefusedP2P) {
197 return this.fallbackToHttp(options, () => {
198 this.player.playbackRate(oldPlaybackRate)
199 return done()
200 })
201 }
202
175 this.addTorrent(this.currentVideoFile.magnetUri, previousVideoFile, options, () => { 203 this.addTorrent(this.currentVideoFile.magnetUri, previousVideoFile, options, () => {
176 this.player.playbackRate(oldPlaybackRate) 204 this.player.playbackRate(oldPlaybackRate)
177 return done() 205 return done()
@@ -242,18 +270,14 @@ class PeerTubePlugin extends Plugin {
242 private addTorrent ( 270 private addTorrent (
243 magnetOrTorrentUrl: string, 271 magnetOrTorrentUrl: string,
244 previousVideoFile: VideoFile, 272 previousVideoFile: VideoFile,
245 options: { 273 options: PlayOptions,
246 forcePlay?: boolean,
247 seek?: number,
248 delay?: number
249 },
250 done: Function 274 done: Function
251 ) { 275 ) {
252 console.log('Adding ' + magnetOrTorrentUrl + '.') 276 console.log('Adding ' + magnetOrTorrentUrl + '.')
253 277
254 const oldTorrent = this.torrent 278 const oldTorrent = this.torrent
255 const torrentOptions = { 279 const torrentOptions = {
256 store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), { 280 store: (chunkLength: number, storeOpts: any) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
257 max: 100 281 max: 100
258 }) 282 })
259 } 283 }
@@ -282,7 +306,7 @@ class PeerTubePlugin extends Plugin {
282 renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => { 306 renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => {
283 this.renderer = renderer 307 this.renderer = renderer
284 308
285 if (err) return this.fallbackToHttp(done) 309 if (err) return this.fallbackToHttp(options, done)
286 310
287 return this.tryToPlay(err => { 311 return this.tryToPlay(err => {
288 if (err) return done(err) 312 if (err) return done(err)
@@ -290,13 +314,13 @@ class PeerTubePlugin extends Plugin {
290 if (options.seek) this.seek(options.seek) 314 if (options.seek) this.seek(options.seek)
291 if (options.forcePlay === false && paused === true) this.player.pause() 315 if (options.forcePlay === false && paused === true) this.player.pause()
292 316
293 return done(err) 317 return done()
294 }) 318 })
295 }) 319 })
296 }, options.delay || 0) 320 }, options.delay || 0)
297 }) 321 })
298 322
299 this.torrent.on('error', err => console.error(err)) 323 this.torrent.on('error', (err: any) => console.error(err))
300 324
301 this.torrent.on('warning', (err: any) => { 325 this.torrent.on('warning', (err: any) => {
302 // We don't support HTTP tracker but we don't care -> we use the web socket tracker 326 // We don't support HTTP tracker but we don't care -> we use the web socket tracker
@@ -324,13 +348,13 @@ class PeerTubePlugin extends Plugin {
324 }) 348 })
325 } 349 }
326 350
327 private tryToPlay (done?: Function) { 351 private tryToPlay (done?: (err?: Error) => void) {
328 if (!done) done = function () { /* empty */ } 352 if (!done) done = function () { /* empty */ }
329 353
330 const playPromise = this.player.play() 354 const playPromise = this.player.play()
331 if (playPromise !== undefined) { 355 if (playPromise !== undefined) {
332 return playPromise.then(done) 356 return playPromise.then(done)
333 .catch(err => { 357 .catch((err: Error) => {
334 if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) { 358 if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) {
335 return 359 return
336 } 360 }
@@ -426,12 +450,6 @@ class PeerTubePlugin extends Plugin {
426 return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime }) 450 return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
427 } 451 }
428 452
429 // Don't try on iOS that does not support MediaSource
430 if (this.isIOS()) {
431 this.currentVideoFile = this.pickAverageVideoFile()
432 return this.fallbackToHttp(undefined, false)
433 }
434
435 // Proxy first play 453 // Proxy first play
436 const oldPlay = this.player.play.bind(this.player) 454 const oldPlay = this.player.play.bind(this.player)
437 this.player.play = () => { 455 this.player.play = () => {
@@ -524,6 +542,21 @@ class PeerTubePlugin extends Plugin {
524 }, 1000) 542 }, 1000)
525 } 543 }
526 544
545 private runUserWatchVideo (options: UserWatching) {
546 let lastCurrentTime = 0
547
548 this.userWatchingVideoInterval = setInterval(() => {
549 const currentTime = Math.floor(this.player.currentTime())
550
551 if (currentTime - lastCurrentTime >= 1) {
552 lastCurrentTime = currentTime
553
554 this.notifyUserIsWatching(currentTime, options.url, options.authorizationHeader)
555 .catch(err => console.error('Cannot notify user is watching.', err))
556 }
557 }, this.CONSTANTS.USER_WATCHING_VIDEO_INTERVAL)
558 }
559
527 private clearVideoViewInterval () { 560 private clearVideoViewInterval () {
528 if (this.videoViewInterval !== undefined) { 561 if (this.videoViewInterval !== undefined) {
529 clearInterval(this.videoViewInterval) 562 clearInterval(this.videoViewInterval)
@@ -537,7 +570,18 @@ class PeerTubePlugin extends Plugin {
537 return fetch(this.videoViewUrl, { method: 'POST' }) 570 return fetch(this.videoViewUrl, { method: 'POST' })
538 } 571 }
539 572
540 private fallbackToHttp (done?: Function, play = true) { 573 private notifyUserIsWatching (currentTime: number, url: string, authorizationHeader: string) {
574 const body = new URLSearchParams()
575 body.append('currentTime', currentTime.toString())
576
577 const headers = new Headers({ 'Authorization': authorizationHeader })
578
579 return fetch(url, { method: 'PUT', body, headers })
580 }
581
582 private fallbackToHttp (options: PlayOptions, done?: Function) {
583 const paused = this.player.paused()
584
541 this.disableAutoResolution(true) 585 this.disableAutoResolution(true)
542 586
543 this.flushVideoFile(this.currentVideoFile, true) 587 this.flushVideoFile(this.currentVideoFile, true)
@@ -549,9 +593,15 @@ class PeerTubePlugin extends Plugin {
549 const httpUrl = this.currentVideoFile.fileUrl 593 const httpUrl = this.currentVideoFile.fileUrl
550 this.player.src = this.savePlayerSrcFunction 594 this.player.src = this.savePlayerSrcFunction
551 this.player.src(httpUrl) 595 this.player.src(httpUrl)
552 if (play) this.tryToPlay()
553 596
554 if (done) return done() 597 return this.tryToPlay(err => {
598 if (err && done) return done(err)
599
600 if (options.seek) this.seek(options.seek)
601 if (options.forcePlay === false && paused === true) this.player.pause()
602
603 if (done) return done()
604 })
555 } 605 }
556 606
557 private handleError (err: Error | string) { 607 private handleError (err: Error | string) {
@@ -581,7 +631,7 @@ class PeerTubePlugin extends Plugin {
581 this.player.options_.inactivityTimeout = saveInactivityTimeout 631 this.player.options_.inactivityTimeout = saveInactivityTimeout
582 } 632 }
583 633
584 const settingsDialog = this.player.children_.find(c => c.name_ === 'SettingsDialog') 634 const settingsDialog = this.player.children_.find((c: any) => c.name_ === 'SettingsDialog')
585 635
586 this.player.controlBar.on('mouseenter', () => disableInactivity()) 636 this.player.controlBar.on('mouseenter', () => disableInactivity())
587 settingsDialog.on('mouseenter', () => disableInactivity()) 637 settingsDialog.on('mouseenter', () => disableInactivity())
@@ -657,7 +707,7 @@ class PeerTubePlugin extends Plugin {
657 const percent = time / this.player_.duration() 707 const percent = time / this.player_.duration()
658 return percent >= 1 ? 1 : percent 708 return percent >= 1 ? 1 : percent
659 } 709 }
660 SeekBar.prototype.handleMouseMove = function handleMouseMove (event) { 710 SeekBar.prototype.handleMouseMove = function handleMouseMove (event: any) {
661 let newTime = this.calculateDistance(event) * this.player_.duration() 711 let newTime = this.calculateDistance(event) * this.player_.duration()
662 if (newTime === this.player_.duration()) { 712 if (newTime === this.player_.duration()) {
663 newTime = newTime - 0.1 713 newTime = newTime - 0.1
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts
index 993d5ee6b..d127230fa 100644
--- a/client/src/assets/player/peertube-videojs-typings.ts
+++ b/client/src/assets/player/peertube-videojs-typings.ts
@@ -1,4 +1,7 @@
1// FIXME: something weird with our path definition in tsconfig and typings
2// @ts-ignore
1import * as videojs from 'video.js' 3import * as videojs from 'video.js'
4
2import { VideoFile } from '../../../../shared/models/videos/video.model' 5import { VideoFile } from '../../../../shared/models/videos/video.model'
3import { PeerTubePlugin } from './peertube-videojs-plugin' 6import { PeerTubePlugin } from './peertube-videojs-plugin'
4 7
@@ -11,9 +14,9 @@ declare namespace videojs {
11interface VideoJSComponentInterface { 14interface VideoJSComponentInterface {
12 _player: videojs.Player 15 _player: videojs.Player
13 16
14 new (player: videojs.Player, options?: any) 17 new (player: videojs.Player, options?: any): any
15 18
16 registerComponent (name: string, obj: any) 19 registerComponent (name: string, obj: any): any
17} 20}
18 21
19type VideoJSCaption = { 22type VideoJSCaption = {
@@ -22,6 +25,11 @@ type VideoJSCaption = {
22 src: string 25 src: string
23} 26}
24 27
28type UserWatching = {
29 url: string,
30 authorizationHeader: string
31}
32
25type PeertubePluginOptions = { 33type PeertubePluginOptions = {
26 videoFiles: VideoFile[] 34 videoFiles: VideoFile[]
27 playerElement: HTMLVideoElement 35 playerElement: HTMLVideoElement
@@ -30,6 +38,8 @@ type PeertubePluginOptions = {
30 startTime: number | string 38 startTime: number | string
31 autoplay: boolean, 39 autoplay: boolean,
32 videoCaptions: VideoJSCaption[] 40 videoCaptions: VideoJSCaption[]
41
42 userWatching?: UserWatching
33} 43}
34 44
35// videojs typings don't have some method we need 45// videojs typings don't have some method we need
@@ -39,5 +49,6 @@ export {
39 VideoJSComponentInterface, 49 VideoJSComponentInterface,
40 PeertubePluginOptions, 50 PeertubePluginOptions,
41 videojsUntyped, 51 videojsUntyped,
42 VideoJSCaption 52 VideoJSCaption,
53 UserWatching
43} 54}
diff --git a/client/src/assets/player/resolution-menu-button.ts b/client/src/assets/player/resolution-menu-button.ts
index d53a24151..a3c1108ca 100644
--- a/client/src/assets/player/resolution-menu-button.ts
+++ b/client/src/assets/player/resolution-menu-button.ts
@@ -1,4 +1,7 @@
1import * as videojs from 'video.js' 1// FIXME: something weird with our path definition in tsconfig and typings
2// @ts-ignore
3import { Player } from 'video.js'
4
2import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 5import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
3import { ResolutionMenuItem } from './resolution-menu-item' 6import { ResolutionMenuItem } from './resolution-menu-item'
4 7
@@ -7,7 +10,7 @@ const MenuButton: VideoJSComponentInterface = videojsUntyped.getComponent('MenuB
7class ResolutionMenuButton extends MenuButton { 10class ResolutionMenuButton extends MenuButton {
8 label: HTMLElement 11 label: HTMLElement
9 12
10 constructor (player: videojs.Player, options) { 13 constructor (player: Player, options: any) {
11 super(player, options) 14 super(player, options)
12 this.player = player 15 this.player = player
13 16
diff --git a/client/src/assets/player/resolution-menu-item.ts b/client/src/assets/player/resolution-menu-item.ts
index 0ab0f53b5..b54fd91ef 100644
--- a/client/src/assets/player/resolution-menu-item.ts
+++ b/client/src/assets/player/resolution-menu-item.ts
@@ -1,10 +1,13 @@
1import * as videojs from 'video.js' 1// FIXME: something weird with our path definition in tsconfig and typings
2// @ts-ignore
3import { Player } from 'video.js'
4
2import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 5import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
3 6
4const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') 7const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem')
5class ResolutionMenuItem extends MenuItem { 8class ResolutionMenuItem extends MenuItem {
6 9
7 constructor (player: videojs.Player, options) { 10 constructor (player: Player, options: any) {
8 const currentResolutionId = player.peertube().getCurrentResolutionId() 11 const currentResolutionId = player.peertube().getCurrentResolutionId()
9 options.selectable = true 12 options.selectable = true
10 options.selected = options.id === currentResolutionId 13 options.selected = options.id === currentResolutionId
@@ -18,7 +21,7 @@ class ResolutionMenuItem extends MenuItem {
18 player.peertube().on('autoResolutionUpdate', () => this.updateSelection()) 21 player.peertube().on('autoResolutionUpdate', () => this.updateSelection())
19 } 22 }
20 23
21 handleClick (event) { 24 handleClick (event: any) {
22 if (this.id === -1 && this.player_.peertube().isAutoResolutionForbidden()) return 25 if (this.id === -1 && this.player_.peertube().isAutoResolutionForbidden()) return
23 26
24 super.handleClick(event) 27 super.handleClick(event)
diff --git a/client/src/assets/player/settings-menu-button.ts b/client/src/assets/player/settings-menu-button.ts
index b51c52506..aa7281727 100644
--- a/client/src/assets/player/settings-menu-button.ts
+++ b/client/src/assets/player/settings-menu-button.ts
@@ -1,7 +1,10 @@
1// Author: Yanko Shterev 1// Author: Yanko Shterev
2// Thanks https://github.com/yshterev/videojs-settings-menu 2// Thanks https://github.com/yshterev/videojs-settings-menu
3 3
4// FIXME: something weird with our path definition in tsconfig and typings
5// @ts-ignore
4import * as videojs from 'video.js' 6import * as videojs from 'video.js'
7
5import { SettingsMenuItem } from './settings-menu-item' 8import { SettingsMenuItem } from './settings-menu-item'
6import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 9import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
7import { toTitleCase } from './utils' 10import { toTitleCase } from './utils'
@@ -11,7 +14,7 @@ const Menu: VideoJSComponentInterface = videojsUntyped.getComponent('Menu')
11const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') 14const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component')
12 15
13class SettingsButton extends Button { 16class SettingsButton extends Button {
14 constructor (player: videojs.Player, options) { 17 constructor (player: videojs.Player, options: any) {
15 super(player, options) 18 super(player, options)
16 19
17 this.playerComponent = player 20 this.playerComponent = player
@@ -48,7 +51,7 @@ class SettingsButton extends Button {
48 } 51 }
49 } 52 }
50 53
51 onDisposeSettingsItem (event, name: string) { 54 onDisposeSettingsItem (event: any, name: string) {
52 if (name === undefined) { 55 if (name === undefined) {
53 let children = this.menu.children() 56 let children = this.menu.children()
54 57
@@ -74,7 +77,7 @@ class SettingsButton extends Button {
74 } 77 }
75 } 78 }
76 79
77 onAddSettingsItem (event, data) { 80 onAddSettingsItem (event: any, data: any) {
78 const [ entry, options ] = data 81 const [ entry, options ] = data
79 82
80 this.addMenuItem(entry, options) 83 this.addMenuItem(entry, options)
@@ -120,7 +123,7 @@ class SettingsButton extends Button {
120 this.resetChildren() 123 this.resetChildren()
121 } 124 }
122 125
123 getComponentSize (element) { 126 getComponentSize (element: any) {
124 let width: number = null 127 let width: number = null
125 let height: number = null 128 let height: number = null
126 129
@@ -178,7 +181,7 @@ class SettingsButton extends Button {
178 this.panelChild.addChild(this.menu) 181 this.panelChild.addChild(this.menu)
179 } 182 }
180 183
181 addMenuItem (entry, options) { 184 addMenuItem (entry: any, options: any) {
182 const openSubMenu = function () { 185 const openSubMenu = function () {
183 if (videojsUntyped.dom.hasClass(this.el_, 'open')) { 186 if (videojsUntyped.dom.hasClass(this.el_, 'open')) {
184 videojsUntyped.dom.removeClass(this.el_, 'open') 187 videojsUntyped.dom.removeClass(this.el_, 'open')
@@ -218,7 +221,7 @@ class SettingsButton extends Button {
218} 221}
219 222
220class SettingsPanel extends Component { 223class SettingsPanel extends Component {
221 constructor (player: videojs.Player, options) { 224 constructor (player: videojs.Player, options: any) {
222 super(player, options) 225 super(player, options)
223 } 226 }
224 227
@@ -232,7 +235,7 @@ class SettingsPanel extends Component {
232} 235}
233 236
234class SettingsPanelChild extends Component { 237class SettingsPanelChild extends Component {
235 constructor (player: videojs.Player, options) { 238 constructor (player: videojs.Player, options: any) {
236 super(player, options) 239 super(player, options)
237 } 240 }
238 241
@@ -246,7 +249,7 @@ class SettingsPanelChild extends Component {
246} 249}
247 250
248class SettingsDialog extends Component { 251class SettingsDialog extends Component {
249 constructor (player: videojs.Player, options) { 252 constructor (player: videojs.Player, options: any) {
250 super(player, options) 253 super(player, options)
251 this.hide() 254 this.hide()
252 } 255 }
diff --git a/client/src/assets/player/settings-menu-item.ts b/client/src/assets/player/settings-menu-item.ts
index 665ce6fc2..698f4627a 100644
--- a/client/src/assets/player/settings-menu-item.ts
+++ b/client/src/assets/player/settings-menu-item.ts
@@ -1,7 +1,10 @@
1// Author: Yanko Shterev 1// Author: Yanko Shterev
2// Thanks https://github.com/yshterev/videojs-settings-menu 2// Thanks https://github.com/yshterev/videojs-settings-menu
3 3
4// FIXME: something weird with our path definition in tsconfig and typings
5// @ts-ignore
4import * as videojs from 'video.js' 6import * as videojs from 'video.js'
7
5import { toTitleCase } from './utils' 8import { toTitleCase } from './utils'
6import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 9import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
7 10
@@ -10,7 +13,7 @@ const component: VideoJSComponentInterface = videojsUntyped.getComponent('Compon
10 13
11class SettingsMenuItem extends MenuItem { 14class SettingsMenuItem extends MenuItem {
12 15
13 constructor (player: videojs.Player, options, entry: string, menuButton: VideoJSComponentInterface) { 16 constructor (player: videojs.Player, options: any, entry: string, menuButton: VideoJSComponentInterface) {
14 super(player, options) 17 super(player, options)
15 18
16 this.settingsButton = menuButton 19 this.settingsButton = menuButton
@@ -55,7 +58,7 @@ class SettingsMenuItem extends MenuItem {
55 this.transitionEndHandler = this.onTransitionEnd.bind(this) 58 this.transitionEndHandler = this.onTransitionEnd.bind(this)
56 } 59 }
57 60
58 onSubmenuClick (event) { 61 onSubmenuClick (event: any) {
59 let target = null 62 let target = null
60 63
61 if (event.type === 'tap') { 64 if (event.type === 'tap') {
@@ -150,7 +153,7 @@ class SettingsMenuItem extends MenuItem {
150 * 153 *
151 * @method PrefixedEvent 154 * @method PrefixedEvent
152 */ 155 */
153 PrefixedEvent (element, type, callback, action = 'addEvent') { 156 PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') {
154 let prefix = ['webkit', 'moz', 'MS', 'o', ''] 157 let prefix = ['webkit', 'moz', 'MS', 'o', '']
155 158
156 for (let p = 0; p < prefix.length; p++) { 159 for (let p = 0; p < prefix.length; p++) {
@@ -166,7 +169,7 @@ class SettingsMenuItem extends MenuItem {
166 } 169 }
167 } 170 }
168 171
169 onTransitionEnd (event) { 172 onTransitionEnd (event: any) {
170 if (event.propertyName !== 'margin-right') { 173 if (event.propertyName !== 'margin-right') {
171 return 174 return
172 } 175 }
@@ -229,8 +232,8 @@ class SettingsMenuItem extends MenuItem {
229 ) 232 )
230 } 233 }
231 234
232 update (event?: Event) { 235 update (event?: any) {
233 let target = null 236 let target: HTMLElement = null
234 let subMenu = this.subMenu.name() 237 let subMenu = this.subMenu.name()
235 238
236 if (event && event.type === 'tap') { 239 if (event && event.type === 'tap') {
diff --git a/client/src/assets/player/theater-button.ts b/client/src/assets/player/theater-button.ts
index 5cf0b6425..4f8fede3d 100644
--- a/client/src/assets/player/theater-button.ts
+++ b/client/src/assets/player/theater-button.ts
@@ -1,3 +1,7 @@
1// FIXME: something weird with our path definition in tsconfig and typings
2// @ts-ignore
3import * as videojs from 'video.js'
4
1import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' 5import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
2import { saveTheaterInStore, getStoredTheater } from './peertube-player-local-storage' 6import { saveTheaterInStore, getStoredTheater } from './peertube-player-local-storage'
3 7
@@ -6,7 +10,7 @@ class TheaterButton extends Button {
6 10
7 private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled' 11 private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled'
8 12
9 constructor (player, options) { 13 constructor (player: videojs.Player, options: any) {
10 super(player, options) 14 super(player, options)
11 15
12 const enabled = getStoredTheater() 16 const enabled = getStoredTheater()
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts
index cf4f60f55..c87287482 100644
--- a/client/src/assets/player/utils.ts
+++ b/client/src/assets/player/utils.ts
@@ -12,7 +12,7 @@ const dictionaryBytes: Array<{max: number, type: string}> = [
12 { max: 1073741824, type: 'MB' }, 12 { max: 1073741824, type: 'MB' },
13 { max: 1.0995116e12, type: 'GB' } 13 { max: 1.0995116e12, type: 'GB' }
14] 14]
15function bytes (value) { 15function bytes (value: number) {
16 const format = dictionaryBytes.find(d => value < d.max) || dictionaryBytes[dictionaryBytes.length - 1] 16 const format = dictionaryBytes.find(d => value < d.max) || dictionaryBytes[dictionaryBytes.length - 1]
17 const calc = Math.floor(value / (format.max / 1024)).toString() 17 const calc = Math.floor(value / (format.max / 1024)).toString()
18 18
diff --git a/client/src/assets/player/video-renderer.ts b/client/src/assets/player/video-renderer.ts
index 2cb05a448..a3415937b 100644
--- a/client/src/assets/player/video-renderer.ts
+++ b/client/src/assets/player/video-renderer.ts
@@ -1,9 +1,9 @@
1// Thanks: https://github.com/feross/render-media 1// Thanks: https://github.com/feross/render-media
2// TODO: use render-media once https://github.com/feross/render-media/issues/32 is fixed 2// TODO: use render-media once https://github.com/feross/render-media/issues/32 is fixed
3 3
4import * as MediaElementWrapper from 'mediasource' 4const MediaElementWrapper = require('mediasource')
5import { extname } from 'path' 5import { extname } from 'path'
6import * as videostream from 'videostream' 6const videostream = require('videostream')
7 7
8const VIDEOSTREAM_EXTS = [ 8const VIDEOSTREAM_EXTS = [
9 '.m4a', 9 '.m4a',
@@ -17,7 +17,7 @@ type RenderMediaOptions = {
17} 17}
18 18
19function renderVideo ( 19function renderVideo (
20 file, 20 file: any,
21 elem: HTMLVideoElement, 21 elem: HTMLVideoElement,
22 opts: RenderMediaOptions, 22 opts: RenderMediaOptions,
23 callback: (err: Error, renderer: any) => void 23 callback: (err: Error, renderer: any) => void
@@ -27,11 +27,11 @@ function renderVideo (
27 return renderMedia(file, elem, opts, callback) 27 return renderMedia(file, elem, opts, callback)
28} 28}
29 29
30function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) { 30function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) {
31 const extension = extname(file.name).toLowerCase() 31 const extension = extname(file.name).toLowerCase()
32 let preparedElem = undefined 32 let preparedElem: any = undefined
33 let currentTime = 0 33 let currentTime = 0
34 let renderer 34 let renderer: any
35 35
36 try { 36 try {
37 if (VIDEOSTREAM_EXTS.indexOf(extension) >= 0) { 37 if (VIDEOSTREAM_EXTS.indexOf(extension) >= 0) {
@@ -45,7 +45,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
45 45
46 function useVideostream () { 46 function useVideostream () {
47 prepareElem() 47 prepareElem()
48 preparedElem.addEventListener('error', function onError (err) { 48 preparedElem.addEventListener('error', function onError (err: Error) {
49 preparedElem.removeEventListener('error', onError) 49 preparedElem.removeEventListener('error', onError)
50 50
51 return callback(err) 51 return callback(err)
@@ -58,7 +58,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
58 const codecs = getCodec(file.name, useVP9) 58 const codecs = getCodec(file.name, useVP9)
59 59
60 prepareElem() 60 prepareElem()
61 preparedElem.addEventListener('error', function onError (err) { 61 preparedElem.addEventListener('error', function onError (err: Error) {
62 preparedElem.removeEventListener('error', onError) 62 preparedElem.removeEventListener('error', onError)
63 63
64 // Try with vp9 before returning an error 64 // Try with vp9 before returning an error
@@ -102,7 +102,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca
102 } 102 }
103} 103}
104 104
105function validateFile (file) { 105function validateFile (file: any) {
106 if (file == null) { 106 if (file == null) {
107 throw new Error('file cannot be null or undefined') 107 throw new Error('file cannot be null or undefined')
108 } 108 }
diff --git a/client/src/assets/player/webtorrent-info-button.ts b/client/src/assets/player/webtorrent-info-button.ts
index deef253ce..c3c1af951 100644
--- a/client/src/assets/player/webtorrent-info-button.ts
+++ b/client/src/assets/player/webtorrent-info-button.ts
@@ -65,7 +65,7 @@ class WebtorrentInfoButton extends Button {
65 subDivHttp.appendChild(subDivHttpText) 65 subDivHttp.appendChild(subDivHttpText)
66 div.appendChild(subDivHttp) 66 div.appendChild(subDivHttp)
67 67
68 this.player_.peertube().on('torrentInfo', (event, data) => { 68 this.player_.peertube().on('torrentInfo', (event: any, data: any) => {
69 // We are in HTTP fallback 69 // We are in HTTP fallback
70 if (!data) { 70 if (!data) {
71 subDivHttp.className = 'vjs-peertube-displayed' 71 subDivHttp.className = 'vjs-peertube-displayed'