diff --git a/src/pages/developer/VideoTesterView.tsx b/src/pages/developer/VideoTesterView.tsx index ef218383..7c234c54 100644 --- a/src/pages/developer/VideoTesterView.tsx +++ b/src/pages/developer/VideoTesterView.tsx @@ -6,6 +6,7 @@ import { Toggle } from "@/components/buttons/Toggle"; import { Dropdown } from "@/components/form/Dropdown"; import { Icon, Icons } from "@/components/Icon"; import { usePlayer } from "@/components/player/hooks/usePlayer"; +import { convertProviderCaption } from "@/components/player/utils/captions"; import { Title } from "@/components/text/Title"; import { AuthInputBox } from "@/components/text-inputs/AuthInputBox"; import { TextInputControl } from "@/components/text-inputs/TextInputControl"; @@ -140,6 +141,101 @@ export default function VideoTesterView() { [playMedia, setMeta, headersEnabled, headers, extensionState], ); + const startFromCli = useCallback(async () => { + try { + const clipboardText = await navigator.clipboard.readText(); + + // Parse JavaScript object notation by evaluating it safely + let cliData; + try { + // Try to parse as JSON first (in case it's already valid JSON) + cliData = JSON.parse(clipboardText); + } catch { + // If JSON parsing fails, try to evaluate as JavaScript object + try { + // Use Function constructor to safely evaluate the JavaScript object + // eslint-disable-next-line no-new-func + cliData = new Function(`return (${clipboardText})`)(); + } catch { + throw new Error( + "Invalid JavaScript object format. Please ensure the CLI output is properly formatted.", + ); + } + } + + if ( + !cliData.stream || + !Array.isArray(cliData.stream) || + cliData.stream.length === 0 + ) { + throw new Error("Invalid CLI output: no stream data found"); + } + + const streamData = cliData.stream[0]; // Take the first stream + + let source: SourceSliceSource; + if (streamData.type === "hls") { + source = { + type: "hls", + url: streamData.playlist, + ...(streamData.headers && { headers: streamData.headers }), + }; + } else if (streamData.type === "file") { + // Handle file type streams + const qualities = streamData.qualities || {}; + const qualityKeys = Object.keys(qualities); + if (qualityKeys.length === 0) { + throw new Error("Invalid file stream: no qualities found"); + } + source = { + type: "file", + qualities, + ...(streamData.headers && { headers: streamData.headers }), + }; + } else { + throw new Error(`Unsupported stream type: ${streamData.type}`); + } + + // Convert captions + const captions = streamData.captions + ? convertProviderCaption(streamData.captions) + : []; + + // Prepare stream headers if extension is active and headers are present + if ( + extensionState === "success" && + streamData.headers && + Object.keys(streamData.headers).length > 0 + ) { + try { + await prepareStream(streamData); + } catch (error) { + console.warn("Failed to prepare stream headers:", error); + } + } + + setMeta(testMeta); + playMedia(source, captions, streamData.id); + } catch (error) { + console.error("Failed to parse CLI data:", error); + + let errorMessage = + error instanceof Error ? error.message : "Unknown error"; + + // Check for common JSON/JavaScript formatting issues + if ( + errorMessage.includes("Expected property name") || + errorMessage.includes("Unexpected token") + ) { + errorMessage += + "\n\nThe CLI output should be in JavaScript object format. Make sure you're copying the complete output from your CLI tool."; + } + + // eslint-disable-next-line no-alert + alert(`Failed to parse CLI data: ${errorMessage}`); + } + }, [playMedia, setMeta, extensionState]); + return ( {status === playerStatus.IDLE ? ( @@ -172,7 +268,7 @@ export default function VideoTesterView() {
-

Headers (Beta)

+

Headers

)} - +
+ + +
Preset tests