mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-19 18:04:22 +02:00
Add global sort utils
This commit is contained in:
@@ -1,22 +1,19 @@
|
|||||||
import orderBy from 'lodash/orderBy';
|
|
||||||
import shuffle from 'lodash/shuffle';
|
|
||||||
import filter from 'lodash/filter';
|
import filter from 'lodash/filter';
|
||||||
import reverse from 'lodash/reverse';
|
import orderBy from 'lodash/orderBy';
|
||||||
import md5 from 'md5';
|
import md5 from 'md5';
|
||||||
import { fsLog } from '/@/logger';
|
import { fsLog } from '/@/logger';
|
||||||
import { subsonicApiClient } from '/@/renderer/api/subsonic/subsonic-api';
|
import { subsonicApiClient } from '/@/renderer/api/subsonic/subsonic-api';
|
||||||
import { subsonicNormalize } from '/@/renderer/api/subsonic/subsonic-normalize';
|
import { subsonicNormalize } from '/@/renderer/api/subsonic/subsonic-normalize';
|
||||||
import { AlbumListSortType, SubsonicApi } from '/@/renderer/api/subsonic/subsonic-types';
|
import { AlbumListSortType, SubsonicApi } from '/@/renderer/api/subsonic/subsonic-types';
|
||||||
import {
|
import {
|
||||||
AlbumArtistListSort,
|
|
||||||
AlbumListSort,
|
AlbumListSort,
|
||||||
AuthenticationResponse,
|
AuthenticationResponse,
|
||||||
ControllerEndpoint,
|
ControllerEndpoint,
|
||||||
GenreListSort,
|
GenreListSort,
|
||||||
LibraryItem,
|
LibraryItem,
|
||||||
PlaylistListSort,
|
PlaylistListSort,
|
||||||
SongListSort,
|
|
||||||
} from '/@/renderer/api/types';
|
} from '/@/renderer/api/types';
|
||||||
|
import { sortAlbumArtistList, sortSongList } from '/@/renderer/api/utils';
|
||||||
import { randomString } from '/@/renderer/utils';
|
import { randomString } from '/@/renderer/utils';
|
||||||
|
|
||||||
const authenticate = async (
|
const authenticate = async (
|
||||||
@@ -204,7 +201,6 @@ export const SubsonicController: ControllerEndpoint = {
|
|||||||
},
|
},
|
||||||
getAlbumArtistList: async (args) => {
|
getAlbumArtistList: async (args) => {
|
||||||
const { query, apiClientProps } = args;
|
const { query, apiClientProps } = args;
|
||||||
const sortOrder = query.sortOrder.toLowerCase() as 'asc' | 'desc';
|
|
||||||
|
|
||||||
const res = await subsonicApiClient(apiClientProps).getArtists({
|
const res = await subsonicApiClient(apiClientProps).getArtists({
|
||||||
query: {
|
query: {
|
||||||
@@ -221,8 +217,9 @@ export const SubsonicController: ControllerEndpoint = {
|
|||||||
(index) => index.artist,
|
(index) => index.artist,
|
||||||
);
|
);
|
||||||
|
|
||||||
let results = artists;
|
let results = artists.map((artist) =>
|
||||||
let totalRecordCount = artists.length;
|
subsonicNormalize.albumArtist(artist, apiClientProps.server),
|
||||||
|
);
|
||||||
|
|
||||||
if (query.searchTerm) {
|
if (query.searchTerm) {
|
||||||
const searchResults = filter(results, (artist) => {
|
const searchResults = filter(results, (artist) => {
|
||||||
@@ -230,36 +227,16 @@ export const SubsonicController: ControllerEndpoint = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
results = searchResults;
|
results = searchResults;
|
||||||
totalRecordCount = searchResults.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (query.sortBy) {
|
if (query.sortBy) {
|
||||||
case AlbumArtistListSort.ALBUM_COUNT:
|
sortAlbumArtistList(results, query.sortBy, query.sortOrder);
|
||||||
results = orderBy(
|
|
||||||
artists,
|
|
||||||
['albumCount', (v) => v.name.toLowerCase()],
|
|
||||||
[sortOrder, 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case AlbumArtistListSort.NAME:
|
|
||||||
results = orderBy(artists, [(v) => v.name.toLowerCase()], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case AlbumArtistListSort.FAVORITED:
|
|
||||||
results = orderBy(artists, ['starred'], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case AlbumArtistListSort.RATING:
|
|
||||||
results = orderBy(artists, ['userRating'], [sortOrder]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: results.map((artist) =>
|
items: results,
|
||||||
subsonicNormalize.albumArtist(artist, apiClientProps.server),
|
|
||||||
),
|
|
||||||
startIndex: query.startIndex,
|
startIndex: query.startIndex,
|
||||||
totalRecordCount,
|
totalRecordCount: results?.length || 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getAlbumArtistListCount: async (args) => {
|
getAlbumArtistListCount: async (args) => {
|
||||||
@@ -665,7 +642,6 @@ export const SubsonicController: ControllerEndpoint = {
|
|||||||
},
|
},
|
||||||
getPlaylistSongList: async (args) => {
|
getPlaylistSongList: async (args) => {
|
||||||
const { query, apiClientProps } = args;
|
const { query, apiClientProps } = args;
|
||||||
const sortOrder = query.sortOrder.toLowerCase() as 'asc' | 'desc';
|
|
||||||
|
|
||||||
const res = await subsonicApiClient(apiClientProps).getPlaylist({
|
const res = await subsonicApiClient(apiClientProps).getPlaylist({
|
||||||
query: {
|
query: {
|
||||||
@@ -678,95 +654,25 @@ export const SubsonicController: ControllerEndpoint = {
|
|||||||
throw new Error('Failed to get playlist song list');
|
throw new Error('Failed to get playlist song list');
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = res.body['subsonic-response'].playlist.entry || [];
|
let results =
|
||||||
|
res.body['subsonic-response'].playlist.entry?.map((song) =>
|
||||||
|
subsonicNormalize.song(song, apiClientProps.server, ''),
|
||||||
|
) || [];
|
||||||
|
|
||||||
if (query.searchTerm) {
|
if (query.searchTerm) {
|
||||||
const searchResults = filter(results, (entry) => {
|
const searchResults = filter(results, (entry) => {
|
||||||
return entry.title.toLowerCase().includes(query.searchTerm!.toLowerCase());
|
return entry.name.toLowerCase().includes(query.searchTerm!.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
results = searchResults;
|
results = searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.sortBy) {
|
if (query.sortBy) {
|
||||||
switch (query.sortBy) {
|
sortSongList(results, query.sortBy, query.sortOrder);
|
||||||
case SongListSort.ALBUM:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
[(v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[sortOrder, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.ALBUM_ARTIST:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['albumArtist', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[sortOrder, sortOrder, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.ARTIST:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['artist', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[sortOrder, sortOrder, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.DURATION:
|
|
||||||
results = orderBy(results, ['duration'], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case SongListSort.FAVORITED:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['starred', (v) => v.title.toLowerCase()],
|
|
||||||
[sortOrder],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.GENRE:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['genre', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[sortOrder, sortOrder, 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.ID:
|
|
||||||
if (sortOrder === 'desc') {
|
|
||||||
results = reverse(results);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SongListSort.NAME:
|
|
||||||
results = orderBy(results, [(v) => v.title.toLowerCase()], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case SongListSort.PLAY_COUNT:
|
|
||||||
results = orderBy(results, ['playCount'], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case SongListSort.RANDOM:
|
|
||||||
results = shuffle(results);
|
|
||||||
break;
|
|
||||||
case SongListSort.RATING:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['userRating', (v) => v.title.toLowerCase()],
|
|
||||||
[sortOrder],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case SongListSort.RECENTLY_ADDED:
|
|
||||||
results = orderBy(results, ['created'], [sortOrder]);
|
|
||||||
break;
|
|
||||||
case SongListSort.YEAR:
|
|
||||||
results = orderBy(
|
|
||||||
results,
|
|
||||||
['year', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
|
||||||
[sortOrder, 'asc', 'asc', 'asc'],
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: results?.map((song) => subsonicNormalize.song(song, apiClientProps.server, '')),
|
items: results,
|
||||||
startIndex: 0,
|
startIndex: 0,
|
||||||
totalRecordCount: results?.length || 0,
|
totalRecordCount: results?.length || 0,
|
||||||
};
|
};
|
||||||
|
|||||||
+136
-1
@@ -1,8 +1,18 @@
|
|||||||
import { AxiosHeaders } from 'axios';
|
import { AxiosHeaders } from 'axios';
|
||||||
import { z } from 'zod';
|
|
||||||
import { toast } from '/@/renderer/components';
|
import { toast } from '/@/renderer/components';
|
||||||
import { useAuthStore } from '/@/renderer/store';
|
import { useAuthStore } from '/@/renderer/store';
|
||||||
import { ServerListItem } from '/@/renderer/types';
|
import { ServerListItem } from '/@/renderer/types';
|
||||||
|
import {
|
||||||
|
AlbumArtist,
|
||||||
|
AlbumArtistListSort,
|
||||||
|
QueueSong,
|
||||||
|
SongListSort,
|
||||||
|
SortOrder,
|
||||||
|
} from '/@/renderer/api/types';
|
||||||
|
import orderBy from 'lodash/orderBy';
|
||||||
|
import reverse from 'lodash/reverse';
|
||||||
|
import shuffle from 'lodash/shuffle';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
// Since ts-rest client returns a strict response type, we need to add the headers to the body object
|
// Since ts-rest client returns a strict response type, we need to add the headers to the body object
|
||||||
export const resultWithHeaders = <ItemType extends z.ZodTypeAny>(itemSchema: ItemType) => {
|
export const resultWithHeaders = <ItemType extends z.ZodTypeAny>(itemSchema: ItemType) => {
|
||||||
@@ -38,3 +48,128 @@ export const authenticationFailure = (currentServer: ServerListItem | null) => {
|
|||||||
useAuthStore.getState().actions.setCurrentServer(null);
|
useAuthStore.getState().actions.setCurrentServer(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const sortSongList = (songs: QueueSong[], sortBy: SongListSort, sortOrder: SortOrder) => {
|
||||||
|
let results = songs;
|
||||||
|
|
||||||
|
const order = sortOrder === SortOrder.ASC ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case SongListSort.ALBUM:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
[(v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ALBUM_ARTIST:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['albumArtist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ARTIST:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['artist', (v) => v.album?.toLowerCase(), 'discNumber', 'trackNumber'],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.DURATION:
|
||||||
|
results = orderBy(results, ['duration'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.FAVORITED:
|
||||||
|
results = orderBy(results, ['userFavorite', (v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.GENRE:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
[
|
||||||
|
(v) => v.genres?.[0].name.toLowerCase(),
|
||||||
|
(v) => v.album?.toLowerCase(),
|
||||||
|
'discNumber',
|
||||||
|
'trackNumber',
|
||||||
|
],
|
||||||
|
[order, order, 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.ID:
|
||||||
|
if (order === 'desc') {
|
||||||
|
results = reverse(results);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.NAME:
|
||||||
|
results = orderBy(results, [(v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.PLAY_COUNT:
|
||||||
|
results = orderBy(results, ['playCount'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RANDOM:
|
||||||
|
results = shuffle(results);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RATING:
|
||||||
|
results = orderBy(results, ['userRating', (v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.RECENTLY_ADDED:
|
||||||
|
results = orderBy(results, ['created'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SongListSort.YEAR:
|
||||||
|
results = orderBy(
|
||||||
|
results,
|
||||||
|
['year', (v) => v.album?.toLowerCase(), 'discNumber', 'track'],
|
||||||
|
[order, 'asc', 'asc', 'asc'],
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sortAlbumArtistList = (
|
||||||
|
artists: AlbumArtist[],
|
||||||
|
sortBy: AlbumArtistListSort,
|
||||||
|
sortOrder: SortOrder,
|
||||||
|
) => {
|
||||||
|
const order = sortOrder === SortOrder.ASC ? 'asc' : 'desc';
|
||||||
|
|
||||||
|
let results = artists;
|
||||||
|
|
||||||
|
switch (sortBy) {
|
||||||
|
case AlbumArtistListSort.ALBUM_COUNT:
|
||||||
|
results = orderBy(artists, ['albumCount', (v) => v.name.toLowerCase()], [order, 'asc']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.NAME:
|
||||||
|
results = orderBy(artists, [(v) => v.name.toLowerCase()], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.FAVORITED:
|
||||||
|
results = orderBy(artists, ['starred'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlbumArtistListSort.RATING:
|
||||||
|
results = orderBy(artists, ['userRating'], [order]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user