diff options
Diffstat (limited to 'client/src/assets')
-rw-r--r-- | client/src/assets/player/peertube-chunk-store.ts | 20 | ||||
-rw-r--r-- | client/src/assets/player/peertube-link-button.ts | 6 | ||||
-rw-r--r-- | client/src/assets/player/peertube-load-progress-bar.ts | 5 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-local-storage.ts | 8 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player.ts | 28 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-plugin.ts | 116 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-typings.ts | 17 | ||||
-rw-r--r-- | client/src/assets/player/resolution-menu-button.ts | 7 | ||||
-rw-r--r-- | client/src/assets/player/resolution-menu-item.ts | 9 | ||||
-rw-r--r-- | client/src/assets/player/settings-menu-button.ts | 19 | ||||
-rw-r--r-- | client/src/assets/player/settings-menu-item.ts | 15 | ||||
-rw-r--r-- | client/src/assets/player/theater-button.ts | 6 | ||||
-rw-r--r-- | client/src/assets/player/utils.ts | 2 | ||||
-rw-r--r-- | client/src/assets/player/video-renderer.ts | 18 | ||||
-rw-r--r-- | client/src/assets/player/webtorrent-info-button.ts | 2 |
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 @@ | |||
1 | import * as videojs from 'video.js' | ||
2 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
3 | import { buildVideoLink } from './utils' | 2 | import { buildVideoLink } from './utils' |
3 | // FIXME: something weird with our path definition in tsconfig and typings | ||
4 | // @ts-ignore | ||
5 | import { Player } from 'video.js' | ||
4 | 6 | ||
5 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 7 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') |
6 | class PeerTubeLinkButton extends Button { | 8 | class 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 @@ | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
2 | // FIXME: something weird with our path definition in tsconfig and typings | ||
3 | // @ts-ignore | ||
4 | import { Player } from 'video.js' | ||
2 | 5 | ||
3 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') | 6 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') |
4 | 7 | ||
5 | class PeerTubeLoadProgressBar extends Component { | 8 | class 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 | ||
13 | function getStoredWebTorrentEnabled (): boolean { | ||
14 | const value = getLocalStorage('webtorrent_enabled') | ||
15 | if (value !== null && value !== undefined) return value === 'true' | ||
16 | |||
17 | return false | ||
18 | } | ||
19 | |||
13 | function getStoredMute () { | 20 | function 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 | ||
57 | export { | 64 | export { |
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' | |||
10 | import './peertube-videojs-plugin' | 10 | import './peertube-videojs-plugin' |
11 | import './peertube-load-progress-bar' | 11 | import './peertube-load-progress-bar' |
12 | import './theater-button' | 12 | import './theater-button' |
13 | import { VideoJSCaption, videojsUntyped } from './peertube-videojs-typings' | 13 | import { UserWatching, VideoJSCaption, videojsUntyped } from './peertube-videojs-typings' |
14 | import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' | 14 | import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' |
15 | import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' | 15 | import { 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 | ||
19 | import { 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) |
18 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' | 22 | videojsUntyped.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 | ||
1 | import * as videojs from 'video.js' | 3 | import * as videojs from 'video.js' |
4 | |||
2 | import * as WebTorrent from 'webtorrent' | 5 | import * as WebTorrent from 'webtorrent' |
3 | import { VideoFile } from '../../../../shared/models/videos/video.model' | 6 | import { VideoFile } from '../../../../shared/models/videos/video.model' |
4 | import { renderVideo } from './video-renderer' | 7 | import { renderVideo } from './video-renderer' |
5 | import './settings-menu-button' | 8 | import './settings-menu-button' |
6 | import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 9 | import { PeertubePluginOptions, UserWatching, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
7 | import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils' | 10 | import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils' |
8 | import * as CacheChunkStore from 'cache-chunk-store' | ||
9 | import { PeertubeChunkStore } from './peertube-chunk-store' | 11 | import { PeertubeChunkStore } from './peertube-chunk-store' |
10 | import { | 12 | import { |
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 | ||
22 | const CacheChunkStore = require('cache-chunk-store') | ||
23 | |||
24 | type PlayOptions = { | ||
25 | forcePlay?: boolean, | ||
26 | seek?: number, | ||
27 | delay?: number | ||
28 | } | ||
29 | |||
19 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | 30 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') |
20 | class PeerTubePlugin extends Plugin { | 31 | class 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 | ||
1 | import * as videojs from 'video.js' | 3 | import * as videojs from 'video.js' |
4 | |||
2 | import { VideoFile } from '../../../../shared/models/videos/video.model' | 5 | import { VideoFile } from '../../../../shared/models/videos/video.model' |
3 | import { PeerTubePlugin } from './peertube-videojs-plugin' | 6 | import { PeerTubePlugin } from './peertube-videojs-plugin' |
4 | 7 | ||
@@ -11,9 +14,9 @@ declare namespace videojs { | |||
11 | interface VideoJSComponentInterface { | 14 | interface 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 | ||
19 | type VideoJSCaption = { | 22 | type VideoJSCaption = { |
@@ -22,6 +25,11 @@ type VideoJSCaption = { | |||
22 | src: string | 25 | src: string |
23 | } | 26 | } |
24 | 27 | ||
28 | type UserWatching = { | ||
29 | url: string, | ||
30 | authorizationHeader: string | ||
31 | } | ||
32 | |||
25 | type PeertubePluginOptions = { | 33 | type 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 @@ | |||
1 | import * as videojs from 'video.js' | 1 | // FIXME: something weird with our path definition in tsconfig and typings |
2 | // @ts-ignore | ||
3 | import { Player } from 'video.js' | ||
4 | |||
2 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 5 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
3 | import { ResolutionMenuItem } from './resolution-menu-item' | 6 | import { ResolutionMenuItem } from './resolution-menu-item' |
4 | 7 | ||
@@ -7,7 +10,7 @@ const MenuButton: VideoJSComponentInterface = videojsUntyped.getComponent('MenuB | |||
7 | class ResolutionMenuButton extends MenuButton { | 10 | class 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 @@ | |||
1 | import * as videojs from 'video.js' | 1 | // FIXME: something weird with our path definition in tsconfig and typings |
2 | // @ts-ignore | ||
3 | import { Player } from 'video.js' | ||
4 | |||
2 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 5 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
3 | 6 | ||
4 | const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') | 7 | const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') |
5 | class ResolutionMenuItem extends MenuItem { | 8 | class 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 | ||
4 | import * as videojs from 'video.js' | 6 | import * as videojs from 'video.js' |
7 | |||
5 | import { SettingsMenuItem } from './settings-menu-item' | 8 | import { SettingsMenuItem } from './settings-menu-item' |
6 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 9 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
7 | import { toTitleCase } from './utils' | 10 | import { toTitleCase } from './utils' |
@@ -11,7 +14,7 @@ const Menu: VideoJSComponentInterface = videojsUntyped.getComponent('Menu') | |||
11 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') | 14 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') |
12 | 15 | ||
13 | class SettingsButton extends Button { | 16 | class 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 | ||
220 | class SettingsPanel extends Component { | 223 | class 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 | ||
234 | class SettingsPanelChild extends Component { | 237 | class 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 | ||
248 | class SettingsDialog extends Component { | 251 | class 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 | ||
4 | import * as videojs from 'video.js' | 6 | import * as videojs from 'video.js' |
7 | |||
5 | import { toTitleCase } from './utils' | 8 | import { toTitleCase } from './utils' |
6 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 9 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
7 | 10 | ||
@@ -10,7 +13,7 @@ const component: VideoJSComponentInterface = videojsUntyped.getComponent('Compon | |||
10 | 13 | ||
11 | class SettingsMenuItem extends MenuItem { | 14 | class 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 | ||
3 | import * as videojs from 'video.js' | ||
4 | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 5 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
2 | import { saveTheaterInStore, getStoredTheater } from './peertube-player-local-storage' | 6 | import { 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 | ] |
15 | function bytes (value) { | 15 | function 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 | ||
4 | import * as MediaElementWrapper from 'mediasource' | 4 | const MediaElementWrapper = require('mediasource') |
5 | import { extname } from 'path' | 5 | import { extname } from 'path' |
6 | import * as videostream from 'videostream' | 6 | const videostream = require('videostream') |
7 | 7 | ||
8 | const VIDEOSTREAM_EXTS = [ | 8 | const VIDEOSTREAM_EXTS = [ |
9 | '.m4a', | 9 | '.m4a', |
@@ -17,7 +17,7 @@ type RenderMediaOptions = { | |||
17 | } | 17 | } |
18 | 18 | ||
19 | function renderVideo ( | 19 | function 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 | ||
30 | function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, callback: (err: Error, renderer?: any) => void) { | 30 | function 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 | ||
105 | function validateFile (file) { | 105 | function 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' |