Dynamic library sources working; Need to expand and test other providers
This commit is contained in:
@ -7,40 +7,41 @@ const LinksSentence = memo(({ items, itemType, className, nolinks }) => {
|
||||
return (
|
||||
<span className={`${className} links-sentence`}>
|
||||
{
|
||||
items.map(({ name, uri, type }, index) => {
|
||||
if (!name) return <span>-</span>;
|
||||
items.map(({ name, uri, type }, index) => {
|
||||
if (!name) return <span>-</span>;
|
||||
|
||||
let separator = null;
|
||||
if (index == items.length - 2) {
|
||||
separator = ' and ';
|
||||
} else if (index < items.length - 2) {
|
||||
separator = ', ';
|
||||
}
|
||||
let separator = null;
|
||||
if (index === items.length - 2) {
|
||||
separator = ' and ';
|
||||
} else if (index < items.length - 2) {
|
||||
separator = ', ';
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
var content = <span>-</span>;
|
||||
} else if (!uri || nolinks) {
|
||||
var content = <span>{name}</span>;
|
||||
} else {
|
||||
var content = (
|
||||
<URILink
|
||||
className="links-sentence__item links-sentence__item--link"
|
||||
uri={uri}
|
||||
type={type || itemType}
|
||||
>
|
||||
{name}
|
||||
</URILink>
|
||||
);
|
||||
}
|
||||
let content = null;
|
||||
if (!name) {
|
||||
content = <span>-</span>;
|
||||
} else if (!uri || nolinks) {
|
||||
content = <span>{name}</span>;
|
||||
} else {
|
||||
content = (
|
||||
<URILink
|
||||
className="links-sentence__item links-sentence__item--link"
|
||||
uri={uri}
|
||||
type={itemType || type}
|
||||
>
|
||||
{name}
|
||||
</URILink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span key={`index_${uri}`}>
|
||||
{content}
|
||||
{separator}
|
||||
</span>
|
||||
);
|
||||
})
|
||||
}
|
||||
return (
|
||||
<span key={`index_${uri}`}>
|
||||
{content}
|
||||
{separator}
|
||||
</span>
|
||||
);
|
||||
})
|
||||
}
|
||||
</span>
|
||||
);
|
||||
});
|
||||
|
||||
@ -1857,6 +1857,7 @@ const MopidyMiddleware = (function () {
|
||||
|
||||
request(store, 'library.browse', { uri: action.uri })
|
||||
.then((browseResponse) => {
|
||||
console.debug({ action, browseResponse })
|
||||
const allUris = arrayOf('uri', browseResponse);
|
||||
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
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;
|
||||
@ -97,6 +98,72 @@ const makeProcessProgressSelector = (keys) => createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
const providers = {
|
||||
albums: [
|
||||
{
|
||||
scheme: 'local:',
|
||||
uri: 'local:directory?type=album',
|
||||
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: 'ytmusic:',
|
||||
uri: 'ytmusic:album',
|
||||
title: i18n('services.youtube.title'),
|
||||
},
|
||||
],
|
||||
artists: [
|
||||
{
|
||||
scheme: 'local:',
|
||||
uri: 'local:directory?type=artist&role=albumartist',
|
||||
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: 'ytmusic:',
|
||||
uri: 'ytmusic:artist',
|
||||
title: i18n('services.youtube.title'),
|
||||
},
|
||||
],
|
||||
tracks: [
|
||||
{
|
||||
scheme: 'local:',
|
||||
uri: 'local:directory?type=track',
|
||||
title: i18n('services.mopidy.local'),
|
||||
},
|
||||
{
|
||||
scheme: 'spotify:',
|
||||
uri: 'spotify:library:tracks',
|
||||
title: i18n('services.spotify.title'),
|
||||
},
|
||||
],
|
||||
};
|
||||
const getUriSchemes = (state) => state.mopidy.uri_schemes;
|
||||
const makeProvidersSelector = (context) => createSelector(
|
||||
[getUriSchemes],
|
||||
(schemes) => {
|
||||
return providers[context]?.filter((p) => schemes.indexOf(p.scheme) > -1);
|
||||
},
|
||||
);
|
||||
|
||||
export {
|
||||
getItem,
|
||||
getLibrary,
|
||||
@ -110,4 +177,5 @@ export {
|
||||
makeSearchResultsSelector,
|
||||
makeProcessProgressSelector,
|
||||
queueHistorySelector,
|
||||
makeProvidersSelector,
|
||||
};
|
||||
|
||||
@ -19,6 +19,7 @@ import {
|
||||
makeLibrarySelector,
|
||||
makeProcessProgressSelector,
|
||||
getLibrarySource,
|
||||
makeProvidersSelector,
|
||||
} from '../../util/selectors';
|
||||
|
||||
const processKeys = [
|
||||
@ -71,6 +72,7 @@ class LibraryAlbums extends React.Component {
|
||||
getLibraries = (forceRefetch = false) => {
|
||||
const {
|
||||
source,
|
||||
providers,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
@ -78,7 +80,7 @@ class LibraryAlbums extends React.Component {
|
||||
|
||||
let uris = [];
|
||||
if (source === 'all') {
|
||||
uris = this.sourceOptions().map((o) => o.value).filter((u) => u !== 'all');
|
||||
uris = providers.map((p) => p.uri);
|
||||
} else {
|
||||
uris.push(source);
|
||||
}
|
||||
@ -161,52 +163,12 @@ class LibraryAlbums extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
sourceOptions = () => {
|
||||
const {
|
||||
spotify_available,
|
||||
google_available,
|
||||
youtube_available,
|
||||
} = this.props;
|
||||
const options = [
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
{
|
||||
value: 'local:directory?type=album',
|
||||
label: i18n('services.mopidy.local'),
|
||||
},
|
||||
];
|
||||
|
||||
if (youtube_available) {
|
||||
options.push({
|
||||
value: 'ytmusic:album',
|
||||
label: i18n('services.youtube.title'),
|
||||
});
|
||||
}
|
||||
|
||||
if (google_available) {
|
||||
options.push({
|
||||
value: 'gmusic:album',
|
||||
label: i18n('services.google.title'),
|
||||
});
|
||||
}
|
||||
|
||||
if (spotify_available) {
|
||||
options.push({
|
||||
value: 'spotify:library:albums',
|
||||
label: i18n('services.spotify.title'),
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
sort,
|
||||
view,
|
||||
source,
|
||||
providers,
|
||||
sort_reverse,
|
||||
uiActions,
|
||||
loading_progress,
|
||||
@ -283,7 +245,13 @@ class LibraryAlbums extends React.Component {
|
||||
name={i18n('fields.source')}
|
||||
value={source}
|
||||
valueAsLabel
|
||||
options={this.sourceOptions()}
|
||||
options={[
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
...providers.map((p) => ({ value: p.uri, label: p.title })),
|
||||
]}
|
||||
handleChange={(val) => { uiActions.set({ library_albums_source: val }); uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<Button
|
||||
@ -312,13 +280,12 @@ class LibraryAlbums extends React.Component {
|
||||
|
||||
const librarySelector = makeLibrarySelector('albums');
|
||||
const processProgressSelector = makeProcessProgressSelector(processKeys);
|
||||
const providersSelector = makeProvidersSelector('albums');
|
||||
const mapStateToProps = (state) => ({
|
||||
loading_progress: processProgressSelector(state),
|
||||
uri_schemes: state.mopidy.uri_schemes,
|
||||
albums: librarySelector(state, 'albums'),
|
||||
spotify_available: state.spotify.access_token,
|
||||
google_available: state.mopidy?.uri_schemes?.includes('gmusic:'),
|
||||
youtube_available: state.mopidy?.uri_schemes?.includes('ytmusic:'),
|
||||
providers: providersSelector(state),
|
||||
view: state.ui.library_albums_view,
|
||||
source: getLibrarySource(state, 'albums'),
|
||||
sort: state.ui.library_albums_sort,
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
makeLibrarySelector,
|
||||
makeProcessProgressSelector,
|
||||
getLibrarySource,
|
||||
makeProvidersSelector,
|
||||
} from '../../util/selectors';
|
||||
|
||||
const processKeys = [
|
||||
@ -89,6 +90,7 @@ class LibraryArtists extends React.Component {
|
||||
getLibraries = (forceRefetch = false) => {
|
||||
const {
|
||||
source,
|
||||
providers,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
@ -96,54 +98,13 @@ class LibraryArtists extends React.Component {
|
||||
|
||||
let uris = [];
|
||||
if (source === 'all') {
|
||||
uris = this.sourceOptions().map((o) => o.value).filter((u) => u !== 'all');
|
||||
uris = providers.map((p) => p.uri);
|
||||
} else {
|
||||
uris.push(source);
|
||||
}
|
||||
uris.forEach((uri) => loadLibrary(uri, 'artists', { forceRefetch }));
|
||||
};
|
||||
|
||||
sourceOptions = () => {
|
||||
const {
|
||||
spotify_available,
|
||||
youtube_available,
|
||||
google_available,
|
||||
} = this.props;
|
||||
const options = [
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
{
|
||||
value: 'local:directory?type=artist&role=albumartist',
|
||||
label: i18n('services.mopidy.local'),
|
||||
},
|
||||
];
|
||||
|
||||
if (youtube_available) {
|
||||
options.push({
|
||||
value: 'ytmusic:artist',
|
||||
label: i18n('services.youtube.title'),
|
||||
});
|
||||
}
|
||||
|
||||
if (google_available) {
|
||||
options.push({
|
||||
value: 'gmusic:artist',
|
||||
label: i18n('services.google.title'),
|
||||
});
|
||||
}
|
||||
|
||||
if (spotify_available) {
|
||||
options.push({
|
||||
value: 'spotify:library:artists',
|
||||
label: i18n('services.spotify.title'),
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
renderView = () => {
|
||||
const {
|
||||
sort,
|
||||
@ -190,7 +151,10 @@ class LibraryArtists extends React.Component {
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { loading_progress } = this.props;
|
||||
const {
|
||||
loading_progress,
|
||||
providers,
|
||||
} = this.props;
|
||||
|
||||
const view_options = [
|
||||
{
|
||||
@ -251,7 +215,13 @@ class LibraryArtists extends React.Component {
|
||||
name={i18n('fields.source')}
|
||||
value={this.props.source}
|
||||
valueAsLabel
|
||||
options={this.sourceOptions()}
|
||||
options={[
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
...providers.map((p) => ({ value: p.uri, label: p.title })),
|
||||
]}
|
||||
handleChange={(value) => { this.props.uiActions.set({ library_artists_source: value }); this.props.uiActions.hideContextMenu(); }}
|
||||
/>
|
||||
<Button
|
||||
@ -280,12 +250,11 @@ class LibraryArtists extends React.Component {
|
||||
|
||||
const librarySelector = makeLibrarySelector('artists');
|
||||
const processProgressSelector = makeProcessProgressSelector(processKeys);
|
||||
const providersSelector = makeProvidersSelector('artists');
|
||||
const mapStateToProps = (state) => ({
|
||||
loading_progress: processProgressSelector(state),
|
||||
uri_schemes: state.mopidy.uri_schemes,
|
||||
spotify_available: (state.spotify.access_token),
|
||||
google_available: state.mopidy?.uri_schemes?.includes('gmusic:'),
|
||||
youtube_available: state.mopidy?.uri_schemes?.includes('ytmusic:'),
|
||||
providers: providersSelector(state),
|
||||
artists: librarySelector(state, 'artists'),
|
||||
source: getLibrarySource(state, 'artists'),
|
||||
sort: (state.ui.library_artists_sort ? state.ui.library_artists_sort : null),
|
||||
|
||||
@ -19,6 +19,7 @@ import {
|
||||
makeLibrarySelector,
|
||||
makeProcessProgressSelector,
|
||||
getLibrarySource,
|
||||
makeProvidersSelector,
|
||||
} from '../../util/selectors';
|
||||
|
||||
const processKeys = [
|
||||
@ -43,16 +44,14 @@ class LibraryTracks extends React.Component {
|
||||
} = this.props;
|
||||
|
||||
setWindowTitle(i18n('library.tracks.title'));
|
||||
this.getMopidyLibrary();
|
||||
this.getSpotifyLibrary();
|
||||
this.getLibraries();
|
||||
}
|
||||
|
||||
componentDidUpdate = ({ source: prevSource }) => {
|
||||
const { source } = this.props;
|
||||
|
||||
if (source !== prevSource) {
|
||||
this.getMopidyLibrary();
|
||||
this.getSpotifyLibrary();
|
||||
this.getLibraries();
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,8 +59,7 @@ class LibraryTracks extends React.Component {
|
||||
const { uiActions: { hideContextMenu } } = this.props;
|
||||
|
||||
hideContextMenu();
|
||||
this.getMopidyLibrary(true);
|
||||
this.getSpotifyLibrary(true);
|
||||
this.getLibraries(true);
|
||||
}
|
||||
|
||||
cancelRefresh = () => {
|
||||
@ -71,32 +69,22 @@ class LibraryTracks extends React.Component {
|
||||
cancelProcess(processKeys);
|
||||
}
|
||||
|
||||
getMopidyLibrary = (forceRefetch = false) => {
|
||||
getLibraries = (forceRefetch = false) => {
|
||||
const {
|
||||
source,
|
||||
providers,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (source !== 'local' && source !== 'all') return;
|
||||
|
||||
loadLibrary('mopidy:library:tracks', 'tracks', { forceRefetch });
|
||||
};
|
||||
|
||||
getSpotifyLibrary = (forceRefetch = false) => {
|
||||
const {
|
||||
source,
|
||||
spotify_available,
|
||||
coreActions: {
|
||||
loadLibrary,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (!spotify_available) return;
|
||||
if (source !== 'spotify' && source !== 'all') return;
|
||||
|
||||
loadLibrary('spotify:library:tracks', 'tracks', { forceRefetch });
|
||||
let uris = [];
|
||||
if (source === 'all') {
|
||||
uris = providers.map((p) => p.uri);
|
||||
} else {
|
||||
uris.push(source);
|
||||
}
|
||||
uris.forEach((uri) => loadLibrary(uri, 'tracks', { forceRefetch }));
|
||||
};
|
||||
|
||||
handleContextMenu = (e, item) => {
|
||||
@ -192,9 +180,9 @@ class LibraryTracks extends React.Component {
|
||||
|
||||
render = () => {
|
||||
const {
|
||||
spotify_available,
|
||||
sort,
|
||||
source,
|
||||
providers,
|
||||
sort_reverse,
|
||||
uiActions,
|
||||
loading_progress,
|
||||
@ -203,24 +191,6 @@ class LibraryTracks extends React.Component {
|
||||
filter,
|
||||
} = this.state;
|
||||
|
||||
const source_options = [
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
{
|
||||
value: 'local',
|
||||
label: i18n('services.mopidy.local'),
|
||||
},
|
||||
];
|
||||
|
||||
if (spotify_available) {
|
||||
source_options.push({
|
||||
value: 'spotify',
|
||||
label: i18n('services.spotify.title'),
|
||||
});
|
||||
}
|
||||
|
||||
const sort_options = [
|
||||
{
|
||||
value: null,
|
||||
@ -261,8 +231,19 @@ class LibraryTracks extends React.Component {
|
||||
name={i18n('fields.source')}
|
||||
value={source}
|
||||
valueAsLabel
|
||||
options={source_options}
|
||||
handleChange={(val) => { uiActions.set({ library_tracks_source: val }); uiActions.hideContextMenu(); }}
|
||||
options={[
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n('fields.filters.all'),
|
||||
},
|
||||
...providers.map((p) => ({ value: p.uri, label: p.title })),
|
||||
]}
|
||||
handleChange={
|
||||
(val) => {
|
||||
uiActions.set({ library_tracks_source: val });
|
||||
uiActions.hideContextMenu();
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
onClick={this.playAll}
|
||||
@ -299,13 +280,14 @@ class LibraryTracks extends React.Component {
|
||||
|
||||
const librarySelector = makeLibrarySelector('tracks');
|
||||
const processProgressSelector = makeProcessProgressSelector(processKeys);
|
||||
const providersSelector = makeProvidersSelector('tracks');
|
||||
const mapStateToProps = (state) => ({
|
||||
loading_progress: processProgressSelector(state),
|
||||
mopidy_uri_schemes: state.mopidy.uri_schemes,
|
||||
tracks: librarySelector(state),
|
||||
spotify_available: state.spotify.access_token,
|
||||
tracks: librarySelector(state, 'tracks'),
|
||||
view: state.ui.library_tracks_view,
|
||||
source: getLibrarySource(state, 'tracks'),
|
||||
providers: providersSelector(state),
|
||||
sort: state.ui.library_tracks_sort,
|
||||
sort_reverse: state.ui.library_tracks_sort_reverse,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user