mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-08 00:25:00 -05:00
rele: 0.7.2
This commit is contained in:
parent
2771fce1b0
commit
435e80165d
@ -27,7 +27,6 @@ First, you must supply the following services with API keys:
|
|||||||
|
|
||||||
- [Clerk](https://clerk.com): Create an app and put the respective keys in `.env.local`
|
- [Clerk](https://clerk.com): Create an app and put the respective keys in `.env.local`
|
||||||
- MongoDB: Create a database, can be anywhere, and put the location to connect in `.env.local` for the key `MONGO_DB` (this isn't required by any means, but if you want to store any short term or historical data, use this.)
|
- MongoDB: Create a database, can be anywhere, and put the location to connect in `.env.local` for the key `MONGO_DB` (this isn't required by any means, but if you want to store any short term or historical data, use this.)
|
||||||
- Inngest: Inngest is a smaller library, but runs the `cron` jobs which will make servers automaticly get added to the database.
|
|
||||||
|
|
||||||
_This project uses `yarn` as the main package manager. If `package-lock.json` is present, your pull request will get denied._
|
_This project uses `yarn` as the main package manager. If `package-lock.json` is present, your pull request will get denied._
|
||||||
Second, run `yarn` and `yarn build`. To start the app, run `yarn start`.
|
Second, run `yarn` and `yarn build`. To start the app, run `yarn start`.
|
||||||
|
|||||||
@ -21,25 +21,30 @@ export default function AfterServerView({ server }: { server: string }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid sm:grid-cols-4 pl-4 pr-4 gap-3.5">
|
<div className="grid sm:grid-cols-4 pl-4 pr-4 gap-3.5">
|
||||||
<Card className="sm:col-span-3">
|
{description != "" && (
|
||||||
<CardDescription className="p-4 prose dark:prose-invert">
|
<Card className="sm:col-span-3">
|
||||||
<Markdown disallowedElements={["img"]}>{description}</Markdown>
|
|
||||||
</CardDescription>
|
|
||||||
</Card>
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Discord Server</CardTitle>
|
|
||||||
<CardDescription className="p-4 prose dark:prose-invert">
|
<CardDescription className="p-4 prose dark:prose-invert">
|
||||||
<iframe
|
<Markdown disallowedElements={["img"]}>{description}</Markdown>
|
||||||
src={`https://discord.com/widget?id=${discord}&theme=${resolvedTheme}`}
|
|
||||||
height="500"
|
|
||||||
allowTransparency={true}
|
|
||||||
className="rounded-lg lg:w-[350px]"
|
|
||||||
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
|
|
||||||
/>
|
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</Card>
|
||||||
</Card>
|
)}
|
||||||
|
{discord != "" && (
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Discord Server</CardTitle>
|
||||||
|
<CardDescription className="p-4 prose dark:prose-invert">
|
||||||
|
<iframe
|
||||||
|
src={`https://discord.com/widget?id=${discord}&theme=${resolvedTheme}`}
|
||||||
|
height="500"
|
||||||
|
allowTransparency={true}
|
||||||
|
className="rounded-lg lg:w-[350px]"
|
||||||
|
sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts"
|
||||||
|
/>
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,22 +2,36 @@
|
|||||||
|
|
||||||
import { getCustomization } from "@/lib/api";
|
import { getCustomization } from "@/lib/api";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { Spinner } from "./ui/spinner";
|
||||||
|
|
||||||
export default function Banner({ server }: { server: string }) {
|
export default function Banner({ server }: { server: string }) {
|
||||||
const [bannerURL, setBannerURL] = useState("");
|
const [bannerURL, setBannerURL] = useState("");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCustomization(server).then((c) => {
|
getCustomization(server).then((c) => {
|
||||||
setBannerURL(c.banner == null ? "" : c.banner);
|
setLoading(false);
|
||||||
|
setBannerURL(c.banner == undefined ? "" : c.banner);
|
||||||
});
|
});
|
||||||
}, [server]);
|
}, [server]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Spinner className="flex items-center" />
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<img
|
{bannerURL != "" && (
|
||||||
src={"https://i.imgur.com/" + bannerURL}
|
<img
|
||||||
className="rounded align-middle block ml-auto mr-auto w-[50%] max-h-[150px]"
|
src={"https://i.imgur.com/" + bannerURL}
|
||||||
/>
|
className="rounded align-middle block ml-auto mr-auto w-[50%] max-h-[150px]"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,124 +0,0 @@
|
|||||||
// inngest in mh-stats provides information periodicly. like every 30 minutes for historical data.
|
|
||||||
// its fully automatic
|
|
||||||
|
|
||||||
import Favorites from "@/app/account/favorites/page";
|
|
||||||
import { OnlineServer } from "@/lib/types/server";
|
|
||||||
import { Inngest } from "inngest";
|
|
||||||
import { serve } from "inngest/next";
|
|
||||||
import { MongoClient } from "mongodb";
|
|
||||||
import { Noto_Sans_Mahajani } from "next/font/google";
|
|
||||||
|
|
||||||
// Create a client to send and receive events
|
|
||||||
export const inngest = new Inngest({ id: "my-app" });
|
|
||||||
|
|
||||||
// Create an API that serves zero functions
|
|
||||||
export default serve({
|
|
||||||
client: inngest,
|
|
||||||
functions: [
|
|
||||||
inngest.createFunction(
|
|
||||||
{ id: "every-30-min" },
|
|
||||||
[{ cron: "*/30 * * * *" }, { event: "test/30-min" }],
|
|
||||||
async ({ event, step }) => {
|
|
||||||
const mongo = new MongoClient(process.env.MONGO_DB as string);
|
|
||||||
try {
|
|
||||||
const mh = await (
|
|
||||||
await fetch("https://api.minehut.com/servers", {
|
|
||||||
headers: {
|
|
||||||
accept: "*/*",
|
|
||||||
"accept-language": Math.random().toString(),
|
|
||||||
priority: "u=1, i",
|
|
||||||
"sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126"',
|
|
||||||
"sec-ch-ua-mobile": "?0",
|
|
||||||
"sec-ch-ua-platform": '"macOS"',
|
|
||||||
"sec-fetch-dest": "empty",
|
|
||||||
"sec-fetch-mode": "cors",
|
|
||||||
"sec-fetch-site": "cross-site",
|
|
||||||
Referer: "http://localhost:3000/",
|
|
||||||
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
||||||
},
|
|
||||||
body: null,
|
|
||||||
method: "GET",
|
|
||||||
})
|
|
||||||
).json();
|
|
||||||
|
|
||||||
const mha = mongo.db("mhsf").collection("mh");
|
|
||||||
const meta = mongo.db("mhsf").collection("meta");
|
|
||||||
const dbl = mongo.db("mhsf").collection("history");
|
|
||||||
mha.insertOne({
|
|
||||||
total_players: mh.total_players,
|
|
||||||
total_servers: mh.total_servers,
|
|
||||||
unix: Date.now(),
|
|
||||||
});
|
|
||||||
mh.servers.forEach(async (server: OnlineServer, i: number) => {
|
|
||||||
const favorites = (async () => {
|
|
||||||
const result = await meta.find({ server: server.name }).toArray();
|
|
||||||
if (result.length == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return result[0].favorites;
|
|
||||||
})();
|
|
||||||
const result = await favorites;
|
|
||||||
|
|
||||||
dbl.insertOne({
|
|
||||||
player_count: server.playerData.playerCount,
|
|
||||||
favorites: result,
|
|
||||||
server: server.name,
|
|
||||||
time: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (i == mh.servers.length) {
|
|
||||||
mongo.close();
|
|
||||||
|
|
||||||
return {
|
|
||||||
event,
|
|
||||||
body: "Finished adding " + mh.servers.length + " servers.",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
mongo.close();
|
|
||||||
return { event, body: "Cloudflare.. aborting " + e };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
inngest.createFunction(
|
|
||||||
{ id: "every-two-months" },
|
|
||||||
[{ cron: "0 0 1 */2 *" }],
|
|
||||||
async ({ event, step }) => {
|
|
||||||
const mongo = new MongoClient(process.env.MONGO_DB as string);
|
|
||||||
const meta = mongo.db("mhsf").collection("history");
|
|
||||||
const historical = mongo.db("mhsf").collection("historical");
|
|
||||||
|
|
||||||
const array = await meta.find().toArray();
|
|
||||||
const result: any = {};
|
|
||||||
|
|
||||||
array.forEach((c) => {
|
|
||||||
if (result[c.server] == undefined) {
|
|
||||||
result[c.server] = {
|
|
||||||
server: c.server,
|
|
||||||
player_count: [c.player_count],
|
|
||||||
favorites: [c.favorites],
|
|
||||||
time: Date.now(),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
result[c.server] = {
|
|
||||||
server: c.server,
|
|
||||||
player_count: [...result[c.server]?.player_count, c.player_count],
|
|
||||||
favorites: [...result[c.server]?.favorites, c.favorites],
|
|
||||||
time: c.time,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
historical.insertMany(Object.values(result));
|
|
||||||
meta.drop();
|
|
||||||
mongo.close();
|
|
||||||
|
|
||||||
return {
|
|
||||||
event,
|
|
||||||
body: "Dropped database. ",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
44
src/pages/api/v1/cron/data-cleanup.ts
Normal file
44
src/pages/api/v1/cron/data-cleanup.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { OnlineServer } from "@/lib/types/server";
|
||||||
|
import { MongoClient } from "mongodb";
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
if (req.headers.Authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
||||||
|
return res.status(401).end("Unauthorized");
|
||||||
|
}
|
||||||
|
const mongo = new MongoClient(process.env.MONGO_DB as string);
|
||||||
|
const meta = mongo.db("mhsf").collection("history");
|
||||||
|
const historical = mongo.db("mhsf").collection("historical");
|
||||||
|
|
||||||
|
const array = await meta.find().toArray();
|
||||||
|
const result: any = {};
|
||||||
|
|
||||||
|
array.forEach((c) => {
|
||||||
|
if (result[c.server] == undefined) {
|
||||||
|
result[c.server] = {
|
||||||
|
server: c.server,
|
||||||
|
player_count: [c.player_count],
|
||||||
|
favorites: [c.favorites],
|
||||||
|
time: Date.now(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
result[c.server] = {
|
||||||
|
server: c.server,
|
||||||
|
player_count: [...result[c.server]?.player_count, c.player_count],
|
||||||
|
favorites: [...result[c.server]?.favorites, c.favorites],
|
||||||
|
time: c.time,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
historical.insertMany(Object.values(result));
|
||||||
|
meta.drop();
|
||||||
|
mongo.close();
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
body: "Dropped database. ",
|
||||||
|
});
|
||||||
|
}
|
||||||
74
src/pages/api/v1/cron/periodic-st.ts
Normal file
74
src/pages/api/v1/cron/periodic-st.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { OnlineServer } from "@/lib/types/server";
|
||||||
|
import { MongoClient } from "mongodb";
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
if (req.headers.Authorization !== `Bearer ${process.env.CRON_SECRET}`) {
|
||||||
|
return res.status(401).end("Unauthorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
const mongo = new MongoClient(process.env.MONGO_DB as string);
|
||||||
|
try {
|
||||||
|
const mh = await (
|
||||||
|
await fetch("https://api.minehut.com/servers", {
|
||||||
|
headers: {
|
||||||
|
accept: "*/*",
|
||||||
|
"accept-language": Math.random().toString(),
|
||||||
|
priority: "u=1, i",
|
||||||
|
"sec-ch-ua": '"Not/A)Brand";v="8", "Chromium";v="126"',
|
||||||
|
"sec-ch-ua-mobile": "?0",
|
||||||
|
"sec-ch-ua-platform": '"macOS"',
|
||||||
|
"sec-fetch-dest": "empty",
|
||||||
|
"sec-fetch-mode": "cors",
|
||||||
|
"sec-fetch-site": "cross-site",
|
||||||
|
Referer: "http://localhost:3000/",
|
||||||
|
"Referrer-Policy": "strict-origin-when-cross-origin",
|
||||||
|
},
|
||||||
|
body: null,
|
||||||
|
method: "GET",
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
|
||||||
|
const mha = mongo.db("mhsf").collection("mh");
|
||||||
|
const meta = mongo.db("mhsf").collection("meta");
|
||||||
|
const dbl = mongo.db("mhsf").collection("history");
|
||||||
|
mha.insertOne({
|
||||||
|
total_players: mh.total_players,
|
||||||
|
total_servers: mh.total_servers,
|
||||||
|
unix: Date.now(),
|
||||||
|
});
|
||||||
|
mh.servers.forEach(async (server: OnlineServer, i: number) => {
|
||||||
|
const favorites = (async () => {
|
||||||
|
const result = await meta.find({ server: server.name }).toArray();
|
||||||
|
if (result.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return result[0].favorites;
|
||||||
|
})();
|
||||||
|
const result = await favorites;
|
||||||
|
|
||||||
|
dbl.insertOne({
|
||||||
|
player_count: server.playerData.playerCount,
|
||||||
|
favorites: result,
|
||||||
|
server: server.name,
|
||||||
|
time: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (i == mh.servers.length) {
|
||||||
|
mongo.close();
|
||||||
|
|
||||||
|
return res.send({
|
||||||
|
body: "Finished adding " + mh.servers.length + " servers.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
mongo.close();
|
||||||
|
return res.send({
|
||||||
|
body: "Cloudflare interferred",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
export const version = "b-0.7.0";
|
export const version = "b-0.7.2";
|
||||||
|
|
||||||
const User = ({ user }: { user: string }) => (
|
const User = ({ user }: { user: string }) => (
|
||||||
<span className="cursor-pointer bg-[rgba(255,165,0,0.25);] rounded p-[2.5px]">
|
<span className="cursor-pointer bg-[rgba(255,165,0,0.25);] rounded p-[2.5px]">
|
||||||
@ -8,6 +8,17 @@ const User = ({ user }: { user: string }) => (
|
|||||||
|
|
||||||
export const Changelog = () => (
|
export const Changelog = () => (
|
||||||
<>
|
<>
|
||||||
|
<div>
|
||||||
|
<strong className="flex items-center">
|
||||||
|
Version b-0.7.2 (August 7th 2024)
|
||||||
|
</strong>
|
||||||
|
<ul>
|
||||||
|
<li>• Adding new spinners to pages that needed it</li>
|
||||||
|
<li>• Fixed lots of bugs</li>
|
||||||
|
<li>• Moved from Inngest to Vercel Cron</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<strong className="flex items-center">
|
<strong className="flex items-center">
|
||||||
Version b-0.7.0 (August 7th 2024)
|
Version b-0.7.0 (August 7th 2024)
|
||||||
|
|||||||
9
vercel.json
Normal file
9
vercel.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"crons": [
|
||||||
|
{
|
||||||
|
"path": "/api/v1/cron/periodic-st",
|
||||||
|
"schedule": "*/30 * * * *"
|
||||||
|
},
|
||||||
|
{ "path": "/api/v1/cron/data-cleanup", "schedule": "0 0 1 */2 *" }
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user