Просмотр исходного кода

Show the YouTube live stream URL (#2837)

* feat(recording): show the YouTube live stream URL

- From the start live stream dialog, push up the broadcast ID
  of the chosen broadcast. It is assumed the ID can be used to
  create the YouTube link.
- Listen for lib-jitsi-meet to emit updates of the known live
  stream URL, shove it into redux, and have InfoDialog display
  it.

* ref(info): pass in dial in and live stream url

Passing these values in should trigger AtlasKit InlineDialog
to re-render and reposition itself.

* ref(info): use conference existence as trigger for autoshowing dialog

* feat(info): add live stream link to invite copy

* Revert "ref(info): use conference existence as trigger for autoshowing dialog"

This reverts commit 1072102267.

* hidden -> url

* _onClickHiddenURL -> _onClickURLText
j8
virtuacoplenny 7 лет назад
Родитель
Сommit
2c4a3b0f60

+ 7
- 0
conference.js Просмотреть файл

28
     redirectWithStoredParams,
28
     redirectWithStoredParams,
29
     reloadWithStoredParams
29
     reloadWithStoredParams
30
 } from './react/features/app';
30
 } from './react/features/app';
31
+import { updateRecordingState } from './react/features/recording';
31
 
32
 
32
 import EventEmitter from 'events';
33
 import EventEmitter from 'events';
33
 
34
 
1851
             APP.store.dispatch(dominantSpeakerChanged(id));
1852
             APP.store.dispatch(dominantSpeakerChanged(id));
1852
         });
1853
         });
1853
 
1854
 
1855
+        room.on(JitsiConferenceEvents.LIVE_STREAM_URL_CHANGED,
1856
+            (from, liveStreamViewURL) =>
1857
+                APP.store.dispatch(updateRecordingState({
1858
+                    liveStreamViewURL
1859
+                })));
1860
+
1854
         if (!interfaceConfig.filmStripOnly) {
1861
         if (!interfaceConfig.filmStripOnly) {
1855
             room.on(JitsiConferenceEvents.CONNECTION_INTERRUPTED, () => {
1862
             room.on(JitsiConferenceEvents.CONNECTION_INTERRUPTED, () => {
1856
                 APP.UI.markVideoInterrupted(true);
1863
                 APP.UI.markVideoInterrupted(true);

+ 4
- 3
css/modals/invite/_info.scss Просмотреть файл

59
         }
59
         }
60
     }
60
     }
61
 
61
 
62
-    .info-dialog-conference-url {
62
+    .info-dialog-conference-url,
63
+    .info-dialog-live-stream-url {
63
         width: max-content;
64
         width: max-content;
64
         width: -moz-max-content;
65
         width: -moz-max-content;
65
         width: -webkit-max-content;
66
         width: -webkit-max-content;
81
         font-size: 16px;
82
         font-size: 16px;
82
     }
83
     }
83
 
84
 
84
-    .info-dialog-invite-link,
85
-    .info-dialog-invite-link:hover {
85
+    .info-dialog-url-text,
86
+    .info-dialog-url-text:hover {
86
         color: inherit;
87
         color: inherit;
87
         cursor: inherit;
88
         cursor: inherit;
88
     }
89
     }

+ 2
- 0
lang/main.json Просмотреть файл

516
         "dialInConferenceID": "PIN:",
516
         "dialInConferenceID": "PIN:",
517
         "dialInNotSupported": "Sorry, dialing in is currently not suppported.",
517
         "dialInNotSupported": "Sorry, dialing in is currently not suppported.",
518
         "genericError": "Whoops, something went wrong.",
518
         "genericError": "Whoops, something went wrong.",
519
+        "inviteLiveStream": "To view the live stream of this meeting, click this link: __url__",
519
         "invitePhone": "To join by phone, dial __number__ and enter this PIN: __conferenceID__#",
520
         "invitePhone": "To join by phone, dial __number__ and enter this PIN: __conferenceID__#",
520
         "invitePhoneAlternatives": "To view more phone numbers, click this link: __url__",
521
         "invitePhoneAlternatives": "To view more phone numbers, click this link: __url__",
521
         "inviteURL": "To join the video meeting, click this link: __url__",
522
         "inviteURL": "To join the video meeting, click this link: __url__",
523
+        "liveStreamURL": "Live stream:",
522
         "moreNumbers": "More numbers",
524
         "moreNumbers": "More numbers",
523
         "noNumbers": "No dial-in numbers.",
525
         "noNumbers": "No dial-in numbers.",
524
         "noPassword": "None",
526
         "noPassword": "None",

+ 9
- 4
modules/UI/recording/Recording.js Просмотреть файл

109
     return new Promise((resolve, reject) =>
109
     return new Promise((resolve, reject) =>
110
         APP.store.dispatch(openDialog(StartLiveStreamDialog, {
110
         APP.store.dispatch(openDialog(StartLiveStreamDialog, {
111
             onCancel: reject,
111
             onCancel: reject,
112
-            onSubmit: resolve
112
+            onSubmit: (streamId, broadcastId) => resolve({
113
+                broadcastId,
114
+                streamId
115
+            })
113
         })));
116
         })));
114
 }
117
 }
115
 
118
 
257
      * @param recordingState gives us the current recording state
260
      * @param recordingState gives us the current recording state
258
      */
261
      */
259
     updateRecordingUI(recordingState) {
262
     updateRecordingUI(recordingState) {
260
-
261
         const oldState = this.currentState;
263
         const oldState = this.currentState;
262
 
264
 
263
         this.currentState = recordingState;
265
         this.currentState = recordingState;
388
         case JitsiRecordingStatus.OFF: {
390
         case JitsiRecordingStatus.OFF: {
389
             if (this.recordingType === 'jibri') {
391
             if (this.recordingType === 'jibri') {
390
                 _requestLiveStreamId()
392
                 _requestLiveStreamId()
391
-                .then(streamId => {
393
+                .then(({ broadcastId, streamId }) => {
392
                     this.eventEmitter.emit(
394
                     this.eventEmitter.emit(
393
                         UIEvents.RECORDING_TOGGLED,
395
                         UIEvents.RECORDING_TOGGLED,
394
-                        { streamId });
396
+                        {
397
+                            broadcastId,
398
+                            streamId
399
+                        });
395
 
400
 
396
                     // The confirm button on the start recording dialog was
401
                     // The confirm button on the start recording dialog was
397
                     // clicked
402
                     // clicked

+ 18
- 11
react/features/invite/components/InfoDialogButton.web.js Просмотреть файл

35
     static propTypes = {
35
     static propTypes = {
36
 
36
 
37
         /**
37
         /**
38
-         * Phone numbers for dialing into the conference.
38
+         * The redux state representing the dial-in numbers feature.
39
          */
39
          */
40
-        _dialInNumbers: PropTypes.oneOfType([
41
-            PropTypes.object,
42
-            PropTypes.array
43
-        ]),
40
+        _dialIn: PropTypes.object,
44
 
41
 
45
         /**
42
         /**
46
          * Whether or not the {@code InfoDialog} should display automatically
43
          * Whether or not the {@code InfoDialog} should display automatically
48
          */
45
          */
49
         _disableAutoShow: PropTypes.bool,
46
         _disableAutoShow: PropTypes.bool,
50
 
47
 
48
+        /**
49
+         * The URL for a currently active live broadcast
50
+         */
51
+        _liveStreamViewURL: PropTypes.string,
52
+
51
         /**
53
         /**
52
          * The number of real participants in the call. If in a lonely call,
54
          * The number of real participants in the call. If in a lonely call,
53
          * the {@code InfoDialog} will be automatically shown.
55
          * the {@code InfoDialog} will be automatically shown.
117
             this._maybeAutoShowDialog();
119
             this._maybeAutoShowDialog();
118
         }, INFO_DIALOG_AUTO_SHOW_TIMEOUT);
120
         }, INFO_DIALOG_AUTO_SHOW_TIMEOUT);
119
 
121
 
120
-        if (!this.props._dialInNumbers) {
122
+        if (!this.props._dialIn.numbers) {
121
             this.props.dispatch(updateDialInNumbers());
123
             this.props.dispatch(updateDialInNumbers());
122
         }
124
         }
123
     }
125
     }
150
      * @returns {ReactElement}
152
      * @returns {ReactElement}
151
      */
153
      */
152
     render() {
154
     render() {
153
-        const { t } = this.props;
155
+        const { _dialIn, _liveStreamViewURL, t } = this.props;
154
         const { showDialog } = this.state;
156
         const { showDialog } = this.state;
155
         const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`;
157
         const iconClass = `icon-info ${showDialog ? 'toggled' : ''}`;
156
 
158
 
158
             <div className = 'toolbox-button-wth-dialog'>
160
             <div className = 'toolbox-button-wth-dialog'>
159
                 <InlineDialog
161
                 <InlineDialog
160
                     content = {
162
                     content = {
161
-                        <InfoDialog onClose = { this._onDialogClose } /> }
163
+                        <InfoDialog
164
+                            dialIn = { _dialIn }
165
+                            liveStreamViewURL = { _liveStreamViewURL }
166
+                            onClose = { this._onDialogClose } /> }
162
                     isOpen = { showDialog }
167
                     isOpen = { showDialog }
163
                     onClose = { this._onDialogClose }
168
                     onClose = { this._onDialogClose }
164
                     position = { 'top right' }>
169
                     position = { 'top right' }>
215
  * @param {Object} state - The Redux state.
220
  * @param {Object} state - The Redux state.
216
  * @private
221
  * @private
217
  * @returns {{
222
  * @returns {{
218
- *     _dialInNumbers: Array,
219
- *     _disableAutoShow: bolean,
223
+ *     _dialIn: Object,
224
+ *     _disableAutoShow: boolean,
225
+ *     _liveStreamViewURL: string,
220
  *     _participantCount: number,
226
  *     _participantCount: number,
221
  *     _toolboxVisible: boolean
227
  *     _toolboxVisible: boolean
222
  * }}
228
  * }}
223
  */
229
  */
224
 function _mapStateToProps(state) {
230
 function _mapStateToProps(state) {
225
     return {
231
     return {
226
-        _dialInNumbers: state['features/invite'].numbers,
232
+        _dialIn: state['features/invite'],
227
         _disableAutoShow: state['features/base/config'].iAmRecorder,
233
         _disableAutoShow: state['features/base/config'].iAmRecorder,
234
+        _liveStreamViewURL: state['features/recording'].liveStreamViewURL,
228
         _participantCount:
235
         _participantCount:
229
             getParticipantCount(state['features/base/participants']),
236
             getParticipantCount(state['features/base/participants']),
230
         _toolboxVisible: state['features/toolbox'].visible
237
         _toolboxVisible: state['features/toolbox'].visible

+ 60
- 52
react/features/invite/components/info-dialog/InfoDialog.web.js Просмотреть файл

10
     getLocalParticipant
10
     getLocalParticipant
11
 } from '../../../base/participants';
11
 } from '../../../base/participants';
12
 
12
 
13
-import { updateDialInNumbers } from '../../actions';
14
-
15
 import DialInNumber from './DialInNumber';
13
 import DialInNumber from './DialInNumber';
16
 import PasswordForm from './PasswordForm';
14
 import PasswordForm from './PasswordForm';
17
 
15
 
24
  * @extends Component
22
  * @extends Component
25
  */
23
  */
26
 class InfoDialog extends Component {
24
 class InfoDialog extends Component {
27
-    /**
28
-     * Default values for {@code InfoDialog} component's properties.
29
-     *
30
-     * @static
31
-     */
32
-    static defaultProps = {
33
-        autoUpdateNumbers: true
34
-    };
35
-
36
     /**
25
     /**
37
      * {@code InfoDialog} component's property types.
26
      * {@code InfoDialog} component's property types.
38
      *
27
      *
57
          */
46
          */
58
         _conferenceName: PropTypes.string,
47
         _conferenceName: PropTypes.string,
59
 
48
 
60
-        /**
61
-         * The redux state representing the dial-in numbers feature.
62
-         */
63
-        _dialIn: PropTypes.object,
64
-
65
         /**
49
         /**
66
          * The current url of the conference to be copied onto the clipboard.
50
          * The current url of the conference to be copied onto the clipboard.
67
          */
51
          */
79
         _password: PropTypes.string,
63
         _password: PropTypes.string,
80
 
64
 
81
         /**
65
         /**
82
-         * Whether or not this component should make a request for dial-in
83
-         * numbers. If false, this component will rely on an outside source
84
-         * updating and passing in numbers through the _dialIn prop.
66
+         * The object representing the dialIn feature.
85
          */
67
          */
86
-        autoUpdateNumbers: PropTypes.bool,
68
+        dialIn: PropTypes.object,
87
 
69
 
88
         /**
70
         /**
89
          * Invoked to open a dialog for adding participants to the conference.
71
          * Invoked to open a dialog for adding participants to the conference.
90
          */
72
          */
91
         dispatch: PropTypes.func,
73
         dispatch: PropTypes.func,
92
 
74
 
75
+        /**
76
+         * The current known URL for a live stream in progress.
77
+         */
78
+        liveStreamViewURL: PropTypes.string,
79
+
93
         /**
80
         /**
94
          * Callback invoked when the dialog should be closed.
81
          * Callback invoked when the dialog should be closed.
95
          */
82
          */
129
     constructor(props) {
116
     constructor(props) {
130
         super(props);
117
         super(props);
131
 
118
 
132
-        const { defaultCountry, numbers } = props._dialIn;
119
+        const { defaultCountry, numbers } = props.dialIn;
133
 
120
 
134
         if (numbers) {
121
         if (numbers) {
135
             this.state.phoneNumber
122
             this.state.phoneNumber
147
         this._copyElement = null;
134
         this._copyElement = null;
148
 
135
 
149
         // Bind event handlers so they are only bound once for every instance.
136
         // Bind event handlers so they are only bound once for every instance.
150
-        this._onClickInviteURL = this._onClickInviteURL.bind(this);
137
+        this._onClickURLText = this._onClickURLText.bind(this);
151
         this._onCopyInviteURL = this._onCopyInviteURL.bind(this);
138
         this._onCopyInviteURL = this._onCopyInviteURL.bind(this);
152
         this._onPasswordRemove = this._onPasswordRemove.bind(this);
139
         this._onPasswordRemove = this._onPasswordRemove.bind(this);
153
         this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
140
         this._onPasswordSubmit = this._onPasswordSubmit.bind(this);
156
         this._setCopyElement = this._setCopyElement.bind(this);
143
         this._setCopyElement = this._setCopyElement.bind(this);
157
     }
144
     }
158
 
145
 
159
-    /**
160
-     * Implements {@link Component#componentDidMount()}. Invoked immediately
161
-     * after this component is mounted. Requests dial-in numbers if not
162
-     * already known.
163
-     *
164
-     * @inheritdoc
165
-     * @returns {void}
166
-     */
167
-    componentDidMount() {
168
-        if (!this.state.phoneNumber && this.props.autoUpdateNumbers) {
169
-            this.props.dispatch(updateDialInNumbers());
170
-        }
171
-    }
172
-
173
     /**
146
     /**
174
      * Implements React's {@link Component#componentWillReceiveProps()}. Invoked
147
      * Implements React's {@link Component#componentWillReceiveProps()}. Invoked
175
      * before this mounted component receives new props.
148
      * before this mounted component receives new props.
182
             this.setState({ passwordEditEnabled: false });
155
             this.setState({ passwordEditEnabled: false });
183
         }
156
         }
184
 
157
 
185
-        if (!this.state.phoneNumber && nextProps._dialIn.numbers) {
186
-            const { defaultCountry, numbers } = nextProps._dialIn;
158
+        if (!this.state.phoneNumber && nextProps.dialIn.numbers) {
159
+            const { defaultCountry, numbers } = nextProps.dialIn;
187
 
160
 
188
             this.setState({
161
             this.setState({
189
                 phoneNumber:
162
                 phoneNumber:
199
      * @returns {ReactElement}
172
      * @returns {ReactElement}
200
      */
173
      */
201
     render() {
174
     render() {
202
-        const { onMouseOver, t } = this.props;
175
+        const { liveStreamViewURL, onMouseOver, t } = this.props;
203
 
176
 
204
         return (
177
         return (
205
             <div
178
             <div
221
                         <span className = 'spacer'>&nbsp;</span>
194
                         <span className = 'spacer'>&nbsp;</span>
222
                         <span className = 'info-value'>
195
                         <span className = 'info-value'>
223
                             <a
196
                             <a
224
-                                className = 'info-dialog-invite-link'
197
+                                className = 'info-dialog-url-text'
225
                                 href = { this.props._inviteURL }
198
                                 href = { this.props._inviteURL }
226
-                                onClick = { this._onClickInviteURL } >
199
+                                onClick = { this._onClickURLText } >
227
                                 { this._getURLToDisplay() }
200
                                 { this._getURLToDisplay() }
228
                             </a>
201
                             </a>
229
                         </span>
202
                         </span>
231
                     <div className = 'info-dialog-dial-in'>
204
                     <div className = 'info-dialog-dial-in'>
232
                         { this._renderDialInDisplay() }
205
                         { this._renderDialInDisplay() }
233
                     </div>
206
                     </div>
207
+                    { liveStreamViewURL && this._renderLiveStreamURL() }
234
                     <div className = 'info-dialog-password'>
208
                     <div className = 'info-dialog-password'>
235
                         <PasswordForm
209
                         <PasswordForm
236
                             editEnabled = { this.state.passwordEditEnabled }
210
                             editEnabled = { this.state.passwordEditEnabled }
321
      * @returns {string}
295
      * @returns {string}
322
      */
296
      */
323
     _getTextToCopy() {
297
     _getTextToCopy() {
324
-        const { t } = this.props;
298
+        const { liveStreamViewURL, t } = this.props;
325
 
299
 
326
         let invite = t('info.inviteURL', {
300
         let invite = t('info.inviteURL', {
327
             url: this.props._inviteURL
301
             url: this.props._inviteURL
328
         });
302
         });
329
 
303
 
304
+        if (liveStreamViewURL) {
305
+            const liveStream = t('info.inviteLiveStream', {
306
+                url: liveStreamViewURL
307
+            });
308
+
309
+            invite = `${invite}\n${liveStream}`;
310
+        }
311
+
330
         if (this._shouldDisplayDialIn()) {
312
         if (this._shouldDisplayDialIn()) {
331
             const dial = t('info.invitePhone', {
313
             const dial = t('info.invitePhone', {
332
                 number: this.state.phoneNumber,
314
                 number: this.state.phoneNumber,
333
-                conferenceID: this.props._dialIn.conferenceID
315
+                conferenceID: this.props.dialIn.conferenceID
334
             });
316
             });
335
             const moreNumbers = t('info.invitePhoneAlternatives', {
317
             const moreNumbers = t('info.invitePhoneAlternatives', {
336
                 url: this._getDialInfoPageURL()
318
                 url: this._getDialInfoPageURL()
353
     }
335
     }
354
 
336
 
355
     /**
337
     /**
356
-     * Callback invoked when the displayed invite URL link is clicked to prevent
357
-     * actual navigation from happening. The invite URL link has an href to
358
-     * display "Copy Link Address" in the context menu but otherwise it should
359
-     * not behave like a link.
338
+     * Callback invoked when a displayed URL link is clicked to prevent actual
339
+     * navigation from happening. The URL links have an href to display "Copy
340
+     * Link Address" in the context menu but otherwise it should not behave like
341
+     * links.
360
      *
342
      *
361
      * @param {Object} event - The click event from clicking on the link.
343
      * @param {Object} event - The click event from clicking on the link.
362
      * @private
344
      * @private
363
      * @returns {void}
345
      * @returns {void}
364
      */
346
      */
365
-    _onClickInviteURL(event) {
347
+    _onClickURLText(event) {
366
         event.preventDefault();
348
         event.preventDefault();
367
     }
349
     }
368
 
350
 
439
         return (
421
         return (
440
             <div>
422
             <div>
441
                 <DialInNumber
423
                 <DialInNumber
442
-                    conferenceID = { this.props._dialIn.conferenceID }
424
+                    conferenceID = { this.props.dialIn.conferenceID }
443
                     phoneNumber = { this.state.phoneNumber } />
425
                     phoneNumber = { this.state.phoneNumber } />
444
                 <a
426
                 <a
445
                     className = 'more-numbers'
427
                     className = 'more-numbers'
490
             : null;
472
             : null;
491
     }
473
     }
492
 
474
 
475
+    /**
476
+     * Returns a ReactElement for display a link to the current url of a
477
+     * live stream in progress.
478
+     *
479
+     * @private
480
+     * @returns {null|ReactElement}
481
+     */
482
+    _renderLiveStreamURL() {
483
+        const { liveStreamViewURL, t } = this.props;
484
+
485
+        return (
486
+            <div className = 'info-dialog-live-stream-url'>
487
+                <span className = 'info-label'>
488
+                    { t('info.liveStreamURL') }
489
+                </span>
490
+                <span className = 'spacer'>&nbsp;</span>
491
+                <span className = 'info-value'>
492
+                    <a
493
+                        className = 'info-dialog-url-text'
494
+                        href = { liveStreamViewURL }
495
+                        onClick = { this._onClickURLText } >
496
+                        { liveStreamViewURL }
497
+                    </a>
498
+                </span>
499
+            </div>
500
+        );
501
+    }
502
+
493
     /**
503
     /**
494
      * Returns whether or not dial-in related UI should be displayed.
504
      * Returns whether or not dial-in related UI should be displayed.
495
      *
505
      *
497
      * @returns {boolean}
507
      * @returns {boolean}
498
      */
508
      */
499
     _shouldDisplayDialIn() {
509
     _shouldDisplayDialIn() {
500
-        const { conferenceID, numbers, numbersEnabled } = this.props._dialIn;
510
+        const { conferenceID, numbers, numbersEnabled } = this.props.dialIn;
501
         const { phoneNumber } = this.state;
511
         const { phoneNumber } = this.state;
502
 
512
 
503
         return Boolean(
513
         return Boolean(
531
  *     _canEditPassword: boolean,
541
  *     _canEditPassword: boolean,
532
  *     _conference: Object,
542
  *     _conference: Object,
533
  *     _conferenceName: string,
543
  *     _conferenceName: string,
534
- *     _dialIn: Object,
535
  *     _inviteURL: string,
544
  *     _inviteURL: string,
536
  *     _locked: string,
545
  *     _locked: string,
537
  *     _password: string
546
  *     _password: string
558
         _canEditPassword: canEditPassword,
567
         _canEditPassword: canEditPassword,
559
         _conference: conference,
568
         _conference: conference,
560
         _conferenceName: room,
569
         _conferenceName: room,
561
-        _dialIn: state['features/invite'],
562
         _inviteURL: getInviteURL(state),
570
         _inviteURL: getInviteURL(state),
563
         _locked: locked,
571
         _locked: locked,
564
         _password: password
572
         _password: password

+ 3
- 3
react/features/recording/components/LiveStream/BroadcastsDropdown.web.js Просмотреть файл

44
          * The boundStreamID of the broadcast that should display as selected in
44
          * The boundStreamID of the broadcast that should display as selected in
45
          * the dropdown.
45
          * the dropdown.
46
          */
46
          */
47
-        selectedBroadcastID: PropTypes.string,
47
+        selectedBoundStreamID: PropTypes.string,
48
 
48
 
49
         /**
49
         /**
50
          * Invoked to obtain translated strings.
50
          * Invoked to obtain translated strings.
84
      * @returns {ReactElement}
84
      * @returns {ReactElement}
85
      */
85
      */
86
     render() {
86
     render() {
87
-        const { broadcasts, selectedBroadcastID, t } = this.props;
87
+        const { broadcasts, selectedBoundStreamID, t } = this.props;
88
 
88
 
89
         const dropdownItems = broadcasts.map(broadcast =>
89
         const dropdownItems = broadcasts.map(broadcast =>
90
             // eslint-disable-next-line react/jsx-wrap-multilines
90
             // eslint-disable-next-line react/jsx-wrap-multilines
96
             </DropdownItem>
96
             </DropdownItem>
97
         );
97
         );
98
         const selected = this.props.broadcasts.find(
98
         const selected = this.props.broadcasts.find(
99
-            broadcast => broadcast.boundStreamID === selectedBroadcastID);
99
+            broadcast => broadcast.boundStreamID === selectedBoundStreamID);
100
         const triggerText = (selected && selected.title)
100
         const triggerText = (selected && selected.title)
101
             || t('liveStreaming.choose');
101
             || t('liveStreaming.choose');
102
 
102
 

+ 21
- 7
react/features/recording/components/LiveStream/StartLiveStreamDialog.web.js Просмотреть файл

89
      * available for use for the logged in Google user's YouTube account.
89
      * available for use for the logged in Google user's YouTube account.
90
      * @property {string} googleProfileEmail - The email of the user currently
90
      * @property {string} googleProfileEmail - The email of the user currently
91
      * logged in to the Google web client application.
91
      * logged in to the Google web client application.
92
+     * @property {string} selectedBoundStreamID - The boundStreamID of the
93
+     * broadcast currently selected in the broadcast dropdown.
92
      * @property {string} streamKey - The selected or entered stream key to use
94
      * @property {string} streamKey - The selected or entered stream key to use
93
      * for YouTube live streaming.
95
      * for YouTube live streaming.
94
      */
96
      */
96
         broadcasts: undefined,
98
         broadcasts: undefined,
97
         googleAPIState: GOOGLE_API_STATES.NEEDS_LOADING,
99
         googleAPIState: GOOGLE_API_STATES.NEEDS_LOADING,
98
         googleProfileEmail: '',
100
         googleProfileEmail: '',
99
-        selectedBroadcastID: undefined,
101
+        selectedBoundStreamID: undefined,
100
         streamKey: ''
102
         streamKey: ''
101
     };
103
     };
102
 
104
 
291
     _onStreamKeyChange(event) {
293
     _onStreamKeyChange(event) {
292
         this._setStateIfMounted({
294
         this._setStateIfMounted({
293
             streamKey: event.target.value,
295
             streamKey: event.target.value,
294
-            selectedBroadcastID: undefined
296
+            selectedBoundStreamID: undefined
295
         });
297
         });
296
     }
298
     }
297
 
299
 
304
      * closing, true to close the modal.
306
      * closing, true to close the modal.
305
      */
307
      */
306
     _onSubmit() {
308
     _onSubmit() {
307
-        if (!this.state.streamKey) {
309
+        const { streamKey, selectedBoundStreamID } = this.state;
310
+
311
+        if (!streamKey) {
308
             return false;
312
             return false;
309
         }
313
         }
310
 
314
 
311
-        this.props.onSubmit(this.state.streamKey);
315
+        let selectedBroadcastID = null;
316
+
317
+        if (selectedBoundStreamID) {
318
+            const selectedBroadcast = this.state.broadcasts.find(
319
+                broadcast => broadcast.boundStreamID === selectedBoundStreamID);
320
+
321
+            selectedBroadcastID = selectedBroadcast && selectedBroadcast.id;
322
+        }
323
+
324
+        this.props.onSubmit(streamKey, selectedBroadcastID);
312
 
325
 
313
         return true;
326
         return true;
314
     }
327
     }
333
 
346
 
334
                 this._setStateIfMounted({
347
                 this._setStateIfMounted({
335
                     streamKey,
348
                     streamKey,
336
-                    selectedBroadcastID: boundStreamID
349
+                    selectedBoundStreamID: boundStreamID
337
                 });
350
                 });
338
             });
351
             });
339
     }
352
     }
358
             if (boundStreamID && !parsedBroadcasts[boundStreamID]) {
371
             if (boundStreamID && !parsedBroadcasts[boundStreamID]) {
359
                 parsedBroadcasts[boundStreamID] = {
372
                 parsedBroadcasts[boundStreamID] = {
360
                     boundStreamID,
373
                     boundStreamID,
374
+                    id: broadcast.id,
361
                     status: broadcast.status.lifeCycleStatus,
375
                     status: broadcast.status.lifeCycleStatus,
362
                     title: broadcast.snippet.title
376
                     title: broadcast.snippet.title
363
                 };
377
                 };
378
         const {
392
         const {
379
             broadcasts,
393
             broadcasts,
380
             googleProfileEmail,
394
             googleProfileEmail,
381
-            selectedBroadcastID
395
+            selectedBoundStreamID
382
         } = this.state;
396
         } = this.state;
383
 
397
 
384
         let googleContent, helpText;
398
         let googleContent, helpText;
399
                 <BroadcastsDropdown
413
                 <BroadcastsDropdown
400
                     broadcasts = { broadcasts }
414
                     broadcasts = { broadcasts }
401
                     onBroadcastSelected = { this._onYouTubeBroadcastIDSelected }
415
                     onBroadcastSelected = { this._onYouTubeBroadcastIDSelected }
402
-                    selectedBroadcastID = { selectedBroadcastID } />
416
+                    selectedBoundStreamID = { selectedBoundStreamID } />
403
             );
417
             );
404
 
418
 
405
             /**
419
             /**

Загрузка…
Отмена
Сохранить