From e66b0444ad5cfb0920c4e0ecec6a9c93bb7f022e Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Sun, 14 Sep 2025 15:41:58 -0700 Subject: [PATCH] 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 --- web/components/admin/VideoVariantForm.tsx | 41 ++++++++++++++++++----- web/i18n/en/translation_old.json | 7 ++++ web/types/localization.ts | 9 +++++ web/utils/config-constants.tsx | 7 ++-- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/web/components/admin/VideoVariantForm.tsx b/web/components/admin/VideoVariantForm.tsx index 4a9fcfbc28..980740fa83 100644 --- a/web/components/admin/VideoVariantForm.tsx +++ b/web/components/admin/VideoVariantForm.tsx @@ -3,6 +3,8 @@ import React, { FC } from 'react'; import { Popconfirm, Row, Col, Slider, Collapse, Typography, Alert, Button } from 'antd'; import classNames from 'classnames'; 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 { TextField } from './TextField'; import { @@ -36,6 +38,7 @@ export const VideoVariantForm: FC = ({ dataState = DEFAULT_VARIANT_STATE, onUpdateField, }) => { + const { t } = useTranslation(); const videoPassthroughEnabled = dataState.videoPassthrough; const handleFramerateChange = (value: number) => { @@ -80,18 +83,40 @@ export const VideoVariantForm: FC = ({ 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 const selectedVideoBRnote = () => { 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) { - note = `${note} - Good for low bandwidth environments.`; - } else if (dataState.videoBitrate < 3500) { - note = `${note} - Good for most bandwidth environments.`; + + const { lowThreshold, highThreshold } = getBitrateThresholds(); + + let note = t(Localization.Admin.VideoVariantForm.bitrateValueKbps, { + 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 { - note = `${note} - Good for high bandwidth environments.`; + note = `${note} - ${t(Localization.Admin.VideoVariantForm.bitrateGoodForHigh)}`; } return note; }; @@ -203,7 +228,7 @@ export const VideoVariantForm: FC = ({ max={VIDEO_BITRATE_DEFAULTS.max} marks={VIDEO_BITRATE_SLIDER_MARKS} /> -

{selectedVideoBRnote()}

+

{selectedVideoBRnote()}

Owncast Directory. This is an external service run by the Owncast project. Learn more.", "serverUrlRequiredForDirectory": "You must set your Server URL 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": { diff --git a/web/types/localization.ts b/web/types/localization.ts index 1d0377f70e..75acc6abca 100644 --- a/web/types/localization.ts +++ b/web/types/localization.ts @@ -110,6 +110,15 @@ export const Localization = { 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 info: 'Info', warning: 'Warning', diff --git a/web/utils/config-constants.tsx b/web/utils/config-constants.tsx index 2f41ae615b..1c8ba020ae 100644 --- a/web/utils/config-constants.tsx +++ b/web/utils/config-constants.tsx @@ -435,12 +435,12 @@ export const FRAMERATE_TOOLTIPS = { 50: '50fps - 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.', - [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 export const VIDEO_BITRATE_DEFAULTS = { min: 400, - max: 6000, + max: 13000, defaultValue: 1200, unit: 'kbps', incrementBy: 100, @@ -463,7 +463,8 @@ export const VIDEO_BITRATE_SLIDER_MARKS = { label: `${VIDEO_BITRATE_DEFAULTS.min} ${VIDEO_BITRATE_DEFAULTS.unit}`, }, 3000: 3000, - 4500: 4500, + 6000: 6000, + 9000: 9000, [VIDEO_BITRATE_DEFAULTS.max]: { style: { marginLeft: '-10px',