From b0b8b6ec8b17d7837307afd05f53d24e701ab526 Mon Sep 17 00:00:00 2001 From: Robert Oanta Date: Tue, 2 May 2023 11:32:34 +0300 Subject: [PATCH 1/6] feat(livestream): add separate fields for stream URL and stream key --- css/_recording.scss | 8 ++- lang/main-enGB.json | 6 ++- lang/main.json | 6 ++- react/features/recording/actionTypes.ts | 10 ++++ .../AbstractStartLiveStreamDialog.ts | 52 ++++++++++++++++--- .../LiveStream/AbstractStreamKeyForm.ts | 51 +++++++++++++----- .../components/LiveStream/constants.ts | 5 ++ .../LiveStream/web/StartLiveStreamDialog.tsx | 9 ++-- .../LiveStream/web/StreamKeyForm.tsx | 18 +++++-- react/features/recording/reducer.ts | 8 +++ 10 files changed, 138 insertions(+), 35 deletions(-) diff --git a/css/_recording.scss b/css/_recording.scss index 2b06bf80ec26..c2deae0dd204 100644 --- a/css/_recording.scss +++ b/css/_recording.scss @@ -191,10 +191,14 @@ .google-panel { align-items: center; - border-bottom: 2px solid rgba(0, 0, 0, 0.3); + border-bottom: 1px solid #5e6d7a; display: flex; flex-direction: column; - padding-bottom: 10px; + padding-bottom: 20px; + } + + .stream-key-form { + padding-top: 20px; } .warning-text { diff --git a/lang/main-enGB.json b/lang/main-enGB.json index 95a4f93ca0b1..69c65e35014e 100644 --- a/lang/main-enGB.json +++ b/lang/main-enGB.json @@ -277,7 +277,8 @@ "stopRecording": "Stop recording", "stopRecordingWarning": "Are you sure you would like to stop the recording?", "stopStreamingWarning": "Are you sure you would like to stop the live streaming?", - "streamKey": "Live stream key", + "streamKey": "Stream key", + "streamBaseURL": "Stream URL", "thankYou": "Thank you for using {{appName}}!", "token": "token", "tokenAuthFailed": "Sorry, you're not allowed to join this call.", @@ -373,7 +374,8 @@ "changeSignIn": "Switch accounts.", "choose": "Choose a live stream", "chooseCTA": "Choose a streaming option. You're currently logged in as {{email}}.", - "enterStreamKey": "Enter your YouTube live stream key here.", + "enterStreamKey": "Enter your live stream key here.", + "enterStreamBaseURL": "Enter your live stream URL here.", "error": "Live Streaming failed. Please try again.", "errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.", "errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.", diff --git a/lang/main.json b/lang/main.json index da3a2813f033..5a9b263d1333 100644 --- a/lang/main.json +++ b/lang/main.json @@ -417,7 +417,8 @@ "stopRecording": "Stop recording", "stopRecordingWarning": "Are you sure you would like to stop the recording?", "stopStreamingWarning": "Are you sure you would like to stop the live streaming?", - "streamKey": "Live stream key", + "streamKey": "Stream key", + "streamBaseURL": "Stream URL", "thankYou": "Thank you for using {{appName}}!", "token": "token", "tokenAuthFailed": "Sorry, you're not allowed to join this call.", @@ -554,7 +555,8 @@ "changeSignIn": "Switch accounts.", "choose": "Choose a live stream", "chooseCTA": "Choose a streaming option. You're currently logged in as {{email}}.", - "enterStreamKey": "Enter your YouTube live stream key here.", + "enterStreamKey": "Enter your live stream key here.", + "enterStreamBaseURL": "Enter your live stream URL here.", "error": "Live Streaming failed. Please try again.", "errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.", "errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.", diff --git a/react/features/recording/actionTypes.ts b/react/features/recording/actionTypes.ts index 71f5b858bb39..856c48e59003 100644 --- a/react/features/recording/actionTypes.ts +++ b/react/features/recording/actionTypes.ts @@ -55,6 +55,16 @@ export const SET_SELECTED_RECORDING_SERVICE = 'SET_SELECTED_RECORDING_SERVICE'; */ export const SET_STREAM_KEY = 'SET_STREAM_KEY'; +/** + * Sets the stream base url last used by the user for later reuse. + * + * { + * type: SET_STREAM_BASE_URL, + * streamKey: string + * } + */ +export const SET_STREAM_BASE_URL = 'SET_STREAM_BASE_URL'; + /** * Sets the enable state of the meeting highlight button. * diff --git a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts index a8fd14e8a973..cffe865f63db 100644 --- a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts +++ b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts @@ -6,6 +6,7 @@ import { sendAnalytics } from '../../../analytics/functions'; import { IReduxState } from '../../../app/types'; import { IJitsiConference } from '../../../base/conference/reducer'; import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet'; +import { YOUTUBE_RTMP_URL } from './constants'; /** * The type of the React {@code Component} props of @@ -35,6 +36,11 @@ export interface IProps extends WithTranslation { */ _streamKey?: string; + /** + * The live stream base URL that was used before. + */ + _streamBaseURL?: string; + /** * The Redux dispatch function. */ @@ -71,6 +77,11 @@ export interface IState { * The selected or entered stream key to use for YouTube live streaming. */ streamKey?: string; + + /** + * The entered stream base URL to use for YouTube live streaming. + */ + streamBaseURL?: string; } /** @@ -96,7 +107,8 @@ export default class AbstractStartLiveStreamDialog

broadcasts: undefined, errorType: undefined, selectedBoundStreamID: undefined, - streamKey: '' + streamKey: '', + streamBaseURL: YOUTUBE_RTMP_URL }; /** @@ -111,6 +123,7 @@ export default class AbstractStartLiveStreamDialog

this._onCancel = this._onCancel.bind(this); this._onStreamKeyChange = this._onStreamKeyChange.bind(this); + this._onStreamBaseURLChange = this._onStreamBaseURLChange.bind(this); this._onSubmit = this._onSubmit.bind(this); } @@ -171,7 +184,22 @@ export default class AbstractStartLiveStreamDialog

*/ _onStreamKeyChange(streamKey: string) { this._setStateIfMounted({ - streamKey, + streamKey: streamKey, + selectedBoundStreamID: undefined + }); + } + + /** + * Callback invoked to update the {@code StartLiveStreamDialog} component's + * display of the entered YouTube stream base URL. + * + * @param {string} streamBaseURL - The stream base URL entered in the field. + * @private + * @returns {void} + */ + _onStreamBaseURLChange(streamBaseURL: string) { + this._setStateIfMounted({ + streamBaseURL: streamBaseURL, selectedBoundStreamID: undefined }); } @@ -188,13 +216,19 @@ export default class AbstractStartLiveStreamDialog

const { broadcasts, selectedBoundStreamID } = this.state; const key = (this.state.streamKey || this.props._streamKey || '').trim(); + const base = (this.state.streamBaseURL || this.props._streamBaseURL || '').trim(); - if (!key) { + if (!base) { return false; } - + if (!key){ + return false; + } + + const rtmpURL = base.endsWith("/") ? base + key : base + "/" + key; let selectedBroadcastID = null; + // to modify this too maybe? if (selectedBoundStreamID) { const selectedBroadcast = broadcasts?.find( broadcast => broadcast.boundStreamID === selectedBoundStreamID); @@ -204,11 +238,11 @@ export default class AbstractStartLiveStreamDialog

sendAnalytics( createLiveStreamingDialogEvent('start', 'confirm.button')); - + this.props._conference?.startRecording({ broadcastId: selectedBroadcastID, mode: JitsiRecordingConstants.mode.STREAM, - streamId: key + streamId: rtmpURL }); return true; @@ -238,7 +272,8 @@ export default class AbstractStartLiveStreamDialog

* _conference: Object, * _googleAPIState: number, * _googleProfileEmail: string, - * _streamKey: string + * _streamKey: string, + * _streamBaseUrl: string * }} */ export function _mapStateToProps(state: IReduxState) { @@ -246,6 +281,7 @@ export function _mapStateToProps(state: IReduxState) { _conference: state['features/base/conference'].conference, _googleAPIState: state['features/google-api'].googleAPIState, _googleProfileEmail: state['features/google-api'].profileEmail, - _streamKey: state['features/recording'].streamKey + _streamKey: state['features/recording'].streamKey, + _streamBaseURL: state['features/recording'].streamBaseURL }; } diff --git a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts index b500d97b462b..72fc6f6826cd 100644 --- a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts +++ b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts @@ -43,12 +43,22 @@ export interface IProps extends WithTranslation { /** * Callback invoked when the entered stream key has changed. */ - onChange: Function; + onStreamKeyChange: Function; + + /** + * Callback invoked when the entered stream base url has changed. + */ + onStreamBaseURLChange: Function; /** * The stream key value to display as having been entered so far. */ - value: string; + streamKeyValue: string; + + /** + * The stream base URL value to display as having been entered so far. + */ + streamBaseURLValue: string; } /** @@ -83,8 +93,8 @@ export default class AbstractStreamKeyForm

super(props); this.state = { - showValidationError: Boolean(this.props.value) - && !this._validateStreamKey(this.props.value) + showValidationError: Boolean(this.props.streamKeyValue) + && !this._validateStreamKey(this.props.streamKeyValue) }; this._debouncedUpdateValidationErrorVisibility = debounce( @@ -94,7 +104,8 @@ export default class AbstractStreamKeyForm

); // Bind event handlers so they are only bound once per instance. - this._onInputChange = this._onInputChange.bind(this); + this._onStreamKeyChange = this._onStreamKeyChange.bind(this); + this._onStreamBaseURLChange = this._onStreamBaseURLChange.bind(this); } /** @@ -103,7 +114,7 @@ export default class AbstractStreamKeyForm

* @inheritdoc */ componentDidUpdate(prevProps: P) { - if (this.props.value !== prevProps.value) { + if (this.props.streamKeyValue !== prevProps.streamKeyValue) { this._debouncedUpdateValidationErrorVisibility(); } } @@ -118,19 +129,35 @@ export default class AbstractStreamKeyForm

} /** - * Callback invoked when the value of the input field has updated through + * Callback invoked when the value of the input stream key field has updated through + * user input. This forwards the value (string only, even if it was a dom + * event) to the onStreamKeyChange prop provided to the component. + * + * @param {Object | string} change - DOM Event for value change or the + * changed text. + * @private + * @returns {void} + */ + _onStreamKeyChange(change: any) { + const value = typeof change === 'object' ? change.target.value : change; + + this.props.onStreamKeyChange(value); + } + + /** + * Callback invoked when the value of the input stream baser url field has updated through * user input. This forwards the value (string only, even if it was a dom - * event) to the onChange prop provided to the component. + * event) to the onStreamBaseURLChange prop provided to the component. * * @param {Object | string} change - DOM Event for value change or the * changed text. * @private * @returns {void} */ - _onInputChange(change: any) { + _onStreamBaseURLChange(change: any) { const value = typeof change === 'object' ? change.target.value : change; - this.props.onChange(value); + this.props.onStreamBaseURLChange(value); } /** @@ -142,8 +169,8 @@ export default class AbstractStreamKeyForm

* @returns {boolean} */ _updateValidationErrorVisibility() { - const newShowValidationError = Boolean(this.props.value) - && !this._validateStreamKey(this.props.value); + const newShowValidationError = Boolean(this.props.streamKeyValue) + && !this._validateStreamKey(this.props.streamKeyValue); if (newShowValidationError !== this.state.showValidationError) { this.setState({ diff --git a/react/features/recording/components/LiveStream/constants.ts b/react/features/recording/components/LiveStream/constants.ts index 1f83107b9b03..9315ef77b3f7 100644 --- a/react/features/recording/components/LiveStream/constants.ts +++ b/react/features/recording/components/LiveStream/constants.ts @@ -24,3 +24,8 @@ export const JITSI_LIVE_STREAMING_HELP_LINK = 'https://jitsi.org/live'; */ export const FOUR_GROUPS_DASH_SEPARATED = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/; +/** + * The default live streaming URL to display. + */ +export const YOUTUBE_RTMP_URL= 'rtmp://a.rtmp.youtube.com/live2'; + diff --git a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx index c882fcfbd81d..f50d9a3b9492 100644 --- a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx +++ b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx @@ -92,10 +92,11 @@ class StartLiveStreamDialog { _googleApiApplicationClientID ? this._renderYouTubePanel() : null } + onStreamKeyChange = { this._onStreamKeyChange } + onStreamBaseURLChange = { this._onStreamBaseURLChange} + streamKeyValue = {this.state.streamKey || this.props._streamKey || ''} + streamBaseURLValue = {this.state.streamBaseURL || this.props._streamBaseURL || ''} + /> ); diff --git a/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx b/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx index 868cd38fa870..d3f2ac30d780 100644 --- a/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx +++ b/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx @@ -38,7 +38,6 @@ const styles = (theme: Theme) => { * @augments Component */ class StreamKeyForm extends AbstractStreamKeyForm { - /** * Initializes a new {@code StreamKeyForm} instance. * @@ -60,18 +59,27 @@ class StreamKeyForm extends AbstractStreamKeyForm { * @returns {ReactElement} */ render() { - const { classes, t, value } = this.props; + const { classes, t, streamKeyValue, streamBaseURLValue} = this.props; return (

+ +
+ value = { streamKeyValue } />
{ diff --git a/react/features/recording/reducer.ts b/react/features/recording/reducer.ts index 9e50a00ba488..bed704cd0fe1 100644 --- a/react/features/recording/reducer.ts +++ b/react/features/recording/reducer.ts @@ -6,6 +6,7 @@ import { SET_MEETING_HIGHLIGHT_BUTTON_STATE, SET_PENDING_RECORDING_NOTIFICATION_UID, SET_SELECTED_RECORDING_SERVICE, + SET_STREAM_BASE_URL, SET_STREAM_KEY } from './actionTypes'; @@ -34,6 +35,7 @@ export interface IRecordingState { }; selectedRecordingService: string; sessionDatas: Array; + streamBaseURL?: string; streamKey?: string; } @@ -88,6 +90,12 @@ ReducerRegistry.register(STORE_NAME, streamKey: action.streamKey }; + case SET_STREAM_BASE_URL: + return { + ...state, + streamBaseURL: action.streamBaseURL + }; + case SET_MEETING_HIGHLIGHT_BUTTON_STATE: return { ...state, From 2692a44ed13edffc5296d457c88a5b9a41b9a38d Mon Sep 17 00:00:00 2001 From: Robert Oanta Date: Tue, 2 May 2023 12:58:46 +0300 Subject: [PATCH 2/6] feat(livestream): alphabetical refactor --- lang/main-enGB.json | 2 +- lang/main.json | 2 +- react/features/recording/actionTypes.ts | 12 +++---- react/features/recording/actions.any.ts | 17 ++++++++++ .../AbstractStartLiveStreamDialog.ts | 16 +++++----- .../LiveStream/AbstractStreamKeyForm.ts | 32 +++++++++---------- .../components/LiveStream/constants.ts | 9 +++--- .../LiveStream/web/StartLiveStreamDialog.tsx | 4 +-- react/features/recording/reducer.ts | 8 ++--- 9 files changed, 60 insertions(+), 42 deletions(-) diff --git a/lang/main-enGB.json b/lang/main-enGB.json index 69c65e35014e..f20befc2ffa1 100644 --- a/lang/main-enGB.json +++ b/lang/main-enGB.json @@ -374,8 +374,8 @@ "changeSignIn": "Switch accounts.", "choose": "Choose a live stream", "chooseCTA": "Choose a streaming option. You're currently logged in as {{email}}.", - "enterStreamKey": "Enter your live stream key here.", "enterStreamBaseURL": "Enter your live stream URL here.", + "enterStreamKey": "Enter your live stream key here.", "error": "Live Streaming failed. Please try again.", "errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.", "errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.", diff --git a/lang/main.json b/lang/main.json index 5a9b263d1333..b628b076c0ff 100644 --- a/lang/main.json +++ b/lang/main.json @@ -417,8 +417,8 @@ "stopRecording": "Stop recording", "stopRecordingWarning": "Are you sure you would like to stop the recording?", "stopStreamingWarning": "Are you sure you would like to stop the live streaming?", - "streamKey": "Stream key", "streamBaseURL": "Stream URL", + "streamKey": "Stream key", "thankYou": "Thank you for using {{appName}}!", "token": "token", "tokenAuthFailed": "Sorry, you're not allowed to join this call.", diff --git a/react/features/recording/actionTypes.ts b/react/features/recording/actionTypes.ts index 856c48e59003..e7943ea63fa2 100644 --- a/react/features/recording/actionTypes.ts +++ b/react/features/recording/actionTypes.ts @@ -46,24 +46,24 @@ export const SET_PENDING_RECORDING_NOTIFICATION_UID export const SET_SELECTED_RECORDING_SERVICE = 'SET_SELECTED_RECORDING_SERVICE'; /** - * Sets the stream key last used by the user for later reuse. + * Sets the stream base url last used by the user for later reuse. * * { - * type: SET_STREAM_KEY, + * type: SET_STREAM_BASE_URL, * streamKey: string * } */ -export const SET_STREAM_KEY = 'SET_STREAM_KEY'; +export const SET_STREAM_BASE_URL = 'SET_STREAM_BASE_URL'; /** - * Sets the stream base url last used by the user for later reuse. + * Sets the stream key last used by the user for later reuse. * * { - * type: SET_STREAM_BASE_URL, + * type: SET_STREAM_KEY, * streamKey: string * } */ -export const SET_STREAM_BASE_URL = 'SET_STREAM_BASE_URL'; +export const SET_STREAM_KEY = 'SET_STREAM_KEY'; /** * Sets the enable state of the meeting highlight button. diff --git a/react/features/recording/actions.any.ts b/react/features/recording/actions.any.ts index 5558deb5de6f..97c50b1c3b88 100644 --- a/react/features/recording/actions.any.ts +++ b/react/features/recording/actions.any.ts @@ -20,6 +20,7 @@ import { SET_PENDING_RECORDING_NOTIFICATION_UID, SET_SELECTED_RECORDING_SERVICE, SET_STREAM_KEY, + SET_STREAM_BASE_URL, START_LOCAL_RECORDING, STOP_LOCAL_RECORDING } from './actionTypes'; @@ -81,6 +82,22 @@ export function hidePendingRecordingNotification(streamType: string) { }; } +/** + * Sets the stream base url last used by the user for later reuse. + * + * @param {string} streamBaseURL - The stream base url to set. + * @returns {{ +* type: SET_STREAM_BASE_URL, +* streamBaseURL: string +* }} +*/ +export function setLiveStreamBaseURL(streamBaseURL: string) { + return { + type: SET_STREAM_BASE_URL, + streamBaseURL + }; +} + /** * Sets the stream key last used by the user for later reuse. * diff --git a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts index cffe865f63db..c2f736a79402 100644 --- a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts +++ b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts @@ -32,14 +32,14 @@ export interface IProps extends WithTranslation { _googleProfileEmail: string; /** - * The live stream key that was used before. + * The live stream base URL that was used before. */ - _streamKey?: string; + _streamBaseURL?: string; /** - * The live stream base URL that was used before. + * The live stream key that was used before. */ - _streamBaseURL?: string; + _streamKey?: string; /** * The Redux dispatch function. @@ -74,14 +74,14 @@ export interface IState { selectedBoundStreamID?: string; /** - * The selected or entered stream key to use for YouTube live streaming. + * The entered stream base URL to use for YouTube live streaming. */ - streamKey?: string; + streamBaseURL?: string; /** - * The entered stream base URL to use for YouTube live streaming. + * The selected or entered stream key to use for YouTube live streaming. */ - streamBaseURL?: string; + streamKey?: string; } /** diff --git a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts index 72fc6f6826cd..ed8f5140032a 100644 --- a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts +++ b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts @@ -40,25 +40,25 @@ export interface IProps extends WithTranslation { classes?: any; + /** + * Callback invoked when the entered stream base url has changed. + */ + onStreamBaseURLChange: Function; + /** * Callback invoked when the entered stream key has changed. */ onStreamKeyChange: Function; /** - * Callback invoked when the entered stream base url has changed. + * The stream base URL value to display as having been entered so far. */ - onStreamBaseURLChange: Function; + streamBaseURLValue: string; /** * The stream key value to display as having been entered so far. */ streamKeyValue: string; - - /** - * The stream base URL value to display as having been entered so far. - */ - streamBaseURLValue: string; } /** @@ -127,37 +127,37 @@ export default class AbstractStreamKeyForm

componentWillUnmount() { this._debouncedUpdateValidationErrorVisibility.cancel(); } - + /** - * Callback invoked when the value of the input stream key field has updated through + * Callback invoked when the value of the input stream baser url field has updated through * user input. This forwards the value (string only, even if it was a dom - * event) to the onStreamKeyChange prop provided to the component. + * event) to the onStreamBaseURLChange prop provided to the component. * * @param {Object | string} change - DOM Event for value change or the * changed text. * @private * @returns {void} */ - _onStreamKeyChange(change: any) { + _onStreamBaseURLChange(change: any) { const value = typeof change === 'object' ? change.target.value : change; - this.props.onStreamKeyChange(value); + this.props.onStreamBaseURLChange(value); } /** - * Callback invoked when the value of the input stream baser url field has updated through + * Callback invoked when the value of the input stream key field has updated through * user input. This forwards the value (string only, even if it was a dom - * event) to the onStreamBaseURLChange prop provided to the component. + * event) to the onStreamKeyChange prop provided to the component. * * @param {Object | string} change - DOM Event for value change or the * changed text. * @private * @returns {void} */ - _onStreamBaseURLChange(change: any) { + _onStreamKeyChange(change: any) { const value = typeof change === 'object' ? change.target.value : change; - this.props.onStreamBaseURLChange(value); + this.props.onStreamKeyChange(value); } /** diff --git a/react/features/recording/components/LiveStream/constants.ts b/react/features/recording/components/LiveStream/constants.ts index 9315ef77b3f7..4b60e845e916 100644 --- a/react/features/recording/components/LiveStream/constants.ts +++ b/react/features/recording/components/LiveStream/constants.ts @@ -9,6 +9,11 @@ export const GOOGLE_PRIVACY_POLICY = 'https://policies.google.com/privacy'; */ export const YOUTUBE_LIVE_DASHBOARD_URL = 'https://www.youtube.com/live_dashboard'; +/** + * The default live streaming URL to display. + */ +export const YOUTUBE_RTMP_URL= 'rtmp://a.rtmp.youtube.com/live2'; + /** * The URL for YouTube terms and conditions. */ @@ -24,8 +29,4 @@ export const JITSI_LIVE_STREAMING_HELP_LINK = 'https://jitsi.org/live'; */ export const FOUR_GROUPS_DASH_SEPARATED = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/; -/** - * The default live streaming URL to display. - */ -export const YOUTUBE_RTMP_URL= 'rtmp://a.rtmp.youtube.com/live2'; diff --git a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx index f50d9a3b9492..5048de35b8bd 100644 --- a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx +++ b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx @@ -92,10 +92,10 @@ class StartLiveStreamDialog { _googleApiApplicationClientID ? this._renderYouTubePanel() : null }

diff --git a/react/features/recording/reducer.ts b/react/features/recording/reducer.ts index bed704cd0fe1..0f5d88bb31e2 100644 --- a/react/features/recording/reducer.ts +++ b/react/features/recording/reducer.ts @@ -84,16 +84,16 @@ ReducerRegistry.register(STORE_NAME, }; } - case SET_STREAM_KEY: + case SET_STREAM_BASE_URL: return { ...state, - streamKey: action.streamKey + streamBaseURL: action.streamBaseURL }; - case SET_STREAM_BASE_URL: + case SET_STREAM_KEY: return { ...state, - streamBaseURL: action.streamBaseURL + streamKey: action.streamKey }; case SET_MEETING_HIGHLIGHT_BUTTON_STATE: From 9b6633df7a1ea3dba06d173c0a46e02b693f3a10 Mon Sep 17 00:00:00 2001 From: Robert Oanta Date: Tue, 2 May 2023 13:08:40 +0300 Subject: [PATCH 3/6] feat(livestream): alphabetical refactor 2 --- lang/main-enGB.json | 2 +- lang/main.json | 2 +- react/features/recording/actions.any.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/main-enGB.json b/lang/main-enGB.json index f20befc2ffa1..172b69092d32 100644 --- a/lang/main-enGB.json +++ b/lang/main-enGB.json @@ -277,8 +277,8 @@ "stopRecording": "Stop recording", "stopRecordingWarning": "Are you sure you would like to stop the recording?", "stopStreamingWarning": "Are you sure you would like to stop the live streaming?", - "streamKey": "Stream key", "streamBaseURL": "Stream URL", + "streamKey": "Stream key", "thankYou": "Thank you for using {{appName}}!", "token": "token", "tokenAuthFailed": "Sorry, you're not allowed to join this call.", diff --git a/lang/main.json b/lang/main.json index b628b076c0ff..969c99448a77 100644 --- a/lang/main.json +++ b/lang/main.json @@ -555,8 +555,8 @@ "changeSignIn": "Switch accounts.", "choose": "Choose a live stream", "chooseCTA": "Choose a streaming option. You're currently logged in as {{email}}.", - "enterStreamKey": "Enter your live stream key here.", "enterStreamBaseURL": "Enter your live stream URL here.", + "enterStreamKey": "Enter your live stream key here.", "error": "Live Streaming failed. Please try again.", "errorAPI": "An error occurred while accessing your YouTube broadcasts. Please try logging in again.", "errorLiveStreamNotEnabled": "Live Streaming is not enabled on {{email}}. Please enable live streaming or log into an account with live streaming enabled.", diff --git a/react/features/recording/actions.any.ts b/react/features/recording/actions.any.ts index 97c50b1c3b88..7833496f53f0 100644 --- a/react/features/recording/actions.any.ts +++ b/react/features/recording/actions.any.ts @@ -19,8 +19,8 @@ import { SET_MEETING_HIGHLIGHT_BUTTON_STATE, SET_PENDING_RECORDING_NOTIFICATION_UID, SET_SELECTED_RECORDING_SERVICE, - SET_STREAM_KEY, SET_STREAM_BASE_URL, + SET_STREAM_KEY, START_LOCAL_RECORDING, STOP_LOCAL_RECORDING } from './actionTypes'; From 87bf5827388b2100d24702f176c01edde16cc284 Mon Sep 17 00:00:00 2001 From: Robert Oanta Date: Tue, 2 May 2023 13:20:22 +0300 Subject: [PATCH 4/6] feat(livestream): fix linter errors --- react/features/recording/actions.any.ts | 8 ++++---- .../LiveStream/AbstractStartLiveStreamDialog.ts | 13 +++++++------ .../components/LiveStream/AbstractStreamKeyForm.ts | 6 +++--- .../recording/components/LiveStream/constants.ts | 2 +- .../LiveStream/web/StartLiveStreamDialog.tsx | 7 +++---- .../components/LiveStream/web/StreamKeyForm.tsx | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/react/features/recording/actions.any.ts b/react/features/recording/actions.any.ts index 7833496f53f0..d5d03696ddd0 100644 --- a/react/features/recording/actions.any.ts +++ b/react/features/recording/actions.any.ts @@ -92,10 +92,10 @@ export function hidePendingRecordingNotification(streamType: string) { * }} */ export function setLiveStreamBaseURL(streamBaseURL: string) { - return { - type: SET_STREAM_BASE_URL, - streamBaseURL - }; + return { + type: SET_STREAM_BASE_URL, + streamBaseURL + }; } /** diff --git a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts index c2f736a79402..5e2bef1f9e70 100644 --- a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts +++ b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts @@ -6,6 +6,7 @@ import { sendAnalytics } from '../../../analytics/functions'; import { IReduxState } from '../../../app/types'; import { IJitsiConference } from '../../../base/conference/reducer'; import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet'; + import { YOUTUBE_RTMP_URL } from './constants'; /** @@ -184,7 +185,7 @@ export default class AbstractStartLiveStreamDialog

*/ _onStreamKeyChange(streamKey: string) { this._setStateIfMounted({ - streamKey: streamKey, + streamKey, selectedBoundStreamID: undefined }); } @@ -199,7 +200,7 @@ export default class AbstractStartLiveStreamDialog

*/ _onStreamBaseURLChange(streamBaseURL: string) { this._setStateIfMounted({ - streamBaseURL: streamBaseURL, + streamBaseURL, selectedBoundStreamID: undefined }); } @@ -221,11 +222,11 @@ export default class AbstractStartLiveStreamDialog

if (!base) { return false; } - if (!key){ + if (!key) { return false; } - - const rtmpURL = base.endsWith("/") ? base + key : base + "/" + key; + + const rtmpURL = base.endsWith('/') ? base + key : `${base}/${key}`; let selectedBroadcastID = null; // to modify this too maybe? @@ -238,7 +239,7 @@ export default class AbstractStartLiveStreamDialog

sendAnalytics( createLiveStreamingDialogEvent('start', 'confirm.button')); - + this.props._conference?.startRecording({ broadcastId: selectedBroadcastID, mode: JitsiRecordingConstants.mode.STREAM, diff --git a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts index ed8f5140032a..69a39bf27aa2 100644 --- a/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts +++ b/react/features/recording/components/LiveStream/AbstractStreamKeyForm.ts @@ -44,7 +44,7 @@ export interface IProps extends WithTranslation { * Callback invoked when the entered stream base url has changed. */ onStreamBaseURLChange: Function; - + /** * Callback invoked when the entered stream key has changed. */ @@ -127,7 +127,7 @@ export default class AbstractStreamKeyForm

componentWillUnmount() { this._debouncedUpdateValidationErrorVisibility.cancel(); } - + /** * Callback invoked when the value of the input stream baser url field has updated through * user input. This forwards the value (string only, even if it was a dom @@ -138,7 +138,7 @@ export default class AbstractStreamKeyForm

* @private * @returns {void} */ - _onStreamBaseURLChange(change: any) { + _onStreamBaseURLChange(change: any) { const value = typeof change === 'object' ? change.target.value : change; this.props.onStreamBaseURLChange(value); diff --git a/react/features/recording/components/LiveStream/constants.ts b/react/features/recording/components/LiveStream/constants.ts index 4b60e845e916..a817945b0308 100644 --- a/react/features/recording/components/LiveStream/constants.ts +++ b/react/features/recording/components/LiveStream/constants.ts @@ -12,7 +12,7 @@ export const YOUTUBE_LIVE_DASHBOARD_URL = 'https://www.youtube.com/live_dashboar /** * The default live streaming URL to display. */ -export const YOUTUBE_RTMP_URL= 'rtmp://a.rtmp.youtube.com/live2'; +export const YOUTUBE_RTMP_URL = 'rtmp://a.rtmp.youtube.com/live2'; /** * The URL for YouTube terms and conditions. diff --git a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx index 5048de35b8bd..cb2c6e70d721 100644 --- a/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx +++ b/react/features/recording/components/LiveStream/web/StartLiveStreamDialog.tsx @@ -92,11 +92,10 @@ class StartLiveStreamDialog { _googleApiApplicationClientID ? this._renderYouTubePanel() : null } + streamBaseURLValue = { this.state.streamBaseURL || this.props._streamBaseURL || '' } + streamKeyValue = { this.state.streamKey || this.props._streamKey || '' } />

); diff --git a/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx b/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx index d3f2ac30d780..23a7c18c4eda 100644 --- a/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx +++ b/react/features/recording/components/LiveStream/web/StreamKeyForm.tsx @@ -59,7 +59,7 @@ class StreamKeyForm extends AbstractStreamKeyForm { * @returns {ReactElement} */ render() { - const { classes, t, streamKeyValue, streamBaseURLValue} = this.props; + const { classes, t, streamKeyValue, streamBaseURLValue } = this.props; return (
From 8fa36ccc0eb2d9da25671b436c79f8f84a6ff16c Mon Sep 17 00:00:00 2001 From: Robert Oanta Date: Tue, 2 May 2023 13:45:34 +0300 Subject: [PATCH 5/6] feat(livestream): fix native errors --- .../LiveStream/native/StartLiveStreamDialog.tsx | 8 ++++---- .../components/LiveStream/native/StreamKeyForm.tsx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx b/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx index c25f996073e2..4891cc3f1a85 100644 --- a/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx +++ b/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx @@ -83,10 +83,10 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog { broadcasts = { this.state.broadcasts } onChange = { this._onStreamKeyPick } /> + onStreamBaseURLChange = { this._onStreamBaseURLChange } + onStreamKeyChange = { this._onStreamKeyChangeNative } + streamBaseURLValue = { this.state.streamBaseURL || this.props._streamBaseURL || '' } + streamKeyValue = { this.state.streamKey || this.props._streamKey || '' } /> ); } diff --git a/react/features/recording/components/LiveStream/native/StreamKeyForm.tsx b/react/features/recording/components/LiveStream/native/StreamKeyForm.tsx index f1a9c01c52cd..019563e190ff 100644 --- a/react/features/recording/components/LiveStream/native/StreamKeyForm.tsx +++ b/react/features/recording/components/LiveStream/native/StreamKeyForm.tsx @@ -61,9 +61,17 @@ class StreamKeyForm extends AbstractStreamKeyForm { customStyles = {{ input: styles.streamKeyInput, container: styles.streamKeyContainer }} - onChange = { this._onInputChange } + onChange = { this._onStreamBaseURLChange } + placeholder = { t('liveStreaming.enterStreamBaseURL') } + value = { this.props.streamBaseURLValue } /> +
+ + value = { this.props.streamKeyValue } /> { this.state.showValidationError && Date: Mon, 15 May 2023 14:58:48 +0300 Subject: [PATCH 6/6] preserve functionality for RTMP URL, use store for StreamBaseURL --- .../AbstractStartLiveStreamDialog.ts | 10 +++++----- .../native/StartLiveStreamDialog.tsx | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts index 5e2bef1f9e70..ac3051934079 100644 --- a/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts +++ b/react/features/recording/components/LiveStream/AbstractStartLiveStreamDialog.ts @@ -222,14 +222,15 @@ export default class AbstractStartLiveStreamDialog

if (!base) { return false; } - if (!key) { - return false; + + let rtmpURL = base; + + if (key) { + rtmpURL = base.endsWith('/') ? base + key : `${base}/${key}`; } - const rtmpURL = base.endsWith('/') ? base + key : `${base}/${key}`; let selectedBroadcastID = null; - // to modify this too maybe? if (selectedBoundStreamID) { const selectedBroadcast = broadcasts?.find( broadcast => broadcast.boundStreamID === selectedBoundStreamID); @@ -239,7 +240,6 @@ export default class AbstractStartLiveStreamDialog

sendAnalytics( createLiveStreamingDialogEvent('start', 'confirm.button')); - this.props._conference?.startRecording({ broadcastId: selectedBroadcastID, mode: JitsiRecordingConstants.mode.STREAM, diff --git a/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx b/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx index 4891cc3f1a85..ae463b1ad5a5 100644 --- a/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx +++ b/react/features/recording/components/LiveStream/native/StartLiveStreamDialog.tsx @@ -11,7 +11,7 @@ import HeaderNavigationButton from '../../../../mobile/navigation/components/HeaderNavigationButton'; import { goBack } from '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef'; -import { setLiveStreamKey } from '../../../actions'; +import { setLiveStreamBaseURL, setLiveStreamKey } from '../../../actions'; import AbstractStartLiveStreamDialog, { IProps, _mapStateToProps } from '../AbstractStartLiveStreamDialog'; import GoogleSigninForm from './GoogleSigninForm'; @@ -34,6 +34,7 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog { // Bind event handlers so they are only bound once per instance. this._onStartPress = this._onStartPress.bind(this); + this._onStreamBaseURLChange = this._onStreamBaseURLChangeNative.bind(this); this._onStreamKeyChangeNative = this._onStreamKeyChangeNative.bind(this); this._onStreamKeyPick = this._onStreamKeyPick.bind(this); @@ -83,7 +84,7 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog { broadcasts = { this.state.broadcasts } onChange = { this._onStreamKeyPick } /> @@ -108,6 +109,18 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog { this._onStreamKeyChange(streamKey); } + /** + * Callback to handle stream base URL changes. + * + * @private + * @param {string} streamBaseURL - The new key value. + * @returns {void} + */ + _onStreamBaseURLChangeNative(streamBaseURL: string) { + this.props.dispatch(setLiveStreamBaseURL(streamBaseURL)); + this._onStreamBaseURLChange(streamBaseURL); + } + /** * Callback to be invoked when the user selects a stream from the picker. * @@ -145,12 +158,14 @@ class StartLiveStreamDialog extends AbstractStartLiveStreamDialog { .catch(() => { this.setState({ broadcasts: undefined, + streamBaseURL: undefined, streamKey: undefined }); }); } else { this.setState({ broadcasts: undefined, + streamBaseURL: undefined, streamKey: undefined }); }