Interface conversion, search bar layout

This commit is contained in:
Geomitron
2023-12-09 18:21:01 -06:00
parent d689843f27
commit ece0f75b99
37 changed files with 1531 additions and 760 deletions

View File

@@ -1,4 +1,3 @@
import { DriveChart } from './songDetails.interface'
/**
* Represents a user's request to interact with the download system.
@@ -16,7 +15,10 @@ export interface NewDownload {
chartName: string
artist: string
charter: string
driveData: DriveChart & { inChartPack: boolean }
// TODO
// eslint-disable-next-line @typescript-eslint/no-explicit-any
driveData: any
// driveData: DriveChart & { inChartPack: boolean }
}
/**

View File

@@ -3,8 +3,6 @@ import { UpdateInfo } from 'electron-updater'
import { Settings } from '../Settings'
import { Download, DownloadProgress } from './download.interface'
import { SongResult, SongSearch } from './search.interface'
import { VersionResult } from './songDetails.interface'
import { UpdateProgress } from './update.interface'
export interface ContextBridgeApi {
@@ -27,18 +25,6 @@ export interface IpcInvokeEvents {
input: void
output: Settings
}
songSearch: {
input: SongSearch
output: SongResult[]
}
getSongDetails: {
input: SongResult['id']
output: VersionResult[]
}
getBatchSongDetails: {
input: number[]
output: VersionResult[]
}
getCurrentVersion: {
input: void
output: string

View File

@@ -1,96 +1,252 @@
/**
* Represents a user's song search query.
*/
export interface SongSearch { // TODO: make limit a setting that's not always 51
query: string
quantity: 'all' | 'any'
similarity: 'similar' | 'exact'
fields: SearchFields
tags: SearchTags
instruments: SearchInstruments
difficulties: SearchDifficulties
minDiff: number
maxDiff: number
limit: number
offset: number
import { EventType, FolderIssueType, MetadataIssueType, NotesData } from 'scan-chart'
import { z } from 'zod'
import { difficulties, instruments, Overwrite } from '../UtilFunctions'
export const GeneralSearchSchema = z.object({
search: z.string(),
page: z.number().positive(),
instrument: z.enum(instruments).nullable(),
difficulty: z.enum(difficulties).nullable(),
})
export type GeneralSearch = z.infer<typeof GeneralSearchSchema>
const md5Validator = z.string().regex(/^[a-f0-9]{32}$/, 'Invalid MD5 hash')
export const AdvancedSearchSchema = z.object({
instrument: z.enum(instruments).nullable(),
difficulty: z.enum(difficulties).nullable(),
name: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
artist: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
album: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
genre: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
year: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
charter: z.object({ value: z.string(), exact: z.boolean(), exclude: z.boolean() }),
minLength: z.number().nullable(),
maxLength: z.number().nullable(),
minIntensity: z.number().nullable(),
maxIntensity: z.number().nullable(),
minAverageNPS: z.number().nullable(),
maxAverageNPS: z.number().nullable(),
minMaxNPS: z.number().nullable(),
maxMaxNPS: z.number().nullable(),
modifiedAfter: z.string().regex(/^\d+-\d{2}-\d{2}$/, 'Invalid date').or(z.literal('')).nullable(),
hash: z.string().transform(data =>
data === '' || data.split(',').every(hash => md5Validator.safeParse(hash).success) ? data : 'invalid'
).nullable(),
hasSoloSections: z.boolean().nullable(),
hasForcedNotes: z.boolean().nullable(),
hasOpenNotes: z.boolean().nullable(),
hasTapNotes: z.boolean().nullable(),
hasLyrics: z.boolean().nullable(),
hasVocals: z.boolean().nullable(),
hasRollLanes: z.boolean().nullable(),
has2xKick: z.boolean().nullable(),
hasIssues: z.boolean().nullable(),
hasVideoBackground: z.boolean().nullable(),
modchart: z.boolean().nullable(),
})
export type AdvancedSearch = z.infer<typeof AdvancedSearchSchema>
export const advancedSearchTextProperties = [
'name',
'artist',
'album',
'genre',
'year',
'charter',
] as const
export const advancedSearchNumberProperties = [
'minLength',
'maxLength',
'minIntensity',
'maxIntensity',
'minAverageNPS',
'maxAverageNPS',
'minMaxNPS',
'maxMaxNPS',
] as const
export const advancedSearchBooleanProperties = [
'hasSoloSections',
'hasForcedNotes',
'hasOpenNotes',
'hasTapNotes',
'hasLyrics',
'hasVocals',
'hasRollLanes',
'has2xKick',
'hasIssues',
'hasVideoBackground',
'modchart',
] as const
export const ReportSchema = z.object({
chartId: z.number().positive(),
reason: z.string(),
extraInfo: z.string(),
})
export type Report = z.infer<typeof ReportSchema>
export type NoteStringNotesData = Overwrite<NotesData, {
maxNps: {
notes: {
type: keyof typeof EventType
}[]
}[]
}>
export interface FolderIssue {
folderIssue: FolderIssueType
description: string
}
export function getDefaultSearch(): SongSearch {
return {
query: '',
quantity: 'all',
similarity: 'similar',
fields: { name: true, artist: true, album: true, genre: true, year: true, charter: true, tag: true },
tags: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'sections': false, 'star power': false, 'forcing': false, 'taps': false, 'lyrics': false,
// eslint-disable-next-line @typescript-eslint/naming-convention
'video': false, 'stems': false, 'solo sections': false, 'open notes': false,
},
instruments: {
guitar: false, bass: false, rhythm: false, keys: false,
drums: false, guitarghl: false, bassghl: false, vocals: false,
},
difficulties: { expert: false, hard: false, medium: false, easy: false },
minDiff: 0,
maxDiff: 6,
limit: 50 + 1,
offset: 0,
}
}
export type ChartData = SearchResult['data'][number]
export interface SearchResult {
found: number
out_of: number
page: number
search_time_ms: number
data: {
/** The song name. */
name: string | null
/** The song artist. */
artist: string | null
/** The song album. */
album: string | null
/** The song genre. */
genre: string | null
/** The song year. */
year: string | null
/** The name of the chart, or `null` if the same as `name`. */
chartName: string | null
/** The genre of the chart, or `null` if the same as `genre`. */
chartGenre: string | null
/** The album of the chart, or `null` if the same as `album`. */
chartAlbum: string | null
/** The year of the chart, or `null` if the same as `year`. */
chartYear: string | null
/** The unique database identifier for the chart. */
chartId: number
/** The unique database identifier for the song, or `null` if there is only one chart of the song. */
songId: number | null
/** The MD5 hash of the normalized album art file. */
albumArtMd5: string | null
/** The MD5 hash of the chart folder or .sng file. */
md5: string
/** The MD5 hash of just the .chart or .mid file. */
chartMd5: string
/**
* Different versions of the same chart have the same `versionGroupId`.
* All charts in a version group have this set to the smallest `id` in the group.
*/
versionGroupId: number
/** The chart's charter(s). */
charter: string | null
/** The length of the chart's audio, in milliseconds. If there are stems, this is the length of the longest stem. */
song_length: number | null
/** The difficulty rating of the chart as a whole. Usually an integer between 0 and 6 (inclusive) */
diff_band: number | null
/** The difficulty rating of the lead guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_guitar: number | null
/** The difficulty rating of the co-op guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_guitar_coop: number | null
/** The difficulty rating of the rhythm guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_rhythm: number | null
/** The difficulty rating of the bass guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_bass: number | null
/** The difficulty rating of the drums chart. Usually an integer between 0 and 6 (inclusive) */
diff_drums: number | null
/** The difficulty rating of the Phase Shift "real drums" chart. Usually an integer between 0 and 6 (inclusive) */
diff_drums_real: number | null
/** The difficulty rating of the keys chart. Usually an integer between 0 and 6 (inclusive) */
diff_keys: number | null
/** The difficulty rating of the GHL (6-fret) lead guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_guitarghl: number | null
/** The difficulty rating of the GHL (6-fret) co-op guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_guitar_coop_ghl: number | null
/** The difficulty rating of the GHL (6-fret) rhythm guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_rhythm_ghl: number | null
/** The difficulty rating of the GHL (6-fret) bass guitar chart. Usually an integer between 0 and 6 (inclusive) */
diff_bassghl: number | null
/** The difficulty rating of the vocals chart. Usually an integer between 0 and 6 (inclusive) */
diff_vocals: number | null
/** The number of milliseconds into the song where the chart's audio preview should start playing. */
preview_start_time: number | null
/** The name of the icon to be displayed on the chart. Usually represents a charter or setlist. */
icon: string | null
/** A text phrase that will be displayed before the chart begins. */
loading_phrase: string | null
/** The ordinal position of the song on the album. This is `undefined` if it's not on an album. */
album_track: number | null
/** The ordinal position of the chart in its setlist. This is `undefined` if it's not on a setlist. */
playlist_track: number | null
/** `true` if the chart is a modchart. This only affects how the chart is filtered and displayed, and doesn't impact gameplay. */
modchart: boolean | null
/** The amount of time the game should delay the start of the track in milliseconds. */
delay: number | null
/** The amount of time the game should delay the start of the track in seconds. */
chart_offset: number | null
/** Overrides the default HOPO threshold with a specified value in ticks. Only applies to .mid charts. */
hopo_frequency: number | null
/** Sets the HOPO threshold to be a 1/8th step. Only applies to .mid charts. */
eighthnote_hopo: boolean | null
/** Overrides the .mid note number for Star Power on 5-Fret Guitar. Valid values are 103 and 116. Only applies to .mid charts. */
multiplier_note: number | null
/**
* The amount of time that should be skipped from the beginning of the video background in milliseconds.
* A negative value will delay the start of the video by that many milliseconds.
*/
video_start_time: number | null
/** `true` if the "drums" track should be interpreted as 5-lane drums. */
five_lane_drums: boolean | null
/** `true` if the "drums" track should be interpreted as 4-lane pro drums. */
pro_drums: boolean | null
/** `true` if the chart's end events should be used to end the chart early. Only applies to .mid charts. */
end_events: boolean | null
/** Data describing properties of the .chart or .mid file. `undefined` if the .chart or .mid file couldn't be parsed. */
notesData: NoteStringNotesData
/** Issues with the chart files. */
folderIssues: FolderIssue[]
/** Issues with the chart's metadata. */
metadataIssues: MetadataIssueType[]
/** `true` if the chart has a video background. */
hasVideoBackground: boolean
/** The date of the last time this chart was modified in Google Drive. */
modifiedTime: string
export interface SearchFields {
name: boolean
artist: boolean
album: boolean
genre: boolean
year: boolean
charter: boolean
tag: boolean
}
export interface SearchTags {
'sections': boolean // Tag inverted
// eslint-disable-next-line @typescript-eslint/naming-convention
'star power': boolean // Tag inverted
'forcing': boolean // Tag inverted
'taps': boolean
'lyrics': boolean
'video': boolean
'stems': boolean
// eslint-disable-next-line @typescript-eslint/naming-convention
'solo sections': boolean
// eslint-disable-next-line @typescript-eslint/naming-convention
'open notes': boolean
}
export interface SearchInstruments {
guitar: boolean
bass: boolean
rhythm: boolean
keys: boolean
drums: boolean
guitarghl: boolean
bassghl: boolean
vocals: boolean
}
export interface SearchDifficulties {
expert: boolean
hard: boolean
medium: boolean
easy: boolean
}
/**
* Represents a single song search result.
*/
export interface SongResult {
id: number
chartCount: number
name: string
artist: string
album: string
genre: string
year: string
/** The Drive ID of the chart's application folder. */
applicationDriveId: string
/** The primary username of the chart's application's applicant, or `null` if packName is not `null` */
applicationUsername: string
/** The name of the pack source, or `null` if the application is not a pack source. */
packName: string | null
/** The `folderId` of the Google Drive folder that contains the chart (or the shortcut to it). */
parentFolderId: string
/**
* A string containing the relative path from the application folder to the `DriveChart`.
*
* Doesn't contain the application folder name, the file name (for file charts), or leading/trailing slashes.
*/
drivePath: string
/** The Drive ID of the chart file, or `null` if the chart is a chart folder. */
driveFileId: string | null
/** The file name of the chart file, or `null` if the chart is a chart folder. */
driveFileName: string | null
/** If there is more than one chart contained inside this `DriveChart`. */
driveChartIsPack: boolean
/**
* A string containing the relative path from the `DriveChart`'s archive to the chart inside the archive.
*
* Doesn't contain the archive name, the chart file name (for file charts), or leading/trailing slashes.
*
* An empty string if the `DriveChart` is not an archive.
*/
archivePath: string
/**
* The name of the .sng file. `null` if the chart is not a .sng file.
*/
chartFileName: string | null
}[]
}

View File

@@ -1,94 +0,0 @@
/**
* Represents a single chart version.
*/
export interface VersionResult {
versionID: number
chartID: number
songID: number
latestVersionID: number
latestSetlistVersionID: number
name: string
chartName: string
artist: string
album: string
genre: string
year: string
songDataIncorrect: boolean
driveData: DriveChart & { inChartPack: boolean }
md5: string
lastModified: string
icon: string
charters: string
charterIDs: string
tags: string | null
songLength: number
diff_band: number
diff_guitar: number
diff_bass: number
diff_rhythm: number
diff_drums: number
diff_keys: number
diff_guitarghl: number
diff_bassghl: number
chartData: ChartData
}
export interface DriveChart {
source: DriveSource
isArchive: boolean
downloadPath: string
filesHash: string
folderName: string
folderID: string
files: DriveFile[]
}
export interface DriveSource {
isSetlistSource: boolean
isDriveFileSource?: boolean
setlistIcon?: string
sourceUserIDs: number[]
sourceName: string
sourceDriveID: string
proxyLink?: string
}
export interface DriveFile {
id: string
name: string
mimeType: string
webContentLink: string
modifiedTime: string
md5Checksum: string
size: string
}
export interface ChartData {
hasSections: boolean
hasStarPower: boolean
hasForced: boolean
hasTap: boolean
hasOpen: {
[instrument: string]: boolean
}
hasSoloSections: boolean
hasLyrics: boolean
is120: boolean
hasBrokenNotes: boolean
noteCounts: {
[instrument in Instrument]: {
[difficulty in ChartedDifficulty]: number
}
}
/** number of seconds */
length: number
/** number of seconds */
effectiveLength: number
}
export type Instrument = 'guitar' | 'bass' | 'rhythm' | 'keys' | 'drums' | 'guitarghl' | 'bassghl' | 'vocals' | 'undefined'
export type ChartedDifficulty = 'x' | 'h' | 'm' | 'e'
export function getInstrumentIcon(instrument: Instrument) {
return `${instrument}.png`
}