Browse Source

fix(live-streaming): show warning if stream key seems wrong

Provide a client-side notice if the YouTube live stream key
looks like it might be in the wrong format. Normally the
stream key looks like 4 groups of 4 numbers and letters,
each separated by a dash. The warning does not block submission
in case YouTube changes their stream key format.
j8
Leonard Kim 6 years ago
parent
commit
920c179f56

+ 10
- 2
css/_recording.scss View File

@@ -65,6 +65,8 @@
65 65
     }
66 66
 
67 67
     .form-footer {
68
+        display: flex;
69
+        margin-top: 5px;
68 70
         text-align: right;
69 71
     }
70 72
 
@@ -95,9 +97,15 @@
95 97
 
96 98
     .stream-key-form {
97 99
         .helper-link {
98
-            display: inline-block;
99 100
             cursor: pointer;
100
-            margin-top: 5px;
101
+            display: inline-block;
102
+            flex-shrink: 0;
103
+            margin-left: auto;
104
+        }
105
+
106
+        .validation-error {
107
+            color:#FFD740;
108
+            font-size: 12px;
101 109
         }
102 110
     }
103 111
 }

+ 1
- 0
lang/main.json View File

@@ -515,6 +515,7 @@
515 515
         "expandedOn": "The meeting is currently being streamed to YouTube.",
516 516
         "expandedPending": "The live streaming is being started...",
517 517
         "failedToStart": "Live Streaming failed to start",
518
+        "invalidStreamKey": "Live stream key may be incorrect.",
518 519
         "off": "Live Streaming stopped",
519 520
         "on": "Live Streaming",
520 521
         "pending": "Starting Live Stream...",

+ 80
- 1
react/features/recording/components/LiveStream/AbstractStreamKeyForm.js View File

@@ -1,5 +1,6 @@
1 1
 // @flow
2 2
 
3
+import debounce from 'lodash/debounce';
3 4
 import { Component } from 'react';
4 5
 
5 6
 declare var interfaceConfig: Object;
@@ -33,14 +34,27 @@ export type Props = {
33 34
     value: string
34 35
 };
35 36
 
37
+/**
38
+ * The state of the component.
39
+ */
40
+type State = {
41
+
42
+    /**
43
+     * Whether or not to show the warnings that the passed in value seems like
44
+     * an improperly formatted stream key.
45
+     */
46
+    showValidationError: boolean
47
+};
48
+
36 49
 /**
37 50
  * An abstract React Component for entering a key for starting a YouTube live
38 51
  * stream.
39 52
  *
40 53
  * @extends Component
41 54
  */
42
-export default class AbstractStreamKeyForm extends Component<Props> {
55
+export default class AbstractStreamKeyForm extends Component<Props, State> {
43 56
     helpURL: string;
57
+    _debouncedUpdateValidationErrorVisibility: Function;
44 58
 
45 59
     /**
46 60
      * Constructor for the component.
@@ -50,14 +64,45 @@ export default class AbstractStreamKeyForm extends Component<Props> {
50 64
     constructor(props: Props) {
51 65
         super(props);
52 66
 
67
+        this.state = {
68
+            showValidationError: Boolean(this.props.value)
69
+                && !this._validateStreamKey(this.props.value)
70
+        };
71
+
53 72
         this.helpURL = (typeof interfaceConfig !== 'undefined'
54 73
             && interfaceConfig.LIVE_STREAMING_HELP_LINK)
55 74
             || LIVE_STREAMING_HELP_LINK;
56 75
 
76
+        this._debouncedUpdateValidationErrorVisibility = debounce(
77
+            this._updateValidationErrorVisibility.bind(this),
78
+            800,
79
+            { leading: false }
80
+        );
81
+
57 82
         // Bind event handlers so they are only bound once per instance.
58 83
         this._onInputChange = this._onInputChange.bind(this);
59 84
     }
60 85
 
86
+    /**
87
+     * Implements React Component's componentDidUpdate.
88
+     *
89
+     * @inheritdoc
90
+     */
91
+    componentDidUpdate(prevProps: Props) {
92
+        if (this.props.value !== prevProps.value) {
93
+            this._debouncedUpdateValidationErrorVisibility();
94
+        }
95
+    }
96
+
97
+    /**
98
+     * Implements React Component's componentWillUnmount.
99
+     *
100
+     * @inheritdoc
101
+     */
102
+    componentWillUnmount() {
103
+        this._debouncedUpdateValidationErrorVisibility.cancel();
104
+    }
105
+
61 106
     _onInputChange: Object => void
62 107
 
63 108
     /**
@@ -75,4 +120,38 @@ export default class AbstractStreamKeyForm extends Component<Props> {
75 120
 
76 121
         this.props.onChange(value);
77 122
     }
123
+
124
+    /**
125
+     * Checks if the stream key value seems like a valid stream key and sets the
126
+     * state for showing or hiding the notification about the stream key seeming
127
+     * invalid.
128
+     *
129
+     * @private
130
+     * @returns {boolean}
131
+     */
132
+    _updateValidationErrorVisibility() {
133
+        const newShowValidationError = Boolean(this.props.value)
134
+            && !this._validateStreamKey(this.props.value);
135
+
136
+        if (newShowValidationError !== this.state.showValidationError) {
137
+            this.setState({
138
+                showValidationError: newShowValidationError
139
+            });
140
+        }
141
+    }
142
+
143
+    /**
144
+     * Checks if a passed in stream key appears to be in a valid format.
145
+     *
146
+     * @param {string} streamKey - The stream key to check for valid formatting.
147
+     * @returns {void}
148
+     * @returns {boolean}
149
+     */
150
+    _validateStreamKey(streamKey = '') {
151
+        const trimmedKey = streamKey.trim();
152
+        const fourGroupsDashSeparated = /^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}/;
153
+        const match = fourGroupsDashSeparated.exec(trimmedKey);
154
+
155
+        return Boolean(match);
156
+    }
78 157
 }

+ 13
- 7
react/features/recording/components/LiveStream/web/StreamKeyForm.js View File

@@ -36,7 +36,7 @@ class StreamKeyForm extends AbstractStreamKeyForm {
36 36
      * @returns {ReactElement}
37 37
      */
38 38
     render() {
39
-        const { value, t } = this.props;
39
+        const { t, value } = this.props;
40 40
 
41 41
         return (
42 42
             <div className = 'stream-key-form'>
@@ -52,16 +52,22 @@ class StreamKeyForm extends AbstractStreamKeyForm {
52 52
                     shouldFitContainer = { true }
53 53
                     type = 'text'
54 54
                     value = { this.props.value } />
55
-                { this.helpURL
56
-                    ? <div className = 'form-footer'>
57
-                        <a
55
+                <div className = 'form-footer'>
56
+                    { this.state.showValidationError
57
+                        ? <span className = 'validation-error'>
58
+                            { t('liveStreaming.invalidStreamKey') }
59
+                        </span>
60
+                        : null
61
+                    }
62
+                    { this.helpURL
63
+                        ? <a
58 64
                             className = 'helper-link'
59 65
                             onClick = { this._onOpenHelp }>
60 66
                             { t('liveStreaming.streamIdHelp') }
61 67
                         </a>
62
-                    </div>
63
-                    : null
64
-                }
68
+                        : null
69
+                    }
70
+                </div>
65 71
             </div>
66 72
         );
67 73
     }

Loading…
Cancel
Save