mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-19 10:22:06 +00:00
add custom headers to dev video test view
This commit is contained in:
parent
f1065e9602
commit
dd2422f852
1 changed files with 146 additions and 4 deletions
|
|
@ -1,14 +1,20 @@
|
|||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { prepareStream } from "@/backend/extension/streams";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
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 { Title } from "@/components/text/Title";
|
||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||
import { TextInputControl } from "@/components/text-inputs/TextInputControl";
|
||||
import { Divider } from "@/components/utils/Divider";
|
||||
import { PlaybackErrorPart } from "@/pages/parts/player/PlaybackErrorPart";
|
||||
import { PlayerPart } from "@/pages/parts/player/PlayerPart";
|
||||
import { PlayerMeta, playerStatus } from "@/stores/player/slices/source";
|
||||
import { SourceSliceSource, StreamType } from "@/stores/player/utils/qualities";
|
||||
import { type ExtensionStatus, getExtensionState } from "@/utils/extension";
|
||||
|
||||
const testMeta: PlayerMeta = {
|
||||
releaseYear: 2010,
|
||||
|
|
@ -32,14 +38,64 @@ export default function VideoTesterView() {
|
|||
const { status, playMedia, setMeta } = usePlayer();
|
||||
const [selected, setSelected] = useState("mp4");
|
||||
const [inputSource, setInputSource] = useState("");
|
||||
const [extensionState, setExtensionState] =
|
||||
useState<ExtensionStatus>("unknown");
|
||||
const [headersEnabled, setHeadersEnabled] = useState(false);
|
||||
const [headers, setHeaders] = useState<Array<{ key: string; value: string }>>(
|
||||
[{ key: "", value: "" }],
|
||||
);
|
||||
|
||||
// Check extension state on mount
|
||||
useEffect(() => {
|
||||
getExtensionState().then(setExtensionState);
|
||||
}, []);
|
||||
|
||||
// Header management functions
|
||||
const addHeader = useCallback(() => {
|
||||
setHeaders((prev) => [...prev, { key: "", value: "" }]);
|
||||
}, []);
|
||||
|
||||
const updateHeader = useCallback(
|
||||
(index: number, field: "key" | "value", value: string) => {
|
||||
setHeaders((prev) =>
|
||||
prev.map((header, i) =>
|
||||
i === index ? { ...header, [field]: value } : header,
|
||||
),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const removeHeader = useCallback((index: number) => {
|
||||
setHeaders((prev) => prev.filter((_, i) => i !== index));
|
||||
}, []);
|
||||
|
||||
const toggleHeaders = useCallback(() => {
|
||||
const newEnabled = !headersEnabled;
|
||||
setHeadersEnabled(newEnabled);
|
||||
if (!newEnabled) {
|
||||
setHeaders([{ key: "", value: "" }]);
|
||||
}
|
||||
}, [headersEnabled]);
|
||||
|
||||
const start = useCallback(
|
||||
(url: string, type: StreamType) => {
|
||||
async (url: string, type: StreamType) => {
|
||||
// Build headers object from enabled headers
|
||||
const headersObj: Record<string, string> = {};
|
||||
if (headersEnabled) {
|
||||
headers.forEach(({ key, value }) => {
|
||||
if (key.trim() && value.trim()) {
|
||||
headersObj[key.trim()] = value.trim();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let source: SourceSliceSource;
|
||||
if (type === "hls") {
|
||||
source = {
|
||||
type: "hls",
|
||||
url,
|
||||
...(Object.keys(headersObj).length > 0 && { headers: headersObj }),
|
||||
};
|
||||
} else if (type === "mp4") {
|
||||
source = {
|
||||
|
|
@ -50,12 +106,38 @@ export default function VideoTesterView() {
|
|||
url,
|
||||
},
|
||||
},
|
||||
...(Object.keys(headersObj).length > 0 && { headers: headersObj }),
|
||||
};
|
||||
} else throw new Error("Invalid type");
|
||||
|
||||
// Prepare stream headers if extension is active and headers are present
|
||||
if (extensionState === "success" && Object.keys(headersObj).length > 0) {
|
||||
// Create a mock Stream object for prepareStream
|
||||
const mockStream: any = {
|
||||
type: type === "hls" ? "hls" : "file",
|
||||
...(type === "hls"
|
||||
? { playlist: url }
|
||||
: {
|
||||
qualities: {
|
||||
unknown: {
|
||||
type: "mp4",
|
||||
url,
|
||||
},
|
||||
},
|
||||
}),
|
||||
headers: headersObj,
|
||||
};
|
||||
try {
|
||||
await prepareStream(mockStream);
|
||||
} catch (error) {
|
||||
console.warn("Failed to prepare stream headers:", error);
|
||||
}
|
||||
}
|
||||
|
||||
setMeta(testMeta);
|
||||
playMedia(source, [], null);
|
||||
},
|
||||
[playMedia, setMeta],
|
||||
[playMedia, setMeta, headersEnabled, headers, extensionState],
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -85,13 +167,73 @@ export default function VideoTesterView() {
|
|||
setSelectedItem={(item) => setSelected(item.id)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{extensionState === "success" && (
|
||||
<div className="flex-1 mb-4">
|
||||
<div className="flex justify-between items-center gap-4">
|
||||
<div className="my-3">
|
||||
<p className="text-white font-bold">Headers</p>
|
||||
</div>
|
||||
<div>
|
||||
<Toggle
|
||||
onClick={toggleHeaders}
|
||||
enabled={headersEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{headersEnabled && (
|
||||
<>
|
||||
<Divider marginClass="my-6 px-8 box-content -mx-8" />
|
||||
<div className="my-6 space-y-2">
|
||||
{headers.length === 0 ? (
|
||||
<p>No headers configured.</p>
|
||||
) : (
|
||||
headers.map((header, index) => (
|
||||
<div
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={index}
|
||||
className="grid grid-cols-[1fr,1fr,auto] items-center gap-2"
|
||||
>
|
||||
<AuthInputBox
|
||||
value={header.key}
|
||||
onChange={(value) =>
|
||||
updateHeader(index, "key", value)
|
||||
}
|
||||
placeholder="Key"
|
||||
/>
|
||||
<AuthInputBox
|
||||
value={header.value}
|
||||
onChange={(value) =>
|
||||
updateHeader(index, "value", value)
|
||||
}
|
||||
placeholder="Value"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeHeader(index)}
|
||||
className="h-full scale-90 hover:scale-100 rounded-full aspect-square bg-authentication-inputBg hover:bg-authentication-inputBgHover flex justify-center items-center transition-transform duration-200 hover:text-white cursor-pointer"
|
||||
>
|
||||
<Icon className="text-xl" icon={Icons.X} />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Button theme="purple" onClick={addHeader}>
|
||||
Add header
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
onClick={() => start(inputSource, selected as StreamType)}
|
||||
>
|
||||
Start stream
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Title>Preset tests</Title>
|
||||
<div className="grid grid-cols-[1fr,1fr] gap-2">
|
||||
|
|
|
|||
Loading…
Reference in a new issue