feat(ssr): add sitemap generator
This commit is contained in:
parent
4b966aaaae
commit
41d1d5f1d7
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,3 +42,6 @@ next-env.d.ts
|
|||||||
|
|
||||||
# Webpack bundle analyzer
|
# Webpack bundle analyzer
|
||||||
analyze
|
analyze
|
||||||
|
|
||||||
|
# Sitemap
|
||||||
|
public/sitemap*
|
@ -38,6 +38,9 @@ COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
|||||||
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
|
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/next.config.js ./next.config.js
|
COPY --from=builder --chown=nextjs:nodejs /app/next.config.js ./next.config.js
|
||||||
|
|
||||||
|
# Generate sitemap
|
||||||
|
RUN npm run generate-sitemap
|
||||||
|
|
||||||
USER nextjs
|
USER nextjs
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
ENV HOSTNAME "0.0.0.0"
|
ENV HOSTNAME "0.0.0.0"
|
||||||
|
54
next-sitemap.config.js
Normal file
54
next-sitemap.config.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
const ssrSettings = require("./src/ssrSettings");
|
||||||
|
const { getCodeList } = require("country-list");
|
||||||
|
|
||||||
|
const SS_API_URL = ssrSettings.proxy + "/https://scoresaber.com/api";
|
||||||
|
const SS_GET_PLAYERS_URL = SS_API_URL + "/players?page={}";
|
||||||
|
|
||||||
|
async function getTopPlayers() {
|
||||||
|
console.log("Fetching top players...");
|
||||||
|
const players = [];
|
||||||
|
const pagesToFetch = 25;
|
||||||
|
for (let i = 0; i < pagesToFetch; i++) {
|
||||||
|
console.log(`Fetching page ${i + 1} of ${pagesToFetch}...`);
|
||||||
|
const response = await fetch(SS_GET_PLAYERS_URL.replace("{}", i));
|
||||||
|
const data = await response.json();
|
||||||
|
players.push(...data.players);
|
||||||
|
}
|
||||||
|
console.log("Done fetching top players.");
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {import('next-sitemap').IConfig} */
|
||||||
|
module.exports = {
|
||||||
|
siteUrl: ssrSettings.siteUrl,
|
||||||
|
generateRobotsTxt: true,
|
||||||
|
additionalPaths: async (config) => {
|
||||||
|
const paths = [];
|
||||||
|
// Add the top 50 global ranking pages
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
paths.push({
|
||||||
|
loc: `/ranking/global/${i + 1}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the top 50 pages for all countries
|
||||||
|
const countries = Object.keys(getCodeList());
|
||||||
|
for (const country of countries) {
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
paths.push({
|
||||||
|
loc: `/ranking/country/${country}/${i + 1}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add top players
|
||||||
|
const players = await getTopPlayers();
|
||||||
|
for (const player of players) {
|
||||||
|
paths.push({
|
||||||
|
loc: `/player/${player.id}/top/1`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
|
},
|
||||||
|
};
|
43
package-lock.json
generated
43
package-lock.json
generated
@ -23,12 +23,14 @@
|
|||||||
"chart.js": "^4.4.0",
|
"chart.js": "^4.4.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"country-list": "^2.3.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"lucide-react": "^0.292.0",
|
"lucide-react": "^0.292.0",
|
||||||
"next": "14.0.1",
|
"next": "14.0.1",
|
||||||
"next-build-id": "^3.0.0",
|
"next-build-id": "^3.0.0",
|
||||||
|
"next-sitemap": "^4.2.3",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"node-fetch-cache": "^3.1.3",
|
"node-fetch-cache": "^3.1.3",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
@ -95,6 +97,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@boiseitguru/cookie-cutter/-/cookie-cutter-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@boiseitguru/cookie-cutter/-/cookie-cutter-0.2.1.tgz",
|
||||||
"integrity": "sha512-MLYTqtyECvjq+Wjq2k++bXReIlClTrtpSWSXeamp868MWKggn6SanFBZRVhI61isf3ETuvmDJObexW36Ck4SCQ=="
|
"integrity": "sha512-MLYTqtyECvjq+Wjq2k++bXReIlClTrtpSWSXeamp868MWKggn6SanFBZRVhI61isf3ETuvmDJObexW36Ck4SCQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@corex/deepmerge": {
|
||||||
|
"version": "4.0.43",
|
||||||
|
"resolved": "https://registry.npmjs.org/@corex/deepmerge/-/deepmerge-4.0.43.tgz",
|
||||||
|
"integrity": "sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ=="
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||||
@ -2464,6 +2471,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/country-list": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/country-list/-/country-list-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-qZk66RlmQm7fQjMYWku1AyjlKPogjPEorAZJG88owPExoPV8EsyCcuFLvO2afTXHEhi9liVOoyd+5A6ZS5QwaA=="
|
||||||
|
},
|
||||||
"node_modules/cross-env": {
|
"node_modules/cross-env": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||||
@ -4788,6 +4800,37 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/next-sitemap": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/iamvishnusankar/next-sitemap.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@corex/deepmerge": "^4.0.43",
|
||||||
|
"@next/env": "^13.4.3",
|
||||||
|
"fast-glob": "^3.2.12",
|
||||||
|
"minimist": "^1.2.8"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"next-sitemap": "bin/next-sitemap.mjs",
|
||||||
|
"next-sitemap-cjs": "bin/next-sitemap.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"next": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/next-sitemap/node_modules/@next/env": {
|
||||||
|
"version": "13.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz",
|
||||||
|
"integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw=="
|
||||||
|
},
|
||||||
"node_modules/next-themes": {
|
"node_modules/next-themes": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
"generate-sitemap": "next-sitemap",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
@ -24,12 +25,14 @@
|
|||||||
"chart.js": "^4.4.0",
|
"chart.js": "^4.4.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
|
"country-list": "^2.3.0",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"encoding": "^0.1.13",
|
"encoding": "^0.1.13",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"lucide-react": "^0.292.0",
|
"lucide-react": "^0.292.0",
|
||||||
"next": "14.0.1",
|
"next": "14.0.1",
|
||||||
"next-build-id": "^3.0.0",
|
"next-build-id": "^3.0.0",
|
||||||
|
"next-sitemap": "^4.2.3",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"node-fetch-cache": "^3.1.3",
|
"node-fetch-cache": "^3.1.3",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
@ -1,2 +1,9 @@
|
|||||||
|
# *
|
||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
|
# Host
|
||||||
|
Host: https://ssr.fascinated.cc
|
||||||
|
|
||||||
|
# Sitemaps
|
||||||
|
Sitemap: https://ssr.fascinated.cc/sitemap.xml
|
||||||
|
@ -2,7 +2,7 @@ import AnalyticsChart from "@/components/AnalyticsChart";
|
|||||||
import Card from "@/components/Card";
|
import Card from "@/components/Card";
|
||||||
import Container from "@/components/Container";
|
import Container from "@/components/Container";
|
||||||
import { ScoresaberMetricsHistory } from "@/schemas/fascinated/scoresaberMetricsHistory";
|
import { ScoresaberMetricsHistory } from "@/schemas/fascinated/scoresaberMetricsHistory";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { formatNumber } from "@/utils/numberUtils";
|
import { formatNumber } from "@/utils/numberUtils";
|
||||||
import { isProduction } from "@/utils/utils";
|
import { isProduction } from "@/utils/utils";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import AppProvider from "@/components/AppProvider";
|
import AppProvider from "@/components/AppProvider";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import PlayerPage from "@/components/player/PlayerPage";
|
import PlayerPage from "@/components/player/PlayerPage";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { formatNumber } from "@/utils/numberUtils";
|
import { formatNumber } from "@/utils/numberUtils";
|
||||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||||
import { normalizedRegionName } from "@/utils/utils";
|
import { normalizedRegionName } from "@/utils/utils";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { isProduction } from "@/utils/utils";
|
import { isProduction } from "@/utils/utils";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Card from "./Card";
|
import Card from "./Card";
|
||||||
|
@ -125,7 +125,8 @@ export default function GlobalRanking({ page, country }: GlobalRankingProps) {
|
|||||||
<p>
|
<p>
|
||||||
You are viewing{" "}
|
You are viewing{" "}
|
||||||
{country
|
{country
|
||||||
? "scores from " + normalizedRegionName(country)
|
? "scores from " +
|
||||||
|
normalizedRegionName(country.toUpperCase())
|
||||||
: "Global scores"}
|
: "Global scores"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
6
src/ssrSettings.json
Normal file
6
src/ssrSettings.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"siteName": "ScoreSaber Reloaded",
|
||||||
|
"description": "Scoresaber Reloaded is a new way to view your scores and get more stats about your and your plays",
|
||||||
|
"siteUrl": "https://ssr.fascinated.cc",
|
||||||
|
"proxy": "https://proxy.fascinated.cc"
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
export const ssrSettings = {
|
|
||||||
siteName: "ScoreSaber Reloaded",
|
|
||||||
description:
|
|
||||||
"Scoresaber Reloaded is a new way to view your scores and get more stats about your and your plays",
|
|
||||||
siteUrl: "https://ssr.fascinated.cc",
|
|
||||||
proxy: "https://proxy.fascinated.cc",
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
import { BeatLeaderPlayer } from "@/schemas/beatleader/player";
|
import { BeatLeaderPlayer } from "@/schemas/beatleader/player";
|
||||||
import { BeatleaderScore } from "@/schemas/beatleader/score";
|
import { BeatleaderScore } from "@/schemas/beatleader/score";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { FetchQueue } from "../fetchWithQueue";
|
import { FetchQueue } from "../fetchWithQueue";
|
||||||
import { formatString } from "../string";
|
import { formatString } from "../string";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { BeatsaverMap } from "@/schemas/beatsaver/BeatsaverMap";
|
import { BeatsaverMap } from "@/schemas/beatsaver/BeatsaverMap";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { FetchQueue } from "../fetchWithQueue";
|
import { FetchQueue } from "../fetchWithQueue";
|
||||||
import { formatString } from "../string";
|
import { formatString } from "../string";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard";
|
|||||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||||
import { ScoresaberPlayerScore } from "@/schemas/scoresaber/playerScore";
|
import { ScoresaberPlayerScore } from "@/schemas/scoresaber/playerScore";
|
||||||
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
||||||
import { ssrSettings } from "@/ssrSettings";
|
import ssrSettings from "@/ssrSettings.json";
|
||||||
import { FetchQueue } from "../fetchWithQueue";
|
import { FetchQueue } from "../fetchWithQueue";
|
||||||
import { formatString } from "../string";
|
import { formatString } from "../string";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user