Files
Iris/src/js/util/selectors.js
2022-06-18 20:40:56 +12:00

285 lines
7.5 KiB
JavaScript
Executable File

import { createSelector } from 'reselect';
import { indexToArray } from './arrays';
import { isLoading } from './helpers';
import { i18n } from '../locale';
const getItem = (state, uri) => state.core.items[uri];
const getItems = (state) => state.core.items;
const getLoadQueue = (state) => state.ui.load_queue;
const getProcesses = (state) => state.ui.processes;
const getLibrary = (state, uri) => state.core.libraries[uri];
const getLibraries = (state) => state.core.libraries;
const getSearchResults = (state) => state.core.search_results;
const getGridGlowEnabled = (state) => state.ui.grid_glow_enabled;
const getSorts = (state) => state.ui.sort;
const getMopidySettings = (state) => state.mopidy;
const makeItemSelector = (uri) => createSelector(
[getItems],
(items) => {
if (Array.isArray(uri)) {
return indexToArray(items, uri);
}
return items[uri];
},
);
const makeArtistSelector = (uri) => createSelector(
[getItems],
(items) => {
const artist = items[uri];
const albums = artist?.albums_uris ? indexToArray(items, artist.albums_uris) : [];
return {
...artist,
albums,
};
},
);
const makeLoadingSelector = (keys) => createSelector(
[getLoadQueue],
(loadQueue) => isLoading(loadQueue, keys),
);
const getQueueHistory = (state) => state.mopidy.queue_history;
const queueHistorySelector = createSelector(
[getItems, getQueueHistory],
(items, queueHistory) => {
if (!queueHistory || !queueHistory.length) return [];
return queueHistory.map((item) => ({
...item,
...(items[item.uri] || {}),
}));
},
);
const getLibrarySource = (state, name) => state.ui[`library_${name}_source`] || 'all';
const makeLibrarySelector = (name, filtered = true) => createSelector(
[getLibraries, getItems, getLibrarySource],
(libraries, items, source) => {
const selectedLibraries = !filtered || source === 'all'
? indexToArray(libraries).filter((l) => l.type === name)
: indexToArray(libraries, [source]);
const itemUris = selectedLibraries.reduce(
(acc, library) => [...acc, ...library.items_uris],
[],
);
return indexToArray(items, itemUris);
},
);
const makeSearchResultsSelector = (term, type) => createSelector(
[getSearchResults],
(searchResults) => {
if (!searchResults || searchResults.query.term !== term) return [];
return searchResults[type] || [];
},
);
const makeProcessProgressSelector = (keys) => createSelector(
[getProcesses],
(processes) => {
const selectedProcesses = keys
.map((key) => processes[key] || {})
.filter((i) => i.status === 'running');
if (!selectedProcesses.length) return undefined;
let total = 0;
let remaining = 0;
selectedProcesses.forEach((process) => {
if (process.total) total += process.total;
if (process.remaining) remaining += process.remaining;
});
return {
total,
remaining,
percent: total && remaining ? ((total - remaining) / total).toFixed(4) : 0,
};
},
);
const providers = {
playlists: [
{
scheme: 'm3u:',
uri: 'm3u:playlists',
title: i18n('services.mopidy.local'),
},
{
scheme: 'spotify:',
uri: 'spotify:library:playlists',
title: i18n('services.spotify.title'),
},
{
scheme: 'tidal:',
uri: 'tidal:my_playlists',
title: i18n('services.tidal.title'),
},
{
scheme: 'jellyfin:',
uri: 'jellyfin:playlists',
title: i18n('services.jellyfin.title'),
},
],
albums: [
{
scheme: 'local:',
setting_name: 'library_albums_uri',
title: i18n('services.mopidy.local'),
},
{
scheme: 'gmusic:',
uri: 'gmusic:album',
title: i18n('services.google.title'),
},
{
scheme: 'spotify:',
uri: 'spotify:library:albums',
title: i18n('services.spotify.title'),
},
{
scheme: 'tidal:',
uri: 'tidal:my_albums',
title: i18n('services.tidal.title'),
},
{
scheme: 'ytmusic:',
uri: 'ytmusic:album',
title: i18n('services.youtube.title'),
},
{
scheme: 'jellyfin:',
uri: 'jellyfin:albums',
title: i18n('services.jellyfin.title'),
},
],
artists: [
{
scheme: 'local:',
setting_name: 'library_artists_uri',
title: i18n('services.mopidy.local'),
},
{
scheme: 'gmusic:',
uri: 'gmusic:artist',
title: i18n('services.google.title'),
},
{
scheme: 'spotify:',
uri: 'spotify:library:artists',
title: i18n('services.spotify.title'),
},
{
scheme: 'tidal:',
uri: 'tidal:my_artists',
title: i18n('services.tidal.title'),
},
{
scheme: 'ytmusic:',
uri: 'ytmusic:artist',
title: i18n('services.youtube.title'),
},
{
scheme: 'jellyfin:',
uri: 'jellyfin:artists',
title: i18n('services.jellyfin.title'),
},
],
tracks: [
{
scheme: 'local:',
setting_name: 'library_tracks_uri',
title: i18n('services.mopidy.local'),
},
{
scheme: 'spotify:',
uri: 'spotify:library:tracks',
title: i18n('services.spotify.title'),
},
],
moods: [
{
scheme: 'spotify:',
uri: 'spotify:categories',
title: i18n('services.spotify.title'),
},
{
scheme: 'tidal:',
uri: 'tidal:moods',
title: i18n('services.tidal.title'),
},
{
scheme: 'tidal:',
uri: 'tidal:genres',
title: i18n('services.tidal.title'),
},
{
scheme: 'ytmusic:',
uri: 'ytmusic:mood',
title: i18n('services.youtube.title'),
},
],
featured_playlists: [
{
scheme: 'spotify:',
uri: 'spotify:featured',
title: i18n('services.spotify.title'),
},
{
scheme: 'ytmusic:',
uri: 'ytmusic:auto',
title: i18n('services.youtube.title'),
},
],
};
const getProvider = (type, scheme) => providers[type]?.find((p) => p.scheme === scheme);
const getUriSchemes = (state) => state.mopidy.uri_schemes || [];
const applyUriSettingToProviders = (filteredProviders, mopidySettings) => filteredProviders.map(
({ setting_name, ...rest }) => ({
uri: setting_name ? mopidySettings[setting_name] : undefined,
...rest,
}),
);
const makeProvidersSelector = (context) => createSelector(
[getUriSchemes, getMopidySettings],
(schemes, mopidySettings) => {
if (!providers[context]) return [];
const results = providers[context].filter((p) => schemes.indexOf(p.scheme) > -1);
return applyUriSettingToProviders(results, mopidySettings);
},
);
const makeSortSelector = (key, defaultField = 'sort_id') => createSelector(
[getSorts],
(sorts) => [
sorts[key]?.field || defaultField,
sorts[key]?.reverse || false,
],
);
const getSortSelector = (state, key, defaultField = 'sort_id') => {
const result = state.ui.sort[key];
return [
result?.field || defaultField,
result?.reverse || false,
];
};
export {
getItem,
getLibrary,
getGridGlowEnabled,
getLibrarySource,
makeItemSelector,
makeArtistSelector,
makeLibrarySelector,
makeLoadingSelector,
makeSearchResultsSelector,
makeProcessProgressSelector,
queueHistorySelector,
makeProvidersSelector,
getProvider,
makeSortSelector,
getSortSelector,
};