diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/package.json | 2 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-manager.ts | 1 | ||||
-rw-r--r-- | client/src/assets/player/shared/control-bar/index.ts | 1 | ||||
-rw-r--r-- | client/src/assets/player/shared/control-bar/peertube-live-display.ts | 89 | ||||
-rw-r--r-- | client/src/assets/player/shared/manager-options/control-bar-options-builder.ts | 21 | ||||
-rw-r--r-- | client/src/sass/player/control-bar.scss | 21 | ||||
-rw-r--r-- | client/yarn.lock | 8 |
7 files changed, 132 insertions, 11 deletions
diff --git a/client/package.json b/client/package.json index 4b86fb947..a026d61c1 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -96,7 +96,7 @@ | |||
96 | "expect-webdriverio": "^3.4.0", | 96 | "expect-webdriverio": "^3.4.0", |
97 | "focus-visible": "^5.0.2", | 97 | "focus-visible": "^5.0.2", |
98 | "geckodriver": "^3.2.0", | 98 | "geckodriver": "^3.2.0", |
99 | "hls.js": "1.2.7", | 99 | "hls.js": "1.2.9", |
100 | "html-loader": "^4.1.0", | 100 | "html-loader": "^4.1.0", |
101 | "html-webpack-plugin": "^5.3.1", | 101 | "html-webpack-plugin": "^5.3.1", |
102 | "https-browserify": "^1.0.0", | 102 | "https-browserify": "^1.0.0", |
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 56310c4e9..710c9dc87 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -11,6 +11,7 @@ import './shared/control-bar/p2p-info-button' | |||
11 | import './shared/control-bar/peertube-link-button' | 11 | import './shared/control-bar/peertube-link-button' |
12 | import './shared/control-bar/peertube-load-progress-bar' | 12 | import './shared/control-bar/peertube-load-progress-bar' |
13 | import './shared/control-bar/theater-button' | 13 | import './shared/control-bar/theater-button' |
14 | import './shared/control-bar/peertube-live-display' | ||
14 | import './shared/settings/resolution-menu-button' | 15 | import './shared/settings/resolution-menu-button' |
15 | import './shared/settings/resolution-menu-item' | 16 | import './shared/settings/resolution-menu-item' |
16 | import './shared/settings/settings-dialog' | 17 | import './shared/settings/settings-dialog' |
diff --git a/client/src/assets/player/shared/control-bar/index.ts b/client/src/assets/player/shared/control-bar/index.ts index db5b8938d..e71e90713 100644 --- a/client/src/assets/player/shared/control-bar/index.ts +++ b/client/src/assets/player/shared/control-bar/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | export * from './next-previous-video-button' | 1 | export * from './next-previous-video-button' |
2 | export * from './p2p-info-button' | 2 | export * from './p2p-info-button' |
3 | export * from './peertube-link-button' | 3 | export * from './peertube-link-button' |
4 | export * from './peertube-live-display' | ||
4 | export * from './peertube-load-progress-bar' | 5 | export * from './peertube-load-progress-bar' |
5 | export * from './theater-button' | 6 | export * from './theater-button' |
diff --git a/client/src/assets/player/shared/control-bar/peertube-live-display.ts b/client/src/assets/player/shared/control-bar/peertube-live-display.ts new file mode 100644 index 000000000..8724ff294 --- /dev/null +++ b/client/src/assets/player/shared/control-bar/peertube-live-display.ts | |||
@@ -0,0 +1,89 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import { PeerTubeLinkButtonOptions } from '../../types' | ||
3 | |||
4 | const ClickableComponent = videojs.getComponent('ClickableComponent') | ||
5 | |||
6 | class PeerTubeLiveDisplay extends ClickableComponent { | ||
7 | private interval: any | ||
8 | |||
9 | private contentEl_: any | ||
10 | |||
11 | constructor (player: videojs.Player, options?: PeerTubeLinkButtonOptions) { | ||
12 | super(player, options as any) | ||
13 | |||
14 | this.interval = this.setInterval(() => this.updateClass(), 1000) | ||
15 | |||
16 | this.show() | ||
17 | this.updateSync(true) | ||
18 | } | ||
19 | |||
20 | dispose () { | ||
21 | if (this.interval) { | ||
22 | this.clearInterval(this.interval) | ||
23 | this.interval = undefined | ||
24 | } | ||
25 | |||
26 | this.contentEl_ = null | ||
27 | |||
28 | super.dispose() | ||
29 | } | ||
30 | |||
31 | createEl () { | ||
32 | const el = super.createEl('div', { | ||
33 | className: 'vjs-live-control vjs-control' | ||
34 | }) | ||
35 | |||
36 | this.contentEl_ = videojs.dom.createEl('div', { | ||
37 | className: 'vjs-live-display' | ||
38 | }, { | ||
39 | 'aria-live': 'off' | ||
40 | }) | ||
41 | |||
42 | this.contentEl_.appendChild(videojs.dom.createEl('span', { | ||
43 | className: 'vjs-control-text', | ||
44 | textContent: `${this.localize('Stream Type')}\u00a0` | ||
45 | })) | ||
46 | |||
47 | this.contentEl_.appendChild(document.createTextNode(this.localize('LIVE'))) | ||
48 | |||
49 | el.appendChild(this.contentEl_) | ||
50 | return el | ||
51 | } | ||
52 | |||
53 | handleClick () { | ||
54 | const hlsjs = this.getHLSJS() | ||
55 | if (!hlsjs) return | ||
56 | |||
57 | this.player().currentTime(hlsjs.liveSyncPosition) | ||
58 | this.updateSync(true) | ||
59 | } | ||
60 | |||
61 | private updateClass () { | ||
62 | const hlsjs = this.getHLSJS() | ||
63 | if (!hlsjs) return | ||
64 | |||
65 | const isSync = Math.abs(this.player().currentTime() - hlsjs.liveSyncPosition) < 10 | ||
66 | this.updateSync(isSync) | ||
67 | } | ||
68 | |||
69 | private updateSync (isSync: boolean) { | ||
70 | if (isSync) { | ||
71 | this.addClass('synced-with-live-edge') | ||
72 | this.removeAttribute('title') | ||
73 | this.disable() | ||
74 | } else { | ||
75 | this.removeClass('synced-with-live-edge') | ||
76 | this.setAttribute('title', this.localize('Go back to the live')) | ||
77 | this.enable() | ||
78 | } | ||
79 | } | ||
80 | |||
81 | private getHLSJS () { | ||
82 | const p2pMediaLoader = this.player()?.p2pMediaLoader | ||
83 | if (!p2pMediaLoader) return undefined | ||
84 | |||
85 | return p2pMediaLoader().getHLSJS() | ||
86 | } | ||
87 | } | ||
88 | |||
89 | videojs.registerComponent('PeerTubeLiveDisplay', PeerTubeLiveDisplay) | ||
diff --git a/client/src/assets/player/shared/manager-options/control-bar-options-builder.ts b/client/src/assets/player/shared/manager-options/control-bar-options-builder.ts index 27f366732..df1e8eabe 100644 --- a/client/src/assets/player/shared/manager-options/control-bar-options-builder.ts +++ b/client/src/assets/player/shared/manager-options/control-bar-options-builder.ts | |||
@@ -30,10 +30,7 @@ export class ControlBarOptionsBuilder { | |||
30 | } | 30 | } |
31 | 31 | ||
32 | Object.assign(children, { | 32 | Object.assign(children, { |
33 | currentTimeDisplay: {}, | 33 | ...this.getTimeControls(), |
34 | timeDivider: {}, | ||
35 | durationDisplay: {}, | ||
36 | liveDisplay: {}, | ||
37 | 34 | ||
38 | flexibleWidthSpacer: {}, | 35 | flexibleWidthSpacer: {}, |
39 | 36 | ||
@@ -90,7 +87,23 @@ export class ControlBarOptionsBuilder { | |||
90 | } | 87 | } |
91 | } | 88 | } |
92 | 89 | ||
90 | private getTimeControls () { | ||
91 | if (this.options.isLive) { | ||
92 | return { | ||
93 | peerTubeLiveDisplay: {} | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return { | ||
98 | currentTimeDisplay: {}, | ||
99 | timeDivider: {}, | ||
100 | durationDisplay: {} | ||
101 | } | ||
102 | } | ||
103 | |||
93 | private getProgressControl () { | 104 | private getProgressControl () { |
105 | if (this.options.isLive) return {} | ||
106 | |||
94 | const loadProgressBar = this.mode === 'webtorrent' | 107 | const loadProgressBar = this.mode === 'webtorrent' |
95 | ? 'peerTubeLoadProgressBar' | 108 | ? 'peerTubeLoadProgressBar' |
96 | : 'loadProgressBar' | 109 | : 'loadProgressBar' |
diff --git a/client/src/sass/player/control-bar.scss b/client/src/sass/player/control-bar.scss index 0082378e4..96b3adf66 100644 --- a/client/src/sass/player/control-bar.scss +++ b/client/src/sass/player/control-bar.scss | |||
@@ -153,8 +153,25 @@ | |||
153 | } | 153 | } |
154 | 154 | ||
155 | .vjs-live-control { | 155 | .vjs-live-control { |
156 | line-height: $control-bar-height; | 156 | padding: 5px 7px; |
157 | min-width: 4em; | 157 | border-radius: 3px; |
158 | height: fit-content; | ||
159 | margin: auto 10px; | ||
160 | font-weight: bold; | ||
161 | max-width: fit-content; | ||
162 | opacity: 1 !important; | ||
163 | line-height: normal; | ||
164 | position: relative; | ||
165 | top: -1px; | ||
166 | |||
167 | &.synced-with-live-edge { | ||
168 | background: #d7281c; | ||
169 | } | ||
170 | |||
171 | &:not(.synced-with-live-edge) { | ||
172 | cursor: pointer; | ||
173 | background: #80807f; | ||
174 | } | ||
158 | } | 175 | } |
159 | 176 | ||
160 | .vjs-peertube { | 177 | .vjs-peertube { |
diff --git a/client/yarn.lock b/client/yarn.lock index eac68d35e..633f90fa8 100644 --- a/client/yarn.lock +++ b/client/yarn.lock | |||
@@ -6136,10 +6136,10 @@ he@1.2.0, he@^1.2.0: | |||
6136 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" | 6136 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" |
6137 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== | 6137 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== |
6138 | 6138 | ||
6139 | hls.js@1.2.7: | 6139 | hls.js@1.2.9: |
6140 | version "1.2.7" | 6140 | version "1.2.9" |
6141 | resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.2.7.tgz#f421e258b10aa797cffb5ab2c3786675ead617f5" | 6141 | resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.2.9.tgz#2f25e42ec4c2ea8c88ab23c0f854f39062d45ac9" |
6142 | integrity sha512-mD4Po7Q5TPNIYX6G8sDD+RS/xfrWjMjrtp+xPw3Thw8Tq557Vn0wdXIX/Zii28F9ncUMMQPZsGkoCWFna9CZCw== | 6142 | integrity sha512-SPjm8ix0xe6cYzwDvdVGh2QvQPDkCYrGWpZu6bRaKNNVyEGWM9uF0pooh/Lqj/g8QBQgPFEx1vHzW8SyMY9rqg== |
6143 | 6143 | ||
6144 | hosted-git-info@^2.1.4: | 6144 | hosted-git-info@^2.1.4: |
6145 | version "2.8.9" | 6145 | version "2.8.9" |