0

Merge branch '0.0.6' of github.com:owncast/owncast-admin into 0.0.6

This commit is contained in:
gingervitis 2021-02-07 19:28:50 -08:00
commit 6de5b3af19
7 changed files with 131 additions and 45 deletions

View File

@ -23,7 +23,7 @@ jobs:
uses: creyD/prettier_action@v3.1
with:
# This part is also where you can pass other options, for example:
prettier_options: --write **/*.{js,tsx,jsx}
prettier_options: --write **/*.{js,tsx,jsx,css,scss}
only_changed: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,6 +1,7 @@
import React, { useState, useContext, useEffect } from 'react';
import { Button, Tooltip } from 'antd';
import { Button, Tooltip, Collapse, Popconfirm } from 'antd';
import { CopyOutlined, RedoOutlined } from '@ant-design/icons';
const { Panel } = Collapse;
import { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD } from './form-textfield';
import TextFieldWithSubmit from './form-textfield-with-submit';
@ -14,6 +15,7 @@ import {
TEXTFIELD_PROPS_STREAM_KEY,
TEXTFIELD_PROPS_WEB_PORT,
} from '../../utils/config-constants';
import { fetchData, API_YP_RESET } from '../../utils/apis';
import { UpdateArgs } from '../../types/config-section';
@ -24,7 +26,7 @@ export default function EditInstanceDetails() {
const { serverConfig } = serverStatusData || {};
const { streamKey, ffmpegPath, rtmpServerPort, webServerPort } = serverConfig;
const { streamKey, ffmpegPath, rtmpServerPort, webServerPort, yp } = serverConfig;
const [copyIsVisible, setCopyVisible] = useState(false);
@ -66,6 +68,41 @@ export default function EditInstanceDetails() {
}
};
const resetDirectoryRegistration = async () => {
try {
await fetchData(API_YP_RESET);
setMessage('');
} catch (error) {
alert(error);
}
};
function ResetYP() {
// TODO: Uncomment this after it's styled.
// if (yp.enabled) {
return (
<div className="field-container">
Reset Directory:
<Popconfirm
placement="topLeft"
title={'Are you sure you want to reset your connection to the Owncast directory?'}
onConfirm={resetDirectoryRegistration}
okText="Yes"
cancelText="No"
>
<Button>Reset Directory Connection</Button>
</Popconfirm>
<p>
If you are experiencing issues with your listing on the Owncast Directory and were asked
to "reset" your connection to the service, you can do that here. The next time you go live
it will try and re-register your server with the directory from scratch.
</p>
</div>
);
// }
// return null;
}
function generateStreamKey() {
let key = '';
for (let i = 0; i < 3; i += 1) {
@ -135,6 +172,13 @@ export default function EditInstanceDetails() {
onChange={handleFieldChange}
onSubmit={showConfigurationRestartMessage}
/>
<Collapse>
<Panel header="Advanced Settings" key="1">
<div className="form-fields">
<ResetYP />
</div>
</Panel>
</Collapse>
</div>
);
}

View File

@ -1,7 +1,8 @@
// This content populates the video variant modal, which is spawned from the variants table.
import React from 'react';
import { Slider, Switch, Collapse } from 'antd';
import { FieldUpdaterFunc, VideoVariant } from '../../types/config-section';
import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section';
import TextField from './form-textfield';
import { DEFAULT_VARIANT_STATE } from '../../utils/config-constants';
import InfoTip from '../info-tip';
import CPUUsageSelector from './cpu-usage';
@ -39,6 +40,20 @@ const VIDEO_VARIANT_DEFAULTS = {
audioPassthrough: {
tip: 'If No is selected, then you should set your desired Audio Bitrate.',
},
scaledWidth: {
fieldName: 'scaledWidth',
label: 'Resized Width',
maxLength: 4,
placeholder: '1080',
tip: "Optionally resize this content's width.",
},
scaledHeight: {
fieldName: 'scaledHeight',
label: 'Resized Height',
maxLength: 4,
placeholder: '720',
tip: "Optionally resize this content's height.",
},
};
interface VideoVariantFormProps {
@ -62,7 +77,21 @@ export default function VideoVariantForm({
const handleVideoCpuUsageLevelChange = (value: number) => {
onUpdateField({ fieldName: 'cpuUsageLevel', value });
};
const handleScaledWidthChanged = (args: UpdateArgs) => {
const value = Number(args.value);
if (!isNaN(value)) {
return;
}
onUpdateField({ fieldName: 'scaledWidth', value: value });
};
const handleScaledHeightChanged = (args: UpdateArgs) => {
const value = Number(args.value);
if (!isNaN(value)) {
return;
}
onUpdateField({ fieldName: 'scaledHeight', value: value });
};
const framerateDefaults = VIDEO_VARIANT_DEFAULTS.framerate;
const framerateMin = framerateDefaults.min;
const framerateMax = framerateDefaults.max;
@ -145,14 +174,29 @@ export default function VideoVariantForm({
</div>
</div>
<br />
<br />
<br />
<br />
<Collapse>
<Panel header="Advanced Settings" key="1">
<div className="section-intro">Touch if you dare.</div>
<div className="section-intro">
Resizing your content will take additional resources on your server. If you wish to
optionally resize your output for this stream variant then you should either set the
width <strong>or</strong> the height to keep your aspect ratio.
</div>
<div className="field">
<TextField
type="number"
{...VIDEO_VARIANT_DEFAULTS.scaledWidth}
value={dataState.scaledWidth}
onChange={handleScaledWidthChanged}
/>
</div>
<div className="field">
<TextField
type="number"
{...VIDEO_VARIANT_DEFAULTS.scaledHeight}
value={dataState.scaledHeight}
onChange={handleScaledHeightChanged}
/>
</div>
{/* FRAME RATE FIELD */}
<div className="field">

View File

@ -56,6 +56,9 @@ export interface VideoVariant {
audioBitrate: number;
videoPassthrough: boolean;
videoBitrate: number;
scaledWidth: number;
scaledHeight: number;
}
export interface VideoSettingsFields {
latencyLevel: number;

View File

@ -63,6 +63,8 @@ export const CREATE_WEBHOOK = `${API_LOCATION}webhooks/create`;
// hard coded social icons list
export const SOCIAL_PLATFORMS_LIST = `${NEXT_PUBLIC_API_HOST}api/socialplatforms`;
export const API_YP_RESET = `${API_LOCATION}yp/reset`;
export const TEMP_UPDATER_API = LOGS_ALL;
const GITHUB_RELEASE_URL = 'https://api.github.com/repos/owncast/owncast/releases/latest';
@ -71,14 +73,10 @@ interface FetchOptions {
data?: any;
method?: string;
auth?: boolean;
};
}
export async function fetchData(url: string, options?: FetchOptions) {
const {
data,
method = 'GET',
auth = true,
} = options || {};
const { data, method = 'GET', auth = true } = options || {};
const requestOptions: RequestInit = {
method,
@ -114,7 +112,6 @@ export async function fetchData(url: string, options?: FetchOptions) {
return {};
}
export async function getGithubRelease() {
try {
const response = await fetch(GITHUB_RELEASE_URL);
@ -133,29 +130,25 @@ export async function getGithubRelease() {
// Stolen from https://gist.github.com/prenagha/98bbb03e27163bc2f5e4
const VPAT = /^\d+(\.\d+){0,2}$/;
function upToDate(local, remote) {
if (!local || !remote || local.length === 0 || remote.length === 0)
return false;
if (local === remote)
return true;
if (VPAT.test(local) && VPAT.test(remote)) {
const lparts = local.split('.');
while(lparts.length < 3)
lparts.push("0");
const rparts = remote.split('.');
while (rparts.length < 3)
rparts.push("0");
// eslint-disable-next-line no-plusplus
for (let i=0; i<3; i++) {
const l = parseInt(lparts[i], 10);
const r = parseInt(rparts[i], 10);
if (l === r)
// eslint-disable-next-line no-continue
continue;
return l > r;
}
return true;
if (!local || !remote || local.length === 0 || remote.length === 0) return false;
if (local === remote) return true;
if (VPAT.test(local) && VPAT.test(remote)) {
const lparts = local.split('.');
while (lparts.length < 3) lparts.push('0');
const rparts = remote.split('.');
while (rparts.length < 3) rparts.push('0');
// eslint-disable-next-line no-plusplus
for (let i = 0; i < 3; i++) {
const l = parseInt(lparts[i], 10);
const r = parseInt(rparts[i], 10);
if (l === r)
// eslint-disable-next-line no-continue
continue;
return l > r;
}
return local >= remote;
return true;
}
return local >= remote;
}
// Make a request to the server status API and the Github releases API
@ -165,11 +158,11 @@ export async function upgradeVersionAvailable(currentVersion) {
let recentReleaseVersion = recentRelease.tag_name;
if (recentReleaseVersion.substr(0, 1) === 'v') {
recentReleaseVersion = recentReleaseVersion.substr(1)
recentReleaseVersion = recentReleaseVersion.substr(1);
}
if (!upToDate(currentVersion, recentReleaseVersion)) {
return recentReleaseVersion
return recentReleaseVersion;
}
return null;

View File

@ -168,6 +168,8 @@ export const DEFAULT_VARIANT_STATE: VideoVariant = {
audioPassthrough: true, // if false, then CAN set audiobitrate
audioBitrate: 0,
cpuUsageLevel: 3,
scaledHeight: null,
scaledWidth: null,
};
export const DEFAULT_SOCIAL_HANDLE: SocialHandle = {

View File

@ -1,4 +1,4 @@
export function isValidUrl(url: string): boolean {
const pattern = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
const pattern = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/i;
return !!pattern.test(url);
}