mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
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
|
uses: creyD/prettier_action@v3.1
|
||||||
with:
|
with:
|
||||||
# This part is also where you can pass other options, for example:
|
# 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
|
only_changed: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useContext, useEffect } from 'react';
|
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';
|
import { CopyOutlined, RedoOutlined } from '@ant-design/icons';
|
||||||
|
const { Panel } = Collapse;
|
||||||
|
|
||||||
import { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD } from './form-textfield';
|
import { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD } from './form-textfield';
|
||||||
import TextFieldWithSubmit from './form-textfield-with-submit';
|
import TextFieldWithSubmit from './form-textfield-with-submit';
|
||||||
@ -14,6 +15,7 @@ import {
|
|||||||
TEXTFIELD_PROPS_STREAM_KEY,
|
TEXTFIELD_PROPS_STREAM_KEY,
|
||||||
TEXTFIELD_PROPS_WEB_PORT,
|
TEXTFIELD_PROPS_WEB_PORT,
|
||||||
} from '../../utils/config-constants';
|
} from '../../utils/config-constants';
|
||||||
|
import { fetchData, API_YP_RESET } from '../../utils/apis';
|
||||||
|
|
||||||
import { UpdateArgs } from '../../types/config-section';
|
import { UpdateArgs } from '../../types/config-section';
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ export default function EditInstanceDetails() {
|
|||||||
|
|
||||||
const { serverConfig } = serverStatusData || {};
|
const { serverConfig } = serverStatusData || {};
|
||||||
|
|
||||||
const { streamKey, ffmpegPath, rtmpServerPort, webServerPort } = serverConfig;
|
const { streamKey, ffmpegPath, rtmpServerPort, webServerPort, yp } = serverConfig;
|
||||||
|
|
||||||
const [copyIsVisible, setCopyVisible] = useState(false);
|
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() {
|
function generateStreamKey() {
|
||||||
let key = '';
|
let key = '';
|
||||||
for (let i = 0; i < 3; i += 1) {
|
for (let i = 0; i < 3; i += 1) {
|
||||||
@ -135,6 +172,13 @@ export default function EditInstanceDetails() {
|
|||||||
onChange={handleFieldChange}
|
onChange={handleFieldChange}
|
||||||
onSubmit={showConfigurationRestartMessage}
|
onSubmit={showConfigurationRestartMessage}
|
||||||
/>
|
/>
|
||||||
|
<Collapse>
|
||||||
|
<Panel header="Advanced Settings" key="1">
|
||||||
|
<div className="form-fields">
|
||||||
|
<ResetYP />
|
||||||
|
</div>
|
||||||
|
</Panel>
|
||||||
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// This content populates the video variant modal, which is spawned from the variants table.
|
// This content populates the video variant modal, which is spawned from the variants table.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Slider, Switch, Collapse } from 'antd';
|
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 { DEFAULT_VARIANT_STATE } from '../../utils/config-constants';
|
||||||
import InfoTip from '../info-tip';
|
import InfoTip from '../info-tip';
|
||||||
import CPUUsageSelector from './cpu-usage';
|
import CPUUsageSelector from './cpu-usage';
|
||||||
@ -39,6 +40,20 @@ const VIDEO_VARIANT_DEFAULTS = {
|
|||||||
audioPassthrough: {
|
audioPassthrough: {
|
||||||
tip: 'If No is selected, then you should set your desired Audio Bitrate.',
|
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 {
|
interface VideoVariantFormProps {
|
||||||
@ -62,7 +77,21 @@ export default function VideoVariantForm({
|
|||||||
const handleVideoCpuUsageLevelChange = (value: number) => {
|
const handleVideoCpuUsageLevelChange = (value: number) => {
|
||||||
onUpdateField({ fieldName: 'cpuUsageLevel', value });
|
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 framerateDefaults = VIDEO_VARIANT_DEFAULTS.framerate;
|
||||||
const framerateMin = framerateDefaults.min;
|
const framerateMin = framerateDefaults.min;
|
||||||
const framerateMax = framerateDefaults.max;
|
const framerateMax = framerateDefaults.max;
|
||||||
@ -145,14 +174,29 @@ export default function VideoVariantForm({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<Collapse>
|
<Collapse>
|
||||||
<Panel header="Advanced Settings" key="1">
|
<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 */}
|
{/* FRAME RATE FIELD */}
|
||||||
<div className="field">
|
<div className="field">
|
||||||
|
@ -56,6 +56,9 @@ export interface VideoVariant {
|
|||||||
audioBitrate: number;
|
audioBitrate: number;
|
||||||
videoPassthrough: boolean;
|
videoPassthrough: boolean;
|
||||||
videoBitrate: number;
|
videoBitrate: number;
|
||||||
|
|
||||||
|
scaledWidth: number;
|
||||||
|
scaledHeight: number;
|
||||||
}
|
}
|
||||||
export interface VideoSettingsFields {
|
export interface VideoSettingsFields {
|
||||||
latencyLevel: number;
|
latencyLevel: number;
|
||||||
|
@ -63,6 +63,8 @@ export const CREATE_WEBHOOK = `${API_LOCATION}webhooks/create`;
|
|||||||
// hard coded social icons list
|
// hard coded social icons list
|
||||||
export const SOCIAL_PLATFORMS_LIST = `${NEXT_PUBLIC_API_HOST}api/socialplatforms`;
|
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;
|
export const TEMP_UPDATER_API = LOGS_ALL;
|
||||||
|
|
||||||
const GITHUB_RELEASE_URL = 'https://api.github.com/repos/owncast/owncast/releases/latest';
|
const GITHUB_RELEASE_URL = 'https://api.github.com/repos/owncast/owncast/releases/latest';
|
||||||
@ -71,14 +73,10 @@ interface FetchOptions {
|
|||||||
data?: any;
|
data?: any;
|
||||||
method?: string;
|
method?: string;
|
||||||
auth?: boolean;
|
auth?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export async function fetchData(url: string, options?: FetchOptions) {
|
export async function fetchData(url: string, options?: FetchOptions) {
|
||||||
const {
|
const { data, method = 'GET', auth = true } = options || {};
|
||||||
data,
|
|
||||||
method = 'GET',
|
|
||||||
auth = true,
|
|
||||||
} = options || {};
|
|
||||||
|
|
||||||
const requestOptions: RequestInit = {
|
const requestOptions: RequestInit = {
|
||||||
method,
|
method,
|
||||||
@ -114,7 +112,6 @@ export async function fetchData(url: string, options?: FetchOptions) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function getGithubRelease() {
|
export async function getGithubRelease() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(GITHUB_RELEASE_URL);
|
const response = await fetch(GITHUB_RELEASE_URL);
|
||||||
@ -133,29 +130,25 @@ export async function getGithubRelease() {
|
|||||||
// Stolen from https://gist.github.com/prenagha/98bbb03e27163bc2f5e4
|
// Stolen from https://gist.github.com/prenagha/98bbb03e27163bc2f5e4
|
||||||
const VPAT = /^\d+(\.\d+){0,2}$/;
|
const VPAT = /^\d+(\.\d+){0,2}$/;
|
||||||
function upToDate(local, remote) {
|
function upToDate(local, remote) {
|
||||||
if (!local || !remote || local.length === 0 || remote.length === 0)
|
if (!local || !remote || local.length === 0 || remote.length === 0) return false;
|
||||||
return false;
|
if (local === remote) return true;
|
||||||
if (local === remote)
|
if (VPAT.test(local) && VPAT.test(remote)) {
|
||||||
return true;
|
const lparts = local.split('.');
|
||||||
if (VPAT.test(local) && VPAT.test(remote)) {
|
while (lparts.length < 3) lparts.push('0');
|
||||||
const lparts = local.split('.');
|
const rparts = remote.split('.');
|
||||||
while(lparts.length < 3)
|
while (rparts.length < 3) rparts.push('0');
|
||||||
lparts.push("0");
|
// eslint-disable-next-line no-plusplus
|
||||||
const rparts = remote.split('.');
|
for (let i = 0; i < 3; i++) {
|
||||||
while (rparts.length < 3)
|
const l = parseInt(lparts[i], 10);
|
||||||
rparts.push("0");
|
const r = parseInt(rparts[i], 10);
|
||||||
// eslint-disable-next-line no-plusplus
|
if (l === r)
|
||||||
for (let i=0; i<3; i++) {
|
// eslint-disable-next-line no-continue
|
||||||
const l = parseInt(lparts[i], 10);
|
continue;
|
||||||
const r = parseInt(rparts[i], 10);
|
return l > r;
|
||||||
if (l === r)
|
}
|
||||||
// eslint-disable-next-line no-continue
|
return true;
|
||||||
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
|
// Make a request to the server status API and the Github releases API
|
||||||
@ -165,12 +158,12 @@ export async function upgradeVersionAvailable(currentVersion) {
|
|||||||
let recentReleaseVersion = recentRelease.tag_name;
|
let recentReleaseVersion = recentRelease.tag_name;
|
||||||
|
|
||||||
if (recentReleaseVersion.substr(0, 1) === 'v') {
|
if (recentReleaseVersion.substr(0, 1) === 'v') {
|
||||||
recentReleaseVersion = recentReleaseVersion.substr(1)
|
recentReleaseVersion = recentReleaseVersion.substr(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!upToDate(currentVersion, recentReleaseVersion)) {
|
if (!upToDate(currentVersion, recentReleaseVersion)) {
|
||||||
return recentReleaseVersion
|
return recentReleaseVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@ export const DEFAULT_VARIANT_STATE: VideoVariant = {
|
|||||||
audioPassthrough: true, // if false, then CAN set audiobitrate
|
audioPassthrough: true, // if false, then CAN set audiobitrate
|
||||||
audioBitrate: 0,
|
audioBitrate: 0,
|
||||||
cpuUsageLevel: 3,
|
cpuUsageLevel: 3,
|
||||||
|
scaledHeight: null,
|
||||||
|
scaledWidth: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_SOCIAL_HANDLE: SocialHandle = {
|
export const DEFAULT_SOCIAL_HANDLE: SocialHandle = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export function isValidUrl(url: string): boolean {
|
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);
|
return !!pattern.test(url);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user