feat: dashboard intro

This commit is contained in:
2024-03-12 12:35:42 +00:00
parent 4d77882114
commit f7b80c0b51
37 changed files with 1204 additions and 454 deletions

View File

@ -1,16 +1,18 @@
import { NostrEvent } from "@snort/system";
import { useContext, useEffect, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { FormattedMessage } from "react-intl";
import { SnortContext } from "@snort/system-react";
import { NostrStreamProvider, StreamProviderEndpoint, StreamProviderInfo } from "@/providers";
import { SendZaps } from "@/element/send-zap";
import { StreamEditor, StreamEditorProps } from "@/element/stream-editor";
import Spinner from "@/element/spinner";
import { unwrap } from "@snort/shared";
import { useRates } from "@/hooks/rates";
import { DefaultButton } from "@/element/buttons";
import Pill from "@/element/pill";
import { AddForwardInputs } from "./fowards";
import StreamKey from "./stream-key";
import AccountTopup from "./topup";
export default function NostrProviderDialog({
provider,
@ -164,23 +166,7 @@ export default function NostrProviderDialog({
</div>
</div>
)}
<div>
<p>
<FormattedMessage defaultMessage="Server Url" id="5kx+2v" />
</p>
<input type="text" value={ep?.url} disabled />
</div>
<div>
<p>
<FormattedMessage defaultMessage="Stream Key" id="LknBsU" />
</p>
<div className="flex gap-2">
<input type="password" value={ep?.key} disabled />
<DefaultButton onClick={() => window.navigator.clipboard.writeText(ep?.key ?? "")}>
<FormattedMessage defaultMessage="Copy" id="4l6vz1" />
</DefaultButton>
</div>
</div>
{ep && <StreamKey ep={ep} />}
<div>
<p>
<FormattedMessage defaultMessage="Balance" id="H5+NAX" />
@ -193,9 +179,12 @@ export default function NostrProviderDialog({
values={{ amount: info.balance?.toLocaleString() }}
/>
</div>
<DefaultButton onClick={() => setTopup(true)}>
<FormattedMessage defaultMessage="Topup" id="nBCvvJ" />
</DefaultButton>
<AccountTopup
provider={provider}
onFinish={async () => {
loadInfo();
}}
/>
</div>
<small>
<FormattedMessage defaultMessage="About {estimate}" id="Q3au2v" values={{ estimate: calcEstimate() }} />
@ -283,167 +272,3 @@ export default function NostrProviderDialog({
</>
);
}
enum ForwardService {
Custom = "custom",
Twitch = "twitch",
Youtube = "youtube",
Facebook = "facebook",
Kick = "kick",
Trovo = "trovo",
}
function AddForwardInputs({
provider,
onAdd,
}: {
provider: NostrStreamProvider;
onAdd: (name: string, target: string) => void;
}) {
const [name, setName] = useState("");
const [target, setTarget] = useState("");
const [svc, setService] = useState(ForwardService.Twitch);
const [error, setError] = useState("");
const { formatMessage } = useIntl();
async function getTargetFull() {
if (svc === ForwardService.Custom) {
return target;
}
if (svc === ForwardService.Twitch) {
const urls = (await (await fetch("https://ingest.twitch.tv/ingests")).json()) as {
ingests: Array<{
availability: number;
name: string;
url_template: string;
}>;
};
const ingestsEurope = urls.ingests.filter(
a => a.name.toLowerCase().startsWith("europe:") && a.availability === 1
);
const random = ingestsEurope.at(ingestsEurope.length * Math.random());
return unwrap(random).url_template.replace("{stream_key}", target);
}
if (svc === ForwardService.Youtube) {
return `rtmp://a.rtmp.youtube.com:1935/live2/${target}`;
}
if (svc === ForwardService.Facebook) {
return `rtmps://live-api-s.facebook.com:443/rtmp/${target}`;
}
if (svc === ForwardService.Trovo) {
return `rtmp://livepush.trovo.live:1935/live/${target}`;
}
if (svc === ForwardService.Kick) {
return `rtmps://fa723fc1b171.global-contribute.live-video.net:443/app/${target}`;
}
}
async function doAdd() {
if (svc === ForwardService.Custom) {
if (!target.startsWith("rtmp://")) {
setError(
formatMessage({
defaultMessage: "Stream url must start with rtmp://",
id: "7+bCC1",
})
);
return;
}
try {
// stupid URL parser doesnt work for non-http protocols
const u = new URL(target.replace("rtmp://", "http://"));
console.debug(u);
if (u.host.length < 1) {
throw new Error();
}
if (u.pathname === "/") {
throw new Error();
}
} catch {
setError(
formatMessage({
defaultMessage: "Not a valid URL",
id: "1q4BO/",
})
);
return;
}
} else {
if (target.length < 2) {
setError(
formatMessage({
defaultMessage: "Stream Key is required",
id: "50+/JW",
})
);
return;
}
}
if (name.length < 2) {
setError(
formatMessage({
defaultMessage: "Name is required",
id: "Gvxoji",
})
);
return;
}
try {
const t = await getTargetFull();
if (!t)
throw new Error(
formatMessage({
defaultMessage: "Could not create stream URL",
id: "E9APoR",
})
);
await provider.addForward(name, t);
} catch (e) {
setError((e as Error).message);
}
setName("");
setTarget("");
onAdd(name, target);
}
return (
<div className="flex flex-col p-4 gap-2 bg-layer-3 rounded-xl">
<div className="flex gap-2">
<select value={svc} onChange={e => setService(e.target.value as ForwardService)} className="flex-1">
<option value="twitch">Twitch</option>
<option value="youtube">Youtube</option>
<option value="facebook">Facebook Gaming</option>
<option value="kick">Kick</option>
<option value="trovo">Trovo</option>
<option value="custom">Custom</option>
</select>
<input
type="text"
className="flex-1"
placeholder={formatMessage({ defaultMessage: "Display name", id: "dOQCL8" })}
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<input
type="text"
placeholder={
svc === ForwardService.Custom ? "rtmp://" : formatMessage({ defaultMessage: "Stream key", id: "QWlMq9" })
}
value={target}
onChange={e => setTarget(e.target.value)}
/>
<DefaultButton onClick={doAdd}>
<FormattedMessage defaultMessage="Add" id="2/2yg+" />
</DefaultButton>
{error && <b className="warning">{error}</b>}
</div>
);
}