Skip to content

Commit 309abc8

Browse files
committed
feat: minato support
fix: dxrating 没有 dx 谱但是实际上是 dx 谱加载不出来
1 parent e0fd977 commit 309abc8

File tree

15 files changed

+443
-109
lines changed

15 files changed

+443
-109
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { routeLoader$ } from '@builder.io/qwik-city';
2+
import { component$ } from '@builder.io/qwik';
3+
import getAquaDxUser from '~/utils/getAquaDxUser';
4+
import B50 from '~/routes/b50/components/B50';
5+
import getMinatoUser from '~/utils/getMinatoUser';
6+
7+
export const useData = routeLoader$(async ({platform, params}) => {
8+
const profile = await getMinatoUser(params.username);
9+
const userRating = await profile.getUserRating();
10+
const userData = await profile.getNameplate();
11+
const profileVer = await profile.getVersion();
12+
13+
return {userRating, userData, profileVer};
14+
});
15+
16+
export default component$(() => {
17+
const data = useData();
18+
19+
return <B50 rating={data.value.userRating} user={data.value.userData} ver={data.value.profileVer} />;
20+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import LevelProgress from '../../../components/LevelProgress';
2+
import { LEVELS, Song } from '@clansty/maibot-types';
3+
import { routeLoader$ } from '@builder.io/qwik-city';
4+
import getAquaDxUser from '~/utils/getAquaDxUser';
5+
import { component$ } from '@builder.io/qwik';
6+
import getMinatoUser from '~/utils/getMinatoUser';
7+
8+
export const useData = routeLoader$(async ({ platform, params, error }) => {
9+
const level = decodeURIComponent(params.level) as typeof LEVELS[number];
10+
if (!LEVELS.includes(level)) {
11+
error(404, 'nya?');
12+
}
13+
14+
const profile = await getMinatoUser(params.username);
15+
const requiredSongList = Song.getByCondition(it => it.sheets.some(chart => chart.level === level));
16+
const userMusic = await profile.getUserMusic(requiredSongList);
17+
const versionLogo = await profile.getVersionLogo();
18+
const version = await profile.getVersion();
19+
20+
return { requiredSongList: requiredSongList.map(it => it.dxId), userMusic, region: profile.region, level, versionLogo, version };
21+
});
22+
23+
export default component$(() => {
24+
const data = useData();
25+
26+
return <LevelProgress userMusic={data.value.userMusic} level={data.value.level} region={data.value.region}
27+
requiredSongIdList={data.value.requiredSongList} logo={data.value.versionLogo!} version={data.value.version} />;
28+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { LEVELS, Song } from '@clansty/maibot-types';
2+
import { routeLoader$ } from '@builder.io/qwik-city';
3+
import getAquaDxUser from '~/utils/getAquaDxUser';
4+
import { component$ } from '@builder.io/qwik';
5+
import LevelScores from '../../../components/LevelScores';
6+
import getMinatoUser from '~/utils/getMinatoUser';
7+
8+
export const useData = routeLoader$(async ({ platform, params, error }) => {
9+
const level = decodeURIComponent(params.level) as typeof LEVELS[number];
10+
if (!LEVELS.includes(level)) {
11+
error(404, 'nya?');
12+
}
13+
14+
const profile = await getMinatoUser(params.username);
15+
const requiredSongList = Song.getByCondition(it => it.sheets.some(chart => chart.level === level)) as Song[];
16+
const userMusic = await profile.getUserMusic(requiredSongList);
17+
const versionLogo = await profile.getVersionLogo();
18+
const version = await profile.getVersion();
19+
const userData = await profile.getNameplate();
20+
21+
return { requiredSongList: requiredSongList.map(it => it.dxId), userMusic, region: profile.region, level, versionLogo, version, userData };
22+
});
23+
24+
export default component$(() => {
25+
const data = useData();
26+
27+
return <LevelScores userMusic={data.value.userMusic} level={data.value.level} logo={data.value.versionLogo!} version={data.value.version} user={data.value.userData} />;
28+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { BA_VE, PLATE_TYPE, PLATE_VER, Song } from '@clansty/maibot-types';
2+
import { routeLoader$ } from '@builder.io/qwik-city';
3+
import getAquaDxUser from '~/utils/getAquaDxUser';
4+
import { component$ } from '@builder.io/qwik';
5+
import PlateProgress from '~/routes/plateProgress/components/PlateProgress';
6+
import getMinatoUser from '~/utils/getMinatoUser';
7+
8+
export const useData = routeLoader$(async ({ platform, params, error }) => {
9+
let type = decodeURIComponent(params.type) as typeof PLATE_TYPE[number] | '';
10+
let ver: typeof PLATE_VER[number] | typeof BA_VE;
11+
if (type as any === BA_VE) {
12+
ver = BA_VE;
13+
type = '';
14+
} else {
15+
ver = type.substring(0, 1) as any;
16+
type = type.substring(1) as any;
17+
if (!(PLATE_VER.includes(ver as any) && PLATE_TYPE.includes(type as any)))
18+
error(404, 'nya?');
19+
}
20+
21+
const profile = await getMinatoUser(params.username);
22+
const profileVer = await profile.getVersion();
23+
// @ts-ignore
24+
const requiredList = (await profile.plateSongs())[ver].map(it => Song.fromId(it, profileVer)) as Song[];
25+
const userMusic = await profile.getUserMusic(requiredList);
26+
const versionLogo = await profile.getVersionLogo();
27+
const version = await profile.getVersion();
28+
29+
return { requiredSongList: requiredList.map(it => it.dxId), userMusic, region: profile.region, type, ver, versionLogo, version };
30+
});
31+
32+
export default component$(() => {
33+
const data = useData();
34+
35+
return <PlateProgress userMusic={data.value.userMusic} type={data.value.type} ver={data.value.ver}
36+
requiredList={data.value.requiredSongList.map(id => Song.fromId(id, data.value.version)!)} logo={data.value.versionLogo!} />;
37+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { UserProfile } from '@clansty/maibot-clients';
2+
3+
export default async (usernameEncoded: string) => {
4+
return await UserProfile.create({
5+
type: 'Minato',
6+
username: decodeURIComponent(usernameEncoded),
7+
});
8+
}

packages/botcore/src/UserContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export default class UserContext<T extends BotTypes> {
7777
let url = `https://maibot-web.pages.dev/${type}/`;
7878
if (currentProfile.dto.type === 'AquaDX-v2') {
7979
url += `aquadx/${encodeURIComponent(currentProfile.dto.username)}`;
80+
} else if (currentProfile.dto.type === 'Minato') {
81+
url += `minato/${encodeURIComponent(currentProfile.dto.username)}`;
8082
} else {
8183
url += `${this.fromId}/${currentProfileId}`;
8284
}

packages/botcore/src/modules/bind.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ export default <T extends BotTypes>({ bot, env, getContext, musicToFile, enableO
3232
return true;
3333
}
3434

35-
const param = event.params.join('');
35+
const minato = event.params.includes('--minato');
36+
37+
const param = event.params.filter(it => it !== '--minato').join('');
3638
let profile: UserProfile;
3739

3840
if (/^\d{20}$/.test(param) && enableOfficialServers) { // is AIME
@@ -62,6 +64,8 @@ export default <T extends BotTypes>({ bot, env, getContext, musicToFile, enableO
6264
.dispatch();
6365
return true;
6466
}
67+
} else if (minato) {
68+
profile = await UserProfile.create({ type: 'Minato', username: param }, env);
6569
} else {
6670
profile = await UserProfile.create({ type: 'AquaDX-v2', username: param }, env);
6771
}

packages/clients/src/AquaDx.ts

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,7 @@
1-
import { UserSource } from './UserSource';
2-
import { Nameplate } from '@clansty/maibot-types';
3-
4-
export default class AquaDx extends UserSource {
5-
private readonly BASE_URL = 'https://aquadx.net/aqua';
1+
import AquaDxLike from './AquaDxLike';
62

3+
export default class AquaDx extends AquaDxLike {
74
public constructor() {
8-
// all override
9-
super(null);
10-
}
11-
12-
private async fetch(endpoint: string, query: Record<string, string>, method = 'GET', body?: any) {
13-
const url = new URL(this.BASE_URL + endpoint);
14-
url.search = new URLSearchParams(query).toString();
15-
const init = {
16-
method,
17-
body: body ? JSON.stringify(body) : undefined,
18-
headers: body ? { 'Content-Type': 'application/json' } : undefined
19-
};
20-
// @ts-ignore
21-
if (typeof window !== 'undefined') {
22-
// @ts-ignore
23-
init.cache = 'no-store';
24-
}
25-
const req = await fetch(url, init);
26-
if (!req.ok) {
27-
console.error(await req.text());
28-
throw new Error(`获取数据时出错: ${req.statusText}`);
29-
}
30-
return await req.json() as any;
31-
}
32-
33-
public override async getUserMusic(username: string, musicIdList: number[]) {
34-
console.log('请求 user-music-from-list', { username, musicIdListLength: musicIdList.length });
35-
return await this.fetch('/api/v2/game/mai2/user-music-from-list', { username }, 'POST', musicIdList);
36-
}
37-
38-
public override async getNameplate(username: string): Promise<Nameplate> {
39-
console.log('请求 user-name-plate', { username });
40-
return await this.fetch('/api/v2/game/mai2/user-name-plate', { username });
41-
}
42-
43-
protected override async _getUserRating(username: string) {
44-
console.log('请求 user-rating', { username });
45-
const data = await this.fetch('/api/v2/game/mai2/user-rating', { username });
46-
for (const key of ['best35', 'best15']) {
47-
data[key] = data[key].map(([musicId, level, romVersion, achievement]) => ({
48-
musicId: parseInt(musicId),
49-
level: parseInt(level),
50-
romVersion: parseInt(romVersion),
51-
achievement: parseInt(achievement)
52-
}));
53-
}
54-
return data;
55-
}
56-
57-
protected override async _getUserPreview(username: string) {
58-
console.log('请求 user-summary', { username });
59-
const res = await this.fetch('/api/v2/game/mai2/user-summary', { username });
60-
61-
// 只需要返回这两个
62-
return {
63-
userName: res.name,
64-
playerRating: res.rating,
65-
lastRomVersion: res.lastVersion
66-
};
67-
}
68-
69-
public override async getChuniUserMusic(username: string, musicIdList: number[]) {
70-
return await this.fetch('/api/v2/game/chu3/user-music-from-list', { username }, 'POST', musicIdList);
71-
}
72-
73-
public override async getChuniUserRating(username: string) {
74-
const data = await this.fetch('/api/v2/game/chu3/user-rating', { username });
75-
for (const key of ['best30', 'recent10']) {
76-
data[key] = data[key].map(([musicId, level, achievement]) => ({
77-
musicId: parseInt(musicId),
78-
level: parseInt(level),
79-
achievement: parseInt(achievement)
80-
}));
81-
}
82-
return data;
83-
}
84-
85-
public override async getChuniUserPreview(username: string) {
86-
const res = await this.fetch('/api/v2/game/chu3/user-summary', { username });
87-
88-
// 只需要返回这两个
89-
return {
90-
userName: res.name,
91-
playerRating: res.rating,
92-
lastRomVersion: res.lastVersion
93-
};
5+
super('https://aquadx.net/aqua');
946
}
95-
}
7+
}

packages/clients/src/AquaDxLike.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { UserSource } from './UserSource';
2+
import { Nameplate } from '@clansty/maibot-types';
3+
4+
export default class AquaDxLike extends UserSource {
5+
public constructor(protected readonly BASE_URL: string) {
6+
// all override
7+
super(null);
8+
}
9+
10+
private async fetch(endpoint: string, query: Record<string, string>, method = 'GET', body?: any) {
11+
const url = new URL(this.BASE_URL + endpoint);
12+
url.search = new URLSearchParams(query).toString();
13+
const init = {
14+
method,
15+
body: body ? JSON.stringify(body) : undefined,
16+
headers: body ? { 'Content-Type': 'application/json' } : undefined
17+
};
18+
// @ts-ignore
19+
if (typeof window !== 'undefined') {
20+
// @ts-ignore
21+
init.cache = 'no-store';
22+
}
23+
const req = await fetch(url, init);
24+
if (!req.ok) {
25+
console.error(await req.text());
26+
throw new Error(`获取数据时出错: ${req.statusText}`);
27+
}
28+
return await req.json() as any;
29+
}
30+
31+
public override async getUserMusic(username: string, musicIdList: number[]) {
32+
console.log('请求 user-music-from-list', { username, musicIdListLength: musicIdList.length });
33+
return await this.fetch('/api/v2/game/mai2/user-music-from-list', { username }, 'POST', musicIdList);
34+
}
35+
36+
public override async getNameplate(username: string): Promise<Nameplate> {
37+
console.log('请求 user-name-plate', { username });
38+
return await this.fetch('/api/v2/game/mai2/user-name-plate', { username });
39+
}
40+
41+
protected override async _getUserRating(username: string) {
42+
console.log('请求 user-rating', { username });
43+
const data = await this.fetch('/api/v2/game/mai2/user-rating', { username });
44+
for (const key of ['best35', 'best15']) {
45+
data[key] = data[key].map(([musicId, level, romVersion, achievement]) => ({
46+
musicId: parseInt(musicId),
47+
level: parseInt(level),
48+
romVersion: parseInt(romVersion),
49+
achievement: parseInt(achievement)
50+
}));
51+
}
52+
return data;
53+
}
54+
55+
protected override async _getUserPreview(username: string) {
56+
console.log('请求 user-summary', { username });
57+
const res = await this.fetch('/api/v2/game/mai2/user-summary', { username });
58+
59+
// 只需要返回这两个
60+
return {
61+
userName: res.name,
62+
playerRating: res.rating,
63+
lastRomVersion: res.lastVersion
64+
};
65+
}
66+
67+
public override async getChuniUserMusic(username: string, musicIdList: number[]) {
68+
return await this.fetch('/api/v2/game/chu3/user-music-from-list', { username }, 'POST', musicIdList);
69+
}
70+
71+
public override async getChuniUserRating(username: string) {
72+
const data = await this.fetch('/api/v2/game/chu3/user-rating', { username });
73+
for (const key of ['best30', 'recent10']) {
74+
data[key] = data[key].map(([musicId, level, achievement]) => ({
75+
musicId: parseInt(musicId),
76+
level: parseInt(level),
77+
achievement: parseInt(achievement)
78+
}));
79+
}
80+
return data;
81+
}
82+
83+
public override async getChuniUserPreview(username: string) {
84+
const res = await this.fetch('/api/v2/game/chu3/user-summary', { username });
85+
86+
// 只需要返回这两个
87+
return {
88+
userName: res.name,
89+
playerRating: res.rating,
90+
lastRomVersion: res.lastVersion
91+
};
92+
}
93+
}

packages/clients/src/Minato.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import AquaDxLike from './AquaDxLike';
2+
3+
export default class Minato extends AquaDxLike {
4+
public constructor() {
5+
super('http://11.11.41.11');
6+
}
7+
}

0 commit comments

Comments
 (0)