aboutsummaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/e2e/src/suites-all/private-videos.e2e-spec.ts15
-rw-r--r--client/e2e/src/utils/urls.ts4
-rw-r--r--client/src/app/+stats/video/video-stats.component.ts2
-rw-r--r--client/src/assets/player/shared/manager-options/hls-options-builder.ts1
-rw-r--r--client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts76
-rw-r--r--client/src/assets/player/shared/p2p-media-loader/segment-validator.ts3
-rw-r--r--client/src/assets/player/types/peertube-videojs-typings.ts1
-rw-r--r--client/src/sass/player/offline-notification.scss6
-rw-r--r--client/src/sass/player/peertube-skin.scss4
9 files changed, 70 insertions, 42 deletions
diff --git a/client/e2e/src/suites-all/private-videos.e2e-spec.ts b/client/e2e/src/suites-all/private-videos.e2e-spec.ts
index db3554659..a25208bb3 100644
--- a/client/e2e/src/suites-all/private-videos.e2e-spec.ts
+++ b/client/e2e/src/suites-all/private-videos.e2e-spec.ts
@@ -15,6 +15,7 @@ describe('Private videos all workflow', () => {
15 let playerPage: PlayerPage 15 let playerPage: PlayerPage
16 16
17 const internalVideoName = 'Internal E2E test' 17 const internalVideoName = 'Internal E2E test'
18 const internalHLSOnlyVideoName = 'Internal E2E test - HLS only'
18 19
19 beforeEach(async () => { 20 beforeEach(async () => {
20 videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari()) 21 videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
@@ -44,6 +45,13 @@ describe('Private videos all workflow', () => {
44 await checkCorrectlyPlay(playerPage) 45 await checkCorrectlyPlay(playerPage)
45 }) 46 })
46 47
48 it('Should play an internal HLS only video', async () => {
49 await go(FIXTURE_URLS.INTERNAL_HLS_ONLY_VIDEO)
50
51 await videoWatchPage.waitWatchVideoName(internalHLSOnlyVideoName)
52 await checkCorrectlyPlay(playerPage)
53 })
54
47 it('Should play an internal WebTorrent video in embed', async () => { 55 it('Should play an internal WebTorrent video in embed', async () => {
48 await go(FIXTURE_URLS.INTERNAL_EMBED_WEBTORRENT_VIDEO) 56 await go(FIXTURE_URLS.INTERNAL_EMBED_WEBTORRENT_VIDEO)
49 57
@@ -57,4 +65,11 @@ describe('Private videos all workflow', () => {
57 await videoWatchPage.waitEmbedForDisplayed() 65 await videoWatchPage.waitEmbedForDisplayed()
58 await checkCorrectlyPlay(playerPage) 66 await checkCorrectlyPlay(playerPage)
59 }) 67 })
68
69 it('Should play an internal HLS only video in embed', async () => {
70 await go(FIXTURE_URLS.INTERNAL_EMBED_HLS_ONLY_VIDEO)
71
72 await videoWatchPage.waitEmbedForDisplayed()
73 await checkCorrectlyPlay(playerPage)
74 })
60}) 75})
diff --git a/client/e2e/src/utils/urls.ts b/client/e2e/src/utils/urls.ts
index f91d9a048..cc0bdfbff 100644
--- a/client/e2e/src/utils/urls.ts
+++ b/client/e2e/src/utils/urls.ts
@@ -1,9 +1,13 @@
1const FIXTURE_URLS = { 1const FIXTURE_URLS = {
2 INTERNAL_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0', 2 INTERNAL_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0',
3 INTERNAL_HLS_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?start=0', 3 INTERNAL_HLS_VIDEO: 'https://peertube2.cpy.re/w/pwfz7NizSdPD4mJcbbmNwa?start=0',
4
4 INTERNAL_EMBED_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0', 5 INTERNAL_EMBED_WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?mode=webtorrent&start=0',
5 INTERNAL_EMBED_HLS_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?start=0', 6 INTERNAL_EMBED_HLS_VIDEO: 'https://peertube2.cpy.re/videos/embed/pwfz7NizSdPD4mJcbbmNwa?start=0',
6 7
8 INTERNAL_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/w/tKQmHcqdYZRdCszLUiWM3V?start=0',
9 INTERNAL_EMBED_HLS_ONLY_VIDEO: 'https://peertube2.cpy.re/videos/embed/tKQmHcqdYZRdCszLUiWM3V?start=0',
10
7 WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e', 11 WEBTORRENT_VIDEO: 'https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e',
8 12
9 HLS_EMBED: 'https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50', 13 HLS_EMBED: 'https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50',
diff --git a/client/src/app/+stats/video/video-stats.component.ts b/client/src/app/+stats/video/video-stats.component.ts
index bfad4f823..18312ec33 100644
--- a/client/src/app/+stats/video/video-stats.component.ts
+++ b/client/src/app/+stats/video/video-stats.component.ts
@@ -175,7 +175,7 @@ export class VideoStatsComponent implements OnInit {
175 this.statsService.getOverallStats({ videoId: this.video.uuid, startDate: this.statsStartDate, endDate: this.statsEndDate }) 175 this.statsService.getOverallStats({ videoId: this.video.uuid, startDate: this.statsStartDate, endDate: this.statsEndDate })
176 .subscribe({ 176 .subscribe({
177 next: res => { 177 next: res => {
178 this.countries = res.countries.slice(0, 10).map(c => ({ 178 this.countries = res.countries.map(c => ({
179 name: this.countryCodeToName(c.isoCode), 179 name: this.countryCodeToName(c.isoCode),
180 viewers: c.viewers 180 viewers: c.viewers
181 })) 181 }))
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 497a97436..63e9fa8c8 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
@@ -32,6 +32,7 @@ export class HLSOptionsBuilder {
32 32
33 const p2pMediaLoader: P2PMediaLoaderPluginOptions = { 33 const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
34 requiresAuth: commonOptions.requiresAuth, 34 requiresAuth: commonOptions.requiresAuth,
35 videoFileToken: commonOptions.videoFileToken,
35 36
36 redundancyUrlManager, 37 redundancyUrlManager,
37 type: 'application/x-mpegURL', 38 type: 'application/x-mpegURL',
diff --git a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts
index b608ee3e2..e6f525fea 100644
--- a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts
+++ b/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts
@@ -3,7 +3,7 @@ import videojs from 'video.js'
3import { Events, Segment } from '@peertube/p2p-media-loader-core' 3import { Events, Segment } from '@peertube/p2p-media-loader-core'
4import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs' 4import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs'
5import { logger } from '@root-helpers/logger' 5import { logger } from '@root-helpers/logger'
6import { timeToInt } from '@shared/core-utils' 6import { addQueryParams, timeToInt } from '@shared/core-utils'
7import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../../types' 7import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../../types'
8import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' 8import { registerConfigPlugin, registerSourceHandler } from './hls-plugin'
9 9
@@ -39,46 +39,37 @@ class P2pMediaLoaderPlugin extends Plugin {
39 super(player) 39 super(player)
40 40
41 this.options = options 41 this.options = options
42 this.startTime = timeToInt(options.startTime)
42 43
43 // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080 44 // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080
44 if (!(videojs as any).Html5Hlsjs) { 45 if (!(videojs as any).Html5Hlsjs) {
45 logger.warn('HLS.js does not seem to be supported. Try to fallback to built in HLS.') 46 if (player.canPlayType('application/vnd.apple.mpegurl')) {
46 47 this.fallbackToBuiltInIOS()
47 let message: string 48 return
48 if (!player.canPlayType('application/vnd.apple.mpegurl')) {
49 message = 'Cannot fallback to built-in HLS'
50 } else if (options.requiresAuth) {
51 message = 'Video requires auth which is not compatible to build-in HLS player'
52 } 49 }
53 50
54 if (message) { 51 const message = 'HLS.js does not seem to be supported. Cannot fallback to built-in HLS'
55 logger.warn(message) 52 logger.warn(message)
56 53
57 const error: MediaError = { 54 const error: MediaError = {
58 code: MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, 55 code: MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED,
59 message, 56 message,
60 MEDIA_ERR_ABORTED: MediaError.MEDIA_ERR_ABORTED, 57 MEDIA_ERR_ABORTED: MediaError.MEDIA_ERR_ABORTED,
61 MEDIA_ERR_DECODE: MediaError.MEDIA_ERR_DECODE, 58 MEDIA_ERR_DECODE: MediaError.MEDIA_ERR_DECODE,
62 MEDIA_ERR_NETWORK: MediaError.MEDIA_ERR_NETWORK, 59 MEDIA_ERR_NETWORK: MediaError.MEDIA_ERR_NETWORK,
63 MEDIA_ERR_SRC_NOT_SUPPORTED: MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED 60 MEDIA_ERR_SRC_NOT_SUPPORTED: MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED
64 }
65
66 player.ready(() => player.error(error))
67 return
68 } 61 }
69 62
70 // Workaround to force video.js to not re create a video element 63 player.ready(() => player.error(error))
71 (this.player as any).playerElIngest_ = this.player.el().parentNode 64 return
72 } else {
73 // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080
74 (videojs as any).Html5Hlsjs.addHook('beforeinitialize', (videojsPlayer: any, hlsjs: any) => {
75 this.hlsjs = hlsjs
76 })
77
78 initVideoJsContribHlsJsPlayer(player)
79 } 65 }
80 66
81 this.startTime = timeToInt(options.startTime) 67 // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080
68 (videojs as any).Html5Hlsjs.addHook('beforeinitialize', (_videojsPlayer: any, hlsjs: any) => {
69 this.hlsjs = hlsjs
70 })
71
72 initVideoJsContribHlsJsPlayer(player)
82 73
83 player.src({ 74 player.src({
84 type: options.type, 75 type: options.type,
@@ -88,9 +79,7 @@ class P2pMediaLoaderPlugin extends Plugin {
88 player.ready(() => { 79 player.ready(() => {
89 this.initializeCore() 80 this.initializeCore()
90 81
91 if ((videojs as any).Html5Hlsjs) { 82 this.initializePlugin()
92 this.initializePlugin()
93 }
94 }) 83 })
95 } 84 }
96 85
@@ -199,6 +188,25 @@ class P2pMediaLoaderPlugin extends Plugin {
199 private arraySum (data: number[]) { 188 private arraySum (data: number[]) {
200 return data.reduce((a: number, b: number) => a + b, 0) 189 return data.reduce((a: number, b: number) => a + b, 0)
201 } 190 }
191
192 private fallbackToBuiltInIOS () {
193 logger.info('HLS.js does not seem to be supported. Fallback to built-in HLS.');
194
195 // Workaround to force video.js to not re create a video element
196 (this.player as any).playerElIngest_ = this.player.el().parentNode
197
198 this.player.src({
199 type: this.options.type,
200 src: addQueryParams(this.options.src, {
201 videoFileToken: this.options.videoFileToken(),
202 reinjectVideoFileToken: 'true'
203 })
204 })
205
206 this.player.ready(() => {
207 this.initializeCore()
208 })
209 }
202} 210}
203 211
204videojs.registerPlugin('p2pMediaLoader', P2pMediaLoaderPlugin) 212videojs.registerPlugin('p2pMediaLoader', P2pMediaLoaderPlugin)
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 a7ee91950..3c76d63f7 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,6 +2,7 @@ import { basename } from 'path'
2import { Segment } from '@peertube/p2p-media-loader-core' 2import { Segment } from '@peertube/p2p-media-loader-core'
3import { logger } from '@root-helpers/logger' 3import { logger } from '@root-helpers/logger'
4import { wait } from '@root-helpers/utils' 4import { wait } from '@root-helpers/utils'
5import { removeQueryParams } from '@shared/core-utils'
5import { isSameOrigin } from '../common' 6import { isSameOrigin } from '../common'
6 7
7type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } } 8type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } }
@@ -24,7 +25,7 @@ function segmentValidatorFactory (options: {
24 // Wait for hash generation from the server 25 // Wait for hash generation from the server
25 if (isLive) await wait(1000) 26 if (isLive) await wait(1000)
26 27
27 const filename = basename(segment.url) 28 const filename = basename(removeQueryParams(segment.url))
28 29
29 const segmentValue = (await segmentsJSON)[filename] 30 const segmentValue = (await segmentsJSON)[filename]
30 31
diff --git a/client/src/assets/player/types/peertube-videojs-typings.ts b/client/src/assets/player/types/peertube-videojs-typings.ts
index 3d9d5270e..c60154f3b 100644
--- a/client/src/assets/player/types/peertube-videojs-typings.ts
+++ b/client/src/assets/player/types/peertube-videojs-typings.ts
@@ -168,6 +168,7 @@ type P2PMediaLoaderPluginOptions = {
168 loader: P2PMediaLoader 168 loader: P2PMediaLoader
169 169
170 requiresAuth: boolean 170 requiresAuth: boolean
171 videoFileToken: () => string
171} 172}
172 173
173export type P2PMediaLoader = { 174export type P2PMediaLoader = {
diff --git a/client/src/sass/player/offline-notification.scss b/client/src/sass/player/offline-notification.scss
index 2108c2e30..450c95bbc 100644
--- a/client/src/sass/player/offline-notification.scss
+++ b/client/src/sass/player/offline-notification.scss
@@ -14,9 +14,3 @@ $height: 40px;
14 justify-content: center; 14 justify-content: center;
15 align-items: center; 15 align-items: center;
16} 16}
17
18.vjs-modal-dialog
19.vjs-modal-dialog-content,
20.video-js .vjs-modal-dialog {
21 top: $height;
22}
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss
index d4c43ff68..4df8dbaf0 100644
--- a/client/src/sass/player/peertube-skin.scss
+++ b/client/src/sass/player/peertube-skin.scss
@@ -202,6 +202,10 @@ body {
202 } 202 }
203} 203}
204 204
205.vjs-modal-dialog-content {
206 padding-top: 40px !important;
207}
208
205// Error display disabled 209// Error display disabled
206.vjs-error:not(.vjs-error-display-enabled) { 210.vjs-error:not(.vjs-error-display-enabled) {
207 .vjs-custom-error-display { 211 .vjs-custom-error-display {