Increases the max bandwidth selectable in the admin UI (#4550)

* feat(admin): Closes #1462. Increases the max bandwidth selectable in the UI + localization for the strings

* chore: update extracted translations

* Javascript formatting autofixes

---------

Co-authored-by: Owncast default web localizations <owncast@owncast.online>
This commit is contained in:
Gabe Kangas
2025-09-14 15:41:58 -07:00
committed by GitHub
co-authored by Owncast default web localizations
parent 14189420c5
commit e66b0444ad
4 changed files with 53 additions and 11 deletions
+33 -8
View File
@@ -3,6 +3,8 @@ import React, { FC } from 'react';
import { Popconfirm, Row, Col, Slider, Collapse, Typography, Alert, Button } from 'antd'; import { Popconfirm, Row, Col, Slider, Collapse, Typography, Alert, Button } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useTranslation } from 'next-export-i18n';
import { Localization } from '../../types/localization';
import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section'; import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section';
import { TextField } from './TextField'; import { TextField } from './TextField';
import { import {
@@ -36,6 +38,7 @@ export const VideoVariantForm: FC<VideoVariantFormProps> = ({
dataState = DEFAULT_VARIANT_STATE, dataState = DEFAULT_VARIANT_STATE,
onUpdateField, onUpdateField,
}) => { }) => {
const { t } = useTranslation();
const videoPassthroughEnabled = dataState.videoPassthrough; const videoPassthroughEnabled = dataState.videoPassthrough;
const handleFramerateChange = (value: number) => { const handleFramerateChange = (value: number) => {
@@ -80,18 +83,40 @@ export const VideoVariantForm: FC<VideoVariantFormProps> = ({
onUpdateField({ fieldName: 'name', value: args.value }); onUpdateField({ fieldName: 'name', value: args.value });
}; };
// Extract threshold values dynamically from slider marks
const getBitrateThresholds = () => {
// Get all numeric keys from slider marks and sort them
const marks = Object.keys(VIDEO_BITRATE_SLIDER_MARKS)
.map(key => parseInt(key, 10))
.filter(value => !Number.isNaN(value))
.sort((a, b) => a - b);
// Current marks: [400, 3000, 6000, 9000, 13000]
// Use the second mark (3000) as low threshold and second-to-last (9000) as high threshold
// This excludes min/max values and uses intermediate marks for quality categories
const lowThreshold = marks.length >= 3 ? marks[1] : marks[0];
const highThreshold = marks.length >= 4 ? marks[marks.length - 2] : marks[marks.length - 1];
return { lowThreshold, highThreshold };
};
// Slider notes // Slider notes
const selectedVideoBRnote = () => { const selectedVideoBRnote = () => {
if (videoPassthroughEnabled) { if (videoPassthroughEnabled) {
return 'Bitrate selection is disabled when Video Passthrough is enabled.'; return t(Localization.Admin.VideoVariantForm.bitrateDisabledPassthrough);
} }
let note = `${dataState.videoBitrate}${VIDEO_BITRATE_DEFAULTS.unit}`;
if (dataState.videoBitrate < 2000) { const { lowThreshold, highThreshold } = getBitrateThresholds();
note = `${note} - Good for low bandwidth environments.`;
} else if (dataState.videoBitrate < 3500) { let note = t(Localization.Admin.VideoVariantForm.bitrateValueKbps, {
note = `${note} - Good for most bandwidth environments.`; bitrate: dataState.videoBitrate,
});
if (dataState.videoBitrate < lowThreshold) {
note = `${note} - ${t(Localization.Admin.VideoVariantForm.bitrateGoodForSlow)}`;
} else if (dataState.videoBitrate < highThreshold) {
note = `${note} - ${t(Localization.Admin.VideoVariantForm.bitrateGoodForMost)}`;
} else { } else {
note = `${note} - Good for high bandwidth environments.`; note = `${note} - ${t(Localization.Admin.VideoVariantForm.bitrateGoodForHigh)}`;
} }
return note; return note;
}; };
@@ -203,7 +228,7 @@ export const VideoVariantForm: FC<VideoVariantFormProps> = ({
max={VIDEO_BITRATE_DEFAULTS.max} max={VIDEO_BITRATE_DEFAULTS.max}
marks={VIDEO_BITRATE_SLIDER_MARKS} marks={VIDEO_BITRATE_SLIDER_MARKS}
/> />
<p className="selected-value-note">{selectedVideoBRnote()}</p> <p style={{ marginTop: '40px' }}>{selectedVideoBRnote()}</p>
</div> </div>
<p className="read-more-subtext"> <p className="read-more-subtext">
<a <a
+7
View File
@@ -71,6 +71,13 @@
"offlineMessageDescription": "The offline message is displayed to your page visitors when you're not streaming. Markdown is supported.", "offlineMessageDescription": "The offline message is displayed to your page visitors when you're not streaming. Markdown is supported.",
"directoryDescription": "Increase your audience by appearing in the <a href=\"https://owncast.directory\" target=\"_blank\" rel=\"noreferrer\"><strong>Owncast Directory</strong></a>. This is an external service run by the Owncast project. <a href=\"https://owncast.online/docs/directory/?source=admin\" target=\"_blank\" rel=\"noopener noreferrer\">Learn more</a>.", "directoryDescription": "Increase your audience by appearing in the <a href=\"https://owncast.directory\" target=\"_blank\" rel=\"noreferrer\"><strong>Owncast Directory</strong></a>. This is an external service run by the Owncast project. <a href=\"https://owncast.online/docs/directory/?source=admin\" target=\"_blank\" rel=\"noopener noreferrer\">Learn more</a>.",
"serverUrlRequiredForDirectory": "You must set your <strong>Server URL</strong> above to enable the directory." "serverUrlRequiredForDirectory": "You must set your <strong>Server URL</strong> above to enable the directory."
},
"VideoVariantForm": {
"bitrateDisabledPassthrough": "Bitrate selection is disabled when Video Passthrough is enabled.",
"bitrateValueKbps": "{{bitrate}} kbps",
"bitrateGoodForSlow": "Good for slow, mobile and low bitrate viewers.",
"bitrateGoodForMost": "Good for most viewers, bandwidths and resolutions.",
"bitrateGoodForHigh": "Good for high speed & high bitrate viewers."
} }
}, },
"Common": { "Common": {
+9
View File
@@ -110,6 +110,15 @@ export const Localization = {
serverUrlRequiredForDirectory: 'Admin.EditInstanceDetails.serverUrlRequiredForDirectory', serverUrlRequiredForDirectory: 'Admin.EditInstanceDetails.serverUrlRequiredForDirectory',
}, },
// VideoVariantForm component specific keys
VideoVariantForm: {
bitrateDisabledPassthrough: 'Admin.VideoVariantForm.bitrateDisabledPassthrough',
bitrateValueKbps: 'Admin.VideoVariantForm.bitrateValueKbps',
bitrateGoodForSlow: 'Admin.VideoVariantForm.bitrateGoodForSlow',
bitrateGoodForMost: 'Admin.VideoVariantForm.bitrateGoodForMost',
bitrateGoodForHigh: 'Admin.VideoVariantForm.bitrateGoodForHigh',
},
// Logging and monitoring // Logging and monitoring
info: 'Info', info: 'Info',
warning: 'Warning', warning: 'Warning',
+4 -3
View File
@@ -435,12 +435,12 @@ export const FRAMERATE_TOOLTIPS = {
50: '50fps - Good for fast/action games, sports, HD video.', 50: '50fps - Good for fast/action games, sports, HD video.',
60: '60fps - Good for fast/action games, sports, HD video.', 60: '60fps - Good for fast/action games, sports, HD video.',
90: '90fps - Good for newer fast games and hardware.', 90: '90fps - Good for newer fast games and hardware.',
[FRAMERATE_DEFAULTS.max]: `${FRAMERATE_DEFAULTS.max}fps - Experimental, use at your own risk!`, [FRAMERATE_DEFAULTS.max]: `${FRAMERATE_DEFAULTS.max}fps - Use at your own risk!`,
}; };
// VIDEO VARIANT FORM - bitrate // VIDEO VARIANT FORM - bitrate
export const VIDEO_BITRATE_DEFAULTS = { export const VIDEO_BITRATE_DEFAULTS = {
min: 400, min: 400,
max: 6000, max: 13000,
defaultValue: 1200, defaultValue: 1200,
unit: 'kbps', unit: 'kbps',
incrementBy: 100, incrementBy: 100,
@@ -463,7 +463,8 @@ export const VIDEO_BITRATE_SLIDER_MARKS = {
label: `${VIDEO_BITRATE_DEFAULTS.min} ${VIDEO_BITRATE_DEFAULTS.unit}`, label: `${VIDEO_BITRATE_DEFAULTS.min} ${VIDEO_BITRATE_DEFAULTS.unit}`,
}, },
3000: 3000, 3000: 3000,
4500: 4500, 6000: 6000,
9000: 9000,
[VIDEO_BITRATE_DEFAULTS.max]: { [VIDEO_BITRATE_DEFAULTS.max]: {
style: { style: {
marginLeft: '-10px', marginLeft: '-10px',