LETS GO BABY
Some checks failed
Deploy Website / deploy (push) Waiting to run
Deploy Backend / deploy (push) Has been cancelled

This commit is contained in:
Lee
2024-10-09 01:17:00 +01:00
parent e0fca1168a
commit e87d73bbdf
69 changed files with 583 additions and 458 deletions

View File

@ -1,35 +0,0 @@
import { NextRequest, NextResponse } from "next/server";
import { connectMongo } from "@/common/mongo";
import { IPlayer, PlayerModel } from "@/common/schema/player-schema";
import { seedPlayerHistory } from "@/common/player-utils";
import { scoresaberService } from "@/common/service/impl/scoresaber";
export async function GET(request: NextRequest) {
const playerIdCookie = request.cookies.get("playerId");
const id = request.nextUrl.searchParams.get("id");
if (id == null) {
return NextResponse.json({ error: "Unknown player. Missing: ?id=" }, { status: 400 });
}
const shouldCreatePlayer = playerIdCookie?.value === id;
await connectMongo(); // Connect to Mongo
// Fetch the player and return their statistic history
let foundPlayer: IPlayer | null = await PlayerModel.findById(id);
if (shouldCreatePlayer && foundPlayer == null) {
foundPlayer = await PlayerModel.create({
_id: id,
trackedSince: new Date().toISOString(),
});
const response = await scoresaberService.lookupPlayer(id, true);
if (response != undefined) {
const { player, rawPlayer } = response;
await seedPlayerHistory(foundPlayer!, player, rawPlayer);
}
}
if (foundPlayer == null) {
return NextResponse.json({ error: "Player not found" }, { status: 404 });
}
return NextResponse.json(foundPlayer.getHistoryPrevious(50));
}

View File

@ -1,22 +0,0 @@
import { NextRequest, NextResponse } from "next/server";
import { connectMongo } from "@/common/mongo";
import { IPlayer, PlayerModel } from "@/common/schema/player-schema";
import { PlayerTrackedSince } from "@/common/player/player-tracked-since";
export async function GET(request: NextRequest) {
const id = request.nextUrl.searchParams.get("id");
if (id == null) {
return NextResponse.json({ error: "Unknown player. Missing: ?id=" }, { status: 400 });
}
await connectMongo(); // Connect to Mongo
const foundPlayer: IPlayer | null = await PlayerModel.findById(id);
const response: PlayerTrackedSince = {
tracked: foundPlayer != null,
};
if (foundPlayer != null) {
response["trackedSince"] = foundPlayer.trackedSince?.toUTCString();
response["daysTracked"] = foundPlayer.getStatisticHistory().size;
}
return NextResponse.json(response);
}

View File

@ -1,47 +0,0 @@
import { validateUrl } from "@/common/utils";
import ky from "ky";
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const url = request.nextUrl.searchParams.get("url");
if (url == null) {
return NextResponse.json({ error: "Missing URL. ?url=" }, { status: 400 });
}
if (!validateUrl(url)) {
return NextResponse.json({ error: "Invalid URL" }, { status: 400 });
}
try {
const response = await ky.get(url, {
next: {
revalidate: 30, // 30 seconds
},
});
const { status, headers } = response;
if (
!headers.has("content-type") ||
(headers.has("content-type") && !headers.get("content-type")?.includes("application/json"))
) {
return NextResponse.json({
error: "We only support proxying JSON responses",
});
}
const body = await response.json();
return NextResponse.json(body, {
status: status,
});
} catch (err) {
console.error(`Error fetching data from ${url}:`, err);
return NextResponse.json(
{ error: "Failed to proxy this request." },
{
status: 500,
headers: {
"Access-Control-Allow-Origin": "*",
},
}
);
}
}

View File

@ -1,10 +0,0 @@
import { createAppRoute } from "@trigger.dev/nextjs";
import { client } from "@/trigger";
import "@/jobs";
//this route is used to send and receive data with Trigger.dev
export const { POST, dynamic } = createAppRoute(client);
//uncomment this to set a higher max duration (it must be inside your plan limits). Full docs: https://vercel.com/docs/functions/serverless-functions/runtimes#max-duration
//export const maxDuration = 60;

View File

@ -1,14 +1,16 @@
import { formatNumberWithCommas, formatPp } from "@/common/number-utils";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { ScoreSort } from "@/common/model/score/score-sort";
import PlayerData from "@/components/player/player-data";
import { format } from "@formkit/tempo";
import { Metadata, Viewport } from "next";
import { redirect } from "next/navigation";
import { Colors } from "@/common/colors";
import ScoreSaberPlayerScoresPageToken from "@/common/model/token/scoresaber/score-saber-player-scores-page-token";
import { getAverageColor } from "@/common/image-utils";
import { cache } from "react";
import { ScoreSort } from "@ssr/common/types/score/score-sort";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
import ScoreSaberPlayerScoresPageToken from "@ssr/common/types/token/scoresaber/score-saber-player-scores-page-token";
import { getScoreSaberPlayerFromToken } from "@ssr/common/types/player/impl/scoresaber-player";
import { config } from "../../../../../config";
const UNKNOWN_PLAYER = {
title: "ScoreSaber Reloaded - Unknown Player",
@ -38,7 +40,8 @@ const getPlayerData = cache(async ({ params }: Props, fetchScores: boolean = tru
const page = parseInt(slug[2]) || 1; // The page number
const search = (slug[3] as string) || ""; // The search query
const player = (await scoresaberService.lookupPlayer(id, false))?.player;
const playerToken = await scoresaberService.lookupPlayer(id);
const player = playerToken && (await getScoreSaberPlayerFromToken(playerToken, config.siteApi));
let scores: ScoreSaberPlayerScoresPageToken | undefined;
if (fetchScores) {
scores = await scoresaberService.lookupPlayerScores({

View File

@ -0,0 +1,23 @@
import { Entity } from "dexie";
import Database from "../database";
import { BeatSaverMapToken } from "@ssr/common/types/token/beatsaver/beat-saver-map-token";
/**
* A beat saver map.
*/
export default class BeatSaverMap extends Entity<Database> {
/**
* The hash of the map.
*/
hash!: string;
/**
* The bsr code for the map.
*/
bsr!: string;
/**
* The full data for the map.
*/
fullData!: BeatSaverMapToken;
}

View File

@ -1,12 +0,0 @@
import * as mongoose from "mongoose";
/**
* Connects to the mongo database
*/
export async function connectMongo() {
const connectionUri = process.env.MONGO_URI;
if (!connectionUri) {
throw new Error("Missing MONGO_URI");
}
await mongoose.connect(connectionUri);
}

View File

@ -1,4 +1,4 @@
import { PlayerHistory } from "@/common/player/player-history";
import { PlayerHistory } from "@ssr/common/types/player/player-history";
/**
* Gets a value from an {@link PlayerHistory}

View File

@ -9,6 +9,15 @@ export function setPlayerIdCookie(playerId: string) {
Cookies.set("playerId", playerId, { path: "/" });
}
/**
* Gets the player id cookie
*
* @returns the player id cookie
*/
export function getPlayerIdCookie() {
return Cookies.get("playerId");
}
/**
* Gets if we're in production
*/

View File

@ -1,5 +1,5 @@
import * as Comlink from "comlink";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
export interface WorkerApi {
getPlayerExample: typeof getPlayerExample;

View File

@ -1,7 +1,5 @@
"use client";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import ScoreSaberPlayerToken from "@/common/model/token/scoresaber/score-saber-player-token";
import { formatNumberWithCommas } from "@/common/number-utils";
import { zodResolver } from "@hookform/resolvers/zod";
import Link from "next/link";
@ -13,6 +11,8 @@ import { Button } from "../ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel } from "../ui/form";
import { Input } from "../ui/input";
import { ScrollArea } from "../ui/scroll-area";
import ScoreSaberPlayerToken from "@ssr/common/types/token/scoresaber/score-saber-player-token";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
const formSchema = z.object({
username: z.string().min(3).max(50),

View File

@ -1,14 +1,13 @@
"use client";
import ScoreSaberLeaderboardScoresPageToken from "@/common/model/token/scoresaber/score-saber-leaderboard-scores-page-token";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import LeaderboardScores from "@/components/leaderboard/leaderboard-scores";
import { LeaderboardInfo } from "@/components/leaderboard/leaderboard-info";
import { useQuery } from "@tanstack/react-query";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { useCallback, useEffect, useState } from "react";
import { useEffect, useState } from "react";
import BeatSaverMap from "@/common/database/types/beatsaver-map";
import { beatsaverService } from "@/common/service/impl/beatsaver";
import ScoreSaberLeaderboardScoresPageToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-scores-page-token";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
type LeaderboardDataProps = {
/**
@ -39,14 +38,15 @@ export function LeaderboardData({ initialPage, initialScores, initialLeaderboard
staleTime: 30 * 1000, // Cache data for 30 seconds
});
const fetchBeatSaverData = useCallback(async () => {
const beatSaverMap = await beatsaverService.lookupMap(initialLeaderboard.songHash);
setBeatSaverMap(beatSaverMap);
}, [initialLeaderboard.songHash]);
useEffect(() => {
fetchBeatSaverData();
}, [fetchBeatSaverData]);
// todo: fix
// const fetchBeatSaverData = useCallback(async () => {
// const beatSaverMap = await beatsaverService.lookupMap(initialLeaderboard.songHash);
// setBeatSaverMap(beatSaverMap);
// }, [initialLeaderboard.songHash]);
//
// useEffect(() => {
// fetchBeatSaverData();
// }, [fetchBeatSaverData]);
/**
* When the leaderboard changes, update the previous and current leaderboards.

View File

@ -1,9 +1,9 @@
import Card from "@/components/card";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import Image from "next/image";
import { LeaderboardSongStarCount } from "@/components/leaderboard/leaderboard-song-star-count";
import ScoreButtons from "@/components/score/score-buttons";
import BeatSaverMap from "@/common/database/types/beatsaver-map";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
type LeaderboardInfoProps = {
/**

View File

@ -1,7 +1,7 @@
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import ScoreSaberScoreToken from "@/common/model/token/scoresaber/score-saber-score-token";
import Image from "next/image";
import Link from "next/link";
import ScoreSaberScoreToken from "@ssr/common/types/token/scoresaber/score-saber-score-token";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Props = {
/**

View File

@ -1,11 +1,11 @@
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import ScoreSaberScoreToken from "@/common/model/token/scoresaber/score-saber-score-token";
import { formatNumberWithCommas } from "@/common/number-utils";
import { XMarkIcon } from "@heroicons/react/24/solid";
import clsx from "clsx";
import { getScoreBadgeFromAccuracy } from "@/common/song-utils";
import Tooltip from "@/components/tooltip";
import { ScoreBadge, ScoreBadges } from "@/components/score/score-badge";
import ScoreSaberScoreToken from "@ssr/common/types/token/scoresaber/score-saber-score-token";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
const badges: ScoreBadge[] = [
{

View File

@ -1,9 +1,9 @@
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import ScoreSaberScoreToken from "@/common/model/token/scoresaber/score-saber-score-token";
import LeaderboardPlayer from "./leaderboard-player";
import LeaderboardScoreStats from "./leaderboard-score-stats";
import ScoreRankInfo from "@/components/score/score-rank-info";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import ScoreSaberScoreToken from "@ssr/common/types/token/scoresaber/score-saber-score-token";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
type Props = {
/**

View File

@ -1,8 +1,5 @@
"use client";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import ScoreSaberLeaderboardScoresPageToken from "@/common/model/token/scoresaber/score-saber-leaderboard-scores-page-token";
import useWindowDimensions from "@/hooks/use-window-dimensions";
import { useQuery } from "@tanstack/react-query";
import { motion, useAnimation } from "framer-motion";
@ -11,10 +8,13 @@ import Card from "../card";
import Pagination from "../input/pagination";
import LeaderboardScore from "./leaderboard-score";
import { scoreAnimation } from "@/components/score/score-animation";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { Button } from "@/components/ui/button";
import { clsx } from "clsx";
import { getDifficultyFromRawDifficulty } from "@/common/song-utils";
import ScoreSaberLeaderboardScoresPageToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-scores-page-token";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
type LeaderboardScoresProps = {
/**

View File

@ -1,7 +1,7 @@
import { songDifficultyToColor } from "@/common/song-utils";
import { StarIcon } from "@heroicons/react/24/solid";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import { getDifficultyFromScoreSaberDifficulty } from "@/common/scoresaber-utils";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
type LeaderboardSongStarCountProps = {
/**

View File

@ -1,10 +1,10 @@
"use client";
import { parseDate } from "@/common/time-utils";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import React from "react";
import GenericChart, { DatasetConfig } from "@/components/chart/generic-chart";
import { getValueFromHistory } from "@/common/player-utils";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import { parseDate } from "@ssr/common/utils/time-utils";
type Props = {
/**

View File

@ -1,9 +1,9 @@
"use client";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import React from "react";
import { DatasetConfig } from "@/components/chart/generic-chart";
import GenericPlayerChart from "@/components/player/chart/generic-player-chart";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Props = {
player: ScoreSaberPlayer;

View File

@ -1,12 +1,12 @@
"use client";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import PlayerRankingChart from "@/components/player/chart/player-ranking-chart";
import { FC, useState } from "react";
import Tooltip from "@/components/tooltip";
import PlayerAccuracyChart from "@/components/player/chart/player-accuracy-chart";
import { GlobeAmericasIcon } from "@heroicons/react/24/solid";
import { TrendingUpIcon } from "lucide-react";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type PlayerChartsProps = {
/**

View File

@ -1,10 +1,10 @@
"use client";
import { formatNumberWithCommas } from "@/common/number-utils";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import React from "react";
import { DatasetConfig } from "@/components/chart/generic-chart";
import GenericPlayerChart from "@/components/player/chart/generic-player-chart";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Props = {
player: ScoreSaberPlayer;

View File

@ -1,6 +1,6 @@
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import Image from "next/image";
import Tooltip from "@/components/tooltip";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Props = {
player: ScoreSaberPlayer;

View File

@ -1,19 +1,20 @@
"use client";
import ScoreSaberPlayerScoresPageToken from "@/common/model/token/scoresaber/score-saber-player-scores-page-token";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { ScoreSort } from "@/common/model/score/score-sort";
import { useQuery } from "@tanstack/react-query";
import Mini from "../ranking/mini";
import PlayerHeader from "./player-header";
import PlayerScores from "./player-scores";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import Card from "@/components/card";
import PlayerBadges from "@/components/player/player-badges";
import { useIsMobile } from "@/hooks/use-is-mobile";
import { useIsVisible } from "@/hooks/use-is-visible";
import { useRef } from "react";
import PlayerCharts from "@/components/player/chart/player-charts";
import ScoreSaberPlayer, { getScoreSaberPlayerFromToken } from "@ssr/common/types/player/impl/scoresaber-player";
import ScoreSaberPlayerScoresPageToken from "@ssr/common/types/token/scoresaber/score-saber-player-scores-page-token";
import { ScoreSort } from "@ssr/common/types/score/score-sort";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
import { config } from "../../../config";
type Props = {
initialPlayerData: ScoreSaberPlayer;
@ -37,12 +38,18 @@ export default function PlayerData({
let player = initialPlayerData;
const { data, isLoading, isError } = useQuery({
queryKey: ["player", player.id],
queryFn: () => scoresaberService.lookupPlayer(player.id),
queryFn: async (): Promise<ScoreSaberPlayer | undefined> => {
const playerResponse = await scoresaberService.lookupPlayer(player.id);
if (playerResponse == undefined) {
return undefined;
}
return await getScoreSaberPlayerFromToken(playerResponse, config.siteApi);
},
staleTime: 1000 * 60 * 5, // Cache data for 5 minutes
});
if (data && (!isLoading || !isError)) {
player = data.player;
player = data;
}
return (

View File

@ -7,15 +7,15 @@ import { useCallback, useEffect, useRef, useState } from "react";
import Card from "../card";
import Pagination from "../input/pagination";
import { Button } from "../ui/button";
import { ScoreSort } from "@/common/model/score/score-sort";
import ScoreSaberPlayerScoresPageToken from "@/common/model/token/scoresaber/score-saber-player-scores-page-token";
import Score from "@/components/score/score";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { Input } from "@/components/ui/input";
import { clsx } from "clsx";
import { useDebounce } from "@uidotdev/usehooks";
import { scoreAnimation } from "@/components/score/score-animation";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import ScoreSaberPlayerScoresPageToken from "@ssr/common/types/token/scoresaber/score-saber-player-scores-page-token";
import { ScoreSort } from "@ssr/common/types/score/score-sort";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
type Props = {
initialScoreData?: ScoreSaberPlayerScoresPageToken;

View File

@ -1,6 +1,6 @@
import { formatNumberWithCommas } from "@/common/number-utils";
import StatValue from "@/components/stat-value";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Badge = {
name: string;

View File

@ -1,15 +1,13 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import ky from "ky";
import { config } from "../../../config";
import Tooltip from "@/components/tooltip";
import { InformationCircleIcon } from "@heroicons/react/16/solid";
import { format } from "@formkit/tempo";
import { PlayerTrackedSince } from "@/common/player/player-tracked-since";
import { getDaysAgo } from "@/common/time-utils";
import { formatNumberWithCommas } from "@/common/number-utils";
import { PlayerTrackedSince } from "@ssr/common/types/player/player-tracked-since";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
type Props = {
player: ScoreSaberPlayer;
@ -18,32 +16,19 @@ type Props = {
export default function PlayerTrackedStatus({ player }: Props) {
const { data, isLoading, isError } = useQuery({
queryKey: ["playerIsBeingTracked", player.id],
queryFn: () => ky.get<PlayerTrackedSince>(`${config.siteUrl}/api/player/isbeingtracked?id=${player.id}`).json(),
queryFn: () => ky.get<PlayerTrackedSince>(`${config.siteApi}/player/tracked/${player.id}`).json(),
});
if (isLoading || isError || !data?.tracked) {
return undefined;
}
const trackedSince = new Date(data.trackedSince!);
const daysAgo = getDaysAgo(trackedSince) + 1;
let daysAgoFormatted = `${formatNumberWithCommas(daysAgo)} day${daysAgo > 1 ? "s" : ""} ago`;
if (daysAgo === 1) {
daysAgoFormatted = "Today";
}
if (daysAgo === 2) {
daysAgoFormatted = "Yesterday";
}
return (
<div className="flex gap-2">
<Tooltip
display={
<div className="flex flex-col justify-center items-center">
<p>This player is having their statistics tracked!</p>
<p>
Tracked Since: {format(trackedSince)} ({daysAgoFormatted})
</p>
<p>Days Tracked: {formatNumberWithCommas(data.daysTracked!)}</p>
</div>
}

View File

@ -1,5 +1,3 @@
import ScoreSaberPlayerToken from "@/common/model/token/scoresaber/score-saber-player-token";
import { ScoreSaberPlayersPageToken } from "@/common/model/token/scoresaber/score-saber-players-page-token";
import { formatNumberWithCommas, formatPp } from "@/common/number-utils";
import { GlobeAmericasIcon } from "@heroicons/react/24/solid";
import { useQuery } from "@tanstack/react-query";
@ -8,9 +6,11 @@ import { ReactElement } from "react";
import Card from "../card";
import CountryFlag from "../country-flag";
import { Avatar, AvatarImage } from "../ui/avatar";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { scoresaberService } from "@/common/service/impl/scoresaber";
import { PlayerRankingSkeleton } from "@/components/ranking/player-ranking-skeleton";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import { ScoreSaberPlayersPageToken } from "@ssr/common/types/token/scoresaber/score-saber-players-page-token";
import { scoresaberService } from "@ssr/common/service/impl/scoresaber";
import ScoreSaberPlayerToken from "@ssr/common/types/token/scoresaber/score-saber-player-token";
const PLAYER_NAME_MAX_LENGTH = 18;

View File

@ -1,5 +1,5 @@
import Card from "@/components/card";
import { Skeleton } from "@/app/components/ui/skeleton";
import { Skeleton } from "@/components/ui/skeleton";
export function PlayerRankingSkeleton() {
const skeletonArray = new Array(5).fill(0);

View File

@ -1,6 +1,6 @@
import ScoreSaberScoreToken from "@/common/model/token/scoresaber/score-saber-score-token";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import StatValue from "@/components/stat-value";
import ScoreSaberScoreToken from "@ssr/common/types/token/scoresaber/score-saber-score-token";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
/**
* A badge to display in the score stats.

View File

@ -1,6 +1,5 @@
"use client";
import { copyToClipboard } from "../../../../common/src/utils/browser-utils";
import BeatSaverMap from "@/common/database/types/beatsaver-map";
import { songNameToYouTubeLink } from "@/common/youtube-utils";
import BeatSaverLogo from "@/components/logos/beatsaver-logo";
@ -9,7 +8,8 @@ import { useToast } from "@/hooks/use-toast";
import { Dispatch, SetStateAction } from "react";
import LeaderboardButton from "./leaderboard-button";
import ScoreButton from "./score-button";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import { copyToClipboard } from "@/common/browser-utils";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
type Props = {
leaderboard: ScoreSaberLeaderboardToken;

View File

@ -1,5 +1,4 @@
import BeatSaverMap from "@/common/database/types/beatsaver-map";
import ScoreSaberLeaderboardToken from "@/common/model/token/scoresaber/score-saber-leaderboard-token";
import { getDifficultyFromScoreSaberDifficulty } from "@/common/scoresaber-utils";
import FallbackLink from "@/components/fallback-link";
import Tooltip from "@/components/tooltip";
@ -8,6 +7,7 @@ import clsx from "clsx";
import Image from "next/image";
import { songDifficultyToColor } from "@/common/song-utils";
import Link from "next/link";
import ScoreSaberLeaderboardToken from "@ssr/common/types/token/scoresaber/score-saber-leaderboard-token";
type Props = {
leaderboard: ScoreSaberLeaderboardToken;

View File

@ -1,9 +1,9 @@
import ScoreSaberScoreToken from "@/common/model/token/scoresaber/score-saber-score-token";
import { formatNumberWithCommas } from "@/common/number-utils";
import { timeAgo } from "@/common/time-utils";
import { format } from "@formkit/tempo";
import { GlobeAmericasIcon } from "@heroicons/react/24/solid";
import Tooltip from "../tooltip";
import ScoreSaberScoreToken from "@ssr/common/types/token/scoresaber/score-saber-score-token";
import { timeAgo } from "@ssr/common/utils/time-utils";
type Props = {
score: ScoreSaberScoreToken;

View File

@ -1,16 +1,15 @@
"use client";
import BeatSaverMap from "@/common/database/types/beatsaver-map";
import ScoreSaberPlayerScoreToken from "@/common/model/token/scoresaber/score-saber-player-score-token";
import { beatsaverService } from "@/common/service/impl/beatsaver";
import LeaderboardScores from "@/components/leaderboard/leaderboard-scores";
import { useCallback, useEffect, useState } from "react";
import { useState } from "react";
import ScoreButtons from "./score-buttons";
import ScoreSongInfo from "./score-info";
import ScoreRankInfo from "./score-rank-info";
import ScoreStats from "./score-stats";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { motion } from "framer-motion";
import ScoreSaberPlayer from "@ssr/common/types/player/impl/scoresaber-player";
import ScoreSaberPlayerScoreToken from "@ssr/common/types/token/scoresaber/score-saber-player-score-token";
type Props = {
/**
@ -29,14 +28,15 @@ export default function Score({ player, playerScore }: Props) {
const [beatSaverMap, setBeatSaverMap] = useState<BeatSaverMap | undefined>();
const [isLeaderboardExpanded, setIsLeaderboardExpanded] = useState(false);
const fetchBeatSaverData = useCallback(async () => {
const beatSaverMap = await beatsaverService.lookupMap(leaderboard.songHash);
setBeatSaverMap(beatSaverMap);
}, [leaderboard.songHash]);
useEffect(() => {
fetchBeatSaverData();
}, [fetchBeatSaverData]);
// todo: fix
// const fetchBeatSaverData = useCallback(async () => {
// const beatSaverMap = await beatsaverService.lookupMap(leaderboard.songHash);
// setBeatSaverMap(beatSaverMap);
// }, [leaderboard.songHash]);
//
// useEffect(() => {
// fetchBeatSaverData();
// }, [fetchBeatSaverData]);
const page = Math.floor(score.rank / 12) + 1;
return (

View File

@ -1,3 +0,0 @@
// export all your job files here
export * from "./track-player-statistics";

View File

@ -1,31 +0,0 @@
import { cronTrigger } from "@trigger.dev/sdk";
import { client } from "@/trigger";
import { connectMongo } from "@/common/mongo";
import { getMidnightAlignedDate } from "@/common/time-utils";
import { IPlayer, PlayerModel } from "@/common/schema/player-schema";
import { trackScoreSaberPlayer } from "@/common/player-utils";
client.defineJob({
id: "track-player-statistics",
name: "Tracks player statistics",
version: "0.0.1",
trigger: cronTrigger({
// Run at 00:01 every day (midnight)
cron: "0 1 * * *",
}),
run: async (payload, io) => {
await io.logger.info("Connecting to Mongo");
await connectMongo();
await io.logger.info("Finding players...");
const players: IPlayer[] = await PlayerModel.find({});
await io.logger.info(`Found ${players.length} player${players.length > 1 ? "s" : ""}.`);
const dateToday = getMidnightAlignedDate(new Date());
for (const foundPlayer of players) {
await io.runTask(`track-player-${foundPlayer.id}`, async () => {
await trackScoreSaberPlayer(dateToday, foundPlayer, io);
});
}
},
});

View File

@ -1,7 +0,0 @@
import { TriggerClient } from "@trigger.dev/sdk";
export const client = new TriggerClient({
id: "scoresaber-reloaded-KB0Z",
apiKey: process.env.TRIGGER_API_KEY,
apiUrl: process.env.TRIGGER_API_URL,
});