From 2c97ec04cde252ffdeafac25ecbe5c02148b4385 Mon Sep 17 00:00:00 2001 From: Viren070 Date: Thu, 5 Jun 2025 15:54:58 +0100 Subject: [PATCH] feat(frontend): use queue and default regex matched to undefined --- .../src/components/menu/formatter.tsx | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/packages/frontend/src/components/menu/formatter.tsx b/packages/frontend/src/components/menu/formatter.tsx index c4e840ea..5744831f 100644 --- a/packages/frontend/src/components/menu/formatter.tsx +++ b/packages/frontend/src/components/menu/formatter.tsx @@ -22,19 +22,40 @@ import { NumberInput } from '../ui/number-input'; import { PageControls } from '../shared/page-controls'; const formatterChoices = Object.values(constants.FORMATTER_DETAILS); -// Simple throttle utility -let lastCall = 0; -function throttle any>( - func: T, - wait: number -): (...args: Parameters) => void { - return (...args: Parameters) => { - const now = Date.now(); - if (now - lastCall >= wait) { - lastCall = now; - func(...args); +// Remove the throttle utility and replace with FormatQueue +class FormatQueue { + private queue: (() => Promise)[] = []; + private processing = false; + private readonly delay: number; + + constructor(delay: number) { + this.delay = delay; + } + + enqueue(formatFn: () => Promise) { + // Replace any existing queued format request with the new one + this.queue = [formatFn]; + this.process(); + } + + private async process() { + if (this.processing) return; + + this.processing = true; + while (this.queue.length > 0) { + const formatFn = this.queue.shift(); + if (formatFn) { + try { + await formatFn(); + } catch (error) { + console.error('Error in format queue:', error); + } + // Wait for the specified delay before processing the next request + await new Promise((resolve) => setTimeout(resolve, this.delay)); + } } - }; + this.processing = false; + } } export function FormatterMenu() { @@ -85,6 +106,9 @@ function Content() { } | null>(null); const [isFormatting, setIsFormatting] = useState(false); + // Create format queue ref to persist between renders + const formatQueueRef = React.useRef(new FormatQueue(200)); + // Stream preview state const [filename, setFilename] = useState( 'Movie.Title.2023.2160p.BluRay.HEVC.DV.TrueHD.Atmos.7.1.iTA.ENG-GROUP.mkv' @@ -106,7 +130,9 @@ function Content() { const [duration, setDuration] = useState(9120000); // 2h 32m in milliseconds const [fileSize, setFileSize] = useState(62500000000); // 58.2 GB in bytes const [proxied, setProxied] = useState(false); - const [regexMatched, setRegexMatched] = useState(''); + const [regexMatched, setRegexMatched] = useState( + undefined + ); // Custom formatter state (to avoid losing one field when editing the other) const [customName, setCustomName] = useState( @@ -247,14 +273,8 @@ function Content() { regexMatched, ]); - // Throttled format function - const throttledFormat = useCallback(throttle(formatStream, 200), [ - formatStream, - ]); - - // Call format whenever relevant values change useEffect(() => { - throttledFormat(); + formatQueueRef.current.enqueue(formatStream); }, [ filename, folder, @@ -424,7 +444,7 @@ function Content() { Regex Matched} value={regexMatched} - onValueChange={(value) => setRegexMatched(value || '')} + onValueChange={(value) => setRegexMatched(value || undefined)} className="w-full" />