Skip to content

Commit 4f9810f

Browse files
authored
Maintenance (2024-03-08) (#11)
* update dependencies * validation fixes * migrate to valibot; improve serialization * support v4 map format * hotfixes * ignore invalid entries in localstorage * support more extensions for text files in archives
1 parent ef3e146 commit 4f9810f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4995
-5340
lines changed

.eslintrc

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"ignorePatterns": ["dist", "package.json", "yarn.lock", "src/styles", "src/router.ts"],
66
"parser": "@typescript-eslint/parser",
77
"parserOptions": {
8-
"project": ["./tsconfig.json"]
8+
"project": ["./tsconfig.json"],
99
},
1010
"plugins": ["react-refresh"],
1111
"rules": {
1212
"react-refresh/only-export-components": ["warn", { "allowConstantExport": true }],
1313
"@typescript-eslint/no-non-null-assertion": "off",
1414
"@typescript-eslint/ban-ts-comment": "off",
15-
"@typescript-eslint/no-unused-vars": "warn"
16-
}
15+
"@typescript-eslint/no-unused-vars": "warn",
16+
},
1717
}

.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs

-541
This file was deleted.

.yarn/releases/yarn-3.6.3.cjs

-874
This file was deleted.

.yarn/releases/yarn-4.0.2.cjs

+893
Large diffs are not rendered by default.

.yarnrc.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
nodeLinker: node-modules
1+
compressionLevel: mixed
2+
3+
enableGlobalCache: false
24

3-
plugins:
4-
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
5-
spec: "@yarnpkg/plugin-interactive-tools"
5+
nodeLinker: node-modules
66

7-
yarnPath: .yarn/releases/yarn-3.6.3.cjs
7+
yarnPath: .yarn/releases/yarn-4.0.2.cjs

package.json

+29-22
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "bs-analysis",
33
"private": true,
44
"type": "module",
5-
"packageManager": "yarn@3.6.3",
5+
"packageManager": "yarn@4.0.2",
66
"scripts": {
77
"prepare": "panda codegen --clean",
88
"postinstall": "husky install",
@@ -14,38 +14,45 @@
1414
"format": "prettier src \"!src/router.ts\""
1515
},
1616
"dependencies": {
17-
"@floating-ui/react": "^0.26.1",
18-
"@generouted/react-router": "^1.16.1",
17+
"@floating-ui/react": "^0.26.7",
18+
"@generouted/react-router": "^1.18.2",
1919
"@radix-ui/react-slot": "^1.0.2",
20-
"@tanstack/react-form": "^0.3.7",
21-
"@tanstack/react-table": "^8.10.7",
20+
"@tanstack/react-form": "^0.13.4",
21+
"@tanstack/react-table": "^8.11.7",
22+
"@tanstack/valibot-form-adapter": "^0.13.4",
2223
"echarts": "^5.4.3",
24+
"fast-xml-parser": "^4.3.4",
2325
"file-saver": "^2.0.5",
2426
"jszip": "^3.10.1",
27+
"pako": "^2.1.0",
2528
"react": "^18.2.0",
2629
"react-dom": "^18.2.0",
27-
"react-router-dom": "^6.18.0",
30+
"react-router-dom": "^6.21.3",
2831
"slugify": "^1.6.6",
29-
"zod": "^3.22.4"
32+
"valibot": "^0.27.1"
3033
},
3134
"devDependencies": {
3235
"@pandacss/dev": "^0.17.5",
33-
"@types/file-saver": "^2.0.6",
34-
"@types/node": "^20.8.10",
35-
"@types/react": "^18.2.34",
36-
"@types/react-dom": "^18.2.14",
37-
"@typescript-eslint/eslint-plugin": "^6.9.1",
38-
"@typescript-eslint/parser": "^6.9.1",
39-
"@vitejs/plugin-react": "^4.1.1",
40-
"eslint": "^8.52.0",
36+
"@types/file-saver": "^2.0.7",
37+
"@types/node": "^20.11.8",
38+
"@types/pako": "^2",
39+
"@types/react": "^18.2.48",
40+
"@types/react-dom": "^18.2.18",
41+
"@typescript-eslint/eslint-plugin": "^6.19.1",
42+
"@typescript-eslint/parser": "^6.19.1",
43+
"@vitejs/plugin-react": "^4.2.1",
44+
"eslint": "^8.56.0",
4145
"eslint-plugin-react-hooks": "^4.6.0",
42-
"eslint-plugin-react-refresh": "^0.4.4",
43-
"husky": "^8.0.3",
44-
"lint-staged": "^15.0.2",
45-
"prettier": "^3.0.3",
46+
"eslint-plugin-react-refresh": "^0.4.5",
47+
"husky": "^9.0.6",
48+
"lint-staged": "^15.2.0",
49+
"prettier": "^3.2.4",
4650
"prompts": "^2.4.2",
47-
"typescript": "^5.2.2",
48-
"vite": "^4.5.0",
49-
"vitest": "^0.34.6"
51+
"typescript": "^5.3.3",
52+
"vite": "^5.0.12",
53+
"vitest": "^1.2.2"
54+
},
55+
"engines": {
56+
"node": ">=18"
5057
}
5158
}

public/images/chain.png

462 Bytes
Loading

scripts/archive.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { readFileSync, writeFileSync } from "node:fs";
44
import { default as prompt } from "prompts";
55
import slugify from "slugify";
6-
import { config, createLevelIndex, extract, resolveLevelStats } from "./helpers.js";
6+
import { config, createLevelIndex, extract, resolveAudioStats, resolveBeatmapStats, resolveLightshowStats } from "./helpers.js";
77

88
const { details, input, metadata, output, minify } = await config(false, [
99
{ name: "input", type: "text", message: "Map Archive (File or URL)", hint: ".zip" }, //
@@ -12,24 +12,21 @@ const { details, input, metadata, output, minify } = await config(false, [
1212
const source = input.startsWith("http") ? await fetch(input).then((r) => r.arrayBuffer()) : readFileSync(input.replaceAll('"', "")).buffer;
1313
const entries = await extract(source);
1414

15-
const id = prompt({ name: "sid", type: "text", message: "ID", initial: slugify(entries[0].info._songName) });
15+
const id = prompt({ name: "sid", type: "text", message: "ID", initial: slugify(entries[0].contents.title) });
1616

1717
const dataset = await entries.reduce(async (record, entry) => {
18-
const { info, level } = entry;
19-
const characteristic = level.beatmap._beatmapCharacteristicName;
20-
const difficulty = level.beatmap._difficulty;
21-
const bid = createLevelIndex({ characteristic, difficulty });
22-
const title = info._songName;
18+
const {
19+
contents: { audio, beatmap, lightshow },
20+
data: metadata,
21+
} = entry;
22+
const bid = createLevelIndex({ characteristic: contents.characteristic, difficulty: contents.difficulty });
2323
const { sid } = await id;
2424
const data = {
2525
id: sid,
26-
title,
27-
bpm: Number(info._beatsPerMinute.toFixed(3)),
28-
characteristic,
29-
difficulty,
30-
...resolveLevelStats(level.data, details),
31-
jumpSpeed: level.beatmap._noteJumpMovementSpeed,
32-
jumpOffset: level.beatmap._noteJumpStartBeatOffset,
26+
...metadata,
27+
...resolveAudioStats(audio?.contents ?? {}, details),
28+
...resolveBeatmapStats(beatmap?.contents ?? {}, details),
29+
...resolveLightshowStats(lightshow?.contents ?? {}, details),
3330
};
3431
return { ...(await record), [`${sid}/${bid}`]: data };
3532
}, Promise.resolve({}));

scripts/beatsaver.js

+12-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable */
22

33
import { writeFileSync } from "node:fs";
4-
import { config, createLevelIndex, extract, nonempty, resolveLevelStats } from "./helpers.js";
4+
import { config, createLevelIndex, extract, nonempty, resolveAudioStats, resolveBeatmapStats, resolveLightshowStats } from "./helpers.js";
55

66
const { details, users, ids, beatsaver, metadata, output, minify } = await config(false, [
77
{ name: "users", type: "list", message: "User ID(s)" },
@@ -52,22 +52,20 @@ const entries = await Promise.all(
5252
).then((x) => x.flat());
5353

5454
const dataset = await entries.reduce(async (record, entry) => {
55-
const { detail, info, level } = entry;
56-
const characteristic = level.beatmap._beatmapCharacteristicName;
57-
const difficulty = level.beatmap._difficulty;
58-
const bid = createLevelIndex({ characteristic, difficulty });
59-
const title = info._songName ?? detail.metadata.songName;
55+
const {
56+
contents: { audio, beatmap, lightshow },
57+
data: metadata,
58+
detail,
59+
} = entry;
60+
const bid = createLevelIndex({ characteristic: contents.characteristic, difficulty: contents.difficulty });
6061
const data = {
6162
id: detail.id,
62-
title,
63-
released: new Date(detail.updatedAt).toISOString(),
6463
length: detail.metadata.duration,
65-
bpm: Number((info._beatsPerMinute ?? detail.metadata.bpm).toFixed(3)),
66-
characteristic,
67-
difficulty,
68-
...resolveLevelStats(level.data, details),
69-
jumpSpeed: level.beatmap._noteJumpMovementSpeed,
70-
jumpOffset: level.beatmap._noteJumpStartBeatOffset,
64+
...metadata,
65+
...resolveAudioStats(audio?.contents ?? {}, details),
66+
...resolveBeatmapStats(beatmap?.contents ?? {}, details),
67+
...resolveLightshowStats(lightshow?.contents ?? {}, details),
68+
released: new Date(detail.updatedAt).toISOString(),
7169
};
7270
return { ...(await record), [`${detail.id}/${bid}`]: data };
7371
}, Promise.resolve({}));

scripts/directory.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { readFileSync, readdirSync, writeFileSync } from "node:fs";
44
import { join } from "node:path";
55
import { default as prompt } from "prompts";
66
import slugify from "slugify";
7-
import { config, createLevelIndex, fromEntries, resolveLevelStats } from "./helpers.js";
7+
import { config, createLevelIndex, fromEntries, resolveAudioStats, resolveBeatmapStats, resolveLightshowStats } from "./helpers.js";
88

99
const { details, directory, metadata, output, minify } = await config(false, [
1010
{ name: "directory", type: "text", message: "Directory" }, //
@@ -13,24 +13,21 @@ const { details, directory, metadata, output, minify } = await config(false, [
1313
const files = readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".dat"));
1414
const entries = fromEntries(files.map((entry) => ({ name: entry.name, contents: JSON.parse(readFileSync(join(directory, entry.name), { encoding: "utf-8" })) })));
1515

16-
const id = prompt({ name: "sid", type: "text", message: "ID", initial: slugify(entries[0].info._songName) });
16+
const id = prompt({ name: "sid", type: "text", message: "ID", initial: slugify(entries[0].contents.title) });
1717

1818
const dataset = await entries.reduce(async (record, entry) => {
19-
const { info, level } = entry;
20-
const characteristic = level.beatmap._beatmapCharacteristicName;
21-
const difficulty = level.beatmap._difficulty;
22-
const bid = createLevelIndex({ characteristic, difficulty });
23-
const title = info._songName;
19+
const {
20+
contents: { audio, beatmap, lightshow },
21+
data: metadata,
22+
} = entry;
23+
const bid = createLevelIndex({ characteristic: contents.characteristic, difficulty: contents.difficulty });
2424
const { sid } = await id;
2525
const data = {
2626
id: sid,
27-
title,
28-
bpm: Number(info._beatsPerMinute.toFixed(3)),
29-
characteristic,
30-
difficulty,
31-
...resolveLevelStats(level.data, details),
32-
jumpSpeed: level.beatmap._noteJumpMovementSpeed,
33-
jumpOffset: level.beatmap._noteJumpStartBeatOffset,
27+
...metadata,
28+
...resolveAudioStats(audio?.contents ?? {}, details),
29+
...resolveBeatmapStats(beatmap?.contents ?? {}, details),
30+
...resolveLightshowStats(lightshow?.contents ?? {}, details),
3431
};
3532
return { ...(await record), [`${sid}/${bid}`]: data };
3633
}, Promise.resolve({}));

0 commit comments

Comments
 (0)