Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Audio Only Mode #7647

Merged
merged 17 commits into from
Mar 10, 2022
Merged
8 changes: 8 additions & 0 deletions docs/guides/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* [width](#width)
* [Video.js-specific Options](#videojs-specific-options)
* [aspectRatio](#aspectratio)
* [audioOnlyMode](#audioonlymode)
* [audioPosterMode](#audiopostermode)
* [autoSetup](#autosetup)
* [breakpoints](#breakpoints)
Expand Down Expand Up @@ -182,6 +183,13 @@ Puts the player in [fluid](#fluid) mode and the value is used when calculating t

Alternatively, the classes `vjs-16-9`, `vjs-9-16`, `vjs-4-3` or `vjs-1-1` can be added to the player.

### `audioOnlyMode`

> Type: `boolean`
> Default: `false`

If set to true, it hides all player components except the control bar, as well as any specific controls that are needed only for video. This option can be set to `true` or `false` by calling `audioOnlyMode([true|false])` at runtime.

### `audioPosterMode`

> Type: `boolean`
Expand Down
4 changes: 4 additions & 0 deletions src/css/components/_captions.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.video-js .vjs-captions-button .vjs-icon-placeholder {
@extend .vjs-icon-captions;
}

.video-js.vjs-audio-only-mode .vjs-captions-button {
display: none;
}
10 changes: 6 additions & 4 deletions src/css/components/_control-bar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
@include background-color-with-alpha($primary-background-color, $primary-background-transparency);
}

// Video has started playing
.vjs-has-started .vjs-control-bar {
// Video has started playing or we are in audioOnlyMode
.vjs-has-started .vjs-control-bar,
.vjs-audio-only-mode .vjs-control-bar {
@include display-flex;
visibility: visible;
opacity: 1;
Expand Down Expand Up @@ -41,8 +42,9 @@
display: none !important;
}

// Don't hide the control bar if it's audio
.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
// Don't hide the control bar if it's audio or in audioOnlyMode
.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar,
.vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
opacity: 1;
visibility: visible;
}
Expand Down
4 changes: 4 additions & 0 deletions src/css/components/_descriptions.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.video-js .vjs-descriptions-button .vjs-icon-placeholder {
@extend .vjs-icon-audio-description;
}

.video-js.vjs-audio-only-mode .vjs-descriptions-button {
display: none;
}
5 changes: 5 additions & 0 deletions src/css/components/_fullscreen.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
@extend .vjs-icon-fullscreen-enter;
}
}

.video-js.vjs-audio-only-mode .vjs-fullscreen-control {
display: none;
}

// Switch to the exit icon when the player is in fullscreen
.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder {
@extend .vjs-icon-fullscreen-exit;
Expand Down
4 changes: 4 additions & 0 deletions src/css/components/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@
height: 100%;
}

.video-js.vjs-audio-only-mode .vjs-tech {
display: none;
}

// Fullscreen Styles
body.vjs-full-window {
padding: 0;
Expand Down
5 changes: 5 additions & 0 deletions src/css/components/_picture-in-picture.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
@extend .vjs-icon-picture-in-picture-enter;
}
}

.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control {
display: none;
}

// Switch to the exit icon when the player is in Picture-in-Picture
.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder {
@extend .vjs-icon-picture-in-picture-exit;
Expand Down
4 changes: 4 additions & 0 deletions src/css/components/_subs-caps.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@
font-size: 1.5em;
line-height: inherit;
}

.video-js.vjs-audio-only-mode .vjs-subs-caps-button {
display: none;
}
112 changes: 112 additions & 0 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,15 @@ class Player extends Component {
// Init debugEnabled_
this.debugEnabled_ = false;

// Init state audioOnlyMode_
this.audioOnlyMode_ = false;

// Init state audioOnlyCache_
this.audioOnlyCache_ = {
playerHeight: null,
hiddenChildren: []
};

// if the global option object was accidentally blown away by
// someone, bail early with an informative error
if (!this.options_ ||
Expand Down Expand Up @@ -574,6 +583,7 @@ class Player extends Component {

this.breakpoints(this.options_.breakpoints);
this.responsive(this.options_.responsive);
this.audioOnlyMode(this.options_.audioOnlyMode);
}

/**
Expand Down Expand Up @@ -4293,6 +4303,107 @@ class Player extends Component {
return !!this.isAudio_;
}

updateAudioOnlyModeState_(value) {
this.audioOnlyMode_ = value;
this.trigger('audioonlymodechange');
}

enableAudioOnlyUI_() {
// Update styling immediately to show the control bar so we can get its height
this.addClass('vjs-audio-only-mode');

const playerChildren = this.children();
const controlBar = this.getChild('ControlBar');
const controlBarHeight = controlBar && controlBar.currentHeight();

// Hide all player components except the control bar. Control bar components
// needed only for video are hidden with CSS
playerChildren.forEach(child => {
if (child === controlBar) {
return;
}

if (child.el_ && !child.hasClass('vjs-hidden')) {
child.hide();

this.audioOnlyCache_.hiddenChildren.push(child);
}
});

this.audioOnlyCache_.playerHeight = this.currentHeight();

// Set the player height the same as the control bar
this.height(controlBarHeight);
this.updateAudioOnlyModeState_(true);
}

disableAudioOnlyUI_() {
this.removeClass('vjs-audio-only-mode');

// Show player components that were previously hidden
this.audioOnlyCache_.hiddenChildren.forEach(child => child.show());

// Reset player height
this.height(this.audioOnlyCache_.playerHeight);
this.updateAudioOnlyModeState_(false);
}

/**
* Get the current audioOnlyMode state or set audioOnlyMode to true or false.
*
* Setting this to `true` will hide all player components except the control bar,
* as well as control bar components needed only for video.
*
* @param {boolean} [value]
* The value to set audioOnlyMode to.
*
* @return {Promise|boolean}
* A Promise is returned when setting the state, and a boolean when getting
* the present state
*/
audioOnlyMode(value) {
if (typeof value !== 'boolean' || value === this.audioOnlyMode_) {
return this.audioOnlyMode_;
}

const PromiseClass = this.options_.Promise || window.Promise;

if (PromiseClass) {
// Enable Audio Only Mode
if (value) {
const exitPromises = [];

// Fullscreen and PiP are not supported in audioOnlyMode, so exit if we need to.
if (this.isInPictureInPicture()) {
exitPromises.push(this.exitPictureInPicture());
}

if (this.isFullscreen()) {
exitPromises.push(this.exitFullscreen());
}

return PromiseClass.all(exitPromises).then(() => this.enableAudioOnlyUI_());
}

// Disable Audio Only Mode
return PromiseClass.resolve().then(() => this.disableAudioOnlyUI_());
}

if (value) {
if (this.isInPictureInPicture()) {
this.exitPictureInPicture();
}

if (this.isFullscreen()) {
this.exitFullscreen();
}

this.enableAudioOnlyUI_();
} else {
this.disableAudioOnlyUI_();
}
}

/**
* Get the current audioPosterMode state or set audioPosterMode to true or false
*
Expand Down Expand Up @@ -5131,6 +5242,7 @@ Player.prototype.options_ = {

breakpoints: {},
responsive: false,
audioOnlyMode: false,
audioPosterMode: false
};

Expand Down
Loading