feat(liveStreamting) add configuration to customize streaming dialog

This commit is contained in:
Steffen Kolmer 2022-08-02 10:27:18 +02:00 committed by GitHub
parent 3f0e50a9cd
commit 87f6d27fb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 165 additions and 38 deletions

View File

@ -310,9 +310,6 @@ var config = {
// DEPRECATED. Use recordingService.sharingEnabled instead.
// fileRecordingsServiceSharingEnabled: false,
// Whether to enable live streaming or not.
// liveStreamingEnabled: false,
// Local recording configuration.
// localRecording: {
// // Whether to disable local recording or not.
@ -325,6 +322,23 @@ var config = {
// disableSelfRecording: false,
// },
// Customize the Live Streaming dialog. Can be modified for a non-YouTube provider.
// liveStreaming: {
// // Whether to enable live streaming or not.
// enabled: false,
// // Terms link
// termsLink: 'https://www.youtube.com/t/terms',
// // Data privacy link
// dataPrivacyLink: 'https://policies.google.com/privacy',
// // RegExp string that validates the stream key input field
// validatorRegExpString: '^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}',
// // Documentation reference for the live streaming feature.
// helpLink: 'https://jitsi.org/live'
// },
// DEPRECATED. Use liveStreaming.enabled instead.
// liveStreamingEnabled: false,
// DEPRECATED. Use transcription.enabled instead.
// transcribingEnabled: false,

View File

@ -90,7 +90,6 @@ var interfaceConfig = {
JITSI_WATERMARK_LINK: 'https://jitsi.org',
LANG_DETECTION: true, // Allow i18n to detect the system language
LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live', // Documentation reference for the live streaming feature.
LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
/**
@ -248,6 +247,10 @@ var interfaceConfig = {
// Moved to config.js as `toolbarConfig.initialTimeout`.
// INITIAL_TOOLBAR_TIMEOUT: 20000,
// Please use `liveStreaming.helpLink` from config.js
// Documentation reference for the live streaming feature.
// LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live',
// Moved to config.js as `toolbarConfig.alwaysVisible`.
// TOOLBAR_ALWAYS_VISIBLE: false,

View File

@ -332,6 +332,13 @@ export interface IConfig {
lastNLimits?: {
[key: number]: number;
};
liveStreaming?: {
dataPrivacyLink?: string;
enabled?: boolean;
helpLink?: string;
termsLink?: string;
validatorRegExpString?: string;
};
liveStreamingEnabled?: boolean;
localRecording?: {
disable?: boolean;

View File

@ -183,6 +183,7 @@ export default [
'iceTransportPolicy',
'ignoreStartMuted',
'inviteAppName',
'liveStreaming',
'liveStreamingEnabled',
'localRecording',
'localSubject',

View File

@ -420,6 +420,26 @@ function _translateLegacyConfig(oldValue: IConfig) {
};
}
newValue.liveStreaming = newValue.liveStreaming || {};
// Migrate config.liveStreamingEnabled
if (oldValue.liveStreamingEnabled !== undefined) {
newValue.liveStreaming = {
...newValue.liveStreaming,
enabled: oldValue.liveStreamingEnabled
};
}
// Migrate interfaceConfig.LIVE_STREAMING_HELP_LINK
if (oldValue.liveStreaming === undefined
&& typeof interfaceConfig === 'object'
&& interfaceConfig.hasOwnProperty('LIVE_STREAMING_HELP_LINK')) {
newValue.liveStreaming = {
...newValue.liveStreaming,
helpLink: interfaceConfig.LIVE_STREAMING_HELP_LINK
};
}
return newValue;
}

View File

@ -3,6 +3,7 @@
import type { Dispatch } from 'redux';
import { getShareInfoText } from '../invite';
import { getLiveStreaming } from '../recording/components/LiveStream/functions';
import {
SET_GOOGLE_API_PROFILE,
@ -36,15 +37,16 @@ export function loadGoogleAPI() {
googleApi.get()
.then(() => {
const {
liveStreamingEnabled,
enableCalendarIntegration,
googleApiApplicationClientID
} = getState()['features/base/config'];
const liveStreaming = getLiveStreaming(getState());
if (getState()['features/google-api'].googleAPIState
=== GOOGLE_API_STATES.NEEDS_LOADING) {
return googleApi.initializeClient(
googleApiApplicationClientID, liveStreamingEnabled, enableCalendarIntegration);
googleApiApplicationClientID, liveStreaming.enabled, enableCalendarIntegration);
}
return Promise.resolve();

View File

@ -12,6 +12,8 @@ import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
import { FEATURES } from '../../../jaas/constants';
import { getActiveSession } from '../../functions';
import { getLiveStreaming } from './functions';
/**
* The type of the React {@code Component} props of
@ -141,12 +143,12 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
// its own to be visible or not.
const isModerator = isLocalParticipantModerator(state);
const {
enableFeaturesBasedOnToken,
liveStreamingEnabled
enableFeaturesBasedOnToken
} = state['features/base/config'];
const liveStreaming = getLiveStreaming(state);
const { features = {} } = getLocalParticipant(state);
visible = isModerator && liveStreamingEnabled;
visible = isModerator && liveStreaming.enabled;
if (enableFeaturesBasedOnToken) {
visible = visible && String(features.livestreaming) === 'true';

View File

@ -3,21 +3,35 @@
import debounce from 'lodash/debounce';
import { Component } from 'react';
declare var interfaceConfig: Object;
import { getLiveStreaming } from './functions';
/**
* The live streaming help link to display. On web it comes from
* interfaceConfig, but we don't have that on mobile.
*
* FIXME: This is in props now to prepare for the Redux-based interfaceConfig.
*/
const LIVE_STREAMING_HELP_LINK = 'https://jitsi.org/live';
export type LiveStreaming = {
enabled: boolean,
helpLink: string, // Documentation reference for the live streaming feature.
termsLink: string, // Terms link
dataPrivacyLink: string, // Data privacy link
validatorRegExpString: string // RegExp string that validates the stream key input field
}
export type LiveStreamingProps = {
enabled: boolean,
helpURL: string,
termsURL: string,
dataPrivacyURL: string,
streamLinkRegexp: RegExp
}
/**
* The props of the component.
*/
export type Props = {
/**
* The live streaming dialog properties.
*/
_liveStreaming: LiveStreamingProps,
/**
* Callback invoked when the entered stream key has changed.
*/
@ -54,7 +68,7 @@ type State = {
*/
export default class AbstractStreamKeyForm<P: Props>
extends Component<P, State> {
helpURL: string;
_debouncedUpdateValidationErrorVisibility: Function;
/**
@ -70,10 +84,6 @@ export default class AbstractStreamKeyForm<P: Props>
&& !this._validateStreamKey(this.props.value)
};
this.helpURL = (typeof interfaceConfig !== 'undefined'
&& interfaceConfig.LIVE_STREAMING_HELP_LINK)
|| LIVE_STREAMING_HELP_LINK;
this._debouncedUpdateValidationErrorVisibility = debounce(
this._updateValidationErrorVisibility.bind(this),
800,
@ -150,9 +160,22 @@ export default class AbstractStreamKeyForm<P: Props>
*/
_validateStreamKey(streamKey = '') {
const trimmedKey = streamKey.trim();
const fourGroupsDashSeparated = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/;
const match = fourGroupsDashSeparated.exec(trimmedKey);
const match = this.props._liveStreaming.streamLinkRegexp.exec(trimmedKey);
return Boolean(match);
}
}
/**
* Maps part of the Redux state to the component's props.
*
* @param {Object} state - The Redux state.
* @returns {{
* _liveStreaming: LiveStreamingProps
* }}
*/
export function _mapStateToProps(state: Object) {
return {
_liveStreaming: getLiveStreaming(state)
};
}

View File

@ -13,3 +13,14 @@ export const YOUTUBE_LIVE_DASHBOARD_URL = 'https://www.youtube.com/live_dashboar
* The URL for YouTube terms and conditions.
*/
export const YOUTUBE_TERMS_URL = 'https://www.youtube.com/t/terms';
/**
* The live streaming help link to display.
*/
export const JITSI_LIVE_STREAMING_HELP_LINK = 'https://jitsi.org/live';
/**
* The YouTube stream link RegExp.
*/
export const FOUR_GROUPS_DASH_SEPARATED = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/;

View File

@ -0,0 +1,27 @@
import {
FOUR_GROUPS_DASH_SEPARATED,
GOOGLE_PRIVACY_POLICY,
JITSI_LIVE_STREAMING_HELP_LINK,
YOUTUBE_TERMS_URL
} from './constants';
/**
* Get the live streaming options.
*
* @param {Object} state - The global state.
* @returns {LiveStreaming}
*/
export function getLiveStreaming(state: Object) {
const { liveStreaming = {} } = state['features/base/config'];
const regexp = liveStreaming.validatorRegExpString
&& new RegExp(liveStreaming.validatorRegExpString);
return {
enabled: Boolean(liveStreaming.enabled),
helpURL: liveStreaming.helpLink || JITSI_LIVE_STREAMING_HELP_LINK,
termsURL: liveStreaming.termsLink || YOUTUBE_TERMS_URL,
dataPrivacyURL: liveStreaming.dataPrivacyLink || GOOGLE_PRIVACY_POLICY,
streamLinkRegexp: regexp || FOUR_GROUPS_DASH_SEPARATED
};
}

View File

@ -10,7 +10,9 @@ import { StyleType } from '../../../../base/styles';
import AbstractStreamKeyForm, {
type Props as AbstractProps
} from '../AbstractStreamKeyForm';
import { GOOGLE_PRIVACY_POLICY, YOUTUBE_TERMS_URL } from '../constants';
import { getLiveStreaming } from '../functions';
import styles, { PLACEHOLDER_COLOR } from './styles';
type Props = AbstractProps & {
@ -20,8 +22,6 @@ type Props = AbstractProps & {
_dialogStyles: StyleType
};
import styles, { PLACEHOLDER_COLOR } from './styles';
/**
* A React Component for entering a key for starting a YouTube live stream.
*
@ -148,7 +148,7 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
* @returns {void}
*/
_onOpenGooglePrivacyPolicy() {
Linking.openURL(GOOGLE_PRIVACY_POLICY);
Linking.openURL(this.props._liveStreaming.dataPrivacyURL);
}
_onOpenHelp: () => void;
@ -161,7 +161,7 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
* @returns {void}
*/
_onOpenHelp() {
const { helpURL } = this;
const helpURL = this.props._liveStreaming.helpURL;
if (typeof helpURL === 'string') {
Linking.openURL(helpURL);
@ -177,8 +177,25 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
* @returns {void}
*/
_onOpenYoutubeTerms() {
Linking.openURL(YOUTUBE_TERMS_URL);
Linking.openURL(this.props._liveStreaming.termsURL);
}
}
export default translate(connect(_abstractMapStateToProps)(StreamKeyForm));
/**
* Maps (parts of) the redux state to the associated props for the
* {@code StreamKeyForm} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _liveStreaming: LiveStreamingProps
* }}
*/
function _mapStateToProps(state: Object) {
return {
..._abstractMapStateToProps(state),
_liveStreaming: getLiveStreaming(state)
};
}
export default translate(connect(_mapStateToProps)(StreamKeyForm));

View File

@ -4,10 +4,10 @@ import { FieldTextStateless } from '@atlaskit/field-text';
import React from 'react';
import { translate } from '../../../../base/i18n';
import { connect } from '../../../../base/redux';
import AbstractStreamKeyForm, {
type Props
type Props, _mapStateToProps
} from '../AbstractStreamKeyForm';
import { GOOGLE_PRIVACY_POLICY, YOUTUBE_TERMS_URL } from '../constants';
/**
* A React Component for entering a key for starting a YouTube live stream.
@ -62,7 +62,7 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
</span>
: null
}
{ this.helpURL
{ this.props._liveStreaming.helpURL
? <a
aria-label = { t('liveStreaming.streamIdHelp') }
className = 'helper-link'
@ -77,14 +77,14 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
</div>
<a
className = 'helper-link'
href = { YOUTUBE_TERMS_URL }
href = { this.props._liveStreaming.termsURL }
rel = 'noopener noreferrer'
target = '_blank'>
{ t('liveStreaming.youtubeTerms') }
</a>
<a
className = 'helper-link'
href = { GOOGLE_PRIVACY_POLICY }
href = { this.props._liveStreaming.dataPrivacyURL }
rel = 'noopener noreferrer'
target = '_blank'>
{ t('liveStreaming.googlePrivacyPolicy') }
@ -106,7 +106,7 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
* @returns {void}
*/
_onOpenHelp() {
window.open(this.helpURL, '_blank', 'noopener');
window.open(this.props._liveStreaming.helpURL, '_blank', 'noopener');
}
_onOpenHelpKeyPress: () => void;
@ -128,4 +128,4 @@ class StreamKeyForm extends AbstractStreamKeyForm<Props> {
}
}
export default translate(StreamKeyForm);
export default translate(connect(_mapStateToProps)(StreamKeyForm));