pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update VideoTesterView.tsx

Pas 3cc98ebd 25139cc4

+107 -6
+107 -6
src/pages/developer/VideoTesterView.tsx
··· 6 6 import { Dropdown } from "@/components/form/Dropdown"; 7 7 import { Icon, Icons } from "@/components/Icon"; 8 8 import { usePlayer } from "@/components/player/hooks/usePlayer"; 9 + import { convertProviderCaption } from "@/components/player/utils/captions"; 9 10 import { Title } from "@/components/text/Title"; 10 11 import { AuthInputBox } from "@/components/text-inputs/AuthInputBox"; 11 12 import { TextInputControl } from "@/components/text-inputs/TextInputControl"; ··· 140 141 [playMedia, setMeta, headersEnabled, headers, extensionState], 141 142 ); 142 143 144 + const startFromCli = useCallback(async () => { 145 + try { 146 + const clipboardText = await navigator.clipboard.readText(); 147 + 148 + // Parse JavaScript object notation by evaluating it safely 149 + let cliData; 150 + try { 151 + // Try to parse as JSON first (in case it's already valid JSON) 152 + cliData = JSON.parse(clipboardText); 153 + } catch { 154 + // If JSON parsing fails, try to evaluate as JavaScript object 155 + try { 156 + // Use Function constructor to safely evaluate the JavaScript object 157 + // eslint-disable-next-line no-new-func 158 + cliData = new Function(`return (${clipboardText})`)(); 159 + } catch { 160 + throw new Error( 161 + "Invalid JavaScript object format. Please ensure the CLI output is properly formatted.", 162 + ); 163 + } 164 + } 165 + 166 + if ( 167 + !cliData.stream || 168 + !Array.isArray(cliData.stream) || 169 + cliData.stream.length === 0 170 + ) { 171 + throw new Error("Invalid CLI output: no stream data found"); 172 + } 173 + 174 + const streamData = cliData.stream[0]; // Take the first stream 175 + 176 + let source: SourceSliceSource; 177 + if (streamData.type === "hls") { 178 + source = { 179 + type: "hls", 180 + url: streamData.playlist, 181 + ...(streamData.headers && { headers: streamData.headers }), 182 + }; 183 + } else if (streamData.type === "file") { 184 + // Handle file type streams 185 + const qualities = streamData.qualities || {}; 186 + const qualityKeys = Object.keys(qualities); 187 + if (qualityKeys.length === 0) { 188 + throw new Error("Invalid file stream: no qualities found"); 189 + } 190 + source = { 191 + type: "file", 192 + qualities, 193 + ...(streamData.headers && { headers: streamData.headers }), 194 + }; 195 + } else { 196 + throw new Error(`Unsupported stream type: ${streamData.type}`); 197 + } 198 + 199 + // Convert captions 200 + const captions = streamData.captions 201 + ? convertProviderCaption(streamData.captions) 202 + : []; 203 + 204 + // Prepare stream headers if extension is active and headers are present 205 + if ( 206 + extensionState === "success" && 207 + streamData.headers && 208 + Object.keys(streamData.headers).length > 0 209 + ) { 210 + try { 211 + await prepareStream(streamData); 212 + } catch (error) { 213 + console.warn("Failed to prepare stream headers:", error); 214 + } 215 + } 216 + 217 + setMeta(testMeta); 218 + playMedia(source, captions, streamData.id); 219 + } catch (error) { 220 + console.error("Failed to parse CLI data:", error); 221 + 222 + let errorMessage = 223 + error instanceof Error ? error.message : "Unknown error"; 224 + 225 + // Check for common JSON/JavaScript formatting issues 226 + if ( 227 + errorMessage.includes("Expected property name") || 228 + errorMessage.includes("Unexpected token") 229 + ) { 230 + errorMessage += 231 + "\n\nThe CLI output should be in JavaScript object format. Make sure you're copying the complete output from your CLI tool."; 232 + } 233 + 234 + // eslint-disable-next-line no-alert 235 + alert(`Failed to parse CLI data: ${errorMessage}`); 236 + } 237 + }, [playMedia, setMeta, extensionState]); 238 + 143 239 return ( 144 240 <PlayerPart backUrl="/dev"> 145 241 {status === playerStatus.IDLE ? ( ··· 172 268 <div className="flex-1 mb-4"> 173 269 <div className="flex justify-between items-center gap-4"> 174 270 <div className="my-3"> 175 - <p className="text-white font-bold">Headers (Beta)</p> 271 + <p className="text-white font-bold">Headers</p> 176 272 </div> 177 273 <div> 178 274 <Toggle ··· 228 324 </div> 229 325 )} 230 326 231 - <Button 232 - onClick={() => start(inputSource, selected as StreamType)} 233 - > 234 - Start stream 235 - </Button> 327 + <div className="flex gap-2"> 328 + <Button 329 + onClick={() => start(inputSource, selected as StreamType)} 330 + > 331 + Start stream 332 + </Button> 333 + <Button onClick={startFromCli} className="col-span-2"> 334 + Paste from CLI 335 + </Button> 336 + </div> 236 337 </div> 237 338 <div className="flex-1"> 238 339 <Title>Preset tests</Title>