add overlay
Some checks failed
deploy / deploy (push) Has been cancelled

This commit is contained in:
Lee
2023-11-05 20:56:19 +00:00
parent d2df95381c
commit 1792648e8d
31 changed files with 1257 additions and 38 deletions

View File

@ -3,7 +3,6 @@ import { ssrSettings } from "@/ssrSettings";
import clsx from "clsx";
import { Metadata } from "next";
import { Inter } from "next/font/google";
import Image from "next/image";
import Script from "next/script";
import "react-toastify/dist/ReactToastify.css";
import "./globals.css";
@ -49,16 +48,7 @@ export default function RootLayout({
src="https://analytics.fascinated.cc/js/script.js"
/>
<body className={clsx(font.className, "bg-black text-primary")}>
<div className="fixed left-0 top-0 z-0 h-full w-full blur-sm">
<Image
className="object-fill object-center"
alt="Background image"
src={"/assets/background.webp"}
fill
/>
</div>
<body className={clsx(font.className, "text-primary")}>
<AppProvider>{children}</AppProvider>
</body>
</html>

View File

@ -0,0 +1,115 @@
"use client";
import Container from "@/components/Container";
import { Input } from "@/components/input/Input";
import { RadioInput } from "@/components/input/RadioInput";
import { SwitchInput } from "@/components/input/SwitchInput";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { useOverlaySettingsStore } from "@/store/overlaySettingsStore";
import useStore from "@/utils/useStore";
import Link from "next/link";
/**
* Opens the overlay with the current settings
*
* @param settings the settings to pass to the overlay
*/
function goToOverlay(settings: any) {
window.open(`/overlay?data=${JSON.stringify(settings)}`, "_blank");
}
export default function Analytics() {
const settingsStore = useStore(useOverlaySettingsStore, (store) => store);
if (!settingsStore) return null;
return (
<main>
<Container>
<Card className="mt-2">
<CardTitle className="p-3">
<h1>Overlay Builder</h1>
</CardTitle>
<CardContent>
<p className="mb-2">
Confused on how to use this? Check out the{" "}
<span className="transform-gpu text-pp-blue transition-all hover:opacity-80">
<Link href={"https://www.youtube.com/watch?v=IjctLf1nX8w"}>
tutorial
</Link>
</span>
.
</p>
<Input
id="ip-address"
label="IP Address"
defaultValue={settingsStore.ipAddress}
onChange={(e) => {
settingsStore.setIpAddress(e);
}}
/>
<Input
id="account-id"
label="Account ID"
defaultValue={settingsStore.accountId}
onChange={(e) => {
settingsStore.setAccountId(e);
}}
/>
<RadioInput
id="platform"
label="Platform"
defaultValue={settingsStore.platform}
items={[
{
id: "scoresaber",
value: "ScoreSaber",
},
// {
// id: "beatleader",
// value: "BeatLeader",
// },
]}
onChange={(value) => {
settingsStore.setPlatform(value);
}}
/>
<div className="mt-2">
<Label>Settings</Label>
<SwitchInput
id="show-player-stats"
label="Show Player Stats"
defaultChecked={settingsStore.settings.showPlayerStats}
onChange={(value) => {
settingsStore.setShowPlayerStats(value);
}}
/>
<SwitchInput
id="show-song-info"
label="Show Song Info"
defaultChecked={settingsStore.settings.showSongInfo}
onChange={(value) => {
settingsStore.setShowSongInfo(value);
}}
/>
</div>
<Button
className="mt-3"
onClick={() => {
goToOverlay(settingsStore);
}}
>
Open Overlay
</Button>
</CardContent>
</Card>
</Container>
</main>
);
}

119
src/app/overlay/page.tsx Normal file
View File

@ -0,0 +1,119 @@
"use client";
import Container from "@/components/Container";
import Spinner from "@/components/Spinner";
import PlayerStats from "@/components/overlay/PlayerStats";
import ScoreStats from "@/components/overlay/ScoreStats";
import SongInfo from "@/components/overlay/SongInfo";
import { Card, CardDescription, CardTitle } from "@/components/ui/card";
import { HttpSiraStatus } from "@/overlay/httpSiraStatus";
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
import { Component } from "react";
const UPDATE_INTERVAL = 1000 * 60 * 5; // 5 minutes
interface OverlayProps {}
interface OverlayState {
mounted: boolean;
player: ScoresaberPlayer | undefined;
settings: any | undefined;
}
export default class Overlay extends Component<OverlayProps, OverlayState> {
constructor(props: OverlayProps) {
super(props);
this.state = {
mounted: false,
player: undefined,
settings: undefined,
};
}
updatePlayer = async (playerId: string) => {
console.log(`Updating player stats for ${playerId}`);
const player = await ScoreSaberAPI.fetchPlayerData(playerId);
if (!player) {
return;
}
this.setState({ player });
};
componentDidMount() {
if (this.state.mounted) {
return;
}
this.setState({ mounted: true });
if (!this.state.mounted) {
HttpSiraStatus.connectWebSocket();
}
const url = new URL(window.location.href);
const searchParams = url.searchParams;
const data = searchParams.get("data");
if (!data) {
return;
}
const settings = JSON.parse(data);
this.setState({ settings: settings });
this.updatePlayer(settings.accountId);
setInterval(() => {
this.updatePlayer(settings.accountId);
}, UPDATE_INTERVAL);
}
render() {
const { player } = this.state;
if (!this.state.mounted || !player) {
return (
<main className="flex items-center p-3">
<Spinner />
<p className="text-xl">Loading player data</p>
</main>
);
}
if (!this.state.settings) {
return (
<main>
<Container>
<Card className="mt-2 p-3">
<CardTitle>Overlay</CardTitle>
<CardDescription className="mt-2">
<p>
This page is meant to be used as an overlay for streaming.
</p>
<p>
To generate an overlay, go to the builder{" "}
<a
className="transform-gpu text-pp-blue transition-all hover:opacity-80"
href="/overlay/builder"
>
here
</a>
.
</p>
</CardDescription>
</Card>
</Container>
</main>
);
}
return (
<main>
<div>
<PlayerStats player={player} />
<ScoreStats />
</div>
<div className="absolute bottom-0 left-0">
<SongInfo />
</div>
</main>
);
}
}