Add caption button to player control bar
This commit is contained in:
parent
7b86b9b458
commit
c97b8fd2ea
|
@ -55,6 +55,8 @@ function getAverageBandwidthInStore () {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function saveLastSubtitle (language: string) {
|
function saveLastSubtitle (language: string) {
|
||||||
return setLocalStorage('last-subtitle', language)
|
return setLocalStorage('last-subtitle', language)
|
||||||
}
|
}
|
||||||
|
@ -63,6 +65,16 @@ function getStoredLastSubtitle () {
|
||||||
return getLocalStorage('last-subtitle')
|
return getLocalStorage('last-subtitle')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function savePreferredSubtitle (language: string) {
|
||||||
|
return setLocalStorage('preferred-subtitle', language)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStoredPreferredSubtitle () {
|
||||||
|
return getLocalStorage('preferred-subtitle')
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function saveVideoWatchHistory (videoUUID: string, duration: number) {
|
function saveVideoWatchHistory (videoUUID: string, duration: number) {
|
||||||
return setLocalStorage(`video-watch-history`, JSON.stringify({
|
return setLocalStorage(`video-watch-history`, JSON.stringify({
|
||||||
...getStoredVideoWatchHistory(),
|
...getStoredVideoWatchHistory(),
|
||||||
|
@ -128,7 +140,9 @@ export {
|
||||||
getStoredLastSubtitle,
|
getStoredLastSubtitle,
|
||||||
saveVideoWatchHistory,
|
saveVideoWatchHistory,
|
||||||
getStoredVideoWatchHistory,
|
getStoredVideoWatchHistory,
|
||||||
cleanupVideoWatch
|
cleanupVideoWatch,
|
||||||
|
savePreferredSubtitle,
|
||||||
|
getStoredPreferredSubtitle
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -6,6 +6,7 @@ import './shared/stats/stats-plugin'
|
||||||
import './shared/bezels/bezels-plugin'
|
import './shared/bezels/bezels-plugin'
|
||||||
import './shared/peertube/peertube-plugin'
|
import './shared/peertube/peertube-plugin'
|
||||||
import './shared/resolutions/peertube-resolutions-plugin'
|
import './shared/resolutions/peertube-resolutions-plugin'
|
||||||
|
import './shared/control-bar/caption-toggle-button'
|
||||||
import './shared/control-bar/storyboard-plugin'
|
import './shared/control-bar/storyboard-plugin'
|
||||||
import './shared/control-bar/chapters-plugin'
|
import './shared/control-bar/chapters-plugin'
|
||||||
import './shared/control-bar/time-tooltip'
|
import './shared/control-bar/time-tooltip'
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import videojs from 'video.js'
|
||||||
|
import { TheaterButtonOptions } from '../../types'
|
||||||
|
import { getStoredPreferredSubtitle } from '../../peertube-player-local-storage'
|
||||||
|
|
||||||
|
const Button = videojs.getComponent('Button')
|
||||||
|
class CaptionToggleButton extends Button {
|
||||||
|
|
||||||
|
constructor (player: videojs.Player, options: TheaterButtonOptions & videojs.ComponentOptions) {
|
||||||
|
super(player, options)
|
||||||
|
|
||||||
|
player.on('texttrackchange', () => this.update())
|
||||||
|
}
|
||||||
|
|
||||||
|
buildCSSClass () {
|
||||||
|
// Inherits vjs-captions-button for the icon
|
||||||
|
return `vjs-caption-toggle-control vjs-captions-button ${super.buildCSSClass()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick (event: any) {
|
||||||
|
super.handleClick(event)
|
||||||
|
|
||||||
|
const toEnable = this.getShowing()
|
||||||
|
? undefined
|
||||||
|
: this.getCaptionToEnable()?.id
|
||||||
|
|
||||||
|
for (const track of this.player_.textTracks().tracks_) {
|
||||||
|
if (toEnable && track.id === toEnable) track.mode = 'showing'
|
||||||
|
else track.mode = 'disabled'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private update () {
|
||||||
|
if (this.getShowing()) {
|
||||||
|
this.controlText('Disable subtitles')
|
||||||
|
this.addClass('enabled')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.controlText(this.player_.localize('Enable {1} subtitle', [ this.getCaptionToEnable()?.label ]))
|
||||||
|
this.removeClass('enabled')
|
||||||
|
}
|
||||||
|
|
||||||
|
private getShowing () {
|
||||||
|
return this.listCaptions().find(t => t.mode === 'showing')
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCaptionToEnable () {
|
||||||
|
const captionToEnable = getStoredPreferredSubtitle() || this.listCaptions()[0]?.id
|
||||||
|
const captions = this.listCaptions()
|
||||||
|
|
||||||
|
return captions.find(t => t.id === captionToEnable) || captions[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
private listCaptions () {
|
||||||
|
return this.player_.textTracks().tracks_.filter(t => t.kind === 'captions')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videojs.registerComponent('CaptionToggleButton', CaptionToggleButton)
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from './caption-toggle-button'
|
||||||
export * from './chapters-plugin'
|
export * from './chapters-plugin'
|
||||||
export * from './next-previous-video-button'
|
export * from './next-previous-video-button'
|
||||||
export * from './p2p-info-button'
|
export * from './p2p-info-button'
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
getStoredVolume,
|
getStoredVolume,
|
||||||
saveLastSubtitle,
|
saveLastSubtitle,
|
||||||
saveMuteInStore,
|
saveMuteInStore,
|
||||||
|
savePreferredSubtitle,
|
||||||
saveVideoWatchHistory,
|
saveVideoWatchHistory,
|
||||||
saveVolumeInStore
|
saveVolumeInStore
|
||||||
} from '../../peertube-player-local-storage'
|
} from '../../peertube-player-local-storage'
|
||||||
|
@ -113,6 +114,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
|
|
||||||
this.currentSubtitle = showing.language
|
this.currentSubtitle = showing.language
|
||||||
saveLastSubtitle(showing.language)
|
saveLastSubtitle(showing.language)
|
||||||
|
savePreferredSubtitle(showing.language)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.player.on('video-change', () => {
|
this.player.on('video-change', () => {
|
||||||
|
@ -382,6 +384,8 @@ class PeerTubePlugin extends Plugin {
|
||||||
|
|
||||||
this.player.tech(true).clearTracks('text')
|
this.player.tech(true).clearTracks('text')
|
||||||
|
|
||||||
|
this.player.removeClass('vjs-has-captions')
|
||||||
|
|
||||||
for (const caption of this.options.videoCaptions()) {
|
for (const caption of this.options.videoCaptions()) {
|
||||||
this.player.addRemoteTextTrack({
|
this.player.addRemoteTextTrack({
|
||||||
kind: 'captions',
|
kind: 'captions',
|
||||||
|
@ -391,6 +395,8 @@ class PeerTubePlugin extends Plugin {
|
||||||
src: caption.src,
|
src: caption.src,
|
||||||
default: this.currentSubtitle === caption.language
|
default: this.currentSubtitle === caption.language
|
||||||
}, true)
|
}, true)
|
||||||
|
|
||||||
|
this.player.addClass('vjs-has-captions')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.player.trigger('captions-changed')
|
this.player.trigger('captions-changed')
|
||||||
|
|
|
@ -34,9 +34,12 @@ export class ControlBarOptionsBuilder {
|
||||||
...this.getProgressControl(),
|
...this.getProgressControl(),
|
||||||
|
|
||||||
p2PInfoButton: {},
|
p2PInfoButton: {},
|
||||||
|
|
||||||
muteToggle: {},
|
muteToggle: {},
|
||||||
volumeControl: {},
|
volumeControl: {},
|
||||||
|
|
||||||
|
captionToggleButton: {},
|
||||||
|
|
||||||
...this.getSettingsButton(),
|
...this.getSettingsButton(),
|
||||||
|
|
||||||
...this.getPeerTubeLinkButton(),
|
...this.getPeerTubeLinkButton(),
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
.vjs-fullscreen-control,
|
.vjs-fullscreen-control,
|
||||||
.vjs-peertube-link,
|
.vjs-peertube-link,
|
||||||
.vjs-theater-control,
|
.vjs-theater-control,
|
||||||
|
.vjs-caption-toggle-control,
|
||||||
.vjs-settings {
|
.vjs-settings {
|
||||||
color: pvar(--embedForegroundColor) !important;
|
color: pvar(--embedForegroundColor) !important;
|
||||||
|
|
||||||
|
@ -297,7 +298,7 @@
|
||||||
.vjs-volume-control {
|
.vjs-volume-control {
|
||||||
@include margin(0, 5px, 0, 5px);
|
@include margin(0, 5px, 0, 5px);
|
||||||
|
|
||||||
width: $control-bar-icon-size;
|
width: 28px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +370,7 @@
|
||||||
@include disable-outline;
|
@include disable-outline;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: $control-bar-button-width;
|
width: $control-bar-button-width - 5px;
|
||||||
|
|
||||||
.vjs-icon-placeholder {
|
.vjs-icon-placeholder {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -418,6 +419,31 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-caption-toggle-control {
|
||||||
|
// Redefined if the player parent has captions class
|
||||||
|
display: none;
|
||||||
|
width: $control-bar-button-width - 4px;
|
||||||
|
|
||||||
|
&,
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.enabled,
|
||||||
|
&.enabled:hover {
|
||||||
|
opacity: $primary-foreground-opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .vjs-icon-placeholder::before {
|
||||||
|
font-size: 2.3em;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.vjs-fullscreen-control {
|
.vjs-fullscreen-control {
|
||||||
@include disable-outline;
|
@include disable-outline;
|
||||||
|
|
||||||
|
@ -456,6 +482,10 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-mute-control {
|
||||||
|
@include margin(0, 5px, 0, 5px);
|
||||||
|
}
|
||||||
|
|
||||||
.vjs-peertube {
|
.vjs-peertube {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|
||||||
|
@ -519,3 +549,7 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-peertube-skin.vjs-has-captions .vjs-caption-toggle-control {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
|
@ -76,7 +76,9 @@ const playerKeys = {
|
||||||
'Cancel': 'Cancel',
|
'Cancel': 'Cancel',
|
||||||
'Up Next': 'Up Next',
|
'Up Next': 'Up Next',
|
||||||
'Autoplay is suspended': 'Autoplay is suspended',
|
'Autoplay is suspended': 'Autoplay is suspended',
|
||||||
'{1} (from edge: {2})': '{1} (from edge: {2})'
|
'{1} (from edge: {2})': '{1} (from edge: {2})',
|
||||||
|
'Disable subtitles': 'Disable subtitles',
|
||||||
|
'Enable {1} subtitle': 'Enable {1} subtitle'
|
||||||
}
|
}
|
||||||
Object.assign(playerKeys, videojs)
|
Object.assign(playerKeys, videojs)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue