diff --git a/src/actions/chuni/music.ts b/src/actions/chuni/music.ts index 5d33421..eb3f547 100644 --- a/src/actions/chuni/music.ts +++ b/src/actions/chuni/music.ts @@ -22,11 +22,14 @@ export const getMusic = async (musicId?: number) => { .on('favorite.favKind', '=', 1) .on('favorite.user', '=', user?.id!) ) + .innerJoin('actaeon_chuni_static_music_ext as musicExt', join => + join.onRef('music.songId', '=', 'musicExt.songId') + .onRef('music.chartId', '=', 'musicExt.chartId')) .select(({ fn }) => [...CHUNI_MUSIC_PROPERTIES, 'score.isFullCombo', 'score.isAllJustice', 'score.isSuccess', 'score.scoreRank', 'score.scoreMax', 'score.maxComboCount', fn('NOT ISNULL', ['favorite.favId']).as('favorite'), - chuniRating()]) + chuniRating()] as const) .where(({ selectFrom, eb, and, or }) => and([ eb('music.version', '=', selectFrom('chuni_static_music') .select(({ fn }) => fn.max('version').as('latest'))), diff --git a/src/actions/chuni/playlog.ts b/src/actions/chuni/playlog.ts index 8a7f339..ebe9d93 100644 --- a/src/actions/chuni/playlog.ts +++ b/src/actions/chuni/playlog.ts @@ -36,6 +36,9 @@ export async function getPlaylog(opts: GetPlaylogOptions) { .innerJoin('chuni_static_music as music', join => join .onRef('music.songId', '=', 'playlog.musicId') .onRef('music.chartId', '=', 'playlog.level')) + .innerJoin('actaeon_chuni_static_music_ext as musicExt', join => join + .onRef('music.songId', '=', 'musicExt.songId') + .onRef('music.chartId', '=', 'musicExt.chartId')) .where(({ and, eb, selectFrom }) => and([ eb('playlog.user', '=', user.id), eb('music.version', '=', selectFrom('chuni_static_music') @@ -52,7 +55,7 @@ export async function getPlaylog(opts: GetPlaylogOptions) { chuniRating(ref('playlog.score')), sql`(playlog.playerRating - (LEAD(playlog.playerRating) OVER (ORDER BY id DESC)))` .as('playerRatingChange') - ]) + ] as const) .orderBy('playlog.id desc') ) .selectFrom('p') diff --git a/src/actions/chuni/profile.ts b/src/actions/chuni/profile.ts index 41238ce..9142ffb 100644 --- a/src/actions/chuni/profile.ts +++ b/src/actions/chuni/profile.ts @@ -93,6 +93,9 @@ export async function getUserRating(user: UserPayload) { ))`.as('score'), join => join.onTrue()) .innerJoin('chuni_static_music as music', join => join.onRef('score.musicId', '=', 'music.songId') .onRef('score.level', '=', 'music.chartId')) + .innerJoin('actaeon_chuni_static_music_ext as musicExt', join => join + .onRef('music.songId', '=', 'musicExt.songId') + .onRef('music.chartId', '=', 'musicExt.chartId')) .select(({ lit }) => [...CHUNI_MUSIC_PROPERTIES, chuniRating(sql.raw(`CAST(score.scoreMax AS INT)`)), sql`CAST(score.scoreMax AS INT)`.as('scoreMax'), lit(1).as('pastIndex') @@ -104,8 +107,10 @@ export async function getUserRating(user: UserPayload) { const top = await db.selectFrom('chuni_score_best as score') .innerJoin('chuni_static_music as music', join => join .onRef('music.songId', '=', 'score.musicId') - .onRef('music.chartId', '=', 'score.level') - ) + .onRef('music.chartId', '=', 'score.level')) + .innerJoin('actaeon_chuni_static_music_ext as musicExt', join => join + .onRef('music.songId', '=', 'musicExt.songId') + .onRef('music.chartId', '=', 'musicExt.chartId')) .where(({ eb, and, selectFrom }) => and([ eb('user', '=', user.id), eb('score.level', '!=', 5), diff --git a/src/components/chuni/playlog-card.tsx b/src/components/chuni/playlog-card.tsx index 1018d87..f6a9104 100644 --- a/src/components/chuni/playlog-card.tsx +++ b/src/components/chuni/playlog-card.tsx @@ -32,6 +32,14 @@ const getChangeColor = (val: number) => { }; export const ChuniPlaylogCard = ({ playlog, className, badgeClass, showDetails }: ChuniPlaylogCardProps) => { + const rate = showDetails ? <> + {!!playlog.tapJudgeCount &&
Tap: {(playlog.rateTap! / 100).toFixed(2)}%
} + {!!playlog.flickJudgeCount &&
Flick: {(playlog.rateFlick! / 100).toFixed(2)}%
} + {!!playlog.holdJudgeCount &&
Hold: {(playlog.rateHold! / 100).toFixed(2)}%
} + {!!playlog.slideJudgeCount &&
Slide: {(playlog.rateSlide! / 100).toFixed(2)}%
} + {!!playlog.airJudgeCount &&
Air: {(playlog.rateAir! / 100).toFixed(2)}%
} + : null; + return ({setHover =>
setHover(true)} onMouseLeave={() => setHover(false)} className={`rounded-md bg-content1 relative flex flex-col p-2 pt-1 border border-black/25 ${className ?? ''}`}>
@@ -68,11 +76,8 @@ export const ChuniPlaylogCard = ({ playlog, className, badgeClass, showDetails } {showDetails &&
{formatJst(playlog.userPlayDate!)}
-
Tap: {(playlog.rateTap! / 100).toFixed(2)}%
-
Flick: {(playlog.rateFlick! / 100).toFixed(2)}%
-
Hold: {(playlog.rateHold! / 100).toFixed(2)}%
-
Slide: {(playlog.rateSlide! / 100).toFixed(2)}%
-
Air: {(playlog.rateAir! / 100).toFixed(2)}%
+ {rate} +
}
-
Tap: {(playlog.rateTap! / 100).toFixed(2)}%
-
Flick: {(playlog.rateFlick! / 100).toFixed(2)}%
-
Hold: {(playlog.rateHold! / 100).toFixed(2)}%
-
Slide: {(playlog.rateSlide! / 100).toFixed(2)}%
-
Air: {(playlog.rateAir! / 100).toFixed(2)}%
+ {rate}
}
} diff --git a/src/helpers/chuni/music.ts b/src/helpers/chuni/music.ts index 70604ca..fbcd560 100644 --- a/src/helpers/chuni/music.ts +++ b/src/helpers/chuni/music.ts @@ -6,6 +6,13 @@ export const CHUNI_MUSIC_PROPERTIES = ['music.songId', 'music.worldsEndTag', 'music.genre', 'music.version', - 'music.level' + 'music.level', + 'musicExt.chartDesigner', + 'musicExt.tapJudgeCount', + 'musicExt.holdJudgeCount', + 'musicExt.slideJudgeCount', + 'musicExt.airJudgeCount', + 'musicExt.flickJudgeCount', + 'musicExt.allJudgeCount' // sql`CAST(music.level AS DECIMAL(3, 1))`.as('level') ] as const; diff --git a/src/types/db.d.ts b/src/types/db.d.ts index 324a798..9dd0f4f 100644 --- a/src/types/db.d.ts +++ b/src/types/db.d.ts @@ -21,6 +21,18 @@ export interface ActaeonChuniStaticMapIcon { sortName: string | null; } +export interface ActaeonChuniStaticMusicExt { + airJudgeCount: number; + allJudgeCount: number; + chartDesigner: string | null; + chartId: number; + flickJudgeCount: number; + holdJudgeCount: number; + slideJudgeCount: number; + songId: number; + tapJudgeCount: number; +} + export interface ActaeonChuniStaticNamePlate { id: number; imagePath: string | null; @@ -3343,6 +3355,7 @@ export interface DB { actaeon_arcade_ext: ActaeonArcadeExt; actaeon_arcade_join_keys: ActaeonArcadeJoinKeys; actaeon_chuni_static_map_icon: ActaeonChuniStaticMapIcon; + actaeon_chuni_static_music_ext: ActaeonChuniStaticMusicExt; actaeon_chuni_static_name_plate: ActaeonChuniStaticNamePlate; actaeon_chuni_static_system_voice: ActaeonChuniStaticSystemVoice; actaeon_chuni_static_trophies: ActaeonChuniStaticTrophies;