mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Merge pull request #601 from silentrald/feat/216
[feat-216] support for sorting maps/songs and playlists
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
|
||||
export enum Comparison {
|
||||
EQUAL = 0,
|
||||
GREATER = 1,
|
||||
LESSER = -1,
|
||||
};
|
||||
|
||||
export type Comparator<T> = (object1: T, object2: T) => number;
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ObjectValues } from "shared/helpers/type.helpers";
|
||||
import { SongDetailDiffCharactertistic, SongDiffName } from "./song-details-cache/song-details-cache.model";
|
||||
import { BsmLocalMap } from "./bsm-local-map.interface";
|
||||
import { Comparator } from "../comparator.type";
|
||||
|
||||
export interface BsvMapDetail {
|
||||
automapper: boolean;
|
||||
@@ -250,6 +252,11 @@ export interface MapFilter {
|
||||
excludedTags?: Set<MapTag>;
|
||||
}
|
||||
|
||||
export interface MapSort {
|
||||
compare: Comparator<BsmLocalMap>;
|
||||
ascending: boolean;
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
docs: BsvMapDetail[];
|
||||
redirect: string;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Comparison } from "../comparator.type";
|
||||
import { Sorter } from "../sorter.model";
|
||||
import { BsmLocalMap } from "./bsm-local-map.interface";
|
||||
|
||||
const sortName = (map1: BsmLocalMap, map2: BsmLocalMap) => map1.mapInfo.songName.localeCompare(map2.mapInfo.songName);
|
||||
|
||||
export const mapSorter = new Sorter<BsmLocalMap>({
|
||||
comparators: {
|
||||
name: sortName,
|
||||
"song-author": (map1, map2) => map1.mapInfo.songAuthorName.localeCompare(map2.mapInfo.songAuthorName),
|
||||
"map-author": (map1, map2) => {
|
||||
// Compare the number of mappers, else compare the first mapper
|
||||
const difference = map1.mapInfo.levelMappers.length - map2.mapInfo.levelMappers.length;
|
||||
return difference || map1.mapInfo.levelMappers[0].localeCompare(map2.mapInfo.levelMappers[0]);
|
||||
},
|
||||
bpm: (map1, map2) => map1.mapInfo.beatsPerMinute - map2.mapInfo.beatsPerMinute,
|
||||
duration: (map1, map2) => {
|
||||
if (!map1.songDetails) {
|
||||
return map2.songDetails ? Comparison.LESSER : Comparison.EQUAL;
|
||||
}
|
||||
|
||||
return !map2.songDetails ? Comparison.GREATER : map1.songDetails.duration - map2.songDetails.duration;
|
||||
},
|
||||
likes: (map1, map2) => {
|
||||
if (!map1.songDetails) {
|
||||
return map2.songDetails ? Comparison.LESSER : Comparison.EQUAL;
|
||||
}
|
||||
|
||||
return !map2.songDetails ? Comparison.GREATER : map1.songDetails.upVotes - map2.songDetails.upVotes;
|
||||
},
|
||||
"date-uploaded": (map1, map2) => {
|
||||
if (!map1.songDetails) {
|
||||
return map2.songDetails ? Comparison.LESSER : Comparison.EQUAL;
|
||||
}
|
||||
|
||||
return !map2.songDetails ? Comparison.GREATER : map1.songDetails.uploadedAt - map2.songDetails.uploadedAt;
|
||||
},
|
||||
},
|
||||
tiebreak: sortName,
|
||||
defaultKey: "name"
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Comparison } from "../comparator.type";
|
||||
import { Sorter } from "../sorter.model";
|
||||
import { LocalBPListsDetails } from "./local-playlist.models";
|
||||
|
||||
const sortTitle = (playlist1: LocalBPListsDetails, playlist2: LocalBPListsDetails) =>
|
||||
playlist1.playlistTitle.localeCompare(playlist2.playlistTitle);
|
||||
|
||||
export const playlistSorter = new Sorter({
|
||||
comparators: {
|
||||
title: sortTitle,
|
||||
author: (playlist1, playlist2) => playlist1.playlistAuthor.localeCompare(playlist2.playlistAuthor),
|
||||
"number-of-maps": (playlist1, playlist2) => playlist1.nbMaps - playlist2.nbMaps,
|
||||
duration: (playlist1, playlist2) => {
|
||||
if (!playlist1.duration) {
|
||||
return playlist2.duration ? Comparison.LESSER : Comparison.EQUAL;
|
||||
}
|
||||
|
||||
return !playlist2.duration ? Comparison.GREATER : playlist1.duration - playlist2.duration;
|
||||
},
|
||||
"notes-per-second": (playlist1, playlist2) => {
|
||||
if (!playlist1.maxNps) {
|
||||
return playlist2.maxNps ? Comparison.LESSER : Comparison.EQUAL;
|
||||
}
|
||||
|
||||
return !playlist2.maxNps ? Comparison.GREATER : playlist1.maxNps - playlist2.maxNps;
|
||||
},
|
||||
},
|
||||
tiebreak: sortTitle,
|
||||
defaultKey: "title",
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Comparator } from "./comparator.type";
|
||||
|
||||
export type SorterOptions<T> = {
|
||||
defaultKey: string;
|
||||
comparators: Record<string, Comparator<T>>;
|
||||
tiebreak: Comparator<T>;
|
||||
}
|
||||
|
||||
export class Sorter<T> {
|
||||
public readonly defaultKey: string;
|
||||
|
||||
private readonly comparators: Record<string, Comparator<T>>;
|
||||
private readonly tiebreak: Comparator<T>;
|
||||
|
||||
constructor(options: SorterOptions<T>) {
|
||||
this.defaultKey = options.defaultKey;
|
||||
this.comparators = options.comparators;
|
||||
this.tiebreak = options.tiebreak;
|
||||
}
|
||||
|
||||
public getComparatorKeys(): string[] {
|
||||
return Object.keys(this.comparators);
|
||||
}
|
||||
|
||||
public getDefaultComparator(): Comparator<T> {
|
||||
return this.comparators[this.defaultKey];
|
||||
}
|
||||
|
||||
public getComparator(key: string): Comparator<T> {
|
||||
const comparator = this.comparators[key] || this.comparators[this.defaultKey];
|
||||
return this.tiebreak === comparator
|
||||
? comparator
|
||||
: (object1, object2) => comparator(object1, object2) || this.tiebreak(object1, object2);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user