diff options
Diffstat (limited to 'client/src/assets/player/shared')
6 files changed, 82 insertions, 15 deletions
diff --git a/client/src/assets/player/shared/common/utils.ts b/client/src/assets/player/shared/common/utils.ts index a010d9184..609240626 100644 --- a/client/src/assets/player/shared/common/utils.ts +++ b/client/src/assets/player/shared/common/utils.ts | |||
@@ -52,6 +52,10 @@ function getRtcConfig () { | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | function isSameOrigin (current: string, target: string) { | ||
56 | return new URL(current).origin === new URL(target).origin | ||
57 | } | ||
58 | |||
55 | // --------------------------------------------------------------------------- | 59 | // --------------------------------------------------------------------------- |
56 | 60 | ||
57 | export { | 61 | export { |
@@ -60,5 +64,7 @@ export { | |||
60 | 64 | ||
61 | videoFileMaxByResolution, | 65 | videoFileMaxByResolution, |
62 | videoFileMinByResolution, | 66 | videoFileMinByResolution, |
63 | bytes | 67 | bytes, |
68 | |||
69 | isSameOrigin | ||
64 | } | 70 | } |
diff --git a/client/src/assets/player/shared/manager-options/hls-options-builder.ts b/client/src/assets/player/shared/manager-options/hls-options-builder.ts index 361c76f4b..933c0d595 100644 --- a/client/src/assets/player/shared/manager-options/hls-options-builder.ts +++ b/client/src/assets/player/shared/manager-options/hls-options-builder.ts | |||
@@ -5,7 +5,7 @@ import { LiveVideoLatencyMode } from '@shared/models' | |||
5 | import { getAverageBandwidthInStore } from '../../peertube-player-local-storage' | 5 | import { getAverageBandwidthInStore } from '../../peertube-player-local-storage' |
6 | import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types' | 6 | import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types' |
7 | import { PeertubePlayerManagerOptions } from '../../types/manager-options' | 7 | import { PeertubePlayerManagerOptions } from '../../types/manager-options' |
8 | import { getRtcConfig } from '../common' | 8 | import { getRtcConfig, isSameOrigin } from '../common' |
9 | import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager' | 9 | import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager' |
10 | import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder' | 10 | import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder' |
11 | import { segmentValidatorFactory } from '../p2p-media-loader/segment-validator' | 11 | import { segmentValidatorFactory } from '../p2p-media-loader/segment-validator' |
@@ -84,7 +84,21 @@ export class HLSOptionsBuilder { | |||
84 | simultaneousHttpDownloads: 1, | 84 | simultaneousHttpDownloads: 1, |
85 | httpFailedSegmentTimeout: 1000, | 85 | httpFailedSegmentTimeout: 1000, |
86 | 86 | ||
87 | segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive), | 87 | xhrSetup: (xhr, url) => { |
88 | if (!this.options.common.requiresAuth) return | ||
89 | if (!isSameOrigin(this.options.common.serverUrl, url)) return | ||
90 | |||
91 | xhr.setRequestHeader('Authorization', this.options.common.authorizationHeader()) | ||
92 | }, | ||
93 | |||
94 | segmentValidator: segmentValidatorFactory({ | ||
95 | segmentsSha256Url: this.options.p2pMediaLoader.segmentsSha256Url, | ||
96 | isLive: this.options.common.isLive, | ||
97 | authorizationHeader: this.options.common.authorizationHeader, | ||
98 | requiresAuth: this.options.common.requiresAuth, | ||
99 | serverUrl: this.options.common.serverUrl | ||
100 | }), | ||
101 | |||
88 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), | 102 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), |
89 | 103 | ||
90 | useP2P: this.options.common.p2pEnabled, | 104 | useP2P: this.options.common.p2pEnabled, |
diff --git a/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts b/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts index 257cf1e05..b5bdcd4e6 100644 --- a/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts +++ b/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { PeertubePlayerManagerOptions } from '../../types' | 1 | import { addQueryParams } from '../../../../../../shared/core-utils' |
2 | import { PeertubePlayerManagerOptions, WebtorrentPluginOptions } from '../../types' | ||
2 | 3 | ||
3 | export class WebTorrentOptionsBuilder { | 4 | export class WebTorrentOptionsBuilder { |
4 | 5 | ||
@@ -16,13 +17,23 @@ export class WebTorrentOptionsBuilder { | |||
16 | 17 | ||
17 | const autoplay = this.autoPlayValue === 'play' | 18 | const autoplay = this.autoPlayValue === 'play' |
18 | 19 | ||
19 | const webtorrent = { | 20 | const webtorrent: WebtorrentPluginOptions = { |
20 | autoplay, | 21 | autoplay, |
21 | 22 | ||
22 | playerRefusedP2P: commonOptions.p2pEnabled === false, | 23 | playerRefusedP2P: commonOptions.p2pEnabled === false, |
23 | videoDuration: commonOptions.videoDuration, | 24 | videoDuration: commonOptions.videoDuration, |
24 | playerElement: commonOptions.playerElement, | 25 | playerElement: commonOptions.playerElement, |
25 | 26 | ||
27 | videoFileToken: commonOptions.videoFileToken, | ||
28 | |||
29 | requiresAuth: commonOptions.requiresAuth, | ||
30 | |||
31 | buildWebSeedUrls: file => { | ||
32 | if (!commonOptions.requiresAuth) return [] | ||
33 | |||
34 | return [ addQueryParams(file.fileUrl, { videoFileToken: commonOptions.videoFileToken() }) ] | ||
35 | }, | ||
36 | |||
26 | videoFiles: webtorrentOptions.videoFiles.length !== 0 | 37 | videoFiles: webtorrentOptions.videoFiles.length !== 0 |
27 | ? webtorrentOptions.videoFiles | 38 | ? webtorrentOptions.videoFiles |
28 | // The WebTorrent plugin won't be able to play these files, but it will fallback to HTTP mode | 39 | // The WebTorrent plugin won't be able to play these files, but it will fallback to HTTP mode |
diff --git a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts index 18cb6750f..a7ee91950 100644 --- a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts +++ b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts | |||
@@ -2,13 +2,22 @@ import { basename } from 'path' | |||
2 | import { Segment } from '@peertube/p2p-media-loader-core' | 2 | import { Segment } from '@peertube/p2p-media-loader-core' |
3 | import { logger } from '@root-helpers/logger' | 3 | import { logger } from '@root-helpers/logger' |
4 | import { wait } from '@root-helpers/utils' | 4 | import { wait } from '@root-helpers/utils' |
5 | import { isSameOrigin } from '../common' | ||
5 | 6 | ||
6 | type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } } | 7 | type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } } |
7 | 8 | ||
8 | const maxRetries = 3 | 9 | const maxRetries = 3 |
9 | 10 | ||
10 | function segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) { | 11 | function segmentValidatorFactory (options: { |
11 | let segmentsJSON = fetchSha256Segments(segmentsSha256Url) | 12 | serverUrl: string |
13 | segmentsSha256Url: string | ||
14 | isLive: boolean | ||
15 | authorizationHeader: () => string | ||
16 | requiresAuth: boolean | ||
17 | }) { | ||
18 | const { serverUrl, segmentsSha256Url, isLive, authorizationHeader, requiresAuth } = options | ||
19 | |||
20 | let segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) | ||
12 | const regex = /bytes=(\d+)-(\d+)/ | 21 | const regex = /bytes=(\d+)-(\d+)/ |
13 | 22 | ||
14 | return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) { | 23 | return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) { |
@@ -28,7 +37,7 @@ function segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) { | |||
28 | 37 | ||
29 | await wait(1000) | 38 | await wait(1000) |
30 | 39 | ||
31 | segmentsJSON = fetchSha256Segments(segmentsSha256Url) | 40 | segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) |
32 | await segmentValidator(segment, _method, _peerId, retry + 1) | 41 | await segmentValidator(segment, _method, _peerId, retry + 1) |
33 | 42 | ||
34 | return | 43 | return |
@@ -68,8 +77,19 @@ export { | |||
68 | 77 | ||
69 | // --------------------------------------------------------------------------- | 78 | // --------------------------------------------------------------------------- |
70 | 79 | ||
71 | function fetchSha256Segments (url: string) { | 80 | function fetchSha256Segments (options: { |
72 | return fetch(url) | 81 | serverUrl: string |
82 | segmentsSha256Url: string | ||
83 | authorizationHeader: () => string | ||
84 | requiresAuth: boolean | ||
85 | }) { | ||
86 | const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options | ||
87 | |||
88 | const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url) | ||
89 | ? { Authorization: authorizationHeader() } | ||
90 | : {} | ||
91 | |||
92 | return fetch(segmentsSha256Url, { headers }) | ||
73 | .then(res => res.json() as Promise<SegmentsJSON>) | 93 | .then(res => res.json() as Promise<SegmentsJSON>) |
74 | .catch(err => { | 94 | .catch(err => { |
75 | logger.error('Cannot get sha256 segments', err) | 95 | logger.error('Cannot get sha256 segments', err) |
diff --git a/client/src/assets/player/shared/peertube/peertube-plugin.ts b/client/src/assets/player/shared/peertube/peertube-plugin.ts index a5d712d70..4bd038bb1 100644 --- a/client/src/assets/player/shared/peertube/peertube-plugin.ts +++ b/client/src/assets/player/shared/peertube/peertube-plugin.ts | |||
@@ -22,7 +22,7 @@ const Plugin = videojs.getPlugin('plugin') | |||
22 | 22 | ||
23 | class PeerTubePlugin extends Plugin { | 23 | class PeerTubePlugin extends Plugin { |
24 | private readonly videoViewUrl: string | 24 | private readonly videoViewUrl: string |
25 | private readonly authorizationHeader: string | 25 | private readonly authorizationHeader: () => string |
26 | 26 | ||
27 | private readonly videoUUID: string | 27 | private readonly videoUUID: string |
28 | private readonly startTime: number | 28 | private readonly startTime: number |
@@ -228,7 +228,7 @@ class PeerTubePlugin extends Plugin { | |||
228 | 'Content-type': 'application/json; charset=UTF-8' | 228 | 'Content-type': 'application/json; charset=UTF-8' |
229 | }) | 229 | }) |
230 | 230 | ||
231 | if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader) | 231 | if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader()) |
232 | 232 | ||
233 | return fetch(this.videoViewUrl, { method: 'POST', body: JSON.stringify(body), headers }) | 233 | return fetch(this.videoViewUrl, { method: 'POST', body: JSON.stringify(body), headers }) |
234 | } | 234 | } |
diff --git a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts index fa3f48a9a..658b7c867 100644 --- a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts | |||
@@ -2,7 +2,7 @@ import videojs from 'video.js' | |||
2 | import * as WebTorrent from 'webtorrent' | 2 | import * as WebTorrent from 'webtorrent' |
3 | import { logger } from '@root-helpers/logger' | 3 | import { logger } from '@root-helpers/logger' |
4 | import { isIOS } from '@root-helpers/web-browser' | 4 | import { isIOS } from '@root-helpers/web-browser' |
5 | import { timeToInt } from '@shared/core-utils' | 5 | import { addQueryParams, timeToInt } from '@shared/core-utils' |
6 | import { VideoFile } from '@shared/models' | 6 | import { VideoFile } from '@shared/models' |
7 | import { getAverageBandwidthInStore, getStoredMute, getStoredVolume, saveAverageBandwidth } from '../../peertube-player-local-storage' | 7 | import { getAverageBandwidthInStore, getStoredMute, getStoredVolume, saveAverageBandwidth } from '../../peertube-player-local-storage' |
8 | import { PeerTubeResolution, PlayerNetworkInfo, WebtorrentPluginOptions } from '../../types' | 8 | import { PeerTubeResolution, PlayerNetworkInfo, WebtorrentPluginOptions } from '../../types' |
@@ -38,6 +38,8 @@ class WebTorrentPlugin extends Plugin { | |||
38 | BANDWIDTH_AVERAGE_NUMBER_OF_VALUES: 5 // Last 5 seconds to build average bandwidth | 38 | BANDWIDTH_AVERAGE_NUMBER_OF_VALUES: 5 // Last 5 seconds to build average bandwidth |
39 | } | 39 | } |
40 | 40 | ||
41 | private readonly buildWebSeedUrls: (file: VideoFile) => string[] | ||
42 | |||
41 | private readonly webtorrent = new WebTorrent({ | 43 | private readonly webtorrent = new WebTorrent({ |
42 | tracker: { | 44 | tracker: { |
43 | rtcConfig: getRtcConfig() | 45 | rtcConfig: getRtcConfig() |
@@ -57,6 +59,9 @@ class WebTorrentPlugin extends Plugin { | |||
57 | private isAutoResolutionObservation = false | 59 | private isAutoResolutionObservation = false |
58 | private playerRefusedP2P = false | 60 | private playerRefusedP2P = false |
59 | 61 | ||
62 | private requiresAuth: boolean | ||
63 | private videoFileToken: () => string | ||
64 | |||
60 | private torrentInfoInterval: any | 65 | private torrentInfoInterval: any |
61 | private autoQualityInterval: any | 66 | private autoQualityInterval: any |
62 | private addTorrentDelay: any | 67 | private addTorrentDelay: any |
@@ -81,6 +86,11 @@ class WebTorrentPlugin extends Plugin { | |||
81 | this.savePlayerSrcFunction = this.player.src | 86 | this.savePlayerSrcFunction = this.player.src |
82 | this.playerElement = options.playerElement | 87 | this.playerElement = options.playerElement |
83 | 88 | ||
89 | this.requiresAuth = options.requiresAuth | ||
90 | this.videoFileToken = options.videoFileToken | ||
91 | |||
92 | this.buildWebSeedUrls = options.buildWebSeedUrls | ||
93 | |||
84 | this.player.ready(() => { | 94 | this.player.ready(() => { |
85 | const playerOptions = this.player.options_ | 95 | const playerOptions = this.player.options_ |
86 | 96 | ||
@@ -268,7 +278,8 @@ class WebTorrentPlugin extends Plugin { | |||
268 | return new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), { | 278 | return new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), { |
269 | max: 100 | 279 | max: 100 |
270 | }) | 280 | }) |
271 | } | 281 | }, |
282 | urlList: this.buildWebSeedUrls(this.currentVideoFile) | ||
272 | } | 283 | } |
273 | 284 | ||
274 | this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => { | 285 | this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => { |
@@ -533,7 +544,12 @@ class WebTorrentPlugin extends Plugin { | |||
533 | // Enable error display now this is our last fallback | 544 | // Enable error display now this is our last fallback |
534 | this.player.one('error', () => this.player.peertube().displayFatalError()) | 545 | this.player.one('error', () => this.player.peertube().displayFatalError()) |
535 | 546 | ||
536 | const httpUrl = this.currentVideoFile.fileUrl | 547 | let httpUrl = this.currentVideoFile.fileUrl |
548 | |||
549 | if (this.requiresAuth && this.videoFileToken) { | ||
550 | httpUrl = addQueryParams(httpUrl, { videoFileToken: this.videoFileToken() }) | ||
551 | } | ||
552 | |||
537 | this.player.src = this.savePlayerSrcFunction | 553 | this.player.src = this.savePlayerSrcFunction |
538 | this.player.src(httpUrl) | 554 | this.player.src(httpUrl) |
539 | 555 | ||