Dynamic library sources working; Need to expand and test other providers

This commit is contained in:
James Barnsley
2021-04-22 21:16:21 +12:00
parent c1493f1a3c
commit faf5f53692
10 changed files with 381 additions and 362 deletions

View File

@ -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>
);
});

View File

@ -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(

View File

@ -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,
};

View File

@ -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,

View File

@ -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),

View File

@ -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,
});