Add title and description fields to streaming services and pre-fill from metadata
This commit is contained in:
parent
9386273731
commit
2455251423
@ -500,6 +500,7 @@ export default function Profile(props) {
|
||||
onChange={handleSourceSettingsChange}
|
||||
onRefresh={handleRefresh}
|
||||
onStore={handleStore}
|
||||
onYoutubeMetadata={props.onYoutubeMetadata}
|
||||
/>
|
||||
</Grid>
|
||||
{$videoProbe.status !== 'none' && (
|
||||
@ -807,4 +808,5 @@ Profile.defaultProps = {
|
||||
onStore: function (name, data) {
|
||||
return '';
|
||||
},
|
||||
onYoutubeMetadata: function (title, description) {},
|
||||
};
|
||||
|
||||
@ -102,6 +102,7 @@ export default function SourceSelect(props) {
|
||||
onProbe={handleProbe}
|
||||
onRefresh={handleRefresh}
|
||||
onStore={handleStore}
|
||||
onYoutubeMetadata={props.onYoutubeMetadata}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -135,6 +136,7 @@ SourceSelect.defaultProps = {
|
||||
onChange: function (type, device, settings) {},
|
||||
onRefresh: function () {},
|
||||
onStore: function (name, data) {},
|
||||
onYoutubeMetadata: function (title, description) {},
|
||||
};
|
||||
|
||||
function Select(props) {
|
||||
|
||||
@ -814,6 +814,14 @@ function Pull(props) {
|
||||
if (data && data.stream_url) {
|
||||
props.onChange('', 'address')({ target: { value: data.stream_url } });
|
||||
setExtractorError('');
|
||||
// Propagar title y description si el servicio los devuelve
|
||||
if (typeof props.onYoutubeMetadata === 'function') {
|
||||
const title = data.title || data.video_title || '';
|
||||
const description = data.description || data.video_description || '';
|
||||
if (title || description) {
|
||||
props.onYoutubeMetadata(title, description);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setExtractorError('No stream_url found in service response.');
|
||||
}
|
||||
@ -1255,7 +1263,7 @@ function Source(props) {
|
||||
</Grid>
|
||||
</Grid>
|
||||
{settings.mode === 'pull' ? (
|
||||
<Pull settings={settings} config={config} skills={skills} onChange={handleChange} onProbe={handleProbe} />
|
||||
<Pull settings={settings} config={config} skills={skills} onChange={handleChange} onProbe={handleProbe} onYoutubeMetadata={props.onYoutubeMetadata} />
|
||||
) : (
|
||||
<Push
|
||||
settings={settings}
|
||||
@ -1278,6 +1286,7 @@ Source.defaultProps = {
|
||||
skills: null,
|
||||
onChange: function (settings) {},
|
||||
onProbe: function (settings, inputs) {},
|
||||
onYoutubeMetadata: function (title, description) {},
|
||||
};
|
||||
|
||||
function SourceIcon(props) {
|
||||
|
||||
@ -278,6 +278,20 @@ export default function Edit(props) {
|
||||
});
|
||||
};
|
||||
|
||||
const handleYoutubeMetadata = (title, description) => {
|
||||
setData((prev) => ({
|
||||
...prev,
|
||||
meta: {
|
||||
...prev.meta,
|
||||
...(title ? { name: title } : {}),
|
||||
...(description ? { description: description } : {}),
|
||||
},
|
||||
}));
|
||||
if (title || description) {
|
||||
notify.Dispatch('success', 'youtube:metadata', i18n._(t`Title and description filled from YouTube`));
|
||||
}
|
||||
};
|
||||
|
||||
const handleLicenseChange = (license) => {
|
||||
setData({
|
||||
...$data,
|
||||
@ -472,6 +486,7 @@ export default function Edit(props) {
|
||||
onDone={handleSourceDone}
|
||||
onAbort={handleSourceAbort}
|
||||
onStore={handleSourceStore}
|
||||
onYoutubeMetadata={handleYoutubeMetadata}
|
||||
/>
|
||||
)}
|
||||
</TabPanel>
|
||||
|
||||
@ -41,6 +41,8 @@ function ServiceIcon(props) {
|
||||
function init(settings) {
|
||||
const initSettings = {
|
||||
key: '',
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -50,6 +52,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -79,6 +89,28 @@ function Service(props) {
|
||||
<Trans>GET</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,10 +4,14 @@ import { faFacebook } from '@fortawesome/free-brands-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Link from '@mui/material/Link';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
import Checkbox from '../../../misc/Checkbox';
|
||||
import FormInlineButton from '../../../misc/FormInlineButton';
|
||||
import Select from '../../../misc/Select';
|
||||
|
||||
const id = 'facebook';
|
||||
const name = 'Facebook Live';
|
||||
@ -16,14 +20,8 @@ const stream_key_link = 'https://www.facebook.com/live/producer?ref=datarhei/res
|
||||
const description = <Trans>Live-Streaming to Facebook Live RTMP service</Trans>;
|
||||
const image_copyright = <Trans>More about licenses here</Trans>;
|
||||
const author = {
|
||||
creator: {
|
||||
name: 'datarhei',
|
||||
link: 'https://github.com/datarhei',
|
||||
},
|
||||
maintainer: {
|
||||
name: 'datarhei',
|
||||
link: 'https://github.com/datarhei',
|
||||
},
|
||||
creator: { name: 'datarhei', link: 'https://github.com/datarhei' },
|
||||
maintainer: { name: 'datarhei', link: 'https://github.com/datarhei' },
|
||||
};
|
||||
const category = 'platform';
|
||||
const requires = {
|
||||
@ -40,12 +38,13 @@ function ServiceIcon(props) {
|
||||
}
|
||||
|
||||
function init(settings) {
|
||||
const initSettings = {
|
||||
return {
|
||||
stream_key_primary: '',
|
||||
stream_key_backup: '',
|
||||
rtmp_primary: true,
|
||||
rtmp_backup: false,
|
||||
// new fields
|
||||
// API fields
|
||||
account_type: 'page', // 'page' | 'user'
|
||||
page_id: '',
|
||||
page_access_token: '',
|
||||
title: '',
|
||||
@ -53,15 +52,26 @@ function init(settings) {
|
||||
create_live: false,
|
||||
...settings,
|
||||
};
|
||||
|
||||
return initSettings;
|
||||
}
|
||||
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
const [$loading, setLoading] = React.useState(false);
|
||||
const [$apiError, setApiError] = React.useState('');
|
||||
const [$apiSuccess, setApiSuccess] = React.useState('');
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event && event.target ? event.target.value : event;
|
||||
setApiError('');
|
||||
setApiSuccess('');
|
||||
|
||||
if (['rtmp_primary', 'rtmp_backup', 'create_live'].includes(what)) {
|
||||
settings[what] = !settings[what];
|
||||
@ -69,97 +79,116 @@ function Service(props) {
|
||||
settings[what] = value;
|
||||
}
|
||||
|
||||
const output = createOutput(settings);
|
||||
|
||||
props.onChange(output, settings);
|
||||
props.onChange(createOutput(settings), settings);
|
||||
};
|
||||
|
||||
const createOutput = (settings) => {
|
||||
const outputs = [];
|
||||
|
||||
const output_primary = {
|
||||
address: 'rtmps://live-api-s.facebook.com:443/rtmp/' + settings.stream_key_primary,
|
||||
options: ['-f', 'flv'],
|
||||
};
|
||||
|
||||
const output_backup = {
|
||||
address: 'rtmps://live-api-s.facebook.com:443/rtmp/' + settings.stream_key_backup,
|
||||
options: ['-f', 'flv'],
|
||||
};
|
||||
|
||||
if (settings.stream_key_primary.length !== 0) {
|
||||
if (settings.rtmp_primary) {
|
||||
outputs.push(output_primary);
|
||||
}
|
||||
if (settings.stream_key_primary.length !== 0 && settings.rtmp_primary) {
|
||||
outputs.push({
|
||||
address: 'rtmps://live-api-s.facebook.com:443/rtmp/' + settings.stream_key_primary,
|
||||
options: ['-f', 'flv'],
|
||||
});
|
||||
}
|
||||
|
||||
if (settings.stream_key_backup.length !== 0) {
|
||||
if (settings.rtmp_backup) {
|
||||
outputs.push(output_backup);
|
||||
}
|
||||
if (settings.stream_key_backup.length !== 0 && settings.rtmp_backup) {
|
||||
outputs.push({
|
||||
address: 'rtmps://live-api-s.facebook.com:443/rtmp/' + settings.stream_key_backup,
|
||||
options: ['-f', 'flv'],
|
||||
});
|
||||
}
|
||||
|
||||
return outputs;
|
||||
};
|
||||
|
||||
// Creates a Facebook live video via Graph API and fills the primary stream key
|
||||
// Extraer stream key desde stream_url de Facebook
|
||||
const extractKey = (streamUrl) => {
|
||||
if (!streamUrl) return '';
|
||||
const parts = streamUrl.split('/');
|
||||
return parts[parts.length - 1] || '';
|
||||
};
|
||||
|
||||
// Crea un Facebook Live via Graph API
|
||||
const createFacebookLive = async () => {
|
||||
if (!settings.page_id || !settings.page_access_token) {
|
||||
window.alert('Please provide Page ID and Page Access Token to create a Facebook Live.');
|
||||
setApiError('');
|
||||
setApiSuccess('');
|
||||
|
||||
if (!settings.page_access_token) {
|
||||
setApiError('You must provide a Page Access Token (or User Access Token for personal profile).');
|
||||
return;
|
||||
}
|
||||
|
||||
// Para tipo 'page' se requiere page_id
|
||||
if (settings.account_type === 'page' && !settings.page_id) {
|
||||
setApiError('You must provide the Page ID when using a Page account. For personal profile, switch to "Personal profile".');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const url = `https://graph.facebook.com/${encodeURIComponent(settings.page_id)}/live_videos`;
|
||||
// El subject puede ser el page_id (para páginas) o 'me' (para perfil personal)
|
||||
const subject = settings.account_type === 'page'
|
||||
? encodeURIComponent(settings.page_id)
|
||||
: 'me';
|
||||
|
||||
const url = `https://graph.facebook.com/v19.0/${subject}/live_videos`;
|
||||
const form = new URLSearchParams();
|
||||
if (settings.title) form.append('title', settings.title);
|
||||
if (settings.description) form.append('description', settings.description);
|
||||
form.append('status', 'LIVE_NOW');
|
||||
form.append('access_token', settings.page_access_token);
|
||||
|
||||
const resp = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: form.toString(),
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
const text = await resp.text();
|
||||
throw new Error('Facebook API error: ' + text);
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
|
||||
// Facebook returns a stream_url or stream_url/secure_stream_url — extract key
|
||||
let stream = '';
|
||||
if (data.stream_url) stream = data.stream_url;
|
||||
else if (data.secure_stream_url) stream = data.secure_stream_url;
|
||||
if (!resp.ok || data.error) {
|
||||
const errMsg = data.error
|
||||
? `[#${data.error.code}] ${data.error.message}`
|
||||
: `HTTP ${resp.status}`;
|
||||
|
||||
if (stream.length === 0) {
|
||||
window.alert('Facebook did not return a stream URL.');
|
||||
// Mensajes de error específicos con solución
|
||||
if (data.error && data.error.code === 100) {
|
||||
setApiError(
|
||||
'Error #100: The subject must be a Page account, not a personal profile. ' +
|
||||
'Switch to "Personal profile" mode or provide a valid Page ID with a Page Access Token. ' +
|
||||
'Get your Page Access Token at: https://developers.facebook.com/tools/explorer/'
|
||||
);
|
||||
} else if (data.error && data.error.code === 190) {
|
||||
setApiError('Error #190: Invalid or expired Access Token. Generate a new one at https://developers.facebook.com/tools/explorer/');
|
||||
} else if (data.error && data.error.code === 200 || data.error && data.error.code === 10) {
|
||||
setApiError('Permission error: Your token needs the "publish_video" permission. Check your app settings at developers.facebook.com');
|
||||
} else {
|
||||
setApiError('Facebook API error: ' + errMsg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// stream like rtmps://live-api-s.facebook.com:443/rtmp/STREAM_KEY
|
||||
const parts = stream.split('/');
|
||||
const key = parts[parts.length - 1] || '';
|
||||
// Extraer stream_url
|
||||
const streamUrl = data.stream_url || data.secure_stream_url || '';
|
||||
if (!streamUrl) {
|
||||
setApiError('Facebook did not return a stream URL. Check that your token has the "publish_video" permission.');
|
||||
return;
|
||||
}
|
||||
|
||||
const key = extractKey(streamUrl);
|
||||
settings.stream_key_primary = key;
|
||||
settings.create_live = true;
|
||||
|
||||
const outputs = createOutput(settings);
|
||||
props.onChange(outputs, settings);
|
||||
|
||||
window.alert('Facebook Live creado y stream key rellenada.');
|
||||
props.onChange(createOutput(settings), settings);
|
||||
setApiSuccess(`✅ Facebook Live created! Stream key filled automatically. Live ID: ${data.id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
window.alert('Error creando Facebook Live: ' + err.message);
|
||||
setApiError('Network error: ' + err.message + '. Check if CORS is enabled or try from a server-side proxy.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container spacing={2}>
|
||||
{/* Stream keys */}
|
||||
{settings.rtmp_primary === true && (
|
||||
<Grid item xs={12} md={9}>
|
||||
<TextField
|
||||
@ -169,11 +198,6 @@ function Service(props) {
|
||||
value={settings.stream_key_primary}
|
||||
onChange={handleChange('stream_key_primary')}
|
||||
/>
|
||||
|
||||
{/* Button to create FB Live and populate stream key */}
|
||||
<FormInlineButton onClick={createFacebookLive} style={{ marginTop: 8 }}>
|
||||
<Trans>Create</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
)}
|
||||
{settings.rtmp_primary === true && (
|
||||
@ -201,27 +225,138 @@ function Service(props) {
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{/* New fields for page id, token, title and description */}
|
||||
<Grid item xs={12} md={6}>
|
||||
<TextField variant="outlined" fullWidth label={<Trans>Facebook Page ID</Trans>} value={settings.page_id} onChange={handleChange('page_id')} />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<TextField variant="outlined" fullWidth label={<Trans>Page Access Token</Trans>} value={settings.page_access_token} onChange={handleChange('page_access_token')} />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField variant="outlined" fullWidth label={<Trans>Title</Trans>} value={settings.title} onChange={handleChange('title')} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField variant="outlined" fullWidth label={<Trans>Description</Trans>} value={settings.description} onChange={handleChange('description')} />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Checkbox label={<Trans>Enable primary stream</Trans>} checked={settings.rtmp_primary} onChange={handleChange('rtmp_primary')} />
|
||||
<Checkbox label={<Trans>Enable backup stream</Trans>} checked={settings.rtmp_backup} onChange={handleChange('rtmp_backup')} />
|
||||
{/* Optionally mark that we created the live via API */}
|
||||
<Checkbox label={<Trans>Create live via API</Trans>} checked={settings.create_live} onChange={handleChange('create_live')} />
|
||||
</Grid>
|
||||
|
||||
{/* Divider visual */}
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h4" style={{ marginTop: 8 }}>
|
||||
<Trans>Create Live via Facebook API (optional)</Trans>
|
||||
</Typography>
|
||||
<Typography variant="caption" style={{ color: '#aaa' }}>
|
||||
<Trans>Fill in the fields below to automatically create the live broadcast and get the stream key.</Trans>{' '}
|
||||
<Link color="secondary" target="_blank" href="https://developers.facebook.com/tools/explorer/">
|
||||
<Trans>Get your token here</Trans>
|
||||
</Link>
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{/* Account type selector */}
|
||||
<Grid item xs={12}>
|
||||
<Select
|
||||
label={<Trans>Account type</Trans>}
|
||||
value={settings.account_type}
|
||||
onChange={handleChange('account_type')}
|
||||
>
|
||||
<MenuItem value="page">
|
||||
Facebook Page (requires Page ID + Page Access Token)
|
||||
</MenuItem>
|
||||
<MenuItem value="user">
|
||||
Personal profile (requires User Access Token with publish_video)
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</Grid>
|
||||
|
||||
{/* Page ID — solo visible cuando account_type = 'page' */}
|
||||
{settings.account_type === 'page' && (
|
||||
<Grid item xs={12} md={6}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Facebook Page ID</Trans>}
|
||||
placeholder="123456789012345"
|
||||
helperText={
|
||||
<Trans>
|
||||
Find it at: facebook.com/YOUR_PAGE → About → Page transparency → Page ID
|
||||
</Trans>
|
||||
}
|
||||
value={settings.page_id}
|
||||
onChange={handleChange('page_id')}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{/* Access Token */}
|
||||
<Grid item xs={12} md={settings.account_type === 'page' ? 6 : 12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={
|
||||
settings.account_type === 'page'
|
||||
? <Trans>Page Access Token</Trans>
|
||||
: <Trans>User Access Token</Trans>
|
||||
}
|
||||
placeholder="EAAxxxxxxx..."
|
||||
helperText={
|
||||
settings.account_type === 'page'
|
||||
? <Trans>Must have publish_video permission. Get it from Graph API Explorer selecting your Page.</Trans>
|
||||
: <Trans>User token with publish_video permission. Get it from Graph API Explorer.</Trans>
|
||||
}
|
||||
value={settings.page_access_token}
|
||||
onChange={handleChange('page_access_token')}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Title */}
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Description */}
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* Error message */}
|
||||
{$apiError && (
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" style={{ color: '#f44336', whiteSpace: 'pre-wrap', fontSize: '0.8rem' }}>
|
||||
⚠️ {$apiError}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{/* Success message */}
|
||||
{$apiSuccess && (
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" style={{ color: '#4caf50', fontSize: '0.8rem' }}>
|
||||
{$apiSuccess}
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{/* Create button */}
|
||||
<Grid item xs={12}>
|
||||
<FormInlineButton
|
||||
onClick={createFacebookLive}
|
||||
disabled={$loading || !settings.page_access_token}
|
||||
>
|
||||
{$loading ? <Trans>Creating...</Trans> : <Trans>Create Live & get stream key</Trans>}
|
||||
</FormInlineButton>
|
||||
<Typography variant="caption" style={{ display: 'block', marginTop: 4, color: '#888' }}>
|
||||
<Trans>
|
||||
Required permissions: <strong>publish_video</strong>.
|
||||
For pages, also: <strong>pages_manage_posts</strong>, <strong>pages_read_engagement</strong>.
|
||||
</Trans>
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
@ -47,6 +47,8 @@ function init(settings) {
|
||||
key: '',
|
||||
service_instafeed: false,
|
||||
service_yellowduck: false,
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -56,6 +58,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -85,6 +95,28 @@ function Service(props) {
|
||||
<Trans>GET</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -50,6 +50,8 @@ function init(settings) {
|
||||
const initSettings = {
|
||||
protocol: 'rtmp://',
|
||||
address: '',
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -59,6 +61,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -96,6 +106,28 @@ function Service(props) {
|
||||
placeholder="{custom_id}.channel.media.azure.net:2935/live/{custom_id}"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -50,6 +50,8 @@ function init(settings) {
|
||||
const initSettings = {
|
||||
server_url: '',
|
||||
stream_key: '',
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -59,6 +61,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -107,6 +117,28 @@ function Service(props) {
|
||||
<Trans>GET</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -44,6 +44,8 @@ function init(settings) {
|
||||
const initSettings = {
|
||||
region: 'live',
|
||||
key: '',
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -53,6 +55,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -155,6 +165,28 @@ function Service(props) {
|
||||
<Trans>GET</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -66,6 +66,8 @@ function init(settings) {
|
||||
mode: 'rtmps',
|
||||
stream_key: '',
|
||||
region: 'de',
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -75,6 +77,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -179,6 +189,28 @@ function Service(props) {
|
||||
<Trans>GET</Trans>
|
||||
</FormInlineButton>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@ -68,6 +68,8 @@ function init(settings) {
|
||||
stream_key: '',
|
||||
primary: true,
|
||||
backup: false,
|
||||
title: '',
|
||||
description: '',
|
||||
...settings,
|
||||
};
|
||||
|
||||
@ -77,6 +79,14 @@ function init(settings) {
|
||||
function Service(props) {
|
||||
const settings = init(props.settings);
|
||||
|
||||
// Pre-fill title/description from channel metadata if not already set
|
||||
if (!settings.title && props.metadata && props.metadata.name) {
|
||||
settings.title = props.metadata.name;
|
||||
}
|
||||
if (!settings.description && props.metadata && props.metadata.description) {
|
||||
settings.description = props.metadata.description;
|
||||
}
|
||||
|
||||
const handleChange = (what) => (event) => {
|
||||
const value = event.target.value;
|
||||
|
||||
@ -197,6 +207,28 @@ function Service(props) {
|
||||
<Checkbox label={<Trans>Primary stream</Trans>} checked={settings.primary} onChange={handleChange('primary')} />
|
||||
<Checkbox label={<Trans>Backup stream</Trans>} checked={settings.backup} onChange={handleChange('backup')} />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
label={<Trans>Stream title</Trans>}
|
||||
placeholder={props.metadata && props.metadata.name ? props.metadata.name : ''}
|
||||
value={settings.title}
|
||||
onChange={handleChange('title')}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
multiline
|
||||
rows={3}
|
||||
label={<Trans>Stream description</Trans>}
|
||||
placeholder={props.metadata && props.metadata.description ? props.metadata.description : ''}
|
||||
value={settings.description}
|
||||
onChange={handleChange('description')}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user