mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 14:19:38 +00:00
Add issues and modchart indicators
This commit is contained in:
@@ -42,6 +42,40 @@
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex-1">
|
||||
@if (hasIssues) {
|
||||
<div class="dropdown dropdown-hover">
|
||||
<label tabindex="0" class="cursor-help"><i class="bi bi-exclamation-triangle text-lg -my-3 ml-1"></i> Issues Detected</label>
|
||||
<div tabindex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box min-w-max">
|
||||
@if (metadataIssues.length > 0) {
|
||||
<div class="menu-title">Metadata Issues Found:</div>
|
||||
<ul class="list-disc ml-9 min-w-[246px] max-w-[min(26.1vw,444px)]">
|
||||
<li *ngFor="let issue of metadataIssues" class="list-item">{{ getMetadataIssueText(issue) }}</li>
|
||||
</ul>
|
||||
}
|
||||
@if (folderIssues.length > 0) {
|
||||
<div class="menu-title">Chart Folder Issues Found:</div>
|
||||
<ul class="list-disc ml-9 min-w-[246px] max-w-[min(26.1vw,444px)]">
|
||||
<li *ngFor="let issue of folderIssues" class="list-item">{{ getFolderIssueText(issue) }}</li>
|
||||
</ul>
|
||||
}
|
||||
@if (chartIssues.length > 0) {
|
||||
<div class="menu-title">Chart Issues Found:</div>
|
||||
<ul class="list-disc ml-9 min-w-[246px] max-w-[min(26.1vw,444px)]">
|
||||
<li *ngFor="let issue of chartIssues" class="list-item">{{ getChartIssueText(issue) }}</li>
|
||||
</ul>
|
||||
}
|
||||
@for (trackIssues of trackIssuesGroups; track $index) {
|
||||
<div class="menu-title">{{ trackIssues.groupName }}</div>
|
||||
<ul class="list-disc ml-9 min-w-[246px] max-w-[min(26.1vw,444px)]">
|
||||
<li *ngFor="let issue of trackIssues.issues" class="list-item">{{ getTrackIssueText(issue) }}</li>
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (selectedChart.modchart) {
|
||||
<div><i class="bi bi-star text-lg -my-3 ml-1"></i> Modchart</div>
|
||||
}
|
||||
@for (pair of boolProperties; track $index) {
|
||||
<p class="flex items-center">
|
||||
<i class="bi text-2xl -my-3" [ngClass]="pair.value ? 'bi-check2' : 'bi-x'" [ngStyle]="{ color: pair.value ? 'green' : 'red' }"> </i>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Component, ElementRef, HostBinding, OnInit, Renderer2, ViewChild } from '@angular/core'
|
||||
import { FormControl } from '@angular/forms'
|
||||
|
||||
import { chain, compact, flatMap, intersection, round, sortBy } from 'lodash'
|
||||
import { Difficulty, Instrument } from 'scan-chart'
|
||||
import { capitalize, chain, compact, flatMap, intersection, round, sortBy } from 'lodash'
|
||||
import { ChartIssueType, Difficulty, FolderIssueType, Instrument, MetadataIssueType, NoteIssueType, TrackIssueType } from 'scan-chart'
|
||||
import { SearchService } from 'src-angular/app/core/services/search.service'
|
||||
import { SettingsService } from 'src-angular/app/core/services/settings.service'
|
||||
import { ChartData } from 'src-shared/interfaces/search.interface'
|
||||
import { setlistNames } from 'src-shared/setlist-names'
|
||||
import { difficulties, difficultyDisplay, driveLink, instruments, msToRoughTime, removeStyleTags, shortInstrumentDisplay } from 'src-shared/UtilFunctions'
|
||||
import { difficulties, difficultyDisplay, driveLink, hasIssues, instruments, msToRoughTime, removeStyleTags, shortInstrumentDisplay } from 'src-shared/UtilFunctions'
|
||||
|
||||
@Component({
|
||||
selector: 'app-chart-sidebar',
|
||||
@@ -91,6 +91,103 @@ export class ChartSidebarComponent implements OnInit {
|
||||
return round((this.selectedChart!.notesData.length - this.selectedChart!.notesData.effectiveLength) / 1000, 1)
|
||||
}
|
||||
|
||||
public get hasIssues() {
|
||||
return hasIssues(this.selectedChart!)
|
||||
}
|
||||
|
||||
public get metadataIssues() {
|
||||
return this.selectedChart!.metadataIssues
|
||||
}
|
||||
public getMetadataIssueText(issue: MetadataIssueType) {
|
||||
switch (issue) {
|
||||
case 'noName': return 'Chart has no name'
|
||||
case 'noArtist': return 'Chart has no artist'
|
||||
case 'noAlbum': return 'Chart has no album'
|
||||
case 'noGenre': return 'Chart has no genre'
|
||||
case 'noYear': return 'Chart has no year'
|
||||
case 'noCharter': return 'Chart has no charter'
|
||||
case 'missingInstrumentDiff': return 'Metadata is missing an instrument intensity rating'
|
||||
case 'extraInstrumentDiff': return 'Metadata contains an instrument intensity rating for an uncharted instrument'
|
||||
case 'nonzeroDelay': return 'Chart uses "delay" for the audio offset'
|
||||
case 'drumsSetTo4And5Lane': return 'It is unclear if the drums chart is intended to be 4-lane or 5-lane'
|
||||
case 'nonzeroOffset': return 'Chart uses "delay" for the audio offset'
|
||||
}
|
||||
}
|
||||
public get folderIssues() {
|
||||
return chain(this.selectedChart!.folderIssues)
|
||||
.filter(i => !['albumArtSize', 'invalidIni', 'multipleVideo', 'badIniLine'].includes(i.folderIssue))
|
||||
.map(i => i.folderIssue)
|
||||
.uniq()
|
||||
.value()
|
||||
}
|
||||
public getFolderIssueText(folderIssue: FolderIssueType) {
|
||||
switch (folderIssue) {
|
||||
case 'noMetadata': return `Metadata file is missing`
|
||||
case 'invalidMetadata': return `Metadata file is invalid`
|
||||
case 'multipleIniFiles': return `Multiple metadata files`
|
||||
case 'noAlbumArt': return `Album art is missing`
|
||||
case 'badAlbumArt': return `Album art is invalid`
|
||||
case 'multipleAlbumArt': return `Multiple album art files`
|
||||
case 'noAudio': return `Audio file is missing`
|
||||
case 'invalidAudio': return `Audio file is invalid`
|
||||
case 'badAudio': return `Audio file is invalid`
|
||||
case 'multipleAudio': return `Audio file is invalid`
|
||||
case 'noChart': return `Notes file is missing`
|
||||
case 'invalidChart': return `Notes file is invalid`
|
||||
case 'badChart': return `Notes file is invalid`
|
||||
case 'multipleChart': return `Multiple notes files`
|
||||
case 'badVideo': return `Video background won't work on Linux`
|
||||
}
|
||||
}
|
||||
|
||||
public get chartIssues() {
|
||||
return this.selectedChart!.notesData?.chartIssues.filter(i => i !== 'isDefaultBPM')
|
||||
}
|
||||
public getChartIssueText(issue: ChartIssueType) {
|
||||
switch (issue) {
|
||||
case 'noResolution': return 'No resolution in chart file'
|
||||
case 'noSyncTrackSection': return 'No tempo map in chart file'
|
||||
case 'noNotes': return 'No notes in chart file'
|
||||
case 'noExpert': return 'Expert is not charted'
|
||||
case 'misalignedTimeSignatures': return 'Broken time signatures'
|
||||
case 'noSections': return 'No sections'
|
||||
}
|
||||
}
|
||||
|
||||
public get trackIssuesGroups() {
|
||||
return chain([
|
||||
...this.selectedChart!.notesData.trackIssues.map(i => ({ ...i, issues: i.trackIssues })),
|
||||
...this.selectedChart!.notesData.noteIssues.map(i => ({ ...i, issues: i.noteIssues.map(ni => ni.issueType) })),
|
||||
])
|
||||
.sortBy(g => instruments.indexOf(g.instrument), g => difficulties.indexOf(g.difficulty))
|
||||
.groupBy(g => `${capitalize(g.instrument)} - ${capitalize(g.difficulty)} Issues Found:`)
|
||||
.toPairs()
|
||||
.map(([groupName, group]) => ({
|
||||
groupName,
|
||||
issues: chain(group)
|
||||
.flatMap(g => g.issues)
|
||||
.filter(i => i !== 'babySustain' && i !== 'noNotesOnNonemptyTrack')
|
||||
.uniq()
|
||||
.value(),
|
||||
}))
|
||||
.value()
|
||||
}
|
||||
|
||||
public getTrackIssueText(issue: NoteIssueType | TrackIssueType) {
|
||||
switch (issue) {
|
||||
case 'babySustain': return 'Has baby sustains'
|
||||
case 'badSustainGap': return 'Has sustain gaps that are too small'
|
||||
case 'brokenNote': return 'Has broken notes'
|
||||
case 'difficultyForbiddenNote': return 'Has notes not allowed on this difficulty'
|
||||
case 'fiveNoteChord': return 'Has five-note chords'
|
||||
case 'noDrumActivationLanes': return 'Has no activation lanes'
|
||||
case 'has4And5LaneFeatures': return 'Has a mix of 4 and 5 lane features on the drum chart'
|
||||
case 'noStarPower': return 'Has no star power'
|
||||
case 'smallLeadingSilence': return 'Leading silence is too small'
|
||||
case 'threeNoteDrumChord': return 'Has three-note drum chords'
|
||||
}
|
||||
}
|
||||
|
||||
public get boolProperties(): ({ value: boolean; text: string })[] {
|
||||
const notesData = this.selectedChart!.notesData
|
||||
const showGuitarlikeProperties = intersection(this.instruments, this.guitarlikeInstruments).length > 0
|
||||
|
||||
@@ -13,3 +13,7 @@ input[type='number'] {
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.dropdown:not(:hover):not(:focus):not(:focus-within):not(.dropdown-open) .dropdown-content {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import _ from 'lodash'
|
||||
import sanitize from 'sanitize-filename'
|
||||
import { Difficulty, Instrument } from 'scan-chart'
|
||||
|
||||
import { ChartData } from './interfaces/search.interface'
|
||||
|
||||
// WARNING: do not import anything related to Electron; the code will not compile correctly.
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -166,3 +168,25 @@ export function removeStyleTags(text: string) {
|
||||
} while (newText !== oldText)
|
||||
return newText
|
||||
}
|
||||
|
||||
export function hasIssues(chart: Pick<ChartData, 'metadataIssues' | 'folderIssues' | 'notesData'>) {
|
||||
if (chart.metadataIssues.length > 0) { return true }
|
||||
for (const folderIssue of chart.folderIssues) {
|
||||
if (!['albumArtSize', 'invalidIni', 'multipleVideo', 'badIniLine'].includes(folderIssue.folderIssue)) { return true }
|
||||
}
|
||||
for (const chartIssue of chart.notesData?.chartIssues ?? []) {
|
||||
if (chartIssue !== 'isDefaultBPM') { return true }
|
||||
}
|
||||
for (const trackIssue of chart.notesData?.trackIssues ?? []) {
|
||||
for (const ti of trackIssue.trackIssues) {
|
||||
if (ti !== 'noNotesOnNonemptyTrack') { return true }
|
||||
}
|
||||
}
|
||||
for (const noteIssue of chart.notesData?.noteIssues ?? []) {
|
||||
for (const ni of noteIssue.noteIssues) {
|
||||
if (ni.issueType !== 'babySustain') { return true }
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user