Skip to content
This repository has been archived by the owner on Aug 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #20 from BaliBalo/features/beatmap-difficulty-meta…
Browse files Browse the repository at this point in the history
…data

Features/beatmap difficulty metadata
  • Loading branch information
luludotdev committed Jul 9, 2019
2 parents 32fed29 + b60e09d commit 751d8b7
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 21 deletions.
12 changes: 7 additions & 5 deletions client/src/ts/components/Beatmap/BeatmapResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ const BeatmapResult: FunctionComponent<IProps> = ({ map }) => {
/>

<div className='tags'>
{parseCharacteristics(map.metadata.characteristics).map((x, i) => (
<span key={`${x}:${i}`} className='tag is-dark'>
{x}
</span>
))}
{parseCharacteristics(map.metadata.characteristics).map(
({ name }, i) => (
<span key={`${name}:${i}`} className='tag is-dark'>
{name}
</span>
)
)}
</div>
</div>

Expand Down
6 changes: 3 additions & 3 deletions client/src/ts/components/Beatmap/Detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ const BeatmapDetail: FunctionComponent<IProps> = ({ user, push, mapKey }) => {

<div className='tags' style={{ marginBottom: '-10px' }}>
{parseCharacteristics(map.metadata.characteristics).map(
(x, i) => (
<span key={`${x}:${i}`} className='tag is-dark'>
{x}
({ name }, i) => (
<span key={`${name}:${i}`} className='tag is-dark'>
{name}
</span>
)
)}
Expand Down
22 changes: 21 additions & 1 deletion client/src/ts/remote/beatmap.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ declare interface IBeatmap {
expertPlus: boolean
}

characteristics: string[]
characteristics: IBeatmapCharacteristic[]
}

stats: {
Expand All @@ -47,4 +47,24 @@ declare interface IBeatmap {
hash: string
}

declare interface IBeatmapCharacteristic {
name: string
difficulties: {
easy: IDifficulty | null
normal: IDifficulty | null
hard: IDifficulty | null
expert: IDifficulty | null
expertPlus: IDifficulty | null
}
}

declare interface IDifficulty {
duration: number
length: number
bombs: number
notes: number
obstacles: number
njs: number
}

declare type IBeatmapResponse = IResponse<IBeatmap>
14 changes: 8 additions & 6 deletions client/src/ts/utils/characteristics.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export const parseCharacteristics = (input: string[]) => {
const chars = input.length === 0 ? ['Standard'] : input

return chars.map(characteristic =>
characteristic
export const parseCharacteristics: (
chars: IBeatmapCharacteristic[]
) => IBeatmapCharacteristic[] = chars => {
return chars.map(({ name, ...rest }) => {
const newName = name
.replace(/([A-Z])/g, ' $1')
.replace(/^./, str => str.toUpperCase())
.trim()
.replace(/( )/g, ' ')
)

return { name: newName, ...rest }
})
}
4 changes: 2 additions & 2 deletions server/src/mongo/models/Beatmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export interface IBeatmapLean {
expertPlus: boolean
}

characteristics: string[]
characteristics: IBeatmapCharacteristic[]
}

stats: {
Expand Down Expand Up @@ -122,7 +122,7 @@ const schema: Schema = new Schema({
normal: { type: Boolean, required: true },
},

characteristics: { type: [String], default: [] },
characteristics: { es_indexed: false, type: [Schema.Types.Mixed] },
},

stats: {
Expand Down
59 changes: 56 additions & 3 deletions server/src/routes/upload/parseBeatmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,61 @@ export const parseBeatmap: (
hash.update(b)
}

const parseCharacteristic: (
rank: number,
set: Readonly<IBeatmapSet>
) => Promise<IParsedDifficulty | null> = async (rank, set) => {
const diff = set._difficultyBeatmaps.find(x => x._difficultyRank === rank)
if (!diff) return null

try {
const content = await zip.file(diff._beatmapFilename).async('text')
const data: IDifficultyJSON = JSON.parse(content)

const bombs = data._notes.filter(note => note._type === 3).length
const duration = Math.max(...data._notes.map(note => note._time)) || 0

const length =
infoJSON._beatsPerMinute === 0
? 0
: (duration / infoJSON._beatsPerMinute) * 60

return {
duration,
length: Math.floor(length),
njs: 0,

bombs,
notes: data._notes.length - bombs,
obstacles: data._obstacles.length,
}
} catch (err) {
return null
}
}

const parseSet = async (set: Readonly<IBeatmapSet>) => {
const [easy, normal, hard, expert, expertPlus] = await Promise.all(
[1, 3, 5, 7, 9].map(x => parseCharacteristic(x, set))
)

return {
difficulties: {
easy,
expert,
expertPlus,
hard,
normal,
},

name: set._beatmapCharacteristicName,
}
}

const characteristics = await Promise.all(
infoJSON._difficultyBeatmapSets.map(parseSet)
)

const sha1 = hash.digest('hex')
const parsed: IParsedBeatmap = {
hash: sha1,
Expand All @@ -121,9 +176,7 @@ export const parseBeatmap: (
normal: difficulties.some(x => x._difficultyRank === 3),
},

characteristics: infoJSON._difficultyBeatmapSets.map(
x => x._beatmapCharacteristicName
),
characteristics,
},

coverExt: `.${coverType.ext}`,
Expand Down
66 changes: 65 additions & 1 deletion server/src/routes/upload/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,50 @@ declare interface IDifficultyBeatmap {
_difficulty: string
_difficultyRank: number
_beatmapFilename: string
_noteJumpMovementSpeed: number
}

declare interface IDifficultyJSON {
_version: string
_BPMChanges: IBPMChange[]
_events: IEvent[]
_notes: INote[]
_obstacles: IObstacle[]
_bookmarks: IBookmark[]
}

declare interface IBPMChange {
_BPM: number
_time: number
_beatsPerBar: number
_metronomeOffset: number
}

declare interface IEvent {
_time: number
_type: number
_value: number
}

declare interface INote {
_time: number
_lineIndex: number
_lineLayer: number
_type: number
_cutDirection: number
}

declare interface IObstacle {
_time: number
_lineIndex: number
_type: number
_duration: number
_width: number
}

declare interface IBookmark {
_time: number
_name: string
}

declare interface IParsedBeatmap {
Expand All @@ -38,9 +82,29 @@ declare interface IParsedBeatmap {
expertPlus: boolean
}

characteristics: string[]
characteristics: IBeatmapCharacteristic[]
}

hash: string
coverExt: string
}

declare interface IBeatmapCharacteristic {
name: string
difficulties: {
easy: IParsedDifficulty | null
normal: IParsedDifficulty | null
hard: IParsedDifficulty | null
expert: IParsedDifficulty | null
expertPlus: IParsedDifficulty | null
}
}

declare interface IParsedDifficulty {
duration: number
length: number
bombs: number
notes: number
obstacles: number
njs: number
}

0 comments on commit 751d8b7

Please sign in to comment.