Merge branch '0.0.6' of github.com:owncast/owncast-admin into 0.0.6
This commit is contained in:
commit
6de5b3af19
2
web/.github/workflows/prettier.yml
vendored
2
web/.github/workflows/prettier.yml
vendored
@ -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 }}
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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">
|
||||
|
@ -56,6 +56,9 @@ export interface VideoVariant {
|
||||
audioBitrate: number;
|
||||
videoPassthrough: boolean;
|
||||
videoBitrate: number;
|
||||
|
||||
scaledWidth: number;
|
||||
scaledHeight: number;
|
||||
}
|
||||
export interface VideoSettingsFields {
|
||||
latencyLevel: number;
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user