This commit is contained in:
parent
662b260e18
commit
3a4435cda6
@ -54,7 +54,7 @@ export default function Modal(props: ModalProps) {
|
||||
{
|
||||
"max-xl:-translate-y-[calc(100vh-100dvh)]": props.ready ?? true,
|
||||
"max-xl:translate-y-[50vh]": !(props.ready ?? true),
|
||||
"lg:w-[500px]": !(props.largeModal ?? false),
|
||||
"lg:w-[50vw]": !(props.largeModal ?? false),
|
||||
"lg:w-[80vw]": props.largeModal ?? false,
|
||||
},
|
||||
)
|
||||
|
@ -57,6 +57,7 @@ export function NewStream({ ev, onFinish }: Omit<StreamEditorProps, "onFinish">
|
||||
showEditor={true}
|
||||
showForwards={false}
|
||||
showBalanceHistory={false}
|
||||
showStreamKeys={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import StreamKey from "./stream-key";
|
||||
import AccountTopup from "./topup";
|
||||
import AccountWithdrawl from "./withdraw";
|
||||
import BalanceHistory from "./history";
|
||||
import StreamKeyList from "./stream-keys";
|
||||
|
||||
export default function NostrProviderDialog({
|
||||
provider,
|
||||
@ -21,6 +22,7 @@ export default function NostrProviderDialog({
|
||||
showEditor,
|
||||
showForwards,
|
||||
showBalanceHistory,
|
||||
showStreamKeys,
|
||||
...others
|
||||
}: {
|
||||
provider: NostrStreamProvider;
|
||||
@ -28,6 +30,7 @@ export default function NostrProviderDialog({
|
||||
showEditor: boolean;
|
||||
showForwards: boolean;
|
||||
showBalanceHistory: boolean;
|
||||
showStreamKeys: boolean;
|
||||
} & StreamEditorProps) {
|
||||
const system = useContext(SnortContext);
|
||||
const [topup, setTopup] = useState(false);
|
||||
@ -263,12 +266,18 @@ export default function NostrProviderDialog({
|
||||
);
|
||||
}
|
||||
|
||||
function streamKeys() {
|
||||
if (!info || !showStreamKeys) return;
|
||||
return <StreamKeyList provider={provider} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{showEndpoints && streamEndpoints()}
|
||||
{streamEditor()}
|
||||
{forwardInputs()}
|
||||
{balanceHist()}
|
||||
{streamKeys()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
76
src/element/provider/nostr/stream-keys.tsx
Normal file
76
src/element/provider/nostr/stream-keys.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import { StreamState } from "@/const";
|
||||
import { Layer2Button } from "@/element/buttons";
|
||||
import Copy from "@/element/copy";
|
||||
import { StatePill } from "@/element/state-pill";
|
||||
import { NostrStreamProvider } from "@/providers";
|
||||
import { StreamKeysResult } from "@/providers/zsz";
|
||||
import { eventLink, extractStreamInfo } from "@/utils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function StreamKeyList({ provider }: { provider: NostrStreamProvider }) {
|
||||
const [keys, setKeys] = useState<StreamKeysResult>();
|
||||
|
||||
async function loadKeys() {
|
||||
const k = await provider.streamKeys();
|
||||
setKeys(k);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadKeys();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3>
|
||||
<FormattedMessage defaultMessage="Stream Keys" />
|
||||
</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<FormattedMessage defaultMessage="Created" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage defaultMessage="Expires" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage defaultMessage="Key" />
|
||||
</th>
|
||||
<th>
|
||||
<FormattedMessage defaultMessage="Stream" />
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{keys?.items.map(a => (
|
||||
<tr>
|
||||
<td>{new Date(a.created * 1000).toLocaleString()}</td>
|
||||
<td>{a.expires && new Date(a.expires * 1000).toLocaleString()}</td>
|
||||
<td>
|
||||
<Copy text={a.key} hideText={true} />
|
||||
</td>
|
||||
<td>
|
||||
{a.stream && (
|
||||
<Link to={`/${eventLink(a.stream)}`}>
|
||||
<StatePill state={extractStreamInfo(a.stream).status as StreamState} />
|
||||
</Link>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{keys?.items.length === 0 && <FormattedMessage defaultMessage="No keys" />}
|
||||
<Layer2Button
|
||||
onClick={async () => {
|
||||
await provider.createStreamKey();
|
||||
loadKeys();
|
||||
}}>
|
||||
<FormattedMessage defaultMessage="Add" />
|
||||
</Layer2Button>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
import { StreamState } from "@/const";
|
||||
import { useLogin } from "@/hooks/login";
|
||||
import { formatSats } from "@/number";
|
||||
import { getHost, extractStreamInfo, findTag } from "@/utils";
|
||||
import { TaggedNostrEvent } from "@snort/system";
|
||||
import { getHost, extractStreamInfo, findTag, eventLink } from "@/utils";
|
||||
import { NostrLink, TaggedNostrEvent } from "@snort/system";
|
||||
import { SnortContext, useUserProfile } from "@snort/system-react";
|
||||
import { useContext } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { WarningButton } from "../buttons";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Layer2Button, WarningButton } from "../buttons";
|
||||
import { ClipButton } from "./clip-button";
|
||||
import { FollowButton } from "../follow-button";
|
||||
import GameInfoCard from "../game-info";
|
||||
@ -33,7 +33,7 @@ export function StreamInfo({ ev, goal }: { ev?: TaggedNostrEvent; goal?: TaggedN
|
||||
const streamContext = useStream();
|
||||
|
||||
const { status, participants, title, summary, service, gameId, gameInfo } = extractStreamInfo(ev);
|
||||
const isMine = ev?.pubkey === login?.pubkey;
|
||||
const isMine = ev?.pubkey === login?.pubkey || host === login?.pubkey;
|
||||
|
||||
async function deleteStream() {
|
||||
const pub = login?.publisher();
|
||||
@ -99,12 +99,19 @@ export function StreamInfo({ ev, goal }: { ev?: TaggedNostrEvent; goal?: TaggedN
|
||||
{ev && <Tags ev={ev} />}
|
||||
</div>
|
||||
{summary && <StreamSummary text={summary} />}
|
||||
{isMine && (
|
||||
<div className="flex gap-4">
|
||||
{ev && <NewStreamDialog text={<FormattedMessage defaultMessage="Edit" />} ev={ev} />}
|
||||
{ev && isMine && (
|
||||
<div className="flex gap-2">
|
||||
<NewStreamDialog text={<FormattedMessage defaultMessage="Edit" />} ev={ev} />
|
||||
<Link to={`/dashboard/${NostrLink.fromEvent(ev).encode()}`}>
|
||||
<Layer2Button>
|
||||
<FormattedMessage defaultMessage="Dashboard" />
|
||||
</Layer2Button>
|
||||
</Link>
|
||||
{ev?.pubkey === login?.pubkey && (
|
||||
<WarningButton onClick={deleteStream}>
|
||||
<FormattedMessage defaultMessage="Delete" />
|
||||
</WarningButton>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -263,6 +263,9 @@
|
||||
"ESyhzp": {
|
||||
"defaultMessage": "Your comment for {name}"
|
||||
},
|
||||
"EcglP9": {
|
||||
"defaultMessage": "Key"
|
||||
},
|
||||
"FAUhZf": {
|
||||
"defaultMessage": "What are sats?"
|
||||
},
|
||||
@ -432,6 +435,9 @@
|
||||
"OKhRC6": {
|
||||
"defaultMessage": "Share"
|
||||
},
|
||||
"ORGv1Q": {
|
||||
"defaultMessage": "Created"
|
||||
},
|
||||
"OadZli": {
|
||||
"defaultMessage": "Manage Servers"
|
||||
},
|
||||
@ -530,6 +536,9 @@
|
||||
"TP/cMX": {
|
||||
"defaultMessage": "Ended"
|
||||
},
|
||||
"TcDwEB": {
|
||||
"defaultMessage": "Stream Keys"
|
||||
},
|
||||
"TwyMau": {
|
||||
"defaultMessage": "Account"
|
||||
},
|
||||
@ -592,6 +601,9 @@
|
||||
"XgWvGA": {
|
||||
"defaultMessage": "Reactions"
|
||||
},
|
||||
"XmQZr5": {
|
||||
"defaultMessage": "No keys"
|
||||
},
|
||||
"Xq2sb0": {
|
||||
"defaultMessage": "To go live, copy and paste your Server URL and Stream Key below into your streaming software settings and press 'Start Streaming'. We recommend <a>OBS</a>."
|
||||
},
|
||||
@ -963,6 +975,9 @@
|
||||
"x82IOl": {
|
||||
"defaultMessage": "Mute"
|
||||
},
|
||||
"xhQMeQ": {
|
||||
"defaultMessage": "Expires"
|
||||
},
|
||||
"xi3sgh": {
|
||||
"defaultMessage": "How do i get more sats?"
|
||||
},
|
||||
|
@ -20,6 +20,7 @@ export default function BalanceHistoryModal({ provider }: { provider: NostrStrea
|
||||
showEditor={false}
|
||||
showEndpoints={true}
|
||||
showForwards={false}
|
||||
showStreamKeys={false}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
@ -25,6 +25,7 @@ export function DashboardSettingsButton({ ev }: { ev?: TaggedNostrEvent }) {
|
||||
showForwards={true}
|
||||
showEditor={false}
|
||||
showBalanceHistory={false}
|
||||
showStreamKeys={true}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -86,7 +86,7 @@ export function DashboardForLink({ link }: { link: NostrLink }) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames("grid gap-2 h-[calc(100dvh-52px)]", {
|
||||
className={classNames("grid gap-2 h-[calc(100dvh-52px)] w-full", {
|
||||
"grid-cols-3": status === StreamState.Live,
|
||||
"grid-cols-[20%_80%]": status === StreamState.Ended,
|
||||
})}>
|
||||
|
@ -20,6 +20,7 @@ export default function ForwardingModal({ provider }: { provider: NostrStreamPro
|
||||
showEditor={false}
|
||||
showEndpoints={false}
|
||||
showForwards={true}
|
||||
showStreamKeys={false}
|
||||
/>
|
||||
</Modal>
|
||||
)}
|
||||
|
@ -146,6 +146,17 @@ export class NostrStreamProvider implements StreamProvider {
|
||||
return await this.#getJson<BalanceHistoryResult>("GET", `history?page=${page}&pageSize=${pageSize}`);
|
||||
}
|
||||
|
||||
async streamKeys(page = 0, pageSize = 20) {
|
||||
return await this.#getJson<StreamKeysResult>("GET", `keys?page=${page}&pageSize=${pageSize}`);
|
||||
}
|
||||
|
||||
async createStreamKey(expires?: undefined) {
|
||||
return await this.#getJson<{ key: string; event: NostrEvent }>("POST", "keys", {
|
||||
event: { title: "New stream key, who dis" },
|
||||
expires,
|
||||
});
|
||||
}
|
||||
|
||||
async #getJson<T>(method: "GET" | "POST" | "PATCH" | "DELETE", path: string, body?: unknown): Promise<T> {
|
||||
const pub = (() => {
|
||||
if (this.#publisher) {
|
||||
@ -217,3 +228,15 @@ export interface BalanceHistoryResult {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface StreamKeysResult {
|
||||
items: Array<{
|
||||
id: string;
|
||||
created: number;
|
||||
key: string;
|
||||
expires?: number;
|
||||
stream?: NostrEvent;
|
||||
}>;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@
|
||||
"E7n6zr": "Current stream cost: {amount} sats/{unit} (about {usd}/day for a {x}hr stream)",
|
||||
"E9APoR": "Could not create stream URL",
|
||||
"ESyhzp": "Your comment for {name}",
|
||||
"EcglP9": "Key",
|
||||
"FAUhZf": "What are sats?",
|
||||
"FIDK5Y": "All Time Top Zappers",
|
||||
"FXepR9": "{m}mo {ago}",
|
||||
@ -143,6 +144,7 @@
|
||||
"O7AeYh": "Description..",
|
||||
"OEW7yJ": "Zaps",
|
||||
"OKhRC6": "Share",
|
||||
"ORGv1Q": "Created",
|
||||
"OadZli": "Manage Servers",
|
||||
"ObZZEz": "No clips yet",
|
||||
"OkXMLE": "Max Audio Bitrate",
|
||||
@ -175,6 +177,7 @@
|
||||
"SC2nJT": "Audio Codec",
|
||||
"TDUfVk": "Started",
|
||||
"TP/cMX": "Ended",
|
||||
"TcDwEB": "Stream Keys",
|
||||
"TwyMau": "Account",
|
||||
"UCDS65": "ago",
|
||||
"UGFYV8": "Welcome to zap.stream!",
|
||||
@ -195,6 +198,7 @@
|
||||
"XIvYvF": "Failed to get invoice",
|
||||
"XMGfiA": "Recent Clips",
|
||||
"XgWvGA": "Reactions",
|
||||
"XmQZr5": "No keys",
|
||||
"Xq2sb0": "To go live, copy and paste your Server URL and Stream Key below into your streaming software settings and press 'Start Streaming'. We recommend <a>OBS</a>.",
|
||||
"Y0DXJb": "Recording URL",
|
||||
"YPh5Nq": "@ {rate}",
|
||||
@ -317,6 +321,7 @@
|
||||
"wTwfnv": "Invalid nostr address",
|
||||
"we4Lby": "Info",
|
||||
"x82IOl": "Mute",
|
||||
"xhQMeQ": "Expires",
|
||||
"xi3sgh": "How do i get more sats?",
|
||||
"xmcVZ0": "Search",
|
||||
"y867Vs": "Volume",
|
||||
|
Loading…
Reference in New Issue
Block a user